Skip to content

Commit

Permalink
Add explicit bundler:config step to support 2.1+ (#122)
Browse files Browse the repository at this point in the history
* Add explicit bundler:config step to support 2.1+

Starting with Bundler 2.1, the `--path`, `--without`, and `--deployment`
options are deprecated. In other words you are no longer supposed to
specify these when running `bundle install`.

Instead, Bundler wants you to set these options _externally_ from the
install command. That way all subsequent invocations of bundler can use
the same external configuration without you having to remember which
flags to use each time.

There are two ways to specify this external configuration: providing
environment variables, or running `bundle config`. This commit
implements the latter.

To summarize, prior to running `bundle check`, `bundle install`, or
`bundle clean`, Capistrano will now run a new `bundler:config` task.
This task executes the following command as many times as needed:

```
bundle config --local KEY VALUE
```

Each execution sets the external Bundler configuration KEY to VALUE.

The following Capistrano variables are automatically consulted to get
theses KEYs and VALUEs:

- :bundle_gemfile
- :bundle_path
- :bundle_without

This commit also introduces a new variable:

- bundle_config

It is a Hash that can contain any arbitrary KEY and VALUE pairs to send
to `bundle config`. By default it has a single entry:

```
set :bundle_config, { deployment: true }
```

Finally, this commit removes `--deployment` option from the default
value of `:bundle_flags`, since that flag is deprecated. It has been
replaced by the default `:bundle_config` as mentioned above.

* Handle nil :bundle_config
  • Loading branch information
mattbrictson committed Jul 11, 2020
1 parent 4a1bb75 commit 148b31f
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 26 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ Configurable options:

```ruby
set :bundle_roles, :all # this is default
set :bundle_config, { deployment: true } # this is default
set :bundle_servers, -> { release_roles(fetch(:bundle_roles)) } # this is default
set :bundle_binstubs, -> { shared_path.join('bin') } # default: nil
set :bundle_gemfile, -> { release_path.join('MyGemfile') } # default: nil
set :bundle_path, -> { shared_path.join('bundle') } # this is default. set it to nil for skipping the --path flag.
set :bundle_path, -> { shared_path.join('bundle') } # this is default. set it to nil to use bundler's default path
set :bundle_without, %w{development test}.join(' ') # this is default
set :bundle_flags, '--deployment --quiet' # this is default
set :bundle_flags, '--quiet' # this is default
set :bundle_env_variables, {} # this is default
set :bundle_clean_options, "" # this is default. Use "--dry-run" if you just want to know what gems would be deleted, without actually deleting them
set :bundle_check_before_install, true # default: true. Set this to false to bypass running `bundle check` before executing `bundle install`
Expand All @@ -96,19 +97,18 @@ To generate binstubs on each deploy, set `:bundle_binstubs` path:
set :bundle_binstubs, -> { shared_path.join('bin') }
```

In the result this would execute the following bundle command on all servers
In the result this would execute the following bundle commands on all servers
(actual paths depend on the real deploy directory):

```sh
$ bundle install \
--binstubs /my_app/shared/bin \
--gemfile /my_app/releases/20130623094732/MyGemfile \
--path /my_app/shared/bundle \
--without development test \
--deployment --quiet
$ bundle config --local deployment true
$ bundle config --local gemfile /my_app/releases/20130623094732/MyGemfile
$ bundle config --local path /my_app/shared/bundle
$ bundle config --local without "development test"
$ bundle install --quiet --binstubs /my_app/shared/bin
```

If any option is set to `nil` it will be excluded from the final bundle command.
If any option is set to `nil` it will be excluded from the final bundle commands.

If you want to clean up gems after a successful deploy, add `after 'deploy:published', 'bundler:clean'` to config/deploy.rb.

Expand Down
61 changes: 45 additions & 16 deletions lib/capistrano/tasks/bundler.cap
Original file line number Diff line number Diff line change
@@ -1,40 +1,67 @@
require "shellwords"

namespace :bundler do
desc <<-DESC
Install the current Bundler environment. By default, gems will be \
installed to the shared/bundle path. Gems in the development and \
test group will not be installed. The install command is executed \
with the --deployment and --quiet flags.
Configure the Bundler environment for the release so that subequent
`bundle check`, `bundle install`, `bundle clean`, and `bundle exec`
commands all behave consistently. The following settings will be
turned into the appropriate `bundle config` executions:

:bundle_config
:bundle_gemfile
:bundle_path
:bundle_without
DESC
task :config do
on fetch(:bundle_servers) do
within release_path do
with fetch(:bundle_env_variables) do
configuration = fetch(:bundle_config).dup || {}
configuration[:gemfile] = fetch(:bundle_gemfile)
configuration[:path] = fetch(:bundle_path)
configuration[:without] = fetch(:bundle_without)

configuration.each do |key, value|
execute :bundle, "config", "--local", key, value.to_s.shellescape unless value.nil?
end
end
end
end
end

desc <<-DESC
Install the current Bundler environment. By default, gems will be
installed to the shared/bundle path. Gems in the development and
test group will not be installed. The install command is executed
with the --quiet and --jobs=4 flags.

By default, bundler will not be run on servers with no_release: true.

You can override any of these defaults by setting the variables shown below.

set :bundle_roles, :all

set :bundle_config, { deployment: true }
set :bundle_servers, -> { release_roles(fetch(:bundle_roles)) }
set :bundle_binstubs, -> { shared_path.join('bin') }
set :bundle_binstubs, nil
set :bundle_gemfile, -> { release_path.join('Gemfile') }
set :bundle_path, -> { shared_path.join('bundle') }
set :bundle_without, %w{development test}.join(' ')
set :bundle_flags, '--deployment --quiet'
set :bundle_jobs, nil
set :bundle_flags, '--quiet'
set :bundle_jobs, 4
set :bundle_env_variables, {}
set :bundle_clean_options, ""
DESC
task :install do
task install: :config do
on fetch(:bundle_servers) do
within release_path do
with fetch(:bundle_env_variables) do
options = []
options << "--gemfile #{fetch(:bundle_gemfile)}" if fetch(:bundle_gemfile)
options << "--path #{fetch(:bundle_path)}" if fetch(:bundle_path)

if fetch(:bundle_check_before_install) && test(:bundle, :check, *options)
if fetch(:bundle_check_before_install) && test(:bundle, :check)
info "The Gemfile's dependencies are satisfied, skipping installation"
else
options = []
options << "--binstubs #{fetch(:bundle_binstubs)}" if fetch(:bundle_binstubs)
options << "--jobs #{fetch(:bundle_jobs)}" if fetch(:bundle_jobs)
options << "--without #{fetch(:bundle_without)}" if fetch(:bundle_without)
options << "#{fetch(:bundle_flags)}" if fetch(:bundle_flags)
execute :bundle, :install, *options
end
Expand All @@ -56,7 +83,7 @@ namespace :bundler do
end

desc "Remove unused gems installed by bundler"
task :clean do
task clean: :config do
on fetch(:bundle_servers) do
within release_path do
with fetch(:bundle_env_variables) do
Expand All @@ -76,12 +103,14 @@ namespace :load do
set :bundle_bins, %w{gem rake rails}

set :bundle_roles, :all

set :bundle_config, { deployment: true }
set :bundle_servers, -> { release_roles(fetch(:bundle_roles)) }
set :bundle_binstubs, nil
set :bundle_gemfile, nil
set :bundle_path, -> { shared_path.join('bundle') }
set :bundle_without, %w{development test}.join(' ')
set :bundle_flags, '--deployment --quiet'
set :bundle_flags, '--quiet'
set :bundle_jobs, 4
set :bundle_env_variables, {}
set :bundle_clean_options, ""
Expand Down

0 comments on commit 148b31f

Please sign in to comment.