capistrano-ops 0.2.13 → 0.2.14

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cec4486500e5ddac70640e6f3d074b51b361d649079e98f9ef6d337712c3de23
4
- data.tar.gz: ac8df454d33822890a673e800db7492bc7d4d2a7f54c0fe91378648fa163a2f8
3
+ metadata.gz: 72b073b9c2ecb5026ab9f56c3953f9bd664e5537087a07c7a22cd390a69fe7da
4
+ data.tar.gz: 60e5b8b52641c59bd1c6c3ec1b99aef79e90269a2ca11deb23b39283348b00e1
5
5
  SHA512:
6
- metadata.gz: c97bd7b0f7b0f9968b30d81a8807da57d690a4700e6674596f64b970727e4d99606af7ac8e192691fae63a0e5cf67ee54936bda0d1d06d935c37e068b3afdf41
7
- data.tar.gz: aac3a0d13aa1c8f78ab77f5943b2ee5944c561829831c117afd8dc1cfd0e0e638406c9bcda52f92c1cc53b1f8eeef455e9d62e1929ffe984e3408812a22de4eb
6
+ metadata.gz: 6bff0e67cad4a819dd93400b7de6b8acbec6642df2bc15e569cfd3a3a2ae6ec38a70f38eb09483f90b335cc423da5ef3ef9e2a912b036fe576911b35f26f1bfa
7
+ data.tar.gz: eb67fd7c492534f4e4086327631ea52c391802f76f3ac17b17525313483eff0ec8e54441a08f045a78d75714ab4fc9691a71de47706ffa7a03ce56786b85900d
data/.rubocop.yml CHANGED
@@ -1,3 +1,6 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rails
1
4
  AllCops:
2
5
  NewCops: disable
3
6
  TargetRubyVersion: 2.7
@@ -19,3 +22,7 @@ Metrics/PerceivedComplexity:
19
22
  Max: 25
20
23
  Style/Documentation:
21
24
  Enabled: false
25
+ Rails/RakeEnvironment:
26
+ Enabled: false
27
+ Rails/Output:
28
+ Enabled: false
@@ -26,4 +26,6 @@ Gem::Specification.new do |s|
26
26
  s.add_dependency 'rails'
27
27
  s.add_development_dependency 'bundler', '~> 2.4.12'
28
28
  s.add_development_dependency 'rake', '~> 10.0'
29
+ s.add_development_dependency 'rubocop', '~> 1.56.2' # rubocop ruby
30
+ s.add_development_dependency 'rubocop-performance', '~> 1.19.0' # speed up rubocop
29
31
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'figaro_yaml_helper'
4
+
5
+ namespace :figaro_yml do
6
+ include FigaroYmlHelper
7
+ rake_roles = fetch(:rake_roles, :app)
8
+
9
+ desc 'compare and set the figaro_yml file on the server'
10
+ task :compare do
11
+ env = fetch(:stage).to_s
12
+ # Read and parse local application.yml
13
+ local = local_yaml
14
+
15
+ # Split into stage-specific and global configurations
16
+ local_global_env, local_stage_env = configs(local, env)
17
+
18
+ # puts local_global_env.to_yaml
19
+ # puts "\n\n\n"
20
+ # puts({ env => local_stage_env }.to_yaml)
21
+ on roles(rake_roles) do
22
+ # Read and parse remote application.yml
23
+ remote = YAML.safe_load(capture("cat #{shared_path}/config/application.yml"))
24
+ remote_global_env, remote_stage_env = configs(remote, env)
25
+
26
+ # puts remote_global_env.to_yaml
27
+ # puts "\n\n\n"
28
+ # puts({ env => remote_stage_env }.to_yaml)
29
+ # puts "Comparing local and remote application.yml for '#{env}' environment..."
30
+
31
+ # Compare hashes and handle nil results with empty hashes
32
+ differences_global = compare_hashes(local_global_env, remote_global_env)
33
+ differences_stage = compare_hashes(local_stage_env, remote_stage_env)
34
+
35
+ print_changes(differences_global, 'Local application.yml has extra/different global entries compared to remote.')
36
+ print_changes(differences_stage, "Local application.yml has extra/different entries in #{env} section compared to remote.") if differences_stage
37
+
38
+ puts 'No Differences found between remote and local application.yml' unless differences_global || differences_stage
39
+
40
+ # ask to overwrite remote yml if differences found
41
+ overwrite_remote = ask_to_overwrite('Overwrite remote application.yml') if differences_global || differences_stage
42
+ puts 'Nothing written to remote application.yml' unless overwrite_remote
43
+
44
+ exit unless overwrite_remote
45
+ # sort local yml before updating remote
46
+ puts 'Preparing local application.yml before updating remote...'
47
+ invoke 'figaro_yml:sort_local'
48
+ puts 'Local application.yml is ready to be updated.'
49
+
50
+ # update remote yml
51
+ invoke 'figaro_yml:setup'
52
+ ##
53
+ # TODO: restart server after updating remote yml
54
+ # let user choose to restart server after updating remote yml
55
+ # let user choose to restart server now or later if they choose to restart now
56
+ # ask for time to restart server if he chooses to restart later
57
+ # restart server after the time given
58
+ ##
59
+ puts 'Remote application.yml has been updated.'
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FigaroYmlHelper
4
+ def environments
5
+ Dir.glob('config/deploy/*.rb')
6
+ end
7
+
8
+ def local_yaml
9
+ YAML.safe_load(File.read('config/application.yml')) || {}
10
+ end
11
+
12
+ def write_to_file(file, content)
13
+ File.open(file, 'w') do |f|
14
+ f.write(content)
15
+ end
16
+ end
17
+
18
+ def write_combined_yaml(yamls_combined)
19
+ if yamls_combined.empty?
20
+ info 'No data to write.'
21
+ else
22
+ # write to new file
23
+ info 'writing to config/application.yml'
24
+ write_to_file('config/application.yml', yamls_combined.to_yaml)
25
+ end
26
+ end
27
+
28
+ def compare_hashes(hash1, hash2)
29
+ all_keys = hash1.keys | hash2.keys # Union of all keys from both hashes
30
+ all_keys.each_with_object({}) do |key, changes_hash|
31
+ old_value = hash2[key].nil? ? 'nil' : hash2[key].to_s
32
+ new_value = hash1[key].nil? ? 'nil' : hash1[key].to_s
33
+
34
+ changes_hash[key] = { old: old_value, new: new_value } if old_value != new_value
35
+ end.tap { |changes| return changes.empty? ? nil : changes }
36
+ end
37
+
38
+ def print_changes(changes, message)
39
+ return unless changes
40
+
41
+ puts "#{message}:\n\n"
42
+ changes.each do |key, diff|
43
+ puts "#{key}: #{diff[:old]} => #{diff[:new]}"
44
+ end
45
+ puts "\n"
46
+ end
47
+
48
+ def ask_to_overwrite(question)
49
+ answer = ''
50
+ until %w[y n].include?(answer)
51
+ print "#{question}? (y/N): "
52
+ answer = $stdin.gets.strip.downcase
53
+ end
54
+ answer == 'y'
55
+ end
56
+
57
+ def configs(yaml, env)
58
+ stage_yml = yaml[env.to_s]&.sort.to_h
59
+ global_yml = remove_nested(yaml)&.sort.to_h
60
+ [global_yml, stage_yml]
61
+ end
62
+
63
+ def remove_nested(hash)
64
+ hash.each_with_object({}) do |(key, value), new_hash|
65
+ new_hash[key] = value unless value.is_a?(Hash)
66
+ end
67
+ end
68
+
69
+ def sort_with_nested(hash)
70
+ hash.each_with_object({}) do |(key, value), new_hash|
71
+ new_hash[key] = value.is_a?(Hash) ? sort_with_nested(value) : value
72
+ end.sort.to_h
73
+ end
74
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'figaro_yaml_helper'
4
+
5
+ namespace :figaro_yml do
6
+ include FigaroYmlHelper
7
+
8
+ rake_roles = fetch(:rake_roles, :app)
9
+ desc 'get the `application.yml` file from server and create local if it does not exist'
10
+ task :get do
11
+ env = fetch(:stage)
12
+ if !File.exist?('config/application.yml')
13
+ run_locally do
14
+ puts "found #{environments.count} stages"
15
+ yamls_combined = {}
16
+
17
+ stages.each 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
+ stage_yaml = YAML.safe_load(res)
23
+ stage_yaml[stage.to_s] = stage_yaml[stage.to_s].sort.to_h
24
+ yamls_combined.merge!(stage_yaml) if stage_yaml
25
+ rescue StandardError
26
+ puts "could not get #{stage} application.yml"
27
+ end
28
+ end
29
+
30
+ write_combined_yaml(yamls_combined.sort.to_h)
31
+ end
32
+ else
33
+ on roles(rake_roles) do
34
+ local_yml = local_yaml.sort.to_h
35
+ local_global, local_stage = configs(local_yml, env)
36
+
37
+ remote = capture("cat #{shared_path}/config/application.yml")
38
+ remote_yml = YAML.safe_load(remote).sort.to_h
39
+ remote_global, remote_stage = configs(remote_yml, env)
40
+
41
+ differences_global = compare_hashes(remote_global, local_global || {})
42
+ differences_stage = compare_hashes(remote_stage, local_stage || {})
43
+
44
+ print_changes(differences_global,
45
+ 'Remote application.yml has extra/different global entries compared to local.')
46
+ print_changes(differences_stage, "Remote application.yml has extra/different entries in #{env} section compared to local.") if differences_stage
47
+
48
+ puts 'No Differences found between remote and local application.yml' unless differences_global || differences_stage
49
+
50
+ # ask to overwrite local yml if differences found
51
+ stage_overwrite = ask_to_overwrite("Overwrite local application.yml #{env} section") if differences_stage
52
+ global_overwrite = ask_to_overwrite('Overwrite local application.yml globals') if differences_global
53
+ puts 'Nothing written to local application.yml' unless stage_overwrite || global_overwrite
54
+ exit unless stage_overwrite || global_overwrite
55
+
56
+ # compose new yml
57
+ composed_yml = {}
58
+ composed_yml.merge!(local_yml) # local yml is always included to avoid losing any data
59
+ composed_yml.merge!(local_global) unless global_overwrite
60
+ composed_yml.merge!(remote_global) if global_overwrite
61
+ composed_yml[env.to_s] = stage_overwrite ? remote_stage : local_stage
62
+
63
+ # write to new file
64
+ write_combined_yaml(composed_yml.sort.to_h)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'figaro_yaml_helper'
4
+
5
+ namespace :figaro_yml do
6
+ rake_roles = fetch(:rake_roles, :app)
7
+
8
+ task :get_stage do
9
+ on roles(rake_roles) do
10
+ puts capture "cat #{shared_path}/config/application.yml"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'figaro_yaml_helper'
4
+
5
+ namespace :figaro_yml do
6
+ include FigaroYmlHelper
7
+
8
+ task :sort_local do
9
+ run_locally do
10
+ info 'Sorting local application.yml...'
11
+ local = local_yaml
12
+ sorted_local = sort_with_nested(local)
13
+ write_combined_yaml(sorted_local)
14
+ end
15
+ end
16
+
17
+ task :sort do
18
+ invoke 'figaro_yml:sort_local'
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir.glob("#{File.expand_path(__dir__)}/figaro_yml/**/*.rake").each { |f| load f }
@@ -5,12 +5,14 @@ require 'capistrano/version'
5
5
  if defined?(Capistrano::VERSION) && Gem::Version.new(Capistrano::VERSION).release >= Gem::Version.new('3.0.0')
6
6
  load File.expand_path('capistrano/v3/tasks/whenever.rake', __dir__)
7
7
  load File.expand_path('capistrano/v3/tasks/backup.rake', __dir__)
8
- load File.expand_path('capistrano/v3/tasks/figaro_yml.rake', __dir__)
8
+ load File.expand_path('capistrano/v3/tasks/figaro_yml.rb', __dir__)
9
+
9
10
  load File.expand_path('capistrano/v3/tasks/invoke.rake', __dir__)
10
11
  path = File.expand_path(__dir__)
11
12
  Dir.glob("#{path}/capistrano/v3/tasks/backup/**/*.rake").each { |f| load f }
12
13
  Dir.glob("#{path}/capistrano/v3/tasks/logrotate/**/*.rake").each { |f| load f }
13
14
  Dir.glob("#{path}/capistrano/v3/tasks/logs/**/*.rake").each { |f| load f }
15
+
14
16
  else
15
17
  puts 'Capistrano 3 is required to use this gem'
16
18
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capistrano
4
4
  module Ops
5
- VERSION = '0.2.13'
5
+ VERSION = '0.2.14'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-ops
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.13
4
+ version: 0.2.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Crusius
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-12 00:00:00.000000000 Z
11
+ date: 2024-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-s3
@@ -94,6 +94,34 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.56.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.56.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-performance
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.19.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.19.0
97
125
  description: A collection of devops tasks for rails applications
98
126
  email:
99
127
  - florian@zauberware.com
@@ -127,7 +155,12 @@ files:
127
155
  - lib/capistrano/ops/capistrano/v3/tasks/backup/database/pull.rake
128
156
  - lib/capistrano/ops/capistrano/v3/tasks/backup/storage/create.rake
129
157
  - lib/capistrano/ops/capistrano/v3/tasks/backup/storage/pull.rake
130
- - lib/capistrano/ops/capistrano/v3/tasks/figaro_yml.rake
158
+ - lib/capistrano/ops/capistrano/v3/tasks/figaro_yml.rb
159
+ - lib/capistrano/ops/capistrano/v3/tasks/figaro_yml/compare.rake
160
+ - lib/capistrano/ops/capistrano/v3/tasks/figaro_yml/figaro_yaml_helper.rb
161
+ - lib/capistrano/ops/capistrano/v3/tasks/figaro_yml/get.rake
162
+ - lib/capistrano/ops/capistrano/v3/tasks/figaro_yml/get_stage.rake
163
+ - lib/capistrano/ops/capistrano/v3/tasks/figaro_yml/sort_local.rake
131
164
  - lib/capistrano/ops/capistrano/v3/tasks/invoke.rake
132
165
  - lib/capistrano/ops/capistrano/v3/tasks/logrotate/check.rake
133
166
  - lib/capistrano/ops/capistrano/v3/tasks/logrotate/disable.rake
@@ -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