Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bundler #27

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 62 additions & 19 deletions Dependency Management/Dependency Management.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <gem_name>`
* 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.
Expand All @@ -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 <command>` instead of `bundle exec pod <command>`.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you think it's better to default to bundle exec pod <command> and have a note to remove bundle exec if Cocoapods is installed globally, or if we should default to pod <command> and have a note about prefixing it with bundle exec if you're using Cocoapods installed with Bundler

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually default to bundle exec <command> but I'm not sure if that's just me.


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 <pod_name>`
* 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:

Expand All @@ -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 <pod_name>`
* 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

Expand Down
42 changes: 37 additions & 5 deletions Development Environment/Development Environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth mentioning the Gemfile.lock and it uses for keeping pinning to specific versions of Gems (and it should be committed to the repository)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely worth mentioning! We have info about the Podfile.lock in the Dependency Management section. Stuff about the Gemfile/Gemfile.lock might technically belong there, since it's how you manage your project's "meta" dependencies (e.g. Fastlane, Cocoapods, etc.). In any case, we should probably create some sort of link between these two sections.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated Dependency Management to include information on Bundler as well as added a link to more information about dependency management in both the Cocoapods and Bundler sections here.

```

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

Expand Down