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
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ # rubocop:disable Metrics/ModuleLength
6
+ module Capistrano
7
+ module Ops
8
+ module FigaroYml
9
+ module Helpers
10
+ def remote_file_exists?
11
+ test("[ -f #{figaro_yml_remote_path} ]")
12
+ end
13
+
14
+ def remote_backup_exists?
15
+ count_remote_files.positive?
16
+ end
17
+
18
+ def rollback_remote_backup
19
+ latest_backup = latest_remote_backup
20
+ puts "mv #{figaro_yml_remote_path.parent.join(latest_backup)} #{figaro_yml_remote_path}"
21
+ execute :mv, figaro_yml_remote_path.parent.join(latest_backup), figaro_yml_remote_path
22
+ execute :ls, '-l', figaro_yml_remote_path.parent
23
+ end
24
+
25
+ def latest_remote_backup
26
+ command = "ls -1t #{figaro_yml_remote_path.parent} | grep -E '#{backup_regex}' | head -n 1"
27
+ capture(command).strip
28
+ end
29
+
30
+ def backup_regex
31
+ # filename we are looking for "#{figaro_yml_remote_path.basename}-yyyy-mm-dd-HH-MM-SS.bak"
32
+ "#{figaro_yml_remote_path.basename}-[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}-[0-9]{2}.bak"
33
+ end
34
+
35
+ def count_remote_files
36
+ command = "ls -1 #{figaro_yml_remote_path.parent} | grep -E '#{backup_regex}' | wc -l"
37
+ capture(command).to_i
38
+ end
39
+
40
+ def create_remote_backup
41
+ backup_file = "#{figaro_yml_remote_path.basename}-#{Time.now.strftime('%Y-%m-%d-%H-%M-%S')}.bak"
42
+ # puts "cp #{figaro_yml_remote_path} #{figaro_yml_remote_path.parent.join(backup_file)}"
43
+ execute :cp, figaro_yml_remote_path, figaro_yml_remote_path.parent.join(backup_file)
44
+ end
45
+
46
+ def cleanup_remote_backups
47
+ number_of_backups = count_remote_files
48
+ return unless number_of_backups > 5
49
+
50
+ diff = number_of_backups - 5
51
+ # remove older backups and keep the latest 5
52
+ command = "ls -1t #{figaro_yml_remote_path.parent} | grep -E '#{backup_regex}' | tail -n #{diff}"
53
+
54
+ capture(command).split("\n").each do |file|
55
+ execute "rm #{figaro_yml_remote_path.parent.join(file)}"
56
+ end
57
+ end
58
+
59
+ def local_figaro_yml(env)
60
+ @local_figaro_yml ||= YAML.load(ERB.new(File.read(figaro_yml_local_path)).result)
61
+ local_figaro = {}
62
+ deployment_env = fetch(:rails_env, env).to_s
63
+
64
+ @local_figaro_yml.each do |key, value|
65
+ if key == env
66
+ local_figaro[deployment_env] = @local_figaro_yml[key]
67
+ elsif !value.is_a?(Hash)
68
+ local_figaro[key] = @local_figaro_yml[key]
69
+ end
70
+ end
71
+
72
+ local_figaro
73
+ end
74
+
75
+ def local_yaml
76
+ YAML.safe_load(File.read(figaro_yml_local_path)) || {}
77
+ end
78
+
79
+ def figaro_yml_env
80
+ fetch(:figaro_yml_env).to_s
81
+ end
82
+
83
+ def figaro_yml_content
84
+ local_figaro_yml(figaro_yml_env).to_yaml
85
+ end
86
+
87
+ def configs(yaml, env)
88
+ stage_yml = yaml[env.to_s]&.sort.to_h
89
+ global_yml = remove_nested(yaml)&.sort.to_h
90
+ [global_yml, stage_yml]
91
+ end
92
+
93
+ def remove_nested(hash)
94
+ hash.each_with_object({}) do |(key, value), new_hash|
95
+ new_hash[key] = value unless value.is_a?(Hash)
96
+ end
97
+ end
98
+
99
+ def sort_with_nested(hash)
100
+ hash.each_with_object({}) do |(key, value), new_hash|
101
+ new_hash[key] = value.is_a?(Hash) ? sort_with_nested(value) : value
102
+ end.sort.to_h
103
+ end
104
+
105
+ def compare_hashes(hash1, hash2)
106
+ all_keys = hash1.keys | hash2.keys # Union of all keys from both hashes
107
+ all_keys.each_with_object({}) do |key, changes_hash|
108
+ old_value = hash2[key].nil? ? 'nil' : hash2[key].to_s
109
+ new_value = hash1[key].nil? ? 'nil' : hash1[key].to_s
110
+
111
+ changes_hash[key] = { old: old_value, new: new_value } if old_value != new_value
112
+ end.tap { |changes| return changes.empty? ? nil : changes }
113
+ end
114
+
115
+ # selection helpers
116
+ def ask_to_overwrite(question)
117
+ answer = ''
118
+ until %w[y n].include?(answer)
119
+ print "#{question}? (y/N): "
120
+ answer = $stdin.gets.strip.downcase
121
+ end
122
+ answer == 'y'
123
+ end
124
+
125
+ # info helpers
126
+
127
+ def print_changes(changes, message)
128
+ return unless changes
129
+
130
+ puts "#{message}:\n\n"
131
+ changes.each do |key, diff|
132
+ puts "#{key}: #{diff[:old]} => #{diff[:new]}"
133
+ end
134
+ puts "\n"
135
+ end
136
+
137
+ # error helpers
138
+
139
+ def check_git_tracking_error
140
+ puts
141
+ puts "Error - please remove '#{fetch(:figaro_yml_local_path)}' from git:"
142
+ puts
143
+ puts " $ git rm --cached #{fetch(:figaro_yml_local_path)}"
144
+ puts
145
+ puts 'and gitignore it:'
146
+ puts
147
+ puts " $ echo '#{fetch(:figaro_yml_local_path)}' >> .gitignore"
148
+ puts
149
+ end
150
+
151
+ def check_config_present_error
152
+ puts
153
+ puts "Error - '#{figaro_yml_env}' config not present in '#{fetch(:figaro_yml_local_path)}'."
154
+ puts 'Please populate it.'
155
+ puts
156
+ end
157
+
158
+ def check_figaro_file_exists_error
159
+ puts
160
+ puts "Error - '#{fetch(:figaro_yml_local_path)}' file does not exists, and it's required."
161
+ puts
162
+ end
163
+
164
+ # file helpers
165
+ def write_to_file(file, content)
166
+ File.open(file, 'w') do |f|
167
+ f.write(content)
168
+ end
169
+ end
170
+
171
+ def write_combined_yaml(yamls_combined)
172
+ if yamls_combined.empty?
173
+ info 'No data to write.'
174
+ else
175
+ # write to new file
176
+ info 'writing to config/application.yml'
177
+ write_to_file(figaro_yml_local_path, yamls_combined.to_yaml)
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
184
+ # rubocop:enable Metrics/ModuleLength
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ module Capistrano
6
+ module Ops
7
+ module FigaroYml
8
+ module Paths
9
+ def figaro_yml_local_path
10
+ Pathname.new fetch(:figaro_yml_local_path)
11
+ end
12
+
13
+ def figaro_yml_remote_path
14
+ shared_path.join fetch(:figaro_yml_remote_path)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Helpers
5
+
6
+ task :backup do
7
+ on release_roles :all do
8
+ unless remote_file_exists?
9
+ puts 'No remote application.yml to backup.'
10
+ next
11
+ end
12
+
13
+ begin
14
+ puts 'Creating backup of remote application.yml...'
15
+ create_remote_backup
16
+ puts 'Backup created successfully.'
17
+
18
+ puts 'Cleaning up remote backups...'
19
+ cleanup_remote_backups
20
+ puts 'Remote backups cleaned up successfully.'
21
+ rescue StandardError => e
22
+ puts "Error during backup process: #{e.message}"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+ desc 'figaro `application.yml` file checks'
7
+ task :check do
8
+ invoke 'figaro_yml:check_figaro_file_exists'
9
+ invoke 'figaro_yml:check_git_tracking'
10
+ invoke 'figaro_yml:check_config_present'
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+ task :check_config_present do
7
+ next unless local_figaro_yml(figaro_yml_env).nil?
8
+
9
+ check_config_present_error
10
+ exit 1
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+ task :check_figaro_file_exists do
7
+ next if File.exist?(figaro_yml_local_path)
8
+
9
+ check_figaro_file_exists_error
10
+ exit 1
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+ task :check_git_tracking do
7
+ next unless system("git ls-files #{fetch(:figaro_yml_local_path)} --error-unmatch >/dev/null 2>&1")
8
+
9
+ check_git_tracking_error
10
+ exit 1
11
+ end
12
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+
7
+ desc 'compare and set the figaro_yml file on the server'
8
+ task :compare do
9
+ # Read and parse local application.yml
10
+ local = local_figaro_yml(figaro_yml_env)
11
+
12
+ # Split into stage-specific and global configurations
13
+ local_global_env, local_stage_env = configs(local, figaro_yml_env)
14
+
15
+ on release_roles :all do
16
+ # Read and parse remote application.yml
17
+ remote = YAML.safe_load(capture("cat #{figaro_yml_remote_path}"))
18
+ remote_global_env, remote_stage_env = configs(remote, figaro_yml_env)
19
+
20
+ # Compare hashes and handle nil results with empty hashes
21
+ differences_global = compare_hashes(local_global_env, remote_global_env)
22
+ differences_stage = compare_hashes(local_stage_env, remote_stage_env)
23
+
24
+ print_changes(differences_global, 'Local application.yml has extra/different global entries compared to remote.')
25
+ if differences_stage
26
+ print_changes(differences_stage, "Local application.yml has extra/different entries in #{figaro_yml_env} section compared to remote.")
27
+ end
28
+
29
+ puts 'No Differences found between remote and local application.yml' unless differences_global || differences_stage
30
+
31
+ # ask to overwrite remote yml if differences found
32
+ overwrite_remote = ask_to_overwrite('Overwrite remote application.yml') if differences_global || differences_stage
33
+ puts 'Nothing written to remote application.yml' unless overwrite_remote
34
+
35
+ exit unless overwrite_remote
36
+ # sort local yml before updating remote
37
+ puts 'Preparing local application.yml before updating remote...'
38
+ invoke 'figaro_yml:sort_local'
39
+ puts 'Local application.yml is ready to be updated.'
40
+
41
+ # update remote yml
42
+ invoke 'figaro_yml:setup'
43
+ ##
44
+ # TODO: restart server after updating remote yml
45
+ # let user choose to restart server after updating remote yml
46
+ # let user choose to restart server now or later if they choose to restart now
47
+ # ask for time to restart server if he chooses to restart later
48
+ # restart server after the time given
49
+ ##
50
+ puts 'Remote application.yml has been updated.'
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+ task :create_local do
7
+ run_locally do
8
+ puts "found #{stages.count} stages"
9
+ yamls_combined = {}
10
+
11
+ stages.each do |f|
12
+ stage = File.basename(f, '.rb')
13
+ puts "download #{stage} application.yml"
14
+ begin
15
+ res = capture "cap #{stage} figaro_yml:get_stage"
16
+ stage_yaml = YAML.safe_load(res)
17
+ stage_yaml[stage.to_s] = stage_yaml[stage.to_s].sort.to_h
18
+ yamls_combined.merge!(stage_yaml) if stage_yaml
19
+ rescue StandardError
20
+ puts "could not get #{stage} application.yml"
21
+ end
22
+ end
23
+
24
+ write_combined_yaml(yamls_combined.sort.to_h)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+ task :figaro_yml_symlink do
7
+ set :linked_files, fetch(:linked_files, []).push(fetch(:figaro_yml_remote_path))
8
+ end
9
+ after 'deploy:started', 'figaro_yml:figaro_yml_symlink'
10
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+ task :get do
7
+ if !File.exist?(figaro_yml_local_path)
8
+ invoke 'figaro_yml:create_local'
9
+ else
10
+ local_yml = local_figaro_yml(figaro_yml_env)
11
+ local_global, local_stage = configs(local_yml, figaro_yml_env)
12
+ on release_roles :all do
13
+ remote = capture "cat #{figaro_yml_remote_path}"
14
+ remote_yml = YAML.safe_load(remote).sort.to_h
15
+ remote_global, remote_stage = configs(remote_yml, figaro_yml_env)
16
+ differences_global = compare_hashes(remote_global, local_global || {})
17
+ differences_stage = compare_hashes(remote_stage, local_stage || {})
18
+
19
+ print_changes(differences_global,
20
+ 'Remote application.yml has extra/different global entries compared to local.')
21
+ if differences_stage
22
+ print_changes(differences_stage, "Remote application.yml has extra/different entries in #{figaro_yml_env} section compared to local.")
23
+ end
24
+
25
+ puts 'No Differences found between remote and local application.yml' unless differences_global || differences_stage
26
+
27
+ # ask to overwrite local yml if differences found
28
+ stage_overwrite = ask_to_overwrite("Overwrite local application.yml #{figaro_yml_env} section") if differences_stage
29
+ global_overwrite = ask_to_overwrite('Overwrite local application.yml globals') if differences_global
30
+ puts 'Nothing written to local application.yml' unless stage_overwrite || global_overwrite
31
+ exit unless stage_overwrite || global_overwrite
32
+
33
+ # compose new yml
34
+ composed_yml = {}
35
+ composed_yml.merge!(local_yml) # local yml is always included to avoid losing any data
36
+ composed_yml.merge!(local_global) unless global_overwrite
37
+ composed_yml.merge!(remote_global) if global_overwrite
38
+ composed_yml[figaro_yml_env.to_s] = stage_overwrite ? remote_stage : local_stage
39
+
40
+ # write to new file
41
+ write_combined_yaml(composed_yml.sort.to_h)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+ rake_roles = fetch(:rake_roles, :app)
7
+
8
+ task :get_stage do
9
+ on roles(rake_roles) do
10
+ raise 'The file does not exist.' unless test "[ -f #{figaro_yml_remote_path} ]"
11
+
12
+ puts capture "cat #{figaro_yml_remote_path}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :load do
4
+ task :defaults do
5
+ set :figaro_yml_local_path, 'config/application.yml'
6
+ set :figaro_yml_remote_path, 'config/application.yml'
7
+ set :figaro_yml_env, -> { fetch(:rails_env) || fetch(:stage) }
8
+ set :figaro_yml_remote_backup, false
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Helpers
5
+
6
+ task :rollback do
7
+ on release_roles :all do
8
+ unless remote_backup_exists?
9
+ puts 'No backup of remote application.yml to rollback.'
10
+ next
11
+ end
12
+
13
+ begin
14
+ puts 'Rolling back remote application.yml...'
15
+ rollback_remote_backup
16
+ puts 'Rollback completed successfully.'
17
+ rescue StandardError => e
18
+ puts "Error during rollback process: #{e.message}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+
7
+ desc 'Setup figaro `application.yml` file on the server(s)'
8
+ task setup: [:check] do
9
+ content = figaro_yml_content
10
+ on release_roles :all do
11
+ execute :mkdir, '-pv', File.dirname(figaro_yml_remote_path)
12
+ upload! StringIO.new(content), figaro_yml_remote_path
13
+ end
14
+ end
15
+ before 'figaro_yml:setup', 'figaro_yml:backup'
16
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :figaro_yml do
4
+ include Capistrano::Ops::FigaroYml::Paths
5
+ include Capistrano::Ops::FigaroYml::Helpers
6
+ task :sort_local do
7
+ run_locally do
8
+ info 'Sorting local application.yml...'
9
+ local = local_yaml
10
+ sorted_local = sort_with_nested(local)
11
+ write_combined_yaml(sorted_local)
12
+ end
13
+ end
14
+
15
+ task :sort do
16
+ invoke 'figaro_yml:sort_local'
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'capistrano/ops/helper'
4
+ require 'capistrano/ops/figaro_yml/paths'
5
+ require 'capistrano/ops/figaro_yml/helpers'
6
+
7
+ module TaskLoader
8
+ extend Capistrano::Ops::Helper
9
+
10
+ def self.load_tasks_if_gem_present(gem_name, task_path, warning_message)
11
+ if gem_in_gemfile?(gem_name)
12
+ Dir.glob("#{File.expand_path(__dir__)}/#{task_path}/**/*.rake").each { |f| load f }
13
+ else
14
+ puts warning_message
15
+ end
16
+ end
17
+ end
18
+
19
+ TaskLoader.load_tasks_if_gem_present('figaro', 'figaro_yml/tasks', 'WARNING: Gemfile does not include figaro gem which is required for figaro_yml tasks')
20
+ # include Capistrano::Ops::Helper
21
+
22
+ # Dir.glob("#{File.expand_path(__dir__)}/figaro_yml/tasks/*.rake").each { |f| load f }
23
+
24
+ # # gem 'figaro' is required for figaro_yml tasks
25
+
26
+ # figaro_gem = gem_in_gemfile?('figaro')
27
+
28
+ # # check if Gemfile environment includes figaro gem and warn user if not found
29
+ # puts 'WARNING: Gemfile does not include figaro gem which is required for figaro_yml tasks' unless figaro_gem
@@ -0,0 +1,14 @@
1
+ module Capistrano
2
+ module Ops
3
+ module Helper
4
+ def gem_in_gemfile?(gem_name)
5
+ if File.exist?('Gemfile')
6
+ File.foreach('Gemfile') do |line|
7
+ return true if line.include?('gem') && line.include?("'#{gem_name}'") && !line.include?('#')
8
+ end
9
+ end
10
+ false
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,25 @@
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
+ task_name = ENV['TASK']
10
+ unless task_name
11
+ puts "\n\nFailed! You need to specify the 'TASK' parameter!",
12
+ 'Usage: cap <stage> invoke:rake TASK=your:task',
13
+ 'Example: cap production invoke:rake TASK=db:migrate'
14
+ exit 1
15
+ end
16
+
17
+ on roles(rake_roles) do
18
+ within current_path do
19
+ with rails_env: fetch(:rails_env) do
20
+ execute :rake, task_name
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir.glob("#{File.expand_path(__dir__)}/invoke/tasks/**/*.rake").each { |f| load f }
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capistrano
4
+ module Ops
5
+ module Logrotate
6
+ module Helpers
7
+ def config_template
8
+ return nil unless File.exist?(File.expand_path(logrotate_config_file_template, __dir__))
9
+
10
+ ERB.new(File.read(File.expand_path(logrotate_config_file_template, __dir__))).result(binding)
11
+ end
12
+
13
+ def schedule_template
14
+ return nil unless File.exist?(File.expand_path(logrotate_schedule_file_template, __dir__))
15
+
16
+ ERB.new(File.read(File.expand_path(logrotate_schedule_file_template, __dir__))).result(binding)
17
+ end
18
+
19
+ def logrotate_enabled
20
+ test("[ -f #{logrotate_config_file_path} ]") && test("[ -f #{logrotate_schedule_file_path} ]")
21
+ end
22
+
23
+ def logrotate_disabled
24
+ !(test("[ -f #{logrotate_config_file_path} ]") && test("[ -f #{logrotate_schedule_file_path} ]"))
25
+ end
26
+
27
+ def make_basepath
28
+ puts capture "mkdir -pv #{logrotate_basepath}"
29
+ end
30
+
31
+ def delete_files
32
+ puts capture "rm -rfv #{logrotate_basepath}"
33
+ end
34
+
35
+ def whenever(type)
36
+ case type
37
+ when 'clear'
38
+ puts capture :bundle, :exec, :whenever, '--clear-crontab',
39
+ "-f #{logrotate_schedule_file_path} #{fetch(:whenever_identifier)}_logrotate"
40
+ when 'update'
41
+ puts capture :bundle, :exec, :whenever, '--update-crontab', "-f #{logrotate_schedule_file_path}",
42
+ "-i #{fetch(:whenever_identifier)}_logrotate"
43
+ else
44
+ puts 'type not found'
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end