diff --git a/Capfile b/Capfile new file mode 100644 index 0000000..3bb980b --- /dev/null +++ b/Capfile @@ -0,0 +1,4 @@ +require 'capistrano/setup' +require 'capistrano/deploy' + +Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r } diff --git a/Gemfile b/Gemfile index 84b9d5a..43ee99f 100644 --- a/Gemfile +++ b/Gemfile @@ -1,34 +1,35 @@ source "https://rubygems.org" group :development, :test do gem 'pry-byebug' end group :development do gem 'guard-minitest', require: false gem 'guard', require: false + gem 'capistrano', '3.2.1', require: false # pkg:capistrano end # Lock jessie versions # gem 'rails', '4.1.8' gem 'i18n', '0.6.9' gem 'json', '1.8.1' gem 'mail', '2.6.1' gem 'mime-types', '1.25' gem 'minitest', '5.4.2' gem 'rack', '1.5.2' gem 'rack-test', '0.6.2' gem 'rake', '10.3.2' gem 'sprockets', '2.12.3' gem 'sprockets-rails', '2.1.3' gem 'thread_safe', '0.3.3' gem 'tzinfo', '1.1.0' gem 'mysql2', '0.3.16' gem 'jquery-rails', '3.1.2' group :test do gem 'factory_girl_rails', '4.4.1' # pkg:ruby-factory-girl-rails end diff --git a/Gemfile.lock b/Gemfile.lock index 81fcada..ae57c44 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,146 +1,159 @@ GEM remote: https://rubygems.org/ specs: actionmailer (4.1.8) actionpack (= 4.1.8) actionview (= 4.1.8) mail (~> 2.5, >= 2.5.4) actionpack (4.1.8) actionview (= 4.1.8) activesupport (= 4.1.8) rack (~> 1.5.2) rack-test (~> 0.6.2) actionview (4.1.8) activesupport (= 4.1.8) builder (~> 3.1) erubis (~> 2.7.0) activemodel (4.1.8) activesupport (= 4.1.8) builder (~> 3.1) activerecord (4.1.8) activemodel (= 4.1.8) activesupport (= 4.1.8) arel (~> 5.0.0) activesupport (4.1.8) i18n (~> 0.6, >= 0.6.9) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) thread_safe (~> 0.1) tzinfo (~> 1.1) arel (5.0.1.20140414130214) builder (3.2.2) byebug (4.0.5) columnize (= 0.9.0) + capistrano (3.2.1) + i18n + rake (>= 10.0.0) + sshkit (~> 1.3) coderay (1.1.0) + colorize (0.7.7) columnize (0.9.0) erubis (2.7.0) factory_girl (4.4.0) activesupport (>= 3.0.0) factory_girl_rails (4.4.1) factory_girl (~> 4.4.0) railties (>= 3.0.0) ffi (1.9.10) formatador (0.2.5) guard (2.13.0) formatador (>= 0.2.4) listen (>= 2.7, <= 4.0) lumberjack (~> 1.0) nenv (~> 0.1) notiffany (~> 0.0) pry (>= 0.9.12) shellany (~> 0.0) thor (>= 0.18.1) guard-compat (1.2.1) guard-minitest (2.4.4) guard-compat (~> 1.2) minitest (>= 3.0) hike (1.2.3) i18n (0.6.9) jquery-rails (3.1.2) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) json (1.8.1) listen (3.0.3) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9) lumberjack (1.0.9) mail (2.6.1) mime-types (>= 1.16, < 3) method_source (0.8.2) mime-types (1.25) minitest (5.4.2) multi_json (1.11.2) mysql2 (0.3.16) nenv (0.2.0) + net-scp (1.2.1) + net-ssh (>= 2.6.5) + net-ssh (2.9.2) notiffany (0.0.8) nenv (~> 0.1) shellany (~> 0.0) pry (0.10.1) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) pry-byebug (3.1.0) byebug (~> 4.0) pry (~> 0.10) rack (1.5.2) rack-test (0.6.2) rack (>= 1.0) rails (4.1.8) actionmailer (= 4.1.8) actionpack (= 4.1.8) actionview (= 4.1.8) activemodel (= 4.1.8) activerecord (= 4.1.8) activesupport (= 4.1.8) bundler (>= 1.3.0, < 2.0) railties (= 4.1.8) sprockets-rails (~> 2.0) railties (4.1.8) actionpack (= 4.1.8) activesupport (= 4.1.8) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rake (10.3.2) rb-fsevent (0.9.6) rb-inotify (0.9.5) ffi (>= 0.5.0) shellany (0.0.1) slop (3.6.0) sprockets (2.12.3) hike (~> 1.2) multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) sprockets-rails (2.1.3) actionpack (>= 3.0) activesupport (>= 3.0) sprockets (~> 2.8) + sshkit (1.7.1) + colorize (>= 0.7.0) + net-scp (>= 1.1.2) + net-ssh (>= 2.8.0) thor (0.19.1) thread_safe (0.3.3) tilt (1.4.1) tzinfo (1.1.0) thread_safe (~> 0.1) PLATFORMS ruby DEPENDENCIES + capistrano (= 3.2.1) factory_girl_rails (= 4.4.1) guard guard-minitest i18n (= 0.6.9) jquery-rails (= 3.1.2) json (= 1.8.1) mail (= 2.6.1) mime-types (= 1.25) minitest (= 5.4.2) mysql2 (= 0.3.16) pry-byebug rack (= 1.5.2) rack-test (= 0.6.2) rails (= 4.1.8) rake (= 10.3.2) sprockets (= 2.12.3) sprockets-rails (= 2.1.3) thread_safe (= 0.3.3) tzinfo (= 1.1.0) diff --git a/config/deploy.rb b/config/deploy.rb new file mode 100644 index 0000000..1ec0a16 --- /dev/null +++ b/config/deploy.rb @@ -0,0 +1,33 @@ +# config valid only for Capistrano 3.1 +lock '3.2.1' + +set :application, 'webdns' +set :repo_url, 'git@bitbucket.org:xlembouras/webns.git' + +set :deploy_to, '/srv/webdns' + +set :linked_files, %w(config/database.yml config/secrets.yml) +set :linked_dirs, %w(log tmp/pids tmp/cache tmp/sockets) + +set :keep_releases, 5 + +namespace :deploy do + desc 'Restart application' + task :restart do + on roles(:app), in: :sequence, wait: 5 do + # Your restart mechanism here, for example: + # execute :touch, release_path.join('tmp/restart.txt') + end + end + + after :publishing, :restart + + after :restart, :clear_cache do + on roles(:web), in: :groups, limit: 3, wait: 10 do + # Here we can do anything such as: + # within release_path do + # execute :rake, 'cache:clear' + # end + end + end +end diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb new file mode 100644 index 0000000..757be32 --- /dev/null +++ b/config/deploy/staging.rb @@ -0,0 +1,5 @@ +set :rails_env, :production + +server 'webdns-edet4.grnet.gr', user: 'webdns', roles: %w(web app db) + +set :ssh_options, forward_agent: false diff --git a/lib/capistrano/tasks/assets.rake b/lib/capistrano/tasks/assets.rake new file mode 100644 index 0000000..803cefa --- /dev/null +++ b/lib/capistrano/tasks/assets.rake @@ -0,0 +1,123 @@ +load File.expand_path("../set_rails_env.rake", __FILE__) + +module Capistrano + class FileNotFound < StandardError + end +end + +namespace :deploy do + desc 'Normalize asset timestamps' + task :normalize_assets => [:set_rails_env] do + on release_roles(fetch(:assets_roles)) do + assets = fetch(:normalize_asset_timestamps) + if assets + within release_path do + execute :find, "#{assets} -exec touch -t #{asset_timestamp} {} ';'; true" + end + end + end + end + + desc 'Compile assets' + task :compile_assets => [:set_rails_env] do + invoke 'deploy:assets:precompile' + invoke 'deploy:assets:backup_manifest' + end + + desc 'Cleanup expired assets' + task :cleanup_assets => [:set_rails_env] do + next unless fetch(:keep_assets) + on release_roles(fetch(:assets_roles)) do + within release_path do + with rails_env: fetch(:rails_env) do + execute :rake, "assets:clean[#{fetch(:keep_assets)}]" + end + end + end + end + + desc 'Rollback assets' + task :rollback_assets => [:set_rails_env] do + begin + invoke 'deploy:assets:restore_manifest' + rescue Capistrano::FileNotFound + invoke 'deploy:compile_assets' + end + end + + after 'deploy:updated', 'deploy:compile_assets' + after 'deploy:updated', 'deploy:cleanup_assets' + after 'deploy:updated', 'deploy:normalize_assets' + after 'deploy:reverted', 'deploy:rollback_assets' + + namespace :assets do + task :precompile do + on release_roles(fetch(:assets_roles)) do + within release_path do + with rails_env: fetch(:rails_env) do + execute :rake, "assets:precompile" + end + end + end + end + + task :backup_manifest do + on release_roles(fetch(:assets_roles)) do + within release_path do + backup_path = release_path.join('assets_manifest_backup') + + execute :mkdir, '-p', backup_path + execute :cp, + detect_manifest_path, + backup_path + end + end + end + + task :restore_manifest do + on release_roles(fetch(:assets_roles)) do + within release_path do + target = detect_manifest_path + source = release_path.join('assets_manifest_backup', File.basename(target)) + if test "[[ -f #{source} && -f #{target} ]]" + execute :cp, source, target + else + msg = 'Rails assets manifest file (or backup file) not found.' + warn msg + fail Capistrano::FileNotFound, msg + end + end + end + end + + def detect_manifest_path + %w( + .sprockets-manifest* + manifest*.* + ).each do |pattern| + candidate = release_path.join('public', fetch(:assets_prefix), pattern) + return capture(:ls, candidate).strip if test(:ls, candidate) + end + msg = 'Rails assets manifest file not found.' + warn msg + fail Capistrano::FileNotFound, msg + end + end +end + +# we can't set linked_dirs in load:defaults, +# as assets_prefix will always have a default value +namespace :deploy do + task :set_linked_dirs do + set :linked_dirs, fetch(:linked_dirs, []).push("public/#{fetch(:assets_prefix)}") + end +end + +after 'deploy:set_rails_env', 'deploy:set_linked_dirs' + +namespace :load do + task :defaults do + set :assets_roles, fetch(:assets_roles, [:web]) + set :assets_prefix, fetch(:assets_prefix, 'assets') + end +end diff --git a/lib/capistrano/tasks/migrations.rake b/lib/capistrano/tasks/migrations.rake new file mode 100644 index 0000000..02137e3 --- /dev/null +++ b/lib/capistrano/tasks/migrations.rake @@ -0,0 +1,31 @@ +load File.expand_path("../set_rails_env.rake", __FILE__) + +namespace :deploy do + + desc 'Runs rake db:migrate if migrations are set' + task :migrate => [:set_rails_env] do + on primary fetch(:migration_role) do + conditionally_migrate = fetch(:conditionally_migrate) + info '[deploy:migrate] Checking changes in /db/migrate' if conditionally_migrate + if conditionally_migrate && test("diff -q #{release_path}/db/migrate #{current_path}/db/migrate") + info '[deploy:migrate] Skip `deploy:migrate` (nothing changed in db/migrate)' + else + info '[deploy:migrate] Run `rake db:migrate`' + within release_path do + with rails_env: fetch(:rails_env) do + execute :rake, "db:migrate" + end + end + end + end + end + + after 'deploy:updated', 'deploy:migrate' +end + +namespace :load do + task :defaults do + set :conditionally_migrate, fetch(:conditionally_migrate, false) + set :migration_role, fetch(:migration_role, :db) + end +end diff --git a/lib/capistrano/tasks/set_rails_env.rake b/lib/capistrano/tasks/set_rails_env.rake new file mode 100644 index 0000000..d751ccc --- /dev/null +++ b/lib/capistrano/tasks/set_rails_env.rake @@ -0,0 +1,9 @@ +namespace :deploy do + task :set_rails_env do + set :rails_env, (fetch(:rails_env) || fetch(:stage)) + end +end + +Capistrano::DSL.stages.each do |stage| + after stage, 'deploy:set_rails_env' +end