capistrano-ops 0.2.13 → 1.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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -0
  3. data/README.md +121 -29
  4. data/capistrano-ops.gemspec +2 -0
  5. data/lib/capistrano/ops/backup/helper.rb +56 -0
  6. data/lib/capistrano/ops/{capistrano/v3/tasks/backup → backup/tasks}/database/create.rake +1 -2
  7. data/lib/capistrano/ops/{capistrano/v3/tasks/backup → backup/tasks}/database/pull.rake +1 -2
  8. data/lib/capistrano/ops/{capistrano/v3/tasks/backup → backup/tasks}/storage/create.rake +1 -2
  9. data/lib/capistrano/ops/{capistrano/v3/tasks/backup → backup/tasks}/storage/pull.rake +1 -2
  10. data/lib/capistrano/ops/backup.rb +14 -4
  11. data/lib/capistrano/ops/capistrano.rb +7 -10
  12. data/lib/capistrano/ops/figaro_yml/helpers.rb +184 -0
  13. data/lib/capistrano/ops/figaro_yml/paths.rb +19 -0
  14. data/lib/capistrano/ops/figaro_yml/tasks/backup.rake +26 -0
  15. data/lib/capistrano/ops/figaro_yml/tasks/check.rake +12 -0
  16. data/lib/capistrano/ops/figaro_yml/tasks/check_config_present.rake +12 -0
  17. data/lib/capistrano/ops/figaro_yml/tasks/check_figaro_file_exists.rake +12 -0
  18. data/lib/capistrano/ops/figaro_yml/tasks/check_git_tracking.rake +12 -0
  19. data/lib/capistrano/ops/figaro_yml/tasks/compare.rake +53 -0
  20. data/lib/capistrano/ops/figaro_yml/tasks/create_local.rake +27 -0
  21. data/lib/capistrano/ops/figaro_yml/tasks/figaro_yml_symlink.rake +10 -0
  22. data/lib/capistrano/ops/figaro_yml/tasks/get.rake +45 -0
  23. data/lib/capistrano/ops/figaro_yml/tasks/get_stage.rake +15 -0
  24. data/lib/capistrano/ops/figaro_yml/tasks/load.rake +10 -0
  25. data/lib/capistrano/ops/figaro_yml/tasks/rollback.rake +22 -0
  26. data/lib/capistrano/ops/figaro_yml/tasks/setup.rake +16 -0
  27. data/lib/capistrano/ops/figaro_yml/tasks/sort_local.rake +18 -0
  28. data/lib/capistrano/ops/figaro_yml.rb +29 -0
  29. data/lib/capistrano/ops/helper.rb +14 -0
  30. data/lib/capistrano/ops/invoke/tasks/invoke.rake +25 -0
  31. data/lib/capistrano/ops/invoke.rb +3 -0
  32. data/lib/capistrano/ops/logrotate/helpers.rb +50 -0
  33. data/lib/capistrano/ops/logrotate/paths.rb +47 -0
  34. data/lib/capistrano/ops/{capistrano/v3/tasks/logrotate → logrotate/tasks}/check.rake +3 -5
  35. data/lib/capistrano/ops/{capistrano/v3/tasks/logrotate → logrotate/tasks}/disable.rake +2 -5
  36. data/lib/capistrano/ops/logrotate/tasks/enable.rake +28 -0
  37. data/lib/capistrano/ops/logrotate/tasks/load.rake +10 -0
  38. data/lib/capistrano/ops/logrotate.rb +19 -0
  39. data/lib/capistrano/ops/logs/helpers.rb +16 -0
  40. data/lib/capistrano/ops/logs/paths.rb +23 -0
  41. data/lib/capistrano/ops/logs/tasks/load.rake +9 -0
  42. data/lib/capistrano/ops/logs/tasks/rails.rake +18 -0
  43. data/lib/capistrano/ops/logs/tasks/sidekiq.rake +42 -0
  44. data/lib/capistrano/ops/logs.rb +18 -0
  45. data/lib/capistrano/ops/{backup → rails/lib/backup}/s3.rb +1 -1
  46. data/lib/capistrano/ops/rails/lib/backup.rb +6 -0
  47. data/lib/capistrano/ops/rails/lib/notification.rb +9 -0
  48. data/lib/capistrano/ops/rails/lib/railtie.rb +17 -0
  49. data/lib/capistrano/ops/{tasks → rails/lib/tasks}/pg/postgres_helper.rb +1 -1
  50. data/lib/capistrano/ops/version.rb +1 -1
  51. data/lib/capistrano/ops/{capistrano/v3/tasks/whenever.rake → whenever/tasks/show_crontab.rake} +1 -3
  52. data/lib/capistrano/ops/whenever.rb +17 -0
  53. data/lib/capistrano/ops/wkhtmltopdf/helpers.rb +50 -0
  54. data/lib/capistrano/ops/wkhtmltopdf/tasks/setup.rake +17 -0
  55. data/lib/capistrano/ops/wkhtmltopdf.rb +17 -1
  56. data/lib/capistrano/ops.rb +4 -3
  57. metadata +88 -31
  58. data/lib/capistrano/ops/capistrano/tasks/wkhtmltopdf.rake +0 -48
  59. data/lib/capistrano/ops/capistrano/v3/tasks/backup/backup_helper.rb +0 -50
  60. data/lib/capistrano/ops/capistrano/v3/tasks/figaro_yml.rake +0 -139
  61. data/lib/capistrano/ops/capistrano/v3/tasks/invoke.rake +0 -23
  62. data/lib/capistrano/ops/capistrano/v3/tasks/logrotate/enable.rake +0 -24
  63. data/lib/capistrano/ops/capistrano/v3/tasks/logrotate/logrotate_helper.rb +0 -68
  64. data/lib/capistrano/ops/capistrano/v3/tasks/logs/rails.rake +0 -16
  65. data/lib/capistrano/ops/notification.rb +0 -9
  66. data/lib/capistrano/ops/railtie.rb +0 -15
  67. /data/lib/capistrano/ops/{capistrano/v3/tasks/logrotate → logrotate/tasks}/templates/logrotate.conf.erb +0 -0
  68. /data/lib/capistrano/ops/{capistrano/v3/tasks/logrotate → logrotate/tasks}/templates/schedule.rb.erb +0 -0
  69. /data/lib/capistrano/ops/{backup → rails/lib/backup}/api.rb +0 -0
  70. /data/lib/capistrano/ops/{backup → rails/lib/backup}/s3_helper.rb +0 -0
  71. /data/lib/capistrano/ops/{notification → rails/lib/notification}/api.rb +0 -0
  72. /data/lib/capistrano/ops/{notification → rails/lib/notification}/slack.rb +0 -0
  73. /data/lib/capistrano/ops/{notification → rails/lib/notification}/webhook.rb +0 -0
  74. /data/lib/capistrano/ops/{tasks → rails/lib/tasks}/pg/dump.rake +0 -0
  75. /data/lib/capistrano/ops/{tasks → rails/lib/tasks}/pg/remove_old_dumps.rake +0 -0
  76. /data/lib/capistrano/ops/{tasks → rails/lib/tasks}/storage/backup.rake +0 -0
  77. /data/lib/capistrano/ops/{tasks → rails/lib/tasks}/storage/remove_old_backups.rake +0 -0
@@ -1,48 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- namespace :wkhtmltopdf do
4
- after 'deploy:symlink:release', 'wkhtmltopdf:setup'
5
-
6
- desc 'unzip wkhtmltopdf if necessary'
7
- task :setup do
8
- on roles(:app) do
9
- within release_path do
10
- binary_path, version = binary_path_and_version
11
- info("setup wkhtmltopdf version #{version}")
12
- check_file_and_permissions(binary_path, version)
13
- end
14
- end
15
- end
16
- end
17
- def binary_path_and_version
18
- # get the binary path of wkhtmltopdf-binary
19
- gem_path = capture(:bundle, 'show', 'wkhtmltopdf-binary').strip
20
- binary_path = "#{gem_path}/bin"
21
-
22
- # get the use wkhtmltopdf_ubuntu version from the wicked_pdf initializer
23
- version = capture(:cat, 'config/initializers/wicked_pdf.rb').scan(/wkhtmltopdf_ubuntu_(\d+\.\d+)_amd64/).flatten.first
24
-
25
- [binary_path, version]
26
- end
27
-
28
- def check_file_and_permissions(binary_path, version)
29
- binary_file = "#{binary_path}/wkhtmltopdf_ubuntu_#{version}_amd64"
30
-
31
- if test("[ -f #{binary_file} ]")
32
- info('wkhtmltopdf binary already extracted')
33
-
34
- if test("[ $(stat -c '%a' #{binary_file}) = '777' ]")
35
- info('wkhtmltopdf binary has already the right permissions')
36
- else
37
- info('adding right permissions to wkhtmltopdf binary')
38
- execute("chmod 777 #{binary_file}")
39
- end
40
- else
41
- info('extracting wkhtmltopdf binary')
42
- # extract the binary but keep the gzip file
43
- execute("cd #{binary_path} && gzip -dk wkhtmltopdf_ubuntu_#{version}_amd64.gz")
44
- # add execute permission to the binary
45
- execute("chmod 777 #{binary_file}")
46
- end
47
- info('wkhtmltopdf setup finished')
48
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module BackupHelper
4
- def backup_file_name(type)
5
- regex = type == 'storage' ? "'.{0,}\.tar.gz'" : "'.{0,}\.dump'"
6
- @backup_file_name ||= capture "cd #{shared_path}/backups && ls -lt | grep -E -i #{regex} | head -n 1 | awk '{print $9}'"
7
- end
8
-
9
- def backup_file_size
10
- @backup_file_size ||= capture "cd #{shared_path}/backups && wc -c #{@backup_file_name} | awk '{print $1}'"
11
- end
12
-
13
- def download_backup(backup_file, type)
14
- puts "Downloading #{type} backup"
15
- download! "#{shared_path}/backups/#{backup_file}", backup_file
16
- puts "Download finished\nDeleting temporary backup..."
17
- cleanup_backup(backup_file, "Download finished\nDeleting temporary backup...")
18
- end
19
-
20
- def cleanup_backup(backup_file, message)
21
- puts message
22
- execute "cd #{shared_path}/backups && rm #{backup_file}"
23
- puts 'Temporary backup deleted'
24
- end
25
-
26
- def question(question, default = 'n', &block)
27
- print "#{question} #{default.downcase == 'n' ? '(y/N)' : '(Y/n)'}: "
28
- input = $stdin.gets.strip.downcase
29
- answer = (input.empty? ? default : input).downcase.to_s
30
-
31
- if %w[y n].include?(answer)
32
- block.call(answer == 'y')
33
- else
34
- question(question, default, &block)
35
- end
36
- end
37
-
38
- def prepare_env
39
- @env = "RAILS_ENV=#{fetch(:stage)}"
40
- @path_cmd = "PATH=$HOME/.rbenv/versions/#{RUBY_VERSION}/bin:$PATH"
41
- @test_command = "cd #{release_path} && #{@path_cmd} && #{@env}"
42
- end
43
-
44
- def size_str(size)
45
- units = %w[B KB MB GB TB]
46
- e = (Math.log(size) / Math.log(1024)).floor
47
- s = format('%.2f', size.to_f / 1024**e)
48
- s.sub(/\.?0*$/, units[e])
49
- end
50
- end
@@ -1,139 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # rubocop:disable Metrics/BlockLength
4
- namespace :figaro_yml do
5
- # Defaults to :app role
6
- rake_roles = fetch(:rake_roles, :app)
7
-
8
- desc 'get the `application.yml` file from server and create local if it does not exist'
9
- task :get do
10
- env = fetch(:stage)
11
- if !File.exist?('config/application.yml')
12
- puts 'config/application.yml does not exist, creating it from all stages'
13
- run_locally do
14
- yamls = {}
15
- stages = Dir.glob('config/deploy/*.rb')
16
- puts "found #{stages.count} stages"
17
- stages.map do |f|
18
- stage = File.basename(f, '.rb')
19
- puts "download #{stage} application.yml"
20
- begin
21
- res = capture "cap #{stage} figaro_yml:get_stage"
22
- yamls = yamls.merge(YAML.safe_load(res))
23
- rescue StandardError
24
- puts "could not get #{stage} application.yml"
25
- end
26
- yamls
27
- end
28
- # write to new file
29
- puts 'writing to config/application.yml'
30
- write_to_file('config/application.yml', yamls.to_yaml)
31
- end
32
- else
33
- local_yml = YAML.safe_load(File.read('config/application.yml'))
34
- on roles(rake_roles) do
35
- remote = capture("cat #{shared_path}/config/application.yml")
36
- remote_yml = YAML.safe_load(remote)
37
- remote_stage = remote_yml[env.to_s]
38
- puts "remote application.yml stage '#{env}':\n\n"
39
- puts "#{remote}\r\n"
40
- puts "\r\n"
41
- loop do
42
- print "Overwrite local application.yml stage '#{env}'? (y/N): "
43
- input = $stdin.gets.strip.downcase
44
- answer = (input.empty? ? 'N' : input).downcase.to_s
45
-
46
- next unless %w[y n].include?(answer)
47
-
48
- if answer == 'y'
49
- puts 'Updating local application.yml'
50
- local_yml[env.to_s] = remote_stage
51
- write_to_file('config/application.yml', local_yml.to_yaml)
52
- exit
53
- end
54
- break
55
- end
56
- puts 'Nothing written to local application.yml'
57
- exit
58
- end
59
- end
60
- end
61
-
62
- task :get_stage do
63
- on roles(rake_roles) do
64
- puts capture "cat #{shared_path}/config/application.yml"
65
- end
66
- end
67
-
68
- desc 'compare and set the figaro_yml file on the server'
69
- task :compare do
70
- env = fetch(:stage)
71
- # read local application.yml
72
- local = File.read('config/application.yml')
73
-
74
- # convert to hash
75
- local_global_env = YAML.safe_load(local)
76
-
77
- # split into stage and global
78
- local_stage_env = local_global_env[env.to_s]
79
- local_global_env.delete('staging')
80
- local_global_env.delete('production')
81
-
82
- on roles(rake_roles) do
83
- # read remote application.yml
84
- remote = capture("cat #{shared_path}/config/application.yml")
85
-
86
- remote_global_env = YAML.safe_load(remote)
87
- remote_stage_env = remote_global_env[env.to_s]
88
- remote_global_env.delete(env.to_s)
89
-
90
- puts "with command 'cap #{env} figaro_yml:setup', following variables will be overwritten:"
91
- puts '--------------------------------------------------------------------------------'
92
- result1 = compare_hashes(local_global_env, remote_global_env)
93
- result2 = compare_hashes(local_stage_env, remote_stage_env)
94
- if !result1.empty? || !result2.empty?
95
- loop do
96
- print 'Update remote application.yml? (y/N): '
97
- input = $stdin.gets.strip.downcase
98
- answer = (input.empty? ? 'N' : input).downcase.to_s
99
-
100
- next unless %w[y n].include?(answer)
101
-
102
- if answer == 'y'
103
- puts 'Updating remote application.yml'
104
- invoke 'figaro_yml:setup'
105
- exit
106
- end
107
- break
108
- end
109
- puts 'remote application.yml not updated'
110
- exit
111
- end
112
- puts 'remote application.yml is up to date'
113
- end
114
- end
115
- def compare_hashes(hash1, hash2)
116
- changes = false
117
- local_server = hash1.to_a - hash2.to_a
118
- server_local = hash2.to_a - hash1.to_a
119
-
120
- [local_server + server_local].flatten(1).to_h.each_key do |k|
121
- new_value = hash1[k].to_s
122
- new_value = new_value.empty? ? 'nil' : new_value
123
- old_value = hash2[k].to_s
124
- old_value = old_value.empty? ? 'nil' : old_value
125
-
126
- if old_value != new_value
127
- puts "#{k}: #{old_value} => #{new_value} \r\n"
128
- changes = true
129
- end
130
- end
131
- end
132
-
133
- def write_to_file(file, content)
134
- File.open(file, 'w') do |f|
135
- f.write(content)
136
- end
137
- end
138
- end
139
- # rubocop:enable Metrics/BlockLength
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- namespace :invoke do
4
- # Defalut to :app roles
5
- rake_roles = fetch(:rake_roles, :app)
6
-
7
- desc 'Execute a rake task on a remote server (cap invoke:rake TASK=db:migrate)'
8
- task :rake do
9
- if ENV['TASK']
10
- on roles(rake_roles) do
11
- within current_path do
12
- with rails_env: fetch(:rails_env) do
13
- execute :rake, ENV['TASK']
14
- end
15
- end
16
- end
17
-
18
- else
19
- puts "\n\nFailed! You need to specify the 'TASK' parameter!",
20
- 'Usage: cap <stage> invoke:rake TASK=your:task'
21
- end
22
- end
23
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'logrotate_helper'
4
-
5
- namespace :logrotate do
6
- include LogrotateHelper
7
- desc 'Enable logrotate for the application'
8
- task :enable do
9
- on roles(:app) do
10
- within release_path do
11
- set_config
12
- if logrotate_enabled
13
- puts "logrotate already enabled:\n========================="
14
- puts capture "cat #{@config_file_path}"
15
- else
16
- make_basepath
17
- upload! StringIO.new(@config_template), @config_file_path
18
- upload! StringIO.new(@schedule_template), @schedule_file_path
19
- whenever 'update' if logrotate_enabled
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LogrotateHelper
4
- # rubocop:disable Naming/MemoizedInstanceVariableName
5
- def set_config
6
- info ''
7
- @shared_path ||= shared_path
8
- @log_file_path ||= fetch(:log_file_path) || "#{@shared_path}/log"
9
- @template_config_filename ||= fetch(:logrotate_template_config_file) || 'templates/logrotate.conf.erb'
10
- @template_schedule_filename ||= fetch(:logrotate_template_schedule_file) || 'templates/schedule.rb.erb'
11
- @basepath ||= fetch(:logrotate_basepath) || "#{shared_path}/logrotate"
12
- @config_filename ||= File.basename(@template_config_filename, '.erb')
13
- @schedule_filename ||= File.basename(@template_schedule_filename, '.erb')
14
- @config_file_path ||= "#{@basepath}/#{@config_filename}"
15
- @schedule_file_path ||= "#{@basepath}/#{@schedule_filename}"
16
- @config_template ||= config_template
17
- @schedule_template ||= schedule_template
18
- end
19
- # rubocop:enable Naming/MemoizedInstanceVariableName
20
-
21
- def config
22
- {
23
- template_config_file: fetch(:logrotate_template_config_file) || 'templates/logrotate.conf.erb',
24
- template_schedule_file: fetch(:logrotate_template_schedule_file) || 'templates/schedule.rb.erb'
25
- }
26
- end
27
-
28
- def make_basepath
29
- puts capture "mkdir -pv #{@basepath}"
30
- end
31
-
32
- def delete_files
33
- puts capture "rm -rfv #{@basepath}"
34
- end
35
-
36
- def config_template
37
- return nil unless @template_config_filename && File.exist?(File.expand_path(@template_config_filename, __dir__))
38
-
39
- ERB.new(File.read(File.expand_path(@template_config_filename, __dir__))).result(binding)
40
- end
41
-
42
- def schedule_template
43
- return nil unless @template_schedule_filename && File.exist?(File.expand_path(@template_schedule_filename, __dir__))
44
-
45
- ERB.new(File.read(File.expand_path(@template_schedule_filename, __dir__))).result(binding)
46
- end
47
-
48
- def logrotate_enabled
49
- test("[ -f #{@config_file_path} ]") && test("[ -f #{@schedule_file_path} ]")
50
- end
51
-
52
- def logrotate_disabled
53
- !(test("[ -f #{@config_file_path} ]") && test("[ -f #{@schedule_file_path} ]"))
54
- end
55
-
56
- def whenever(type)
57
- case type
58
- when 'clear'
59
- puts capture :bundle, :exec, :whenever, '--clear-crontab',
60
- "-f #{@schedule_file_path} #{fetch(:whenever_identifier)}_logrotate"
61
- when 'update'
62
- puts capture :bundle, :exec, :whenever, '--update-crontab', "-f #{@schedule_file_path}",
63
- "-i #{fetch(:whenever_identifier)}_logrotate"
64
- else
65
- puts 'type not found'
66
- end
67
- end
68
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- namespace :logs do
4
- # Default to :app role
5
- rake_roles = fetch(:rake_roles, :app)
6
- desc 'tail rails logs'
7
- task :rails do
8
- on roles(rake_roles) do
9
- trap('SIGINT') do
10
- puts "\nDisconnecting..."
11
- exit
12
- end
13
- execute "tail -f #{shared_path}/log/#{fetch(:rails_env)}.log"
14
- end
15
- end
16
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'capistrano/ops/notification/api'
4
- require 'capistrano/ops/notification/slack'
5
- require 'capistrano/ops/notification/webhook'
6
-
7
- module Notification
8
- class Error < StandardError; end
9
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails'
4
- # require 'capistrano/ops'
5
- module Capistrano
6
- module Ops
7
- class Railtie < ::Rails::Railtie
8
- railtie_name :ops
9
- rake_tasks do
10
- path = File.expand_path(__dir__)
11
- Dir.glob("#{path}/tasks/**/*.rake").each { |f| load f }
12
- end
13
- end
14
- end
15
- end