diff --git a/Dependency Management/Dependency Management.md b/Dependency Management/Dependency Management.md index 9b742ca..ca54639 100644 --- a/Dependency Management/Dependency Management.md +++ b/Dependency Management/Dependency Management.md @@ -4,6 +4,47 @@ External dependencies should be added to your project only after careful conside Software built with many dependencies starts to feel a bit like "software engineering with duct tape" and will become a maintenance nightmare down the road. Simply put, fewer dependencies leads to a better understanding of the code and gives you more control over its evolution over time. +## Bundler + +[Bundler](https://https://bundler.io/) is the preferred mechanism for managing the gems needed to build our iOS apps. + +### Understanding `bundle` Commands + +Knowing when to use `bundle install` vs `bundle update`, or even what the differences between the commands are, can be tricky. In summary: + +* `bundle install` + * Fetches and installs the dependencies listed in the `Gemfile` according to the versions listed in the `Gemfile.lock`. This is the first command you'll use to install dependencies when you initially check out a repository as well as when you add or remove dependencies from the `Gemfile`. + * If no `Gemfile.lock` is present, then the latest available versions of each dependency will be used (and a new `Gemfile.lock` generated). +* `bundle update` + * Updates all dependencies, respecting any version locks present in the `Gemfile`. For example, if you lock a dependency down to version `2.0.0`, but version `3.1.0` is available, then Bundler will continue to use version `2.0.0`. This is the reason we recommend letting the `Gemfile.lock` handle versioning rather than manually defining version locks in the `Gemfile`. +* `bundle update ` + * Updates a specific dependency, again respecting any version locks present in the `Gemfile`. + +### Versioning Ruby Gems + +The `Gemfile.lock` should always be checked in to source control, as it contains the versioning information for the dependencies specified in the `Gemfile`. In general, it's not necessary to define explicit versions in your `Gemfile` because the `Gemfile.lock` will take care of this for you. In many cases, locking down your `Gemfile` with explicit version numbers will make it more difficult for you to quickly update the dependencies using the `bundle update` command. + +In summary, we prefer `Gemfile` entries like this: + +```ruby +gem 'cocoapods' +``` + +We discourage `Gemfile` entries like this: + +```ruby +gem 'cocoapods', '1.9.3' +``` + +Your `Gemfile` makes use of the pessimistic version operator (`~>`) which can be a good middle ground, since it will still allow `bundle update` to work until the next major/minor version is released. In the example below, `bundle update` would continue to update `cocoapods` up until version `2.0` and `fastlane` up until version `2.150.0`: + +```ruby +gem 'cocoapods', '~> 1.0' +gem 'fastlane', "~> 2.149.1" +``` + +Though `bundle update` can make updating dependencies a breeze, you should always take an extra few minutes to read the release notes for the dependencies being updated. Even if there are no obvious changes, it is generally a good idea to know how the dependencies you rely on change over time. + ## CocoaPods [CocoaPods](https://cocoapods.org/) is the preferred mechanism for managing dependencies in our iOS apps. @@ -15,9 +56,27 @@ In order to keep repository size as minimal as possible, most of our apps do not * Primarily deal with sensitive data or financial transactions. For these apps, we will check in the `Pods` folder so that we can more easily audit the changes made to third party libraries as they are updated over time. * Require a non-BR build environment. Some client build environments don't allow network connections during the build process so all pod sources need to be present in the repository at build-time. +### Understanding `pod` Commands + +Assuming you are using Bundler and have not installed Cocoapods globally all of these commands are used. If you **have** install Cocoapods globally simply use `pod ` instead of `bundle exec pod `. + +Knowing when to use `bundle exec pod install` vs `bundle exec pod update`, or even what the differences between the commands are, can be tricky. In summary: + +* `bundle exec pod install` + * Fetches and installs the dependencies listed in the `Podfile` according to the versions listed in the `Podfile.lock`. This is the main command you'll use to install dependencies when you initially check out a repository as well as when you add or remove dependencies from the `Podfile`. + * If no `Podfile.lock` is present, then the latest available versions of each dependency will be used (and a new `Podfile.lock` generated). +* `bundle exec pod update` + * Updates all dependencies, respecting any version locks present in the `Podfile`. For example, if you lock a dependency down to version `2.0.0`, but version `3.1.0` is available, then Cocoapods will continue to use version `2.0.0`. This is the reason we recommend letting the `Podfile.lock` handle versioning rather than manually defining version locks in the `Podfile`. +* `bundle exec pod update ` + * Updates a specific dependency, again respecting any version locks present in the `Podfile`. +* `bundle exec pod repo update` + * Updates your local copy of the [Cocoapods master repo](https://github.com/CocoaPods/Specs). You need to run this command periodically to make sure your local Cocoapods installation is aware of the latest versions of pods available during `bundle exec pod install` and `bundle exec pod update` commands. +* `bundle exec pod deintegrate` + * Completely removes all traces of Cocoapods from your project. This really only needs to be run when there is a problem since it will rework your project's structure, which can lead to nasty merge conflicts. + ### Versioning Pods -The `Podfile.lock` should always be checked in to source control, as it contains the versioning information for the dependencies specified in the `Podfile`. In general, it's not necessary to define explicit versions in your `Podfile` because the `Podfile.lock` will take care of this for you. In many cases, locking down your `Podfile` with explicit version numbers will make it more difficult for you to quickly update the dependencies using the `pod update` command. +Similar to the `Gemfile.lock`, the `Podfile.lock` should always be checked in to source control, as it contains the versioning information for the dependencies specified in the `Podfile`. Here too, you should avoid defining explicit versions in your `Podfile` because the `Podfile.lock` will take care of this for you. In many cases, locking down your `Podfile` with explicit version numbers will make it more difficult for you to quickly update the dependencies using the `bundle exec pod update` command. In summary, we prefer `Podfile` entries like this: @@ -31,29 +90,13 @@ We discourage `Podfile` entries like this: pod 'Hyperspace', '2.0.0' ``` -If you really do feel you have a need to lock down your dependencies in the `Podfile`, the `~>` operator can be a good middle ground, since it will still allow `pod update` to work until the next major/minor version is released. In the example below, `pod update` would continue to update the dependency up until version `3.0`: +If you really do feel you have a need to lock down your dependencies in the `Podfile`, the `~>` operator can be a good middle ground, since it will still allow `bundle exec pod update` to work until the next major/minor version is released. In the example below, `bundle exec pod update` would continue to update the dependency up until version `3.0`: ```ruby pod 'Hyperspace', '~> 2.0' ``` -Though `pod update` can make updating dependencies a breeze, you should always take an extra few minutes to read the release notes for the dependencies being updated. Even if there are no obvious syntax changes, it is generally a good idea to know how the dependencies you rely on change over time. - -### Understanding `pod` Commands - -Knowing when to use `pod install` vs `pod update`, or even what the differences between the commands are can be tricky. In summary: - -* `pod install` - * Fetches and installs the dependencies listed in the `Podfile` according to the versions listed in the `Podfile.lock`. This is the main command you'll use to install dependencies when you initially check out a repository as well as when you add or remove dependencies from the `Podfile`. - * If no `Podfile.lock` is present, then the latest available versions of each dependency will be used (and a new `Podfile.lock` generated). -* `pod update` - * Updates all dependencies, respecting any version locks present in the `Podfile`. For example, if you lock a dependency down to version `2.0.0`, but version `3.1.0` is available, then Cocoapods will continue to use version `2.0.0`. This is the reason we recommend letting the `Podfile.lock` handle versioning rather than manually defining version locks in the `Podfile`. -* `pod update ` - * Updates a specific dependency, again respecting any version locks present in the `Podfile`. -* `pod repo update` - * Updates your local copy of the [Cocoapods master repo](https://github.com/CocoaPods/Specs). You need to run this command periodically to make sure your local Cocoapods installation is aware of the latest versions of pods available during `pod install` and `pod update` commands. -* `pod deintegrate` - * Completely removes all traces of Cocoapods from your project. This really only needs to be run when there is a problem since it will rework your project's structure, which can lead to nasty merge conflicts. +When using `bundle exec pod update` you should always take an extra few minutes to read the release notes for the dependencies being updated the same way you are for your gems. Even if there are no obvious syntax changes, it is generally a good idea to know how the dependencies you rely on change over time. ## Carthage diff --git a/Development Environment/Development Environment.md b/Development Environment/Development Environment.md index 7e44a97..43aa637 100644 --- a/Development Environment/Development Environment.md +++ b/Development Environment/Development Environment.md @@ -18,21 +18,53 @@ We prefer to keep our development environment as close to "stock" as possible. T We make use of [GitHub's Swift gitignore](https://github.com/github/gitignore/blob/master/Swift.gitignore) as the default gitignore for our projects. The only change that we typically make is uncommenting the `Pods/` line so that the [`Pods` folder isn't included in source control](../Dependency%20Management/Dependency%20Management.md#checking-in-the-pods-folder). +## Bundler + +Many developers naively use the built-in system Ruby to install gems such as Bundler using the `sudo gem install bundler` command. Unfortunately, this can lead to headaches due to the use of `sudo`. + +The better way to install Bundler is to get off the system Ruby and use a Ruby version manager to negate the need for `sudo` access when installing or executing gems. Follow the instructions in [Ruby Environment Setup](./Ruby%20Environment%20Setup.md) to install and setup [`rbenv`](https://github.com/rbenv/rbenv). + +Once your Ruby is properly setup, installing Bundler is as simple as: + +```bash +gem install Bundler +``` + +In order to use bundler in your repo you'll need to create a Gemfile to manage your dependencies. To create that file while in your repo's root directory use: + +```bash +touch Gemfile +``` + +Now you can simply add gems to this file using the text editor of your choice. + +To install all the gems in your Gemfile simply use the command: + +```bash +bundle install +``` + +For information on managing dependencies, both cocoapods and gems, see [Dependency Management.md](./Dependency%20Management/Dependency%20Management.md). + ## Cocoapods -Many developers naively use the built-in system Ruby to install Cocoapods using the `sudo gem install cocoapods` command. Unfortunately, this can lead to headaches due to the use of `sudo`. +Once Bundler is properly setup, adding Cocoapods as a dependency is as simple as adding it to your Gemfile: -The better way to install Cocoapods is to get off the system Ruby and use a Ruby version manager to negate the need for `sudo` access when installing or executing gems. Follow the instructions in [Ruby Environment Setup](./Ruby%20Environment%20Setup.md) to install and setup [`rbenv`](https://github.com/rbenv/rbenv). +``` +gem 'cocoapods' +``` -Once your Ruby is properly setup, installing Cocoapods is as simple as: +Then install it by using: ```bash -gem install cocoapods +bundle install ``` +For information on managing dependencies, both cocoapods and gems, see [Dependency Management.md](./Dependency%20Management/Dependency%20Management.md). + ## Fastlane -[Fastlane](https://fastlane.tools/) is our main build tool. Again, a Ruby version manager should be used so that a `sudo`-less installation of Fastlane can be achieved. +[Fastlane](https://fastlane.tools/) is our main build tool. Again, Bundler should be used so that a `sudo`-less `non`global installation of Fastlane can be achieved. ## Build Servers