capistrano: Cannot deploy without SCM

If I delete :scm, I simply cannot deploy with Capistrano 3.

For a bit of context, I use JRuby’s Warbler for deployment so I don’t actually use a SCM at all.

About this issue

  • Original URL
  • State: closed
  • Created 11 years ago
  • Reactions: 1
  • Comments: 34 (12 by maintainers)

Most upvoted comments

An update for those interested: Capistrano 3.7 added the option to disable SCM entirely like this:

set :scm, nil

So now you can use Capistrano sans SCM, per the original request of this issue.

Furthermore, 3.7 adds a documented SCM plugin system to make building things like “git copy” more straightforward: http://capistranorb.com/documentation/advanced-features/custom-scm/

I solved this with such setup (thanks @chqr for his None SCM example!)

  1. Added lib folder to load path in Capfile

    $LOAD_PATH.unshift File.join(File.dirname(__FILE__), 'lib')
    
  2. Added None SCM as lib/capistrano/none.rb file with contents:

    # See https://github.com/capistrano/capistrano/issues/722
    namespace :none do
      task :check do
        true
      end
    
      task :create_release do
        on release_roles(:web) do |_host|
          execute :mkdir, '-p', release_path
        end
      end
    
      task :set_current_revision do
        on release_roles(:web) do |_host|
          execute :ln, '-s', release_path, current_path
        end
      end
    end
    
  3. And then in config/deploy.rb

    set :scm, :none
    
  4. PROFIT!

As I personally think, Capistrano should be decoupled from SCMs, ad deploy not always requires git checkout or anything, but Capistrano provides a lot of good stuff like rollbacks, plugins, and very good flow, but sometimes all you need is rsync some prebuilt content to the server (and I do not want to set up build environment on server only for deploy).

Thanks everyone!

I wanted to keep the core deploy task functionality, but deploy build artifacts from Travis CI. So I wrote a custom Travis “SCM” to package the build artifacts from Travis CI. It has been working well. Here’s the relevant code:

set :scm, :git

namespace :travis do

  desc 'Check that travis is reachable'
  task :check do
      exit 1 unless true
  end

  desc 'Package to release'
  task :create_release do
      run_locally do
          execute :mkdir, '-p', :'tmp'
          execute "tar -cz --exclude tests --exclude vendor --exclude .git --exclude node_modules --exclude tmp/#{fetch(:release_timestamp)}.tar.gz -f tmp/#{fetch(:release_timestamp)}.tar.gz ."
      end
      on release_roles :all do
          execute :mkdir, '-p', release_path
          upload! "tmp/#{fetch(:release_timestamp)}.tar.gz", "#{release_path}/#{fetch(:release_timestamp)}.tar.gz"
          execute "tar -xvf #{release_path}/#{fetch(:release_timestamp)}.tar.gz --directory #{release_path}"
          execute "rm #{release_path}/#{fetch(:release_timestamp)}.tar.gz"
      end
      run_locally do
          execute "rm -rf tmp"
      end
  end

  desc 'Determine the revision that will be deployed'
  task :set_current_revision do
      run_locally do
          set :current_revision, capture(:git, "rev-parse --short #{fetch(:branch)}")
      end
  end

end

namespace :deploy do

  desc 'Use Travis'
  task :use_travis do
    set :scm, :travis
  end

  before :starting, :use_travis

end

After building a release tool for rolling out Play framework release artifacts with Capistrano, I have to say: Capistrano is super easy to customize! I believe that it’s a good pattern to just define your own deployment tasks, if you deviate from the “standard capistrano” deploy process.

To start, only include:

require 'capistrano/setup'
require 'capistrano/install'
require 'capistrano/framework'

This gives you the following deployment pipeline (have a look at http://www.capistranorb.com/documentation/getting-started/flow/ ):

deploy:starting    - start a deployment, make sure everything is ready
deploy:started     - started hook (for custom tasks)
deploy:updating    - update server(s) with a new release
deploy:updated     - updated hook
deploy:publishing  - publish the new release
deploy:published   - published hook
deploy:finishing   - finish the deployment, clean up everything
deploy:finished    - finished hook

Then populate those pipelined taks with your deployment functionality, e.g. something like this for release uploading (consult the examples @leehambley linked):

task :updating => :new_release_path do
  invoke 'deploy:upload_release'
end

task :upload_release do
  builds_path = fetch(:builds_path, '.')
  build_name = fetch(:application)
  zip_file = "#{build_name}-#{release_version}.zip"
  zip_tempdir = '/var/tmp/releases'
  on roles(:app) do
    execute :mkdir, '-pv', zip_tempdir
    upload!("#{builds_path}/#{zip_file}", zip_tempdir)
    execute :unzip, '-o', "#{zip_tempdir}/#{zip_file}" , "-d #{releases_path}"
  end
end

Remember it is rake, so you cannot just redefine tasks to overwrite them.

Actually you can overwrite rake tasks, but I consider this ugly. Have a look at this stack overflow article: http://stackoverflow.com/questions/8112074/overriding-rails-default-rake-tasks .

If you included the Capistrano standard deploy tasks you would need to override at least this two tasks:

deploy:updating
deploy:check

Have a look at the Capistrano source, to see the way the scm tasks are called:

task :updating => :new_release_path do
  invoke "#{scm}:create_release"
  invoke 'deploy:symlink:shared'
end

task :updating => :new_release_path do
  invoke "#{scm}:create_release"
  invoke 'deploy:symlink:shared'
end

You may want to replace those tasks with tasks calling your own upload functionality.

I still think its better to populate the release pipeline with your own tasks, than overwriting existing tasks. But if you really want to do it, it is possible 😉

To play the advocate for the devil here (because I use capistrano v3 without SCM) cap does offer a lot of things that a rake/SSHKit combo lacks. Just the support for stages and the set/fetch mechanism are enough additional value to make using cap worth while.

Having said that, I don’t get the “delete :scm” line. In what context would you remove it and how is it interfering when you don’t remove it?