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.
- checksums.yaml +4 -4
- data/.rubocop.yml +7 -0
- data/README.md +121 -29
- data/capistrano-ops.gemspec +2 -0
- data/lib/capistrano/ops/backup/helper.rb +56 -0
- data/lib/capistrano/ops/{capistrano/v3/tasks/backup → backup/tasks}/database/create.rake +1 -2
- data/lib/capistrano/ops/{capistrano/v3/tasks/backup → backup/tasks}/database/pull.rake +1 -2
- data/lib/capistrano/ops/{capistrano/v3/tasks/backup → backup/tasks}/storage/create.rake +1 -2
- data/lib/capistrano/ops/{capistrano/v3/tasks/backup → backup/tasks}/storage/pull.rake +1 -2
- data/lib/capistrano/ops/backup.rb +14 -4
- data/lib/capistrano/ops/capistrano.rb +7 -10
- data/lib/capistrano/ops/figaro_yml/helpers.rb +184 -0
- data/lib/capistrano/ops/figaro_yml/paths.rb +19 -0
- data/lib/capistrano/ops/figaro_yml/tasks/backup.rake +26 -0
- data/lib/capistrano/ops/figaro_yml/tasks/check.rake +12 -0
- data/lib/capistrano/ops/figaro_yml/tasks/check_config_present.rake +12 -0
- data/lib/capistrano/ops/figaro_yml/tasks/check_figaro_file_exists.rake +12 -0
- data/lib/capistrano/ops/figaro_yml/tasks/check_git_tracking.rake +12 -0
- data/lib/capistrano/ops/figaro_yml/tasks/compare.rake +53 -0
- data/lib/capistrano/ops/figaro_yml/tasks/create_local.rake +27 -0
- data/lib/capistrano/ops/figaro_yml/tasks/figaro_yml_symlink.rake +10 -0
- data/lib/capistrano/ops/figaro_yml/tasks/get.rake +45 -0
- data/lib/capistrano/ops/figaro_yml/tasks/get_stage.rake +15 -0
- data/lib/capistrano/ops/figaro_yml/tasks/load.rake +10 -0
- data/lib/capistrano/ops/figaro_yml/tasks/rollback.rake +22 -0
- data/lib/capistrano/ops/figaro_yml/tasks/setup.rake +16 -0
- data/lib/capistrano/ops/figaro_yml/tasks/sort_local.rake +18 -0
- data/lib/capistrano/ops/figaro_yml.rb +29 -0
- data/lib/capistrano/ops/helper.rb +14 -0
- data/lib/capistrano/ops/invoke/tasks/invoke.rake +25 -0
- data/lib/capistrano/ops/invoke.rb +3 -0
- data/lib/capistrano/ops/logrotate/helpers.rb +50 -0
- data/lib/capistrano/ops/logrotate/paths.rb +47 -0
- data/lib/capistrano/ops/{capistrano/v3/tasks/logrotate → logrotate/tasks}/check.rake +3 -5
- data/lib/capistrano/ops/{capistrano/v3/tasks/logrotate → logrotate/tasks}/disable.rake +2 -5
- data/lib/capistrano/ops/logrotate/tasks/enable.rake +28 -0
- data/lib/capistrano/ops/logrotate/tasks/load.rake +10 -0
- data/lib/capistrano/ops/logrotate.rb +19 -0
- data/lib/capistrano/ops/logs/helpers.rb +16 -0
- data/lib/capistrano/ops/logs/paths.rb +23 -0
- data/lib/capistrano/ops/logs/tasks/load.rake +9 -0
- data/lib/capistrano/ops/logs/tasks/rails.rake +18 -0
- data/lib/capistrano/ops/logs/tasks/sidekiq.rake +42 -0
- data/lib/capistrano/ops/logs.rb +18 -0
- data/lib/capistrano/ops/{backup → rails/lib/backup}/s3.rb +1 -1
- data/lib/capistrano/ops/rails/lib/backup.rb +6 -0
- data/lib/capistrano/ops/rails/lib/notification.rb +9 -0
- data/lib/capistrano/ops/rails/lib/railtie.rb +17 -0
- data/lib/capistrano/ops/{tasks → rails/lib/tasks}/pg/postgres_helper.rb +1 -1
- data/lib/capistrano/ops/version.rb +1 -1
- data/lib/capistrano/ops/{capistrano/v3/tasks/whenever.rake → whenever/tasks/show_crontab.rake} +1 -3
- data/lib/capistrano/ops/whenever.rb +17 -0
- data/lib/capistrano/ops/wkhtmltopdf/helpers.rb +50 -0
- data/lib/capistrano/ops/wkhtmltopdf/tasks/setup.rake +17 -0
- data/lib/capistrano/ops/wkhtmltopdf.rb +17 -1
- data/lib/capistrano/ops.rb +4 -3
- metadata +88 -31
- data/lib/capistrano/ops/capistrano/tasks/wkhtmltopdf.rake +0 -48
- data/lib/capistrano/ops/capistrano/v3/tasks/backup/backup_helper.rb +0 -50
- data/lib/capistrano/ops/capistrano/v3/tasks/figaro_yml.rake +0 -139
- data/lib/capistrano/ops/capistrano/v3/tasks/invoke.rake +0 -23
- data/lib/capistrano/ops/capistrano/v3/tasks/logrotate/enable.rake +0 -24
- data/lib/capistrano/ops/capistrano/v3/tasks/logrotate/logrotate_helper.rb +0 -68
- data/lib/capistrano/ops/capistrano/v3/tasks/logs/rails.rake +0 -16
- data/lib/capistrano/ops/notification.rb +0 -9
- data/lib/capistrano/ops/railtie.rb +0 -15
- /data/lib/capistrano/ops/{capistrano/v3/tasks/logrotate → logrotate/tasks}/templates/logrotate.conf.erb +0 -0
- /data/lib/capistrano/ops/{capistrano/v3/tasks/logrotate → logrotate/tasks}/templates/schedule.rb.erb +0 -0
- /data/lib/capistrano/ops/{backup → rails/lib/backup}/api.rb +0 -0
- /data/lib/capistrano/ops/{backup → rails/lib/backup}/s3_helper.rb +0 -0
- /data/lib/capistrano/ops/{notification → rails/lib/notification}/api.rb +0 -0
- /data/lib/capistrano/ops/{notification → rails/lib/notification}/slack.rb +0 -0
- /data/lib/capistrano/ops/{notification → rails/lib/notification}/webhook.rb +0 -0
- /data/lib/capistrano/ops/{tasks → rails/lib/tasks}/pg/dump.rake +0 -0
- /data/lib/capistrano/ops/{tasks → rails/lib/tasks}/pg/remove_old_dumps.rake +0 -0
- /data/lib/capistrano/ops/{tasks → rails/lib/tasks}/storage/backup.rake +0 -0
- /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,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
|