ndr_dev_support 3.1.3 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +13 -0
- data/code_safety.yml +39 -11
- data/lib/ndr_dev_support/capistrano/assets.rb +23 -0
- data/lib/ndr_dev_support/capistrano/ndr_model.rb +175 -0
- data/lib/ndr_dev_support/capistrano/restart.rb +9 -0
- data/lib/ndr_dev_support/capistrano/revision_logger.rb +14 -0
- data/lib/ndr_dev_support/capistrano/ruby_version.rb +10 -0
- data/lib/ndr_dev_support/capistrano/standalone_gems.rb +30 -0
- data/lib/ndr_dev_support/capistrano/svn_cache.rb +23 -0
- data/lib/ndr_dev_support/capistrano/sysadmin_scripts.rb +25 -0
- data/lib/ndr_dev_support/daemon/ci_server.rb +37 -1
- data/lib/ndr_dev_support/integration_testing/drivers/chrome.rb +1 -0
- data/lib/ndr_dev_support/integration_testing/drivers/chrome_headless.rb +1 -0
- data/lib/ndr_dev_support/tasks.rb +0 -1
- data/lib/ndr_dev_support/version.rb +1 -1
- data/ndr_dev_support.gemspec +5 -1
- metadata +43 -8
- data/lib/tasks/ci/bundle_install.rake +0 -21
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: a77c75ad60b45a91190083d470912db589015a7237713b510b9aa4b6cfc03284
         | 
| 4 | 
            +
              data.tar.gz: 9ddefdc49d88b6d445586537284590fb656fb8a97425c77e7881660bfb8f467d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: dd8c7362ccb13351c211cb068a61fe660a2f4fa36b7bc93d98b5f2c395a93cfa23e503ddb07578382d631e617a1c06593c32d53c3cbfa40fffc29103f92880ba
         | 
| 7 | 
            +
              data.tar.gz: 9534b04645eae6cae4d72902773f04809f8488c6a342e07e7fbf762da02372194c21f6ce0713a66856fb3034c04e341c861b939427c3205c5e37ae8d18f170a5
         | 
    
        data/README.md
    CHANGED
    
    | @@ -6,6 +6,7 @@ providing: | |
| 6 6 | 
             
            1. rake tasks to manage code auditing of ruby based projects
         | 
| 7 7 | 
             
            2. rake tasks to limit Rubocop's output to changed (and related) code
         | 
| 8 8 | 
             
            3. integration testing support, which can be required from a project's `test_helper.rb`
         | 
| 9 | 
            +
            4. Deployment support, through Capistrano.
         | 
| 9 10 |  | 
| 10 11 | 
             
            ## Installation
         | 
| 11 12 |  | 
| @@ -127,6 +128,18 @@ Beyond standard Capybara testing DSL, ndr_dev_support bundles some additional fu | |
| 127 128 |  | 
| 128 129 | 
             
            When using a headless browser for integration tests, the test database must be consistent between the test runner and the application being tested. With transactional tests in operation, this means that both must share a connection. It is up to the individual project to provide this facility; as of Rails 5.1, it is built in to the framework directly.
         | 
| 129 130 |  | 
| 131 | 
            +
            ### Deployment support
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            There are various capistrano plugins in the `ndr_dev_support/capistrano` directory - see each one for details.
         | 
| 134 | 
            +
            For new projects, you should likely add the following:
         | 
| 135 | 
            +
             | 
| 136 | 
            +
            ```ruby
         | 
| 137 | 
            +
            # in config/deploy.rb
         | 
| 138 | 
            +
            require 'ndr_dev_support/capistrano/ndr_model'
         | 
| 139 | 
            +
            ```
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            This will pull in the majority of behaviour needed to deploy in our preferred style.
         | 
| 142 | 
            +
             | 
| 130 143 | 
             
            ## Development
         | 
| 131 144 |  | 
| 132 145 | 
             
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         | 
    
        data/code_safety.yml
    CHANGED
    
    | @@ -31,7 +31,7 @@ file safety: | |
| 31 31 | 
             
              README.md:
         | 
| 32 32 | 
             
                comments: 
         | 
| 33 33 | 
             
                reviewed_by: josh.pencheon
         | 
| 34 | 
            -
                safe_revision:  | 
| 34 | 
            +
                safe_revision: a2b7c20eb58572c213f77677b36aa2f7e6db747e
         | 
| 35 35 | 
             
              Rakefile:
         | 
| 36 36 | 
             
                comments: 
         | 
| 37 37 | 
             
                reviewed_by: josh.pencheon
         | 
| @@ -48,10 +48,42 @@ file safety: | |
| 48 48 | 
             
                comments: 
         | 
| 49 49 | 
             
                reviewed_by: timgentry
         | 
| 50 50 | 
             
                safe_revision: c59a45986f8b6d087c8c21b1e889f31f7346da17
         | 
| 51 | 
            +
              lib/ndr_dev_support/capistrano/assets.rb:
         | 
| 52 | 
            +
                comments: 
         | 
| 53 | 
            +
                reviewed_by: josh.pencheon
         | 
| 54 | 
            +
                safe_revision: a2b7c20eb58572c213f77677b36aa2f7e6db747e
         | 
| 55 | 
            +
              lib/ndr_dev_support/capistrano/ndr_model.rb:
         | 
| 56 | 
            +
                comments: 
         | 
| 57 | 
            +
                reviewed_by: josh.pencheon
         | 
| 58 | 
            +
                safe_revision: bcecae9e1eeffa84687f1748abebc0c8505a228d
         | 
| 59 | 
            +
              lib/ndr_dev_support/capistrano/restart.rb:
         | 
| 60 | 
            +
                comments: 
         | 
| 61 | 
            +
                reviewed_by: josh.pencheon
         | 
| 62 | 
            +
                safe_revision: a2b7c20eb58572c213f77677b36aa2f7e6db747e
         | 
| 63 | 
            +
              lib/ndr_dev_support/capistrano/revision_logger.rb:
         | 
| 64 | 
            +
                comments: 
         | 
| 65 | 
            +
                reviewed_by: josh.pencheon
         | 
| 66 | 
            +
                safe_revision: a2b7c20eb58572c213f77677b36aa2f7e6db747e
         | 
| 67 | 
            +
              lib/ndr_dev_support/capistrano/ruby_version.rb:
         | 
| 68 | 
            +
                comments: 
         | 
| 69 | 
            +
                reviewed_by: josh.pencheon
         | 
| 70 | 
            +
                safe_revision: a2b7c20eb58572c213f77677b36aa2f7e6db747e
         | 
| 71 | 
            +
              lib/ndr_dev_support/capistrano/standalone_gems.rb:
         | 
| 72 | 
            +
                comments: 
         | 
| 73 | 
            +
                reviewed_by: josh.pencheon
         | 
| 74 | 
            +
                safe_revision: a2b7c20eb58572c213f77677b36aa2f7e6db747e
         | 
| 75 | 
            +
              lib/ndr_dev_support/capistrano/svn_cache.rb:
         | 
| 76 | 
            +
                comments: 
         | 
| 77 | 
            +
                reviewed_by: josh.pencheon
         | 
| 78 | 
            +
                safe_revision: 123d0cd32bdf9e0940fac8945985aa9f467616c1
         | 
| 79 | 
            +
              lib/ndr_dev_support/capistrano/sysadmin_scripts.rb:
         | 
| 80 | 
            +
                comments: 
         | 
| 81 | 
            +
                reviewed_by: josh.pencheon
         | 
| 82 | 
            +
                safe_revision: a2b7c20eb58572c213f77677b36aa2f7e6db747e
         | 
| 51 83 | 
             
              lib/ndr_dev_support/daemon/ci_server.rb:
         | 
| 52 84 | 
             
                comments: 
         | 
| 53 85 | 
             
                reviewed_by: josh.pencheon
         | 
| 54 | 
            -
                safe_revision:  | 
| 86 | 
            +
                safe_revision: ec3d1f3fa1d1f1f3d039587a2f31bda28062f731
         | 
| 55 87 | 
             
              lib/ndr_dev_support/daemon/stoppable.rb:
         | 
| 56 88 | 
             
                comments: 
         | 
| 57 89 | 
             
                reviewed_by: josh.pencheon
         | 
| @@ -63,11 +95,11 @@ file safety: | |
| 63 95 | 
             
              lib/ndr_dev_support/integration_testing/drivers/chrome.rb:
         | 
| 64 96 | 
             
                comments: 
         | 
| 65 97 | 
             
                reviewed_by: josh.pencheon
         | 
| 66 | 
            -
                safe_revision:  | 
| 98 | 
            +
                safe_revision: 1c2b62f359b64c1cfb1754216533fbd4a86fd60e
         | 
| 67 99 | 
             
              lib/ndr_dev_support/integration_testing/drivers/chrome_headless.rb:
         | 
| 68 100 | 
             
                comments: 
         | 
| 69 101 | 
             
                reviewed_by: josh.pencheon
         | 
| 70 | 
            -
                safe_revision:  | 
| 102 | 
            +
                safe_revision: 1c2b62f359b64c1cfb1754216533fbd4a86fd60e
         | 
| 71 103 | 
             
              lib/ndr_dev_support/integration_testing/drivers/firefox.rb:
         | 
| 72 104 | 
             
                comments: 
         | 
| 73 105 | 
             
                reviewed_by: josh.pencheon
         | 
| @@ -119,11 +151,11 @@ file safety: | |
| 119 151 | 
             
              lib/ndr_dev_support/tasks.rb:
         | 
| 120 152 | 
             
                comments: 
         | 
| 121 153 | 
             
                reviewed_by: josh.pencheon
         | 
| 122 | 
            -
                safe_revision:  | 
| 154 | 
            +
                safe_revision: ec3d1f3fa1d1f1f3d039587a2f31bda28062f731
         | 
| 123 155 | 
             
              lib/ndr_dev_support/version.rb:
         | 
| 124 156 | 
             
                comments: 
         | 
| 125 157 | 
             
                reviewed_by: josh.pencheon
         | 
| 126 | 
            -
                safe_revision:  | 
| 158 | 
            +
                safe_revision: 3efca19afad2f7dedc1d470cd8dd51e95ec77545
         | 
| 127 159 | 
             
              lib/tasks/audit_code.rake:
         | 
| 128 160 | 
             
                comments: Identical to the version reviewed by josh.pencheon when contained within
         | 
| 129 161 | 
             
                  ndr_support
         | 
| @@ -137,10 +169,6 @@ file safety: | |
| 137 169 | 
             
                comments: 
         | 
| 138 170 | 
             
                reviewed_by: josh.pencheon
         | 
| 139 171 | 
             
                safe_revision: ddcf7de0bf1f5fb17cc28e2460009e162ff8917c
         | 
| 140 | 
            -
              lib/tasks/ci/bundle_install.rake:
         | 
| 141 | 
            -
                comments: 
         | 
| 142 | 
            -
                reviewed_by: timgentry
         | 
| 143 | 
            -
                safe_revision: cf22c7ab8b2eb67b501b5ebd1309c832db4fdf6c
         | 
| 144 172 | 
             
              lib/tasks/ci/dependencies.rake:
         | 
| 145 173 | 
             
                comments: 
         | 
| 146 174 | 
             
                reviewed_by: josh.pencheon
         | 
| @@ -188,7 +216,7 @@ file safety: | |
| 188 216 | 
             
              ndr_dev_support.gemspec:
         | 
| 189 217 | 
             
                comments: 
         | 
| 190 218 | 
             
                reviewed_by: josh.pencheon
         | 
| 191 | 
            -
                safe_revision:  | 
| 219 | 
            +
                safe_revision: ec3d1f3fa1d1f1f3d039587a2f31bda28062f731
         | 
| 192 220 | 
             
              test/daemon/ci_server_test.rb:
         | 
| 193 221 | 
             
                comments: 
         | 
| 194 222 | 
             
                reviewed_by: josh.pencheon
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            Capistrano::Configuration.instance(:must_exist).load do
         | 
| 2 | 
            +
              namespace :ndr_dev_support do
         | 
| 3 | 
            +
                desc 'Configure  / precompile assets'
         | 
| 4 | 
            +
                task :configure_assets do
         | 
| 5 | 
            +
                  asset_script = fetch(:asset_script, <<~SHELL)
         | 
| 6 | 
            +
                    set -e
         | 
| 7 | 
            +
                    ruby -ryaml -e "puts YAML.dump('production' => { 'secret_key_base' => 'compile_me' })" > config/secrets.yml
         | 
| 8 | 
            +
                    RAILS_ENV=production bundle exec rake assets:precompile
         | 
| 9 | 
            +
                    rm config/secrets.yml
         | 
| 10 | 
            +
                  SHELL
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  if fetch(:webapp_deployment)
         | 
| 13 | 
            +
                    # Prepend the build script with asset compilation steps:
         | 
| 14 | 
            +
                    set :build_script, asset_script + fetch(:build_script, '')
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                    # We'll have replaced all the assets if they're needed:
         | 
| 17 | 
            +
                    set :normalize_asset_timestamps, false
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              after 'ndr_dev_support:prepare', 'ndr_dev_support:configure_assets'
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,175 @@ | |
| 1 | 
            +
            require 'rainbow'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # Discrete bits of functionality we use automatically:
         | 
| 4 | 
            +
            require_relative 'assets'
         | 
| 5 | 
            +
            require_relative 'restart'
         | 
| 6 | 
            +
            require_relative 'revision_logger'
         | 
| 7 | 
            +
            require_relative 'ruby_version'
         | 
| 8 | 
            +
            # require_relative 'standalone_gems' # This doesn't work with the permissions model
         | 
| 9 | 
            +
            require_relative 'svn_cache'
         | 
| 10 | 
            +
            require_relative 'sysadmin_scripts'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            # This file contains logic for managing deployments structured in our preferred "NDRv2" style.
         | 
| 13 | 
            +
            # More details on the structure can be found on plan.io issue #6565.
         | 
| 14 | 
            +
            #
         | 
| 15 | 
            +
            # == Configuration
         | 
| 16 | 
            +
            #
         | 
| 17 | 
            +
            #   The following variables are used:
         | 
| 18 | 
            +
            #     * :application
         | 
| 19 | 
            +
            #     * :application_user
         | 
| 20 | 
            +
            #     * :explicitly_writeable_shared_paths
         | 
| 21 | 
            +
            #     * :repository_branches
         | 
| 22 | 
            +
            #     * :ruby
         | 
| 23 | 
            +
            #     * :shared_paths
         | 
| 24 | 
            +
            #
         | 
| 25 | 
            +
            #   You'll want to use the `add_target` helper method to register individual deployment targets,
         | 
| 26 | 
            +
            #   by supplying "env" (beta/live etc), "name", "host", "port", "app_user" (e.g. "blog_live"),
         | 
| 27 | 
            +
            #   and "is_web_server" (e.g. should it get assets compiled).
         | 
| 28 | 
            +
            #
         | 
| 29 | 
            +
            #   A configuration file (config/deployments.yml) can be used to set per-environment ruby versions
         | 
| 30 | 
            +
            #   and SVN branches. To use the latter, be sure to set the `:repository_branches` variable
         | 
| 31 | 
            +
            #   to point at the root of the branches. Otherwise, just set `:repository` directly as normal.
         | 
| 32 | 
            +
            #
         | 
| 33 | 
            +
            Capistrano::Configuration.instance(:must_exist).load do
         | 
| 34 | 
            +
              # Paths that are symlinked for each release to the "shared" directory:
         | 
| 35 | 
            +
              set :shared_paths, %w[config/database.yml config/secrets.yml log tmp]
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              # Paths in shared/ that the application can write to:
         | 
| 38 | 
            +
              set :explicitly_writeable_shared_paths, %w[log tmp tmp/pids]
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              # This flag gets set only when running `ndr_dev_support:prepare`, which means it can be used
         | 
| 41 | 
            +
              # to toggle behaviour in environments where some targets are using the NDR model of deployment,
         | 
| 42 | 
            +
              # and others aren't.
         | 
| 43 | 
            +
              set :ndr_model_deployment, false
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              namespace :ndr_dev_support do
         | 
| 46 | 
            +
                desc 'Custom tasks to be run once, immediately before the initial `cap setup`'
         | 
| 47 | 
            +
                task :pre_setup do
         | 
| 48 | 
            +
                  # Ensure that the deployment area is owned by the deployer group, and that this is
         | 
| 49 | 
            +
                  # sticky; all deployments made within it should be owned by the deployer group too. This
         | 
| 50 | 
            +
                  # means that e.g. a deployment by "bob.smith" can then be rolled back by "tom.jones".
         | 
| 51 | 
            +
                  run "mkdir -p #{deploy_to}"
         | 
| 52 | 
            +
                  run "chgrp -R deployer #{deploy_to}"
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  # The sticky group will apply automatically to new subdirectories, but
         | 
| 55 | 
            +
                  # any existing subdirectories will need it manually applying via `-R`.
         | 
| 56 | 
            +
                  run "chmod -R g+s #{deploy_to}"
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                desc 'Custom tasks to be run once, after the initial `cap setup`'
         | 
| 60 | 
            +
                task :post_setup do
         | 
| 61 | 
            +
                  fetch(:explicitly_writeable_shared_paths, []).each do |path|
         | 
| 62 | 
            +
                    full_path = File.join(shared_path, path)
         | 
| 63 | 
            +
                    run "mkdir -p #{full_path}"
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    # Allow the application to write into here:
         | 
| 66 | 
            +
                    run "chgrp -R #{application_group} #{full_path}"
         | 
| 67 | 
            +
                    run "chmod -R g+s #{full_path}"
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  fetch(:shared_paths, []).each do |path|
         | 
| 71 | 
            +
                    full_path = File.join(shared_path, path)
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    if /^n$/ =~ capture("test -e #{full_path} && echo 'y' || echo 'n'")
         | 
| 74 | 
            +
                      warn Rainbow("Warning: shared '#{path}' is not yet present!").red
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                before 'deploy:setup', 'ndr_dev_support:pre_setup'
         | 
| 80 | 
            +
                after  'deploy:setup', 'ndr_dev_support:post_setup'
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                desc 'More generic configuration, built on top of target-specific config.'
         | 
| 83 | 
            +
                task :prepare do
         | 
| 84 | 
            +
                  warn Rainbow('                                                                        ').red.underline
         | 
| 85 | 
            +
                  warn Rainbow('')
         | 
| 86 | 
            +
                  warn Rainbow("Target: #{Rainbow(fetch(:name)).bright.green}")
         | 
| 87 | 
            +
                  warn Rainbow("Branch: #{Rainbow(fetch(:branch)).bright.green} (see config/deployments.yml)")
         | 
| 88 | 
            +
                  warn Rainbow("Ruby:   #{Rainbow(fetch(:ruby)).bright.green}")
         | 
| 89 | 
            +
                  warn Rainbow('')
         | 
| 90 | 
            +
                  warn Rainbow("DBs:    Migrations are not run automatically by capistrano;")
         | 
| 91 | 
            +
                  warn Rainbow("        #{Rainbow('please run any necessary manually before proceeding').underline.bright}.")
         | 
| 92 | 
            +
                  warn Rainbow('                                                                        ').red.underline
         | 
| 93 | 
            +
                  warn Rainbow('')
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  # Gather SSH credentials: (password is asked for by Net::SSH, if needed)
         | 
| 96 | 
            +
                  set :use_sudo, false
         | 
| 97 | 
            +
                  set :user, Capistrano::CLI.ui.ask('Deploy as: ')
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  # If no alternate user is specified, deploy to the crediental-holding user.
         | 
| 100 | 
            +
                  set :application_user, fetch(:user) unless fetch(:application_user)
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                  # The home folder of the application user:
         | 
| 103 | 
            +
                  set :application_home, File.join('/home', fetch(:application_user))
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  # The deploying user will need to be a member of the application user's group,
         | 
| 106 | 
            +
                  # as well as being a member of the "deployer" group:
         | 
| 107 | 
            +
                  set :application_group, fetch(:application_user)
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  # Where we'll be deploying to:
         | 
| 110 | 
            +
                  set :deploy_to, File.join(application_home, fetch(:application))
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  # Use the application user's ruby:
         | 
| 113 | 
            +
                  set(:default_environment) do
         | 
| 114 | 
            +
                    { 'PATH' => "#{application_home}/.rbenv/shims:#{application_home}/.rbenv/bin:$PATH" }
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                  # Set a flag so behaviour can toggle in mixed use cases
         | 
| 118 | 
            +
                  set(:ndr_model_deployment, true)
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                after 'deploy:update', 'deploy:cleanup' # Keep only 5 deployments
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                desc 'Symlink to the release any :shared_paths, ensure private/ is writeable'
         | 
| 124 | 
            +
                task :filesystem_tweaks do
         | 
| 125 | 
            +
                  fetch(:shared_paths, []).each do |path|
         | 
| 126 | 
            +
                    # Symlink `path` from the shared space to the release being prepared, replacing anything
         | 
| 127 | 
            +
                    # already there:
         | 
| 128 | 
            +
                    run "rm -rf #{File.join(release_path, path)} && ln -s #{File.join(shared_path, path)} #{File.join(release_path, path)}"
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  # Make the private/ directory in the release writeable to the application user:
         | 
| 132 | 
            +
                  private_directory = File.join(release_path, 'private')
         | 
| 133 | 
            +
                  run "mkdir -p #{private_directory} && chgrp #{fetch(:application_group)} #{private_directory} && chmod g+s #{private_directory}"
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                after 'deploy:finalize_update', 'ndr_dev_support:filesystem_tweaks'
         | 
| 137 | 
            +
              end
         | 
| 138 | 
            +
            end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
            def release_config_for(env)
         | 
| 141 | 
            +
              branches = YAML.load_file('config/deployments.yml')
         | 
| 142 | 
            +
              branches.fetch(env.to_s) { raise 'Unknown release branch!' }
         | 
| 143 | 
            +
            end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
            def target_ruby_version_for(env)
         | 
| 146 | 
            +
              raw   = release_config_for(env).fetch('ruby')
         | 
| 147 | 
            +
              match = raw.match(/\A(?<version>\d+\.\d+\.\d+)\z/)
         | 
| 148 | 
            +
             | 
| 149 | 
            +
              match ? match[:version] : raise('Unrecognized Ruby version!')
         | 
| 150 | 
            +
            end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            def add_target(env, name, app, port, app_user, is_web_server)
         | 
| 153 | 
            +
              desc "Deploy to #{env} service #{app_user || 'you'}@#{app}:#{port}"
         | 
| 154 | 
            +
              task(name) do
         | 
| 155 | 
            +
                set :name, name
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                set :application_user, app_user
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                role :app, app
         | 
| 160 | 
            +
                set :port, port
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                set :webapp_deployment, is_web_server
         | 
| 163 | 
            +
                set :daemon_deployment, !is_web_server
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                set :branch, release_config_for(env).fetch('branch')
         | 
| 166 | 
            +
                if exists?(:repository_branches)
         | 
| 167 | 
            +
                  set :repository, fetch(:repository_branches) + fetch(:branch)
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                # Extract Ruby configuration if available:
         | 
| 171 | 
            +
                ruby_version = target_ruby_version_for(env)
         | 
| 172 | 
            +
                set :ruby, ruby_version if ruby_version
         | 
| 173 | 
            +
              end
         | 
| 174 | 
            +
              after name, 'ndr_dev_support:prepare'
         | 
| 175 | 
            +
            end
         | 
| @@ -0,0 +1,9 @@ | |
| 1 | 
            +
            Capistrano::Configuration.instance(:must_exist).load do
         | 
| 2 | 
            +
              namespace :deploy do
         | 
| 3 | 
            +
                desc 'Trigger application to restart'
         | 
| 4 | 
            +
                task :restart do
         | 
| 5 | 
            +
                  # The tmp/ directory should be shared, so this affects all prior deployments
         | 
| 6 | 
            +
                  run "touch #{shared_path}/tmp/restart.txt"
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
            end
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            Capistrano::Configuration.instance(:must_exist).load do
         | 
| 2 | 
            +
              namespace :ndr_dev_support do
         | 
| 3 | 
            +
                desc 'Append to the log of deployments the user and revision.'
         | 
| 4 | 
            +
                task :log_deployment, except: { no_release: true } do
         | 
| 5 | 
            +
                  name = fetch(:deployer_name, capture('id -un'))
         | 
| 6 | 
            +
                  log  = File.join(shared_path, 'revisions.log')
         | 
| 7 | 
            +
                  msg  = "[#{Time.now}] #{name} deployed #{latest_revision}"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  run "(test -e #{log} || (touch #{log} && chmod 664 #{log})) && echo #{msg} >> #{log};"
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              after 'deploy:update_code', 'ndr_dev_support:log_deployment'
         | 
| 14 | 
            +
            end
         | 
| @@ -0,0 +1,10 @@ | |
| 1 | 
            +
            Capistrano::Configuration.instance(:must_exist).load do
         | 
| 2 | 
            +
              namespace :ndr_dev_support do
         | 
| 3 | 
            +
                desc 'Creates a .ruby-version file for this release'
         | 
| 4 | 
            +
                task :set_ruby_version, except: { no_release: true } do
         | 
| 5 | 
            +
                  run "cd #{release_path} && echo #{fetch(:ruby)} > .ruby-version"
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              before 'bundle:install', 'ndr_dev_support:set_ruby_version'
         | 
| 10 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            require_relative 'ruby_version'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Capistrano::Configuration.instance(:must_exist).load do
         | 
| 4 | 
            +
              namespace :ndr_dev_support do
         | 
| 5 | 
            +
                desc 'Ensure gems outside the bundle are up to date'
         | 
| 6 | 
            +
                task :update_out_of_bundle_gems, except: { no_release: true } do
         | 
| 7 | 
            +
                  # You can seed this list in your configuration with something like:
         | 
| 8 | 
            +
                  #
         | 
| 9 | 
            +
                  #   before 'ndr_dev_support:update_out_of_bundle_gems' do
         | 
| 10 | 
            +
                  #     set :out_of_bundle_gems, webapp_deployment ? %w[puma] : %[god]
         | 
| 11 | 
            +
                  #   end
         | 
| 12 | 
            +
                  #
         | 
| 13 | 
            +
                  gem_list = Array(fetch(:out_of_bundle_gems, []))
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  # Extract the current version requirements for each of the gems from the lockfile,
         | 
| 16 | 
            +
                  # and then check they're installed. If not, install them from the vendored cache.
         | 
| 17 | 
            +
                  run <<~CMD if gem_list.any?
         | 
| 18 | 
            +
                    export RBENV_VERSION=`cat "#{latest_release}/.ruby-version"`;
         | 
| 19 | 
            +
                    cat "#{latest_release}/Gemfile.lock" | egrep "^    (#{gem_list.join('|')}) " | tr -d '()' | \
         | 
| 20 | 
            +
                    while read gem ver; do
         | 
| 21 | 
            +
                      gem list -i "$gem" --version "$ver" > /dev/null || \
         | 
| 22 | 
            +
                      gem install "#{latest_release}/vendor/cache/$gem-$ver.gem" --ignore-dependencies \
         | 
| 23 | 
            +
                                  --conservative --no-document;
         | 
| 24 | 
            +
                    done
         | 
| 25 | 
            +
                  CMD
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              after 'bundle:install', 'ndr_dev_support:update_out_of_bundle_gems'
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            Capistrano::Configuration.instance(:must_exist).load do
         | 
| 2 | 
            +
              # Maintains a second checkout SVN locally, then uses sftp to push.
         | 
| 3 | 
            +
              # This avoids the deployment target needing to have any direct
         | 
| 4 | 
            +
              # access to the source code repository.
         | 
| 5 | 
            +
              set :scm, :subversion
         | 
| 6 | 
            +
              set :deploy_via, :copy
         | 
| 7 | 
            +
              set :copy_strategy, :export
         | 
| 8 | 
            +
              set :copy_cache, 'tmp/deployment'
         | 
| 9 | 
            +
              set :copy_dir, 'tmp/staging'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              namespace :ndr_dev_support do
         | 
| 12 | 
            +
                desc 'Remove the SVN cache (it may be pointing at the wrong branch)'
         | 
| 13 | 
            +
                task :remove_svn_cache_if_needed do
         | 
| 14 | 
            +
                  cache = fetch(:copy_cache)
         | 
| 15 | 
            +
                  unless Dir.exist?(cache) && `svn info #{cache}`.include?(fetch(:repository))
         | 
| 16 | 
            +
                    logger.debug "Cache is stale for #{fetch(:branch)}, wiping..."
         | 
| 17 | 
            +
                    system("rm -rf #{cache}")
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              before 'deploy:update_code', 'ndr_dev_support:remove_svn_cache_if_needed'
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            Capistrano::Configuration.instance(:must_exist).load do
         | 
| 2 | 
            +
              namespace :ndr_dev_support do
         | 
| 3 | 
            +
                desc "Refresh the start/stop scripts in the app user's $HOME directory"
         | 
| 4 | 
            +
                task :refresh_sysadmin_scripts, except: { no_release: true } do
         | 
| 5 | 
            +
                  # This is desirable, but opt-in, behaviour:
         | 
| 6 | 
            +
                  if fetch(:synchronise_sysadmin_scripts, false)
         | 
| 7 | 
            +
                    type    = fetch(:daemon_deployment) ? 'god' : 'server'
         | 
| 8 | 
            +
                    scripts = %W(start_#{type}.sh stop_#{type}_gracefully.sh)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    scripts.each do |script|
         | 
| 11 | 
            +
                      source  = File.join(release_path, 'script', "#{script}.sample")
         | 
| 12 | 
            +
                      dest    = File.join(fetch(:application_home), script)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                      # Ensure the script is pre-existing, with the correct permissions (should be writeable
         | 
| 15 | 
            +
                      # by deployers, but only runnable by the application user, to prevent the wrong user
         | 
| 16 | 
            +
                      # attempting to start the processes.)
         | 
| 17 | 
            +
                      run "test -w #{dest}"                              # Should exist and be writeable
         | 
| 18 | 
            +
                      run "test -e #{source} && cat #{source} > #{dest}" # Replace without changing permissions
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              after 'deploy:update_code', 'ndr_dev_support:refresh_sysadmin_scripts'
         | 
| 25 | 
            +
            end
         | 
| @@ -1,5 +1,7 @@ | |
| 1 | 
            +
            require 'English'
         | 
| 1 2 | 
             
            require_relative 'stoppable'
         | 
| 2 3 | 
             
            require 'rugged'
         | 
| 4 | 
            +
            require 'with_clean_rbenv'
         | 
| 3 5 |  | 
| 4 6 | 
             
            module NdrDevSupport
         | 
| 5 7 | 
             
              module Daemon
         | 
| @@ -46,7 +48,12 @@ module NdrDevSupport | |
| 46 48 | 
             
                    objectids_between_master_and_remote.each do |oid|
         | 
| 47 49 | 
             
                      `git rebase #{oid}`
         | 
| 48 50 |  | 
| 49 | 
            -
                       | 
| 51 | 
            +
                      WithCleanRbenv.with_clean_rbenv do
         | 
| 52 | 
            +
                        # TODO: rbenv_install
         | 
| 53 | 
            +
                        bundle_install
         | 
| 54 | 
            +
                        `rbenv exec bundle exec rake ci:all`
         | 
| 55 | 
            +
                        git_discard_changes
         | 
| 56 | 
            +
                      end
         | 
| 50 57 | 
             
                    end
         | 
| 51 58 | 
             
                  end
         | 
| 52 59 |  | 
| @@ -58,6 +65,13 @@ module NdrDevSupport | |
| 58 65 | 
             
                    `git checkout #{oid}`
         | 
| 59 66 | 
             
                  end
         | 
| 60 67 |  | 
| 68 | 
            +
                  def git_discard_changes
         | 
| 69 | 
            +
                    # git clean would remove all unstaged files
         | 
| 70 | 
            +
                    stash_output = `git stash`
         | 
| 71 | 
            +
                    return if stash_output.start_with?('No local changes to save')
         | 
| 72 | 
            +
                    `git stash drop stash@{0}`
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 61 75 | 
             
                  def svn_remote?
         | 
| 62 76 | 
             
                    GIT_SVN_REMOTE_BRANCH_NAME == remote_branch
         | 
| 63 77 | 
             
                  end
         | 
| @@ -89,6 +103,28 @@ module NdrDevSupport | |
| 89 103 |  | 
| 90 104 | 
             
                    revisions.reverse
         | 
| 91 105 | 
             
                  end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  def bundle_install
         | 
| 108 | 
            +
                    return unless File.file?('Gemfile')
         | 
| 109 | 
            +
                    return if system('bundle check')
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                    `rbenv exec bundle install --local --jobs=3`
         | 
| 112 | 
            +
                    return if $CHILD_STATUS.exitstatus.zero? || ENV['SLACK_WEBHOOK_URL'].nil?
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                    slack_publisher = NdrDevSupport::SlackMessagePublisher.new(ENV['SLACK_WEBHOOK_URL'],
         | 
| 115 | 
            +
                                                                               username: 'Rake CI',
         | 
| 116 | 
            +
                                                                               icon_emoji: ':robot_face:',
         | 
| 117 | 
            +
                                                                               channel: ENV['SLACK_CHANNEL'])
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                    attachment = {
         | 
| 120 | 
            +
                      color: 'danger',
         | 
| 121 | 
            +
                      fallback: 'Failure running bundle install --local',
         | 
| 122 | 
            +
                      text: 'Failure running `bundle install --local`',
         | 
| 123 | 
            +
                      footer: 'bundle exec rake ci:bundle_install'
         | 
| 124 | 
            +
                    }
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                    slack_publisher.post(attachments: [attachment])
         | 
| 127 | 
            +
                  end
         | 
| 92 128 | 
             
                end
         | 
| 93 129 | 
             
              end
         | 
| 94 130 | 
             
            end
         | 
    
        data/ndr_dev_support.gemspec
    CHANGED
    
    | @@ -34,7 +34,7 @@ Gem::Specification.new do |spec| | |
| 34 34 | 
             
              # Integration test dependencies:
         | 
| 35 35 | 
             
              spec.add_dependency 'capybara'
         | 
| 36 36 | 
             
              spec.add_dependency 'capybara-screenshot'
         | 
| 37 | 
            -
              spec.add_dependency 'chromedriver-helper'
         | 
| 37 | 
            +
              spec.add_dependency 'chromedriver-helper', '~> 2.0'
         | 
| 38 38 | 
             
              spec.add_dependency 'poltergeist', '>= 1.8.0'
         | 
| 39 39 | 
             
              spec.add_dependency 'selenium-webdriver'
         | 
| 40 40 |  | 
| @@ -45,6 +45,10 @@ Gem::Specification.new do |spec| | |
| 45 45 | 
             
              spec.add_dependency 'github-linguist'
         | 
| 46 46 | 
             
              spec.add_dependency 'prometheus-client'
         | 
| 47 47 | 
             
              spec.add_dependency 'rugged'
         | 
| 48 | 
            +
              spec.add_dependency 'with_clean_rbenv'
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              # Deployment dependencies:
         | 
| 51 | 
            +
              spec.add_dependency 'capistrano', '~> 2.15'
         | 
| 48 52 |  | 
| 49 53 | 
             
              spec.add_development_dependency 'bundler', '~> 1.7'
         | 
| 50 54 | 
             
              spec.add_development_dependency 'minitest', '~> 5.0'
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: ndr_dev_support
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version:  | 
| 4 | 
            +
              version: 4.0.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - NCRS Development Team
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2018- | 
| 11 | 
            +
            date: 2018-10-17 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: pry
         | 
| @@ -112,16 +112,16 @@ dependencies: | |
| 112 112 | 
             
              name: chromedriver-helper
         | 
| 113 113 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 114 114 | 
             
                requirements:
         | 
| 115 | 
            -
                - - " | 
| 115 | 
            +
                - - "~>"
         | 
| 116 116 | 
             
                  - !ruby/object:Gem::Version
         | 
| 117 | 
            -
                    version: '0'
         | 
| 117 | 
            +
                    version: '2.0'
         | 
| 118 118 | 
             
              type: :runtime
         | 
| 119 119 | 
             
              prerelease: false
         | 
| 120 120 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 121 121 | 
             
                requirements:
         | 
| 122 | 
            -
                - - " | 
| 122 | 
            +
                - - "~>"
         | 
| 123 123 | 
             
                  - !ruby/object:Gem::Version
         | 
| 124 | 
            -
                    version: '0'
         | 
| 124 | 
            +
                    version: '2.0'
         | 
| 125 125 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 126 126 | 
             
              name: poltergeist
         | 
| 127 127 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -234,6 +234,34 @@ dependencies: | |
| 234 234 | 
             
                - - ">="
         | 
| 235 235 | 
             
                  - !ruby/object:Gem::Version
         | 
| 236 236 | 
             
                    version: '0'
         | 
| 237 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 238 | 
            +
              name: with_clean_rbenv
         | 
| 239 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 240 | 
            +
                requirements:
         | 
| 241 | 
            +
                - - ">="
         | 
| 242 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 243 | 
            +
                    version: '0'
         | 
| 244 | 
            +
              type: :runtime
         | 
| 245 | 
            +
              prerelease: false
         | 
| 246 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 247 | 
            +
                requirements:
         | 
| 248 | 
            +
                - - ">="
         | 
| 249 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 250 | 
            +
                    version: '0'
         | 
| 251 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 252 | 
            +
              name: capistrano
         | 
| 253 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 254 | 
            +
                requirements:
         | 
| 255 | 
            +
                - - "~>"
         | 
| 256 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 257 | 
            +
                    version: '2.15'
         | 
| 258 | 
            +
              type: :runtime
         | 
| 259 | 
            +
              prerelease: false
         | 
| 260 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 261 | 
            +
                requirements:
         | 
| 262 | 
            +
                - - "~>"
         | 
| 263 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 264 | 
            +
                    version: '2.15'
         | 
| 237 265 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 238 266 | 
             
              name: bundler
         | 
| 239 267 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -308,6 +336,14 @@ files: | |
| 308 336 | 
             
            - bin/setup
         | 
| 309 337 | 
             
            - code_safety.yml
         | 
| 310 338 | 
             
            - lib/ndr_dev_support.rb
         | 
| 339 | 
            +
            - lib/ndr_dev_support/capistrano/assets.rb
         | 
| 340 | 
            +
            - lib/ndr_dev_support/capistrano/ndr_model.rb
         | 
| 341 | 
            +
            - lib/ndr_dev_support/capistrano/restart.rb
         | 
| 342 | 
            +
            - lib/ndr_dev_support/capistrano/revision_logger.rb
         | 
| 343 | 
            +
            - lib/ndr_dev_support/capistrano/ruby_version.rb
         | 
| 344 | 
            +
            - lib/ndr_dev_support/capistrano/standalone_gems.rb
         | 
| 345 | 
            +
            - lib/ndr_dev_support/capistrano/svn_cache.rb
         | 
| 346 | 
            +
            - lib/ndr_dev_support/capistrano/sysadmin_scripts.rb
         | 
| 311 347 | 
             
            - lib/ndr_dev_support/daemon/ci_server.rb
         | 
| 312 348 | 
             
            - lib/ndr_dev_support/daemon/stoppable.rb
         | 
| 313 349 | 
             
            - lib/ndr_dev_support/integration_testing.rb
         | 
| @@ -330,7 +366,6 @@ files: | |
| 330 366 | 
             
            - lib/tasks/audit_code.rake
         | 
| 331 367 | 
             
            - lib/tasks/ci/brakeman.rake
         | 
| 332 368 | 
             
            - lib/tasks/ci/bundle_audit.rake
         | 
| 333 | 
            -
            - lib/tasks/ci/bundle_install.rake
         | 
| 334 369 | 
             
            - lib/tasks/ci/dependencies.rake
         | 
| 335 370 | 
             
            - lib/tasks/ci/housekeep.rake
         | 
| 336 371 | 
             
            - lib/tasks/ci/linguist.rake
         | 
| @@ -363,7 +398,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 363 398 | 
             
                  version: '0'
         | 
| 364 399 | 
             
            requirements: []
         | 
| 365 400 | 
             
            rubyforge_project: 
         | 
| 366 | 
            -
            rubygems_version: 2. | 
| 401 | 
            +
            rubygems_version: 2.7.6
         | 
| 367 402 | 
             
            signing_key: 
         | 
| 368 403 | 
             
            specification_version: 4
         | 
| 369 404 | 
             
            summary: NDR Developer Support library
         | 
| @@ -1,21 +0,0 @@ | |
| 1 | 
            -
            namespace :ci do
         | 
| 2 | 
            -
              desc 'Install bundled gems'
         | 
| 3 | 
            -
              task :bundle_install do
         | 
| 4 | 
            -
                require 'English'
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                # `gem install bundler`
         | 
| 7 | 
            -
                `bundle install --local`
         | 
| 8 | 
            -
                next if $CHILD_STATUS.exitstatus.zero?
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                attachment = {
         | 
| 11 | 
            -
                  color: 'danger',
         | 
| 12 | 
            -
                  fallback: 'Failure running bundle install --local',
         | 
| 13 | 
            -
                  text: 'Failure running `bundle install --local`',
         | 
| 14 | 
            -
                  footer: 'bundle exec rake ci:bundle_install'
         | 
| 15 | 
            -
                }
         | 
| 16 | 
            -
             | 
| 17 | 
            -
                @attachments ||= []
         | 
| 18 | 
            -
                @attachments << attachment
         | 
| 19 | 
            -
                puts attachment.inspect
         | 
| 20 | 
            -
              end
         | 
| 21 | 
            -
            end
         |