Search code examples
ruby-on-railscapistranocapistrano3

How can I place capistrano stages into a sub-directory?


By default, the capistrano stages are placed in /config/deploy/. I have a ton of stages here. I'd also like to have some of my stages grouped like /config/deploy/group1/ and /config/deploy/group2. How could I include multiple paths?

I noticed you could set this:

set :stage_config_path, 'cap/stages'

But I need it to look recursively at config/deploy instead of only in that folder.

It would be nice if I could even do things like:

$ cap group1/stage1 deploy

How would I go about accomplishing this in my Ruby on Rails application?


Solution

  • I was able to override some Capistrano methods to get this to work. I wrote the following code at the top of my Capfile:

    module Capistrano
      module DSL
        module Stages
    
          def stages
            names = Dir[stage_definitions].map { |f| "#{File.dirname(f)}/#{File.basename(f, ".rb")}".gsub("#{stage_config_path.to_s}/", '') }
            assert_valid_stage_names(names)
            names
          end
    
          # Override stage_definitions to include subfolders
          def stage_definitions
            stage_config_path.join("**/*.rb")
          end
        end
      end
    end
    

    Explanation

    By overriding the #stage_definitions method, I added **/ to that it would look for the .rb files in sub directories.

    The next issue was that capistrano/setup.rb had this line of code:

    load stage_config_path.join("#{stage}.rb")
    

    That means I need stage to include the folder name. Then I overrode #stages so that the names variable would be an array of stages, including the subdirectory if any. Example:

    config/
    ├── deploy/
    │   ├── group_1/
    |   ├──   ├── stage1.rb
    │   ├── stage2.rb
    │   ├── stage3.rb
    

    Becomes:

    ['group_1/stage1', 'stage2', 'stage3']
    

    That allows the Rake tasks to be created and load the files correctly!

    $ cap group_1/stage1 deploy