geordi 3.0.0 → 3.2.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/.gitignore +0 -1
- data/CHANGELOG.md +36 -2
- data/Gemfile.lock +1 -1
- data/README.md +46 -3
- data/lib/geordi/COMMAND_TEMPLATE +2 -3
- data/lib/geordi/chromedriver_updater.rb +7 -8
- data/lib/geordi/cli.rb +0 -1
- data/lib/geordi/commands/_setup_vnc.rb +22 -22
- data/lib/geordi/commands/bundle_install.rb +1 -1
- data/lib/geordi/commands/capistrano.rb +4 -4
- data/lib/geordi/commands/clean.rb +6 -5
- data/lib/geordi/commands/commit.rb +1 -1
- data/lib/geordi/commands/console.rb +11 -3
- data/lib/geordi/commands/create_database_yml.rb +2 -2
- data/lib/geordi/commands/create_databases.rb +1 -1
- data/lib/geordi/commands/cucumber.rb +16 -9
- data/lib/geordi/commands/delete_dumps.rb +5 -5
- data/lib/geordi/commands/deploy.rb +19 -19
- data/lib/geordi/commands/drop_databases.rb +3 -3
- data/lib/geordi/commands/dump.rb +8 -9
- data/lib/geordi/commands/firefox.rb +2 -2
- data/lib/geordi/commands/migrate.rb +3 -3
- data/lib/geordi/commands/png_optimize.rb +5 -5
- data/lib/geordi/commands/rake.rb +1 -1
- data/lib/geordi/commands/remove_executable_flags.rb +2 -2
- data/lib/geordi/commands/rspec.rb +5 -5
- data/lib/geordi/commands/security_update.rb +76 -19
- data/lib/geordi/commands/server.rb +2 -2
- data/lib/geordi/commands/setup.rb +3 -3
- data/lib/geordi/commands/shell.rb +7 -3
- data/lib/geordi/commands/tests.rb +1 -1
- data/lib/geordi/commands/unit.rb +2 -2
- data/lib/geordi/commands/update.rb +2 -2
- data/lib/geordi/commands/with_rake.rb +2 -2
- data/lib/geordi/commands/yarn_install.rb +1 -1
- data/lib/geordi/cucumber.rb +18 -17
- data/lib/geordi/db_cleaner.rb +21 -22
- data/lib/geordi/dump_loader.rb +5 -4
- data/lib/geordi/firefox_for_selenium.rb +17 -19
- data/lib/geordi/gitpt.rb +10 -53
- data/lib/geordi/interaction.rb +2 -6
- data/lib/geordi/remote.rb +17 -6
- data/lib/geordi/settings.rb +155 -0
- data/lib/geordi/util.rb +14 -9
- data/lib/geordi/version.rb +1 -1
- metadata +4 -3
@@ -4,7 +4,7 @@ def create_database_yml
|
|
4
4
|
sample_yml = 'config/database.sample.yml'
|
5
5
|
|
6
6
|
if File.exist?(sample_yml) && !File.exist?(real_yml)
|
7
|
-
announce 'Creating ' + real_yml
|
7
|
+
Interaction.announce 'Creating ' + real_yml
|
8
8
|
|
9
9
|
sample = File.read(sample_yml)
|
10
10
|
adapter = sample.match(/adapter: (\w+)\n/).captures.first
|
@@ -15,6 +15,6 @@ def create_database_yml
|
|
15
15
|
real = sample.gsub(/password:.*$/, "password: #{db_password}")
|
16
16
|
File.open(real_yml, 'w') { |f| f.write(real) }
|
17
17
|
|
18
|
-
note "Created #{real_yml}."
|
18
|
+
Interaction.note "Created #{real_yml}."
|
19
19
|
end
|
20
20
|
end
|
@@ -15,6 +15,13 @@ or `-d`.
|
|
15
15
|
|
16
16
|
- *Options:* Any unknown option will be passed through to Cucumber,
|
17
17
|
e.g. `--format pretty`.
|
18
|
+
|
19
|
+
- *VNC:* By default, test browsers will run in a VNC session. When using a
|
20
|
+
headless test browser anyway, you can disable VNC by putting the following
|
21
|
+
config into `.geordi.yml` in the project root:
|
22
|
+
|
23
|
+
use_vnc: false
|
24
|
+
|
18
25
|
LONGDESC
|
19
26
|
|
20
27
|
option :modified, aliases: '-m', type: :boolean,
|
@@ -34,7 +41,7 @@ def cucumber(*args)
|
|
34
41
|
if options.modified?
|
35
42
|
modified_features = `git status --short`.split($INPUT_RECORD_SEPARATOR).map do |line|
|
36
43
|
indicators = line.slice!(0..2) # Remove leading indicators
|
37
|
-
line if line.include?('.feature') && indicators.
|
44
|
+
line if line.include?('.feature') && !indicators.include?('D')
|
38
45
|
end.compact
|
39
46
|
args = modified_features
|
40
47
|
end
|
@@ -56,7 +63,7 @@ def cucumber(*args)
|
|
56
63
|
|
57
64
|
# Serial run of @solo scenarios ############################################
|
58
65
|
if files.any? { |f| f.include? ':' }
|
59
|
-
note '@solo run skipped when called with line numbers' if options.verbose
|
66
|
+
Interaction.note '@solo run skipped when called with line numbers' if options.verbose
|
60
67
|
else
|
61
68
|
solo_files = if files.empty?
|
62
69
|
'features' # Proper grepping
|
@@ -70,14 +77,14 @@ def cucumber(*args)
|
|
70
77
|
solo_cmd_opts = cmd_opts.dup
|
71
78
|
solo_cmd_opts << '--tags' << '@solo'
|
72
79
|
|
73
|
-
announce 'Running @solo features'
|
80
|
+
Interaction.announce 'Running @solo features'
|
74
81
|
solo_success = Geordi::Cucumber.new.run files, solo_cmd_opts, verbose: options.verbose, parallel: false
|
75
|
-
solo_success ||
|
82
|
+
solo_success || Interaction.fail('Features failed.')
|
76
83
|
end
|
77
84
|
end
|
78
85
|
|
79
86
|
# Parallel run of all given features + reruns ##############################
|
80
|
-
announce 'Running features'
|
87
|
+
Interaction.announce 'Running features'
|
81
88
|
normal_run_successful = Geordi::Cucumber.new.run(files, cmd_opts, verbose: options.verbose)
|
82
89
|
|
83
90
|
unless normal_run_successful
|
@@ -85,16 +92,16 @@ def cucumber(*args)
|
|
85
92
|
|
86
93
|
# Reruns
|
87
94
|
(options.rerun + 1).times do |i|
|
88
|
-
|
95
|
+
Interaction.fail 'Features failed.' if i == options.rerun # All reruns done?
|
89
96
|
|
90
|
-
announce "Rerun ##{i + 1} of #{options.rerun}"
|
97
|
+
Interaction.announce "Rerun ##{i + 1} of #{options.rerun}"
|
91
98
|
break if Geordi::Cucumber.new.run([], cmd_opts, verbose: options.verbose, parallel: false)
|
92
99
|
end
|
93
100
|
end
|
94
101
|
|
95
|
-
success 'Features green.'
|
102
|
+
Interaction.success 'Features green.'
|
96
103
|
|
97
104
|
else
|
98
|
-
note 'Cucumber not employed.'
|
105
|
+
Interaction.note 'Cucumber not employed.'
|
99
106
|
end
|
100
107
|
end
|
@@ -20,24 +20,24 @@ def delete_dumps(dump_directory = nil)
|
|
20
20
|
else
|
21
21
|
[dump_directory]
|
22
22
|
end
|
23
|
-
announce 'Looking for *.dump in ' << dump_directories.join(',')
|
23
|
+
Interaction.announce 'Looking for *.dump in ' << dump_directories.join(',')
|
24
24
|
dump_directories.each do |d|
|
25
25
|
d_2 = File.expand_path(d)
|
26
26
|
unless File.directory? File.realdirpath(d_2)
|
27
|
-
warn "Directory #{d_2} does not exist"
|
27
|
+
Interaction.warn "Directory #{d_2} does not exist"
|
28
28
|
next
|
29
29
|
end
|
30
30
|
deletable_dumps.concat(Dir.glob("#{d_2}/**/*.dump"))
|
31
31
|
end
|
32
32
|
if deletable_dumps.empty?
|
33
|
-
success 'No dumps to delete' if deletable_dumps.empty?
|
33
|
+
Interaction.success 'No dumps to delete' if deletable_dumps.empty?
|
34
34
|
exit 0
|
35
35
|
end
|
36
36
|
deletable_dumps.uniq!.sort!
|
37
|
-
note 'The following dumps can be deleted:'
|
37
|
+
Interaction.note 'The following dumps can be deleted:'
|
38
38
|
puts
|
39
39
|
puts deletable_dumps
|
40
|
-
prompt('Delete those dumps', 'n', /y|yes/) || raise('Cancelled.')
|
40
|
+
Interaction.prompt('Delete those dumps', 'n', /y|yes/) || raise('Cancelled.')
|
41
41
|
deletable_dumps.each do |dump|
|
42
42
|
File.delete dump unless File.directory? dump
|
43
43
|
end
|
@@ -38,17 +38,17 @@ option :current_branch, aliases: '-c', type: :boolean,
|
|
38
38
|
def deploy(target_stage = nil)
|
39
39
|
# Set/Infer default values
|
40
40
|
branch_stage_map = { 'master' => 'staging', 'production' => 'production' }
|
41
|
-
if target_stage &&
|
41
|
+
if target_stage && !Util.deploy_targets.include?(target_stage)
|
42
42
|
# Target stage autocompletion from available stages
|
43
43
|
target_stage = Util.deploy_targets.find { |t| t.start_with? target_stage }
|
44
|
-
target_stage || warn('Given deployment stage not found')
|
44
|
+
target_stage || Interaction.warn('Given deployment stage not found')
|
45
45
|
end
|
46
46
|
|
47
47
|
# Ask for required information
|
48
|
-
target_stage ||= prompt 'Deployment stage:', branch_stage_map.fetch(Util.current_branch, 'staging')
|
48
|
+
target_stage ||= Interaction.prompt 'Deployment stage:', branch_stage_map.fetch(Util.current_branch, 'staging')
|
49
49
|
if options.current_branch
|
50
50
|
stage_file = "config/deploy/#{target_stage}.rb"
|
51
|
-
Util.file_containing?(stage_file, 'DEPLOY_BRANCH') ||
|
51
|
+
Util.file_containing?(stage_file, 'DEPLOY_BRANCH') || Interaction.fail(<<-ERROR)
|
52
52
|
To deploy from the current branch, configure #{stage_file} to respect the
|
53
53
|
environment variable DEPLOY_BRANCH. Example:
|
54
54
|
|
@@ -57,38 +57,38 @@ set :branch, ENV['DEPLOY_BRANCH'] || 'master'
|
|
57
57
|
|
58
58
|
source_branch = target_branch = Util.current_branch
|
59
59
|
else
|
60
|
-
source_branch = prompt 'Source branch:', Util.current_branch
|
61
|
-
target_branch = prompt 'Deploy branch:', branch_stage_map.invert.fetch(target_stage, 'master')
|
60
|
+
source_branch = Interaction.prompt 'Source branch:', Util.current_branch
|
61
|
+
target_branch = Interaction.prompt 'Deploy branch:', branch_stage_map.invert.fetch(target_stage, 'master')
|
62
62
|
end
|
63
63
|
|
64
64
|
merge_needed = (source_branch != target_branch)
|
65
65
|
push_needed = merge_needed || `git cherry -v | wc -l`.strip.to_i > 0
|
66
66
|
push_needed = false if Util.testing? # Hard to test
|
67
67
|
|
68
|
-
announce "Checking whether your #{source_branch} branch is ready" ############
|
68
|
+
Interaction.announce "Checking whether your #{source_branch} branch is ready" ############
|
69
69
|
Util.system! "git checkout #{source_branch}"
|
70
70
|
if (`git status -s | wc -l`.strip != '0') && !Util.testing?
|
71
|
-
warn "Your #{source_branch} branch holds uncommitted changes."
|
72
|
-
prompt('Continue anyway?', 'n', /y|yes/) || raise('Cancelled.')
|
71
|
+
Interaction.warn "Your #{source_branch} branch holds uncommitted changes."
|
72
|
+
Interaction.prompt('Continue anyway?', 'n', /y|yes/) || raise('Cancelled.')
|
73
73
|
else
|
74
|
-
note 'All good.'
|
74
|
+
Interaction.note 'All good.'
|
75
75
|
end
|
76
76
|
|
77
77
|
if merge_needed
|
78
|
-
announce "Checking what's in your #{target_branch} branch right now" #######
|
78
|
+
Interaction.announce "Checking what's in your #{target_branch} branch right now" #######
|
79
79
|
Util.system! "git checkout #{target_branch} && git pull"
|
80
80
|
end
|
81
81
|
|
82
|
-
announce 'You are about to:' #################################################
|
83
|
-
note "Merge branch #{source_branch} into #{target_branch}" if merge_needed
|
82
|
+
Interaction.announce 'You are about to:' #################################################
|
83
|
+
Interaction.note "Merge branch #{source_branch} into #{target_branch}" if merge_needed
|
84
84
|
if push_needed
|
85
|
-
note 'Push these commits:' if push_needed
|
85
|
+
Interaction.note 'Push these commits:' if push_needed
|
86
86
|
Util.system! "git --no-pager log origin/#{target_branch}..#{source_branch} --oneline"
|
87
87
|
end
|
88
|
-
note "Deploy to #{target_stage}"
|
89
|
-
note "From current branch #{source_branch}" if options.current_branch
|
88
|
+
Interaction.note "Deploy to #{target_stage}"
|
89
|
+
Interaction.note "From current branch #{source_branch}" if options.current_branch
|
90
90
|
|
91
|
-
if prompt('Go ahead with the deployment?', 'n', /y|yes/)
|
91
|
+
if Interaction.prompt('Go ahead with the deployment?', 'n', /y|yes/)
|
92
92
|
puts
|
93
93
|
git_call = []
|
94
94
|
git_call << "git merge #{source_branch}" if merge_needed
|
@@ -107,9 +107,9 @@ set :branch, ENV['DEPLOY_BRANCH'] || 'master'
|
|
107
107
|
|
108
108
|
Util.system! capistrano_call, show_cmd: true
|
109
109
|
|
110
|
-
success 'Deployment complete.'
|
110
|
+
Interaction.success 'Deployment complete.'
|
111
111
|
else
|
112
112
|
Util.system! "git checkout #{source_branch}"
|
113
|
-
|
113
|
+
Interaction.fail 'Deployment cancelled.'
|
114
114
|
end
|
115
115
|
end
|
@@ -28,7 +28,7 @@ option :mysql, banner: 'PORT_OR_SOCKET',
|
|
28
28
|
|
29
29
|
def drop_databases
|
30
30
|
require 'geordi/db_cleaner'
|
31
|
-
|
31
|
+
Interaction.fail '-P and -M are mutually exclusive' if options.postgres_only && options.mysql_only
|
32
32
|
mysql_flags = nil
|
33
33
|
postgres_flags = nil
|
34
34
|
|
@@ -38,7 +38,7 @@ def drop_databases
|
|
38
38
|
mysql_flags = "--port=#{mysql_port} --protocol=TCP"
|
39
39
|
rescue AttributeError
|
40
40
|
unless File.exist? options.mysql
|
41
|
-
|
41
|
+
Interaction.fail "Path #{options.mysql} is not a valid MySQL socket"
|
42
42
|
end
|
43
43
|
mysql_flags = "--socket=#{options.mysql}"
|
44
44
|
end
|
@@ -54,5 +54,5 @@ def drop_databases
|
|
54
54
|
cleaner.clean_mysql unless options.postgres_only
|
55
55
|
cleaner.clean_postgres unless options.mysql_only
|
56
56
|
|
57
|
-
success 'Done.'
|
57
|
+
Interaction.success 'Done.'
|
58
58
|
end
|
data/lib/geordi/commands/dump.rb
CHANGED
@@ -21,7 +21,6 @@ dump into the development database after downloading it.
|
|
21
21
|
DESC
|
22
22
|
|
23
23
|
option :load, aliases: ['-l'], type: :string, desc: 'Load a dump'
|
24
|
-
option :select_server, default: false, type: :boolean, aliases: '-s'
|
25
24
|
|
26
25
|
def dump(target = nil, *_args)
|
27
26
|
require 'geordi/dump_loader'
|
@@ -30,33 +29,33 @@ def dump(target = nil, *_args)
|
|
30
29
|
if target.nil?
|
31
30
|
if options.load
|
32
31
|
# validate load option
|
33
|
-
|
32
|
+
Interaction.fail 'Missing a dump file.' if options.load == 'load'
|
34
33
|
File.exist?(options.load) || raise('Could not find the given dump file: ' + options.load)
|
35
34
|
|
36
35
|
loader = DumpLoader.new(options.load)
|
37
36
|
|
38
|
-
announce "Sourcing dump into the #{loader.config['database']} db"
|
37
|
+
Interaction.announce "Sourcing dump into the #{loader.config['database']} db"
|
39
38
|
loader.load
|
40
39
|
|
41
|
-
success "Your #{loader.config['database']} database has now the data of #{options.load}."
|
40
|
+
Interaction.success "Your #{loader.config['database']} database has now the data of #{options.load}."
|
42
41
|
|
43
42
|
else
|
44
|
-
announce 'Dumping the development database'
|
43
|
+
Interaction.announce 'Dumping the development database'
|
45
44
|
Util.system! 'dumple development'
|
46
|
-
success 'Successfully dumped the development database.'
|
45
|
+
Interaction.success 'Successfully dumped the development database.'
|
47
46
|
end
|
48
47
|
|
49
48
|
else
|
50
|
-
announce 'Dumping the database of ' + target
|
49
|
+
Interaction.announce 'Dumping the database of ' + target
|
51
50
|
dump_path = Geordi::Remote.new(target).dump(options)
|
52
51
|
|
53
52
|
if options.load
|
54
53
|
loader = DumpLoader.new(dump_path)
|
55
54
|
|
56
|
-
announce "Sourcing dump into the #{loader.config['database']} db"
|
55
|
+
Interaction.announce "Sourcing dump into the #{loader.config['database']} db"
|
57
56
|
loader.load
|
58
57
|
|
59
|
-
success "Your #{loader.config['database']} database has now the data of #{target}."
|
58
|
+
Interaction.success "Your #{loader.config['database']} database has now the data of #{target}."
|
60
59
|
end
|
61
60
|
end
|
62
61
|
end
|
@@ -15,7 +15,7 @@ option :setup, banner: 'FIREFOX_VERSION',
|
|
15
15
|
|
16
16
|
def firefox(*command)
|
17
17
|
if options.setup
|
18
|
-
|
18
|
+
Interaction.fail 'Firefox version required (e.g. --setup 24.0)' if options.setup == 'setup'
|
19
19
|
|
20
20
|
require 'geordi/firefox_for_selenium'
|
21
21
|
Geordi::FirefoxForSelenium.install(options.setup)
|
@@ -27,7 +27,7 @@ def firefox(*command)
|
|
27
27
|
FirefoxForSelenium.setup_firefox
|
28
28
|
|
29
29
|
puts
|
30
|
-
note_cmd command.join(' ')
|
30
|
+
Interaction.note_cmd command.join(' ')
|
31
31
|
system *command # Util.system! would reset the Firefox PATH
|
32
32
|
end
|
33
33
|
end
|
@@ -10,11 +10,11 @@ LONGDESC
|
|
10
10
|
def migrate
|
11
11
|
invoke_cmd 'bundle_install'
|
12
12
|
invoke_cmd 'yarn_install'
|
13
|
-
announce 'Migrating'
|
13
|
+
Interaction.announce 'Migrating'
|
14
14
|
|
15
15
|
if File.directory?('db/migrate')
|
16
16
|
if Util.file_containing?('Gemfile', /parallel_tests/)
|
17
|
-
note 'Development and parallel test databases'
|
17
|
+
Interaction.note 'Development and parallel test databases'
|
18
18
|
puts
|
19
19
|
|
20
20
|
Util.system! 'bundle exec rake db:migrate parallel:prepare'
|
@@ -22,6 +22,6 @@ def migrate
|
|
22
22
|
invoke_cmd 'rake', 'db:migrate'
|
23
23
|
end
|
24
24
|
else
|
25
|
-
note 'No migrations directory found.'
|
25
|
+
Interaction.note 'No migrations directory found.'
|
26
26
|
end
|
27
27
|
end
|
@@ -10,10 +10,10 @@ LONGDESC
|
|
10
10
|
def png_optimize(path)
|
11
11
|
require 'fileutils'
|
12
12
|
|
13
|
-
announce 'Optimizing .png files'
|
13
|
+
Interaction.announce 'Optimizing .png files'
|
14
14
|
|
15
15
|
if `which pngcrush`.strip.empty?
|
16
|
-
|
16
|
+
Interaction.fail 'Please install pngcrush first (sudo apt-get install pngcrush)'
|
17
17
|
end
|
18
18
|
|
19
19
|
po = PngOptimizer.new
|
@@ -22,10 +22,10 @@ def png_optimize(path)
|
|
22
22
|
elsif File.file?(path)
|
23
23
|
po.optimize_inplace(path)
|
24
24
|
else
|
25
|
-
|
25
|
+
Interaction.fail 'Neither directory nor file: ' + path
|
26
26
|
end
|
27
27
|
|
28
|
-
success 'PNG optimization completed.'
|
28
|
+
Interaction.success 'PNG optimization completed.'
|
29
29
|
end
|
30
30
|
|
31
31
|
class PngOptimizer
|
@@ -64,7 +64,7 @@ class PngOptimizer
|
|
64
64
|
FileUtils.rm(input_file)
|
65
65
|
FileUtils.mv(temp_file.to_s, input_file.to_s)
|
66
66
|
else
|
67
|
-
|
67
|
+
Interaction.fail 'Error:' + $?
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
data/lib/geordi/commands/rake.rb
CHANGED
@@ -13,7 +13,7 @@ def rake(*args)
|
|
13
13
|
%w[development test cucumber].each do |env| # update long_desc when changing this
|
14
14
|
if File.exist? "config/environments/#{env}.rb"
|
15
15
|
call = %w[bundle exec rake] + args + ["RAILS_ENV=#{env}"]
|
16
|
-
note_cmd call.join(' ')
|
16
|
+
Interaction.note_cmd call.join(' ')
|
17
17
|
|
18
18
|
Util.system! *call
|
19
19
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
desc 'remove-executable-flags', 'Remove executable-flags from files that should not be executable'
|
2
2
|
def remove_executable_flags
|
3
|
-
announce 'Removing executable-flags'
|
3
|
+
Interaction.announce 'Removing executable-flags'
|
4
4
|
|
5
5
|
patterns = %w[
|
6
6
|
*.rb *.html *.erb *.haml *.yml *.css *.sass *.rake *.png *.jpg
|
7
7
|
*.gif *.pdf *.txt *.rdoc *.feature Rakefile VERSION README Capfile
|
8
8
|
]
|
9
9
|
patterns.each do |pattern|
|
10
|
-
note pattern
|
10
|
+
Interaction.note pattern
|
11
11
|
`find . -name "#{pattern}" -exec chmod -x {} ';'`
|
12
12
|
end
|
13
13
|
puts 'Done.'
|
@@ -11,19 +11,19 @@ def rspec(*files)
|
|
11
11
|
invoke_cmd 'bundle_install'
|
12
12
|
invoke_cmd 'yarn_install'
|
13
13
|
|
14
|
-
announce 'Running specs'
|
14
|
+
Interaction.announce 'Running specs'
|
15
15
|
|
16
16
|
if Util.file_containing?('Gemfile', /parallel_tests/) && files.empty?
|
17
|
-
note 'All specs at once (using parallel_tests)'
|
17
|
+
Interaction.note 'All specs at once (using parallel_tests)'
|
18
18
|
Util.system! 'bundle exec rake parallel:spec', fail_message: 'Specs failed.'
|
19
19
|
|
20
20
|
else
|
21
21
|
# tell which specs will be run
|
22
22
|
if files.empty?
|
23
23
|
files << 'spec/'
|
24
|
-
note 'All specs in spec/'
|
24
|
+
Interaction.note 'All specs in spec/'
|
25
25
|
else
|
26
|
-
note 'Only: ' + files.join(', ')
|
26
|
+
Interaction.note 'Only: ' + files.join(', ')
|
27
27
|
end
|
28
28
|
|
29
29
|
command = ['bundle exec']
|
@@ -41,6 +41,6 @@ def rspec(*files)
|
|
41
41
|
Util.system! command.join(' '), fail_message: 'Specs failed.'
|
42
42
|
end
|
43
43
|
else
|
44
|
-
note 'RSpec not employed.'
|
44
|
+
Interaction.note 'RSpec not employed.'
|
45
45
|
end
|
46
46
|
end
|
@@ -2,39 +2,63 @@ desc 'security-update [STEP]', 'Support for performing security updates'
|
|
2
2
|
long_desc <<-LONGDESC
|
3
3
|
Preparation for security update: `geordi security-update`
|
4
4
|
|
5
|
+
Checks out production and pulls.
|
6
|
+
|
5
7
|
After performing the update: `geordi security-update finish`
|
6
8
|
|
7
9
|
Switches branches, pulls, pushes and deploys as required by our workflow. Tells
|
8
|
-
what it will do before it does it.
|
10
|
+
what it will do before it does it. In detail:
|
11
|
+
|
12
|
+
1. Asks user, if tests are green
|
13
|
+
|
14
|
+
2. Pushes production
|
15
|
+
|
16
|
+
3. Checks out master and pulls
|
17
|
+
|
18
|
+
4. Merges production and pushes in master
|
19
|
+
|
20
|
+
5. Deploys staging first, if there is a staging environment
|
21
|
+
|
22
|
+
6. Asks user, if deployment log is okay and application is still running on staging
|
23
|
+
|
24
|
+
7. Deploys other stages
|
25
|
+
|
26
|
+
8. Asks user, if deployment log is okay and application is still running on all other stages
|
27
|
+
|
28
|
+
9. Informs user about the next steps
|
9
29
|
LONGDESC
|
10
30
|
|
11
31
|
def security_update(step = 'prepare')
|
12
32
|
case step
|
13
33
|
when 'prepare'
|
14
|
-
announce 'Preparing for security update'
|
15
|
-
warn 'Please read https://makandracards.com/makandra/1587 before applying security updates!'
|
16
|
-
note 'About to checkout production and pull'
|
17
|
-
prompt('Continue?', 'y', /y|yes/) ||
|
34
|
+
Interaction.announce 'Preparing for security update'
|
35
|
+
Interaction.warn 'Please read https://makandracards.com/makandra/1587 before applying security updates!'
|
36
|
+
Interaction.note 'About to checkout production and pull.'
|
37
|
+
Interaction.prompt('Continue?', 'y', /y|yes/) || Interaction.fail('Cancelled.')
|
18
38
|
|
19
39
|
Util.system! 'git checkout production', show_cmd: true
|
20
40
|
Util.system! 'git pull', show_cmd: true
|
21
41
|
|
22
|
-
success 'Successfully prepared for security update'
|
42
|
+
Interaction.success 'Successfully prepared for security update'
|
23
43
|
puts
|
24
|
-
note 'Please apply the security update now and commit your changes.'
|
25
|
-
note 'When you are done, run `geordi security-update finish`.'
|
44
|
+
Interaction.note 'Please apply the security update now and commit your changes.'
|
45
|
+
Interaction.note 'When you are done, run `geordi security-update finish`.'
|
26
46
|
|
27
47
|
|
28
48
|
when 'f', 'finish'
|
29
49
|
# ensure everything is committed
|
30
|
-
|
50
|
+
if Util.testing?
|
51
|
+
puts 'Util.system! git status --porcelain'
|
52
|
+
else
|
53
|
+
`git status --porcelain`.empty? || Interaction.fail('Please commit your changes before finishing the update.')
|
54
|
+
end
|
31
55
|
|
32
|
-
announce 'Finishing security update'
|
33
|
-
note 'Working directory clean.'
|
34
|
-
prompt('Have you successfully run all tests?', 'n', /y|yes/) ||
|
56
|
+
Interaction.announce 'Finishing security update'
|
57
|
+
Interaction.note 'Working directory clean.'
|
58
|
+
Interaction.prompt('Have you successfully run all tests?', 'n', /y|yes/) || Interaction.fail('Please run tests first.')
|
35
59
|
|
36
|
-
note 'About to: push production, checkout & pull master, merge production, push master'
|
37
|
-
prompt('Continue?', 'n', /y|yes/) ||
|
60
|
+
Interaction.note 'About to: push production, checkout & pull master, merge production, push master.'
|
61
|
+
Interaction.prompt('Continue?', 'n', /y|yes/) || Interaction.fail('Cancelled.')
|
38
62
|
|
39
63
|
Util.system! 'git push', show_cmd: true
|
40
64
|
Util.system! 'git checkout master', show_cmd: true
|
@@ -42,13 +66,46 @@ def security_update(step = 'prepare')
|
|
42
66
|
Util.system! 'git merge production', show_cmd: true
|
43
67
|
Util.system! 'git push', show_cmd: true
|
44
68
|
|
45
|
-
announce '
|
69
|
+
Interaction.announce 'Deployment'
|
46
70
|
deploy = (Util.gem_major_version('capistrano') == 3) ? 'deploy' : 'deploy:migrations'
|
47
|
-
invoke_cmd 'capistrano', deploy
|
48
71
|
|
49
|
-
|
72
|
+
all_deploy_targets = Util.deploy_targets
|
73
|
+
Interaction.fail 'There are no deploy targets!' if all_deploy_targets.empty?
|
74
|
+
|
75
|
+
if all_deploy_targets.include?('staging')
|
76
|
+
Interaction.note 'There is a staging environment.'
|
77
|
+
Interaction.prompt('Deploy staging now?', 'y', /y|yes/) || Interaction.fail('Cancelled.')
|
78
|
+
|
79
|
+
Interaction.announce 'Deploy staging'
|
80
|
+
Util.system! "bundle exec cap staging #{deploy}", show_cmd: true
|
81
|
+
|
82
|
+
Interaction.prompt('Is the deployment log okay and the application is still running on staging?', 'y', /y|yes/) || Interaction.fail('Please fix the deployment issues on staging before you continue.')
|
83
|
+
else
|
84
|
+
Interaction.note 'There is no staging environment.'
|
85
|
+
end
|
86
|
+
|
87
|
+
deploy_targets_without_staging = all_deploy_targets.select { |target| target != 'staging' }
|
88
|
+
|
89
|
+
if deploy_targets_without_staging.empty?
|
90
|
+
Interaction.note 'There are no other stages.'
|
91
|
+
else
|
92
|
+
puts
|
93
|
+
Interaction.note 'Found the following other stages:'
|
94
|
+
puts deploy_targets_without_staging
|
95
|
+
puts
|
96
|
+
Interaction.prompt('Deploy other stages now?', 'y', /y|yes/) || Interaction.fail('Cancelled.')
|
97
|
+
|
98
|
+
deploy_targets_without_staging.each do |target|
|
99
|
+
Interaction.announce "Deploy #{target}"
|
100
|
+
Util.system! "bundle exec cap #{target} #{deploy}", show_cmd: true
|
101
|
+
end
|
102
|
+
|
103
|
+
Interaction.prompt('Is the application still running on all other stages and the logs are okay?', 'y', /y|yes/) || Interaction.fail('Please fix the application immediately!')
|
104
|
+
end
|
105
|
+
|
106
|
+
Interaction.success 'Successfully pushed and deployed security update'
|
50
107
|
puts
|
51
|
-
note 'Now send an email to customer and project lead, informing them about the update.'
|
52
|
-
note 'Do not forget to make a joblog on a security budget, if available.'
|
108
|
+
Interaction.note 'Now send an email to customer and project lead, informing them about the update.'
|
109
|
+
Interaction.note 'Do not forget to make a joblog on a security budget, if available.'
|
53
110
|
end
|
54
111
|
end
|