prima-twig 0.4.6 → 0.5.27

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,13 +2,19 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require_relative '../lib/prima_twig.rb'
5
+ require_relative '../lib/prima_aws_client.rb'
5
6
  require 'colorize'
6
7
  require 'highline/import'
7
- require 'aws-sdk'
8
+ require 'aws-sdk-batch'
9
+ require 'aws-sdk-cloudformation'
10
+ require 'aws-sdk-ecs'
11
+ require 'aws-sdk-s3'
8
12
  require 'redcarpet'
9
13
  require 'mail'
10
14
  require 'erb'
11
15
  require 'base64'
16
+ require 'rubyflare'
17
+ require 'pp'
12
18
 
13
19
  def help_content
14
20
  <<-HELP
@@ -43,17 +49,35 @@ end
43
49
 
44
50
  class Review
45
51
  include Command
52
+ include PrimaAwsClient
46
53
 
47
54
  def initialize
48
55
  @prima = Prima.new
56
+ output "Controllo se ci sono aggiornamenti da fare..."
57
+ exec "gem update prima-twig && twig deploy #{ARGV.join ' '}" unless `gem outdated`.lines.grep(/^prima-twig \(.*\)/).empty?
49
58
  @cf = Aws::CloudFormation::Client.new
50
59
  @ecs = Aws::ECS::Client.new
60
+ @s3 = Aws::S3::Client.new
61
+ @batch = Aws::Batch::Client.new
62
+ @s3_bucket = "prima-artifacts-encrypted"
51
63
  end
52
64
 
53
- def execute!
54
- stop_if @prima.head_detached?, :detached_head
65
+ def execute! args
66
+ unless args.empty?
67
+ case args[0]
68
+ when "parameters"
69
+ reload_parameters!
70
+ else
71
+ stop_if true, [:wrong_args, ['parameters']]
72
+ end
73
+ else
74
+ deploy_revision!
75
+ end
76
+ end
55
77
 
56
- `git checkout master && git pull`
78
+ def deploy_revision!
79
+ stop_if @prima.head_detached?, :detached_head
80
+ stop_if @prima.repo_has_modified_files?, "Non posso deployare con file non commitati"
57
81
 
58
82
  output "Recupero degli artifacts in corso, attendi qualche secondo...".yellow
59
83
  artifacts = get_artifacts[0..49]
@@ -70,26 +94,10 @@ class Review
70
94
  end
71
95
  end
72
96
 
73
- user = `git config user.name`
97
+ user = `git config user.name`.delete "\n"
74
98
  artifact = artifacts.select {|v| v[:rev] == artifact_rev}.first
75
99
 
76
- deploy_command = "bin/deploy #{artifact_rev}"
77
-
78
- output "Il comando per il deploy sara': #{deploy_command}".yellow
79
-
80
- exit unless @prima.yesno "Sei sicuro di voler effettuare il deploy in produzione?".blue
81
-
82
- exec_step deploy_command
83
-
84
- stack_name_web = 'ecs-task-web-production'
85
- stack_name_consumer = 'ecs-task-consumer-production'
86
- stack_name_cron = 'ecs-task-consumer-production'
87
- wait_for_stack_ready(stack_name_web) unless stack_ready?(stack_name_web)
88
- wait_for_stack_ready(stack_name_consumer) unless stack_ready?(stack_name_consumer)
89
- wait_for_stack_ready(stack_name_cron) unless stack_ready?(stack_name_cron)
90
-
91
- output "Avvio paparatzinger per gli screenshot".yellow
92
- job_name = launch_paparatzinger(artifact[:commit_msg])
100
+ do_deploy! artifact_rev
93
101
 
94
102
  mail = Mail.new do
95
103
  from 'deploy@prima.it'
@@ -97,13 +105,14 @@ class Review
97
105
  subject "#{user} ha effettuato il deploy della revision #{artifact[:rev]}"
98
106
  end
99
107
 
108
+ commit_msg = clean_commit_message(artifact[:commit_msg])
109
+
100
110
  body = "## Deploy in produzione effettuato con successo\n\n"
101
111
  body << "Data: #{Time.now.strftime('%d/%m/%Y %H:%M:%S')}\n\n"
102
112
  body << "Utente: #{user}\n\n"
103
113
  body << "Revision: [#{artifact[:rev]}](https://github.com/primait/prima/commit/#{artifact[:rev]}) del #{artifact[:created_at].strftime('%d/%m/%Y %H:%M:%S')}\n\n"
104
114
  body << "Branch: [#{artifact[:branch]}](https://github.com/primait/prima/tree/#{artifact[:branch]})\n\n"
105
- body << "Commit: #{artifact[:commit_msg].gsub(/_/, '\_')}\n\n"
106
- body << "Screenshots (tra qualche minuto): [BrowserStack](https://www.browserstack.com/automate) (Filtrare per: \"#{job_name.gsub(/_/, '\_')}\")"
115
+ body << "Commit: #{commit_msg.gsub(/_/, '\_')}\n\n"
107
116
 
108
117
  htmlBody = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new).render body
109
118
 
@@ -118,94 +127,122 @@ class Review
118
127
  mail.html_part = html_part
119
128
  mail.text_part = text_part
120
129
 
121
- opts = {address: 'smtp.mandrillapp.com', port: '587'}
122
- opts[:user_name] = 'deploy@prima.it'
123
- opts[:password] = @prima.config['mandrill']
130
+ opts = {address: 'email-smtp.eu-west-1.amazonaws.com', port: '587'}
131
+ opts[:user_name] = @prima.config['aws_username']
132
+ opts[:password] = @prima.config['aws_password']
133
+
134
+ exec_step "git checkout master"
124
135
 
125
136
  mail.delivery_method(:smtp, opts)
126
137
  mail.deliver
127
138
 
139
+ invalidate_prismic_cache
140
+
141
+ launch_crawler
142
+
143
+ exec_step "terminal-notifier -message 'Deploy terminato'" if which 'terminal-notifier'
144
+ end
145
+
146
+ def invalidate_prismic_cache
147
+ [
148
+ "guarantee",
149
+ "glossary",
150
+ "guide",
151
+ "faq"
152
+ ].each do |page|
153
+
154
+ exec_step "curl -X POST -H \"Content-Type: application/json\" https://www.prima.it/api/cms/update/#{page}?apikey=#{@prima.config['prima_apikey']}"
155
+ end
156
+ end
157
+
158
+ def reload_parameters!
159
+ artifact_rev = ''
160
+ resp = @cf.describe_stacks({
161
+ stack_name: "ecs-task-web-vpc-production"
162
+ })
163
+ resp.stacks[0].parameters.each do |param|
164
+ if param.parameter_key == 'ReleaseVersion'
165
+ artifact_rev = param.parameter_value
166
+ break
167
+ end
168
+ end
169
+
170
+ do_deploy!(artifact_rev, true)
171
+
172
+ output "\nFinito di aggiornare i parameters.yml\n".green
173
+ end
174
+
175
+ def do_deploy!(artifact_rev, reload_parameters=false)
176
+ deploy_command = "bin/deploy #{artifact_rev}"
177
+ deploy_command << " reloadparameters" if reload_parameters
178
+
179
+ output "Il comando per il deploy sara': #{deploy_command}".yellow
180
+ confirm_message = "Sei sicuro di voler effettuare "
181
+ reload_parameters ? (confirm_message << "il reload dei parameters ") : (confirm_message << " il deploy ")
182
+ confirm_message << "in produzione?"
183
+
184
+ exit unless @prima.yesno confirm_message.blue
185
+
186
+ exec_step "git fetch"
187
+ exec_step "git checkout #{artifact_rev}"
188
+ exec_step deploy_command
189
+
190
+ stack_name_web = 'ecs-task-web-vpc-production'
191
+ stack_name_consumer = 'ecs-task-consumer-vpc-production'
192
+ stack_name_cron = 'ecs-task-consumer-vpc-production'
193
+ stack_name_job = 'batch-job-php-production'
194
+ wait_for_stack_ready(stack_name_web) unless stack_ready?(stack_name_web)
195
+ wait_for_stack_ready(stack_name_consumer) unless stack_ready?(stack_name_consumer)
196
+ wait_for_stack_ready(stack_name_cron) unless stack_ready?(stack_name_cron)
197
+ wait_for_stack_ready(stack_name_job) unless stack_ready?(stack_name_job)
128
198
  end
129
199
 
130
200
  def get_artifacts
131
201
  artifacts = []
132
- s3 = Aws::S3::Client.new
133
- resp = s3.list_objects(bucket: 'prima-artifacts', prefix: 'prima')
202
+ resp = @s3.list_objects(bucket: @s3_bucket, prefix: 'prima')
134
203
  resp.contents.each do |l|
135
- rev = l.key.match(/(\w{15}).tar.gz$/).captures.first if l.key.match(/(\w{15}).tar.gz$/)
204
+ # aggiungiamo solo gli artefatti prodotti a partire dal branch master, riconosciuti tramite i metadata
205
+ rev = l.key.match(/^prima\/(\w{15}).tar.gz$/).captures.first if l.key.match(/^prima\/(\w{15}).tar.gz$/)
136
206
  if rev
137
- object = s3.head_object(bucket: 'prima-artifacts', key: l.key)
207
+ object = @s3.head_object(bucket: @s3_bucket, key: l.key)
138
208
  commit_msg = ''
139
209
  commit_msg = Base64.decode64(object.metadata['commit_msg']).strip if object.metadata.has_key? 'commit_msg'
140
- artifacts << {rev: rev, created_at: object.last_modified, branch: object.metadata['branch'], commit_msg: commit_msg } if object.metadata.has_key? 'branch'
210
+ artifacts << {rev: rev, created_at: object.last_modified, branch: object.metadata['branch'], commit_msg: commit_msg } if (object.metadata.has_key? 'branch') && (object.metadata['branch'] == 'master')
141
211
  end
142
212
  end
143
213
  artifacts.sort_by { |v| v[:created_at] }.reverse
144
214
  end
145
215
 
146
- def wait_for_stack_ready(stack_name)
147
- ready = false
148
- sleep_seconds = 5
149
- output "Attendo che lo stack #{stack_name} finisca di essere deployato...\n".yellow
150
- while !ready
151
- ready = true if stack_ready?(stack_name)
152
- seconds_elapsed = 0
153
- while true
154
- break if seconds_elapsed >= sleep_seconds
155
- print '.'.yellow; STDOUT.flush
156
- sleep 1
157
- seconds_elapsed += 1
158
- end
159
- end
216
+ def launch_crawler()
217
+ resp = describe_stack_resource('batch-job-crawler-production', 'JobDefinition')
160
218
 
161
- output "\nStack #{stack_name} deployato con successo!\n".green
162
- end
163
-
164
- def stack_ready?(stack_name)
165
- resp = @cf.describe_stacks({
166
- stack_name: stack_name
219
+ @batch.submit_job({
220
+ job_name: "crawler", # required
221
+ job_queue: "tools-production", # required
222
+ job_definition: resp.stack_resource_detail.physical_resource_id # required
167
223
  })
168
- ['CREATE_COMPLETE', 'UPDATE_COMPLETE'].include? resp.stacks[0].stack_status
169
- end
170
224
 
171
- def launch_paparatzinger(job_name)
172
- job_name.gsub! /Merge pull request /i, ''
173
- job_name.gsub! /from primait\/feature\//i, ''
174
- job_name[0..99].gsub! /[^0-9a-z]/i, '\_'
225
+ output "Crawler lanciato con successo!\n".green
226
+ end
175
227
 
176
- logical_resource_id = 'TaskDefinitionPaparatzinger'
177
- resp = @cf.describe_stack_resource({
178
- stack_name: 'ecs-task-paparatzinger-production',
179
- logical_resource_id: logical_resource_id
180
- })
228
+ end
181
229
 
182
- resp = @ecs.run_task({
183
- cluster: 'ecs-cluster-microservices-production-ECSCluster-N4APBU860IA1',
184
- task_definition: resp.stack_resource_detail.physical_resource_id,
185
- overrides: {
186
- container_overrides: [
187
- {
188
- name: 'paparatzinger',
189
- environment: [
190
- {
191
- name: 'JOB_NAME',
192
- value: job_name,
193
- },
194
- {
195
- name: 'VERSION',
196
- value: '1.0.6',
197
- }
198
- ]
199
- }
200
- ]
201
- },
202
- count: 1
203
- })
204
- output "paparatzinger lanciato con successo\n".green
230
+ def clean_commit_message(commit_msg)
231
+ commit_msg.gsub! /Merge pull request /i, ''
232
+ commit_msg.gsub! /from primait\/feature\//i, ''
233
+ commit_msg = commit_msg[/.+?\(#\d+\)/m] unless commit_msg[/.+?\(#\d+\)/m].nil? # rimuove tutto quello che sta dopo la fine del numero di issue
234
+ commit_msg[0..99]
235
+ end
205
236
 
206
- job_name
237
+ def which(cmd)
238
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
239
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
240
+ exts.each { |ext|
241
+ exe = File.join(path, "#{cmd}#{ext}")
242
+ return exe if File.executable?(exe) && !File.directory?(exe)
243
+ }
207
244
  end
208
-
245
+ return nil
209
246
  end
210
247
 
211
- Review.new.execute!
248
+ Review.new.execute! args
@@ -2,51 +2,110 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require_relative '../lib/prima_twig.rb'
5
- require 'launchy'
5
+ require_relative '../lib/prima_aws_client.rb'
6
6
  require 'digest'
7
+ require 'json'
8
+ require 'launchy'
7
9
  require 'pp'
10
+ require 'redis'
8
11
 
9
12
  class Release
10
13
  include Command
14
+ include PrimaAwsClient
11
15
 
12
- def initialize
16
+ def initialize(update_gem=true)
13
17
  @prima = Prima.new
14
- @cf = Aws::CloudFormation::Client.new
15
- @elb = Aws::ElasticLoadBalancing::Client.new
16
- @ec2 = Aws::EC2::Client.new
17
- @ecs = Aws::ECS::Client.new
18
- @s3 = Aws::S3::Client.new
19
- @asg = Aws::AutoScaling::Client.new
20
- @s3_bucket = 'prima-artifacts'
21
- @artifact_path = '/tmp/prima-artifact.zip'
22
- @import_db_task = 'arn:aws:ecs:eu-west-1:001575623345:task-definition/ecs-task-db-restore-TaskDefinitionDbRestore-1ON8T3XFRV72W:1'
23
- @prima_built = false
24
- @urania_built = false
25
- @backoffice_built = false
18
+ if update_gem
19
+ output 'Controllo se ci sono aggiornamenti da fare (potrebbe richiedere qualche minuto)'
20
+ unless `gem update prima-twig`=="Updating installed gems\nNothing to update\n"
21
+ output 'Gemma prima-twig aggiornata'
22
+ exec "twig feature #{ARGV.join ' '}"
23
+ end
24
+ end
26
25
  @dns_record_identifier = nil
27
26
  @ecs_cluster_name = nil
27
+ @deploy_update = false
28
+ @projects = {
29
+ 'prima' => {},
30
+ 'urania' => {},
31
+ 'ermes' => {},
32
+ 'bburago' => {},
33
+ 'hal9000' => {},
34
+ 'fidaty' => {},
35
+ 'peano' => {},
36
+ # 'rogoreport' => {},
37
+ 'assange' => {},
38
+ 'borat' => {},
39
+ 'crash' => {},
40
+ 'activia' => {},
41
+ 'skynet' => {},
42
+ 'roger' => {},
43
+ 'rachele' => {},
44
+ 'leftorium' => {},
45
+ 'pyxis-npm' => {},
46
+ 'starsky' => {},
47
+ 'hutch' => {},
48
+ 'maia' => {},
49
+ 'legion' => {}
50
+ }
51
+ @base_stack_name_alb = 'ecs-alb-http-public-qa-'
52
+ @base_stack_name_alb_ws = 'ecs-alb-ws-public-qa-'
53
+ @git_branch = ''
54
+ @cloudflare = Rubyflare.connect_with(ENV['CLOUDFLARE_EMAIL'], ENV['CLOUDFLARE_APIKEY'])
28
55
  end
29
56
 
30
- def execute! args
57
+ def execute!(args)
31
58
  case args[0]
32
- when "start"
59
+ when 'start'
33
60
  start_feature!
34
- when "finish"
61
+ when 'finish'
35
62
  finish_feature!
36
- when "deploy"
63
+ when 'qainit'
64
+ abort('Non sei nella cartella di qainit') unless Dir.pwd.match 'qainit$' or Dir.pwd.match '/drone/src'
37
65
  if ['terminate', 'stop', 'shutdown', 'halt', 'destroy'].include? args[1]
38
- deploy_shutdown!
66
+ qainit_deploy_shutdown!
67
+ elsif 'update' == args[1]
68
+ qainit_deploy_update!
69
+ else
70
+ if args[1]
71
+ select_branches(args[1..-1])
72
+ else
73
+ select_branches
74
+ end
75
+ qainit_deploy!
76
+ end
77
+ when 'suite'
78
+ abort('Non sei nella cartella di qainit') unless Dir.pwd.match 'qainit$'
79
+ if 'deploy' == args[1]
80
+ suite_py_branches(args[2])
81
+ qainit_deploy!(true)
82
+ end
83
+ when 'deploy'
84
+ abort('Non sei nella cartella di artemide') unless Dir.pwd.match 'artemide$'
85
+ if 'lock' == args[1]
86
+ deploy_lock!
87
+ end
88
+ when 'aggregator'
89
+ if 'enable' == args[1]
90
+ aggregator_enable!
91
+ elsif 'disable' == args[1]
92
+ aggregator_disable!
39
93
  else
40
- deploy_feature!
94
+ stop_for_wrong_args
41
95
  end
42
96
  else
43
- stop_if true, [:wrong_args, ['start', 'finish', 'deploy', 'deploy stop']]
97
+ stop_for_wrong_args
44
98
  end
45
99
  end
46
100
 
101
+ def stop_for_wrong_args
102
+ puts help_content
103
+ stop_if true, [:wrong_args, ['start', 'finish', 'deploy', 'deploy project_name', 'deploy stop', 'deploy update', 'aggregator enable', 'aggregator disable']]
104
+ end
105
+
47
106
  def start_feature!
48
107
  branch_name = @prima.clean_branch_name(ask('Inserisci il nome del branch (puoi omettere feature/): '.cyan))
49
- stop_unless branch_name.length > 0, 'Devi inserire il nome del branch'
108
+ stop_unless !branch_name.empty?, 'Devi inserire il nome del branch'
50
109
  branch_name.prepend 'feature/' unless branch_name.include? 'feature'
51
110
 
52
111
  output "Il nome del branch sarà " + branch_name.yellow
@@ -56,6 +115,135 @@ class Release
56
115
  exec_step "git checkout -b " + branch_name
57
116
  end
58
117
 
118
+ def aggregator_disable!
119
+ output 'Disable aggregator'
120
+
121
+ output "Recupero le informazioni relative al puntamento dei record DNS..."
122
+ output "Recupero le informazioni sui QA attivi..."
123
+ stack_list, envs = get_stacks()
124
+
125
+ env_hash = nil
126
+ unless envs.empty?
127
+ env_hash = envs.detect do |key, tags|
128
+ aggregator_enabled = tags.detect do |tag|
129
+ tag.key === "hostname_pattern_priority" and tag.value === "1"
130
+ end.is_a?(Aws::CloudFormation::Types::Tag)
131
+ aggregator_enabled
132
+ end[0]
133
+ dns_records = @cloudflare.get("zones/1fb634f19c43dfb0162cc4cb91915da2/dns_records", {per_page: 100, type: 'CNAME', content: get_alb_host(@base_stack_name_alb + env_hash[3..8])})
134
+ stop_if dns_records.body[:result].empty?, "I record DNS degli aggregatori non stanno puntando ad un QA".red
135
+ change_hostname_priority(env_hash, hostname_pattern_priority())
136
+ dns_to_staging(env_hash)
137
+ else
138
+ output 'Nessun QA trovato'.red
139
+ exit
140
+ end
141
+
142
+ output 'Finito!'.green
143
+ end
144
+
145
+ def aggregator_enable!
146
+ output 'Enable aggregator'
147
+
148
+ output 'Recupero le informazioni relative al puntamento dei record DNS...'
149
+ dns_records = @cloudflare.get('zones/1fb634f19c43dfb0162cc4cb91915da2/dns_records', { per_page: 100, type: 'CNAME', content: 'staging.prima.it' })
150
+ stop_if dns_records.body[:result].empty?, "I record DNS degli aggregatori stanno gia' puntando ad un QA".red
151
+
152
+ output "Recupero le informazioni sui QA attivi..."
153
+ stack_list, envs = get_stacks()
154
+
155
+ env_hash = nil
156
+ unless envs.empty?
157
+ env_hash = choose do |menu|
158
+ menu.prompt = "Scegli il QA al quale vuoi far puntare gli ambienti di staging dei comparatori: ".cyan
159
+ menu.shell = true
160
+ envs.each do |key, env|
161
+ title = ""
162
+ env.each do |e|
163
+ title << "\n#{e.key.upcase}: #{e.value}"
164
+ end
165
+ msg = "#{@prima.reduce_size(title, 1000)}".light_blue
166
+ menu.choice(msg) { key }
167
+ end
168
+ end
169
+ else
170
+ output "Nessun QA trovato".red
171
+ exit
172
+ end
173
+
174
+ change_hostname_priority(env_hash, "1")
175
+
176
+ dns_records.body[:result].each do |dns|
177
+ if dns[:name] =~ /^\w+\-\w+\-staging\.prima\.it$/
178
+ output "Changing #{dns[:name]} DNS record"
179
+ @cloudflare.put("zones/1fb634f19c43dfb0162cc4cb91915da2/dns_records/#{dns[:id]}", {type: 'CNAME', name: dns[:name], content: get_alb_host(@base_stack_name_alb + env_hash[3..8]), proxied: true, ttl: 1})
180
+ end
181
+ end
182
+
183
+ output "Finito!".green
184
+ end
185
+
186
+ def change_hostname_priority(env_hash, hostname_pattern_priority)
187
+ cluster_stack_name = "ecs-cluster-#{env_hash}"
188
+ tags = get_stack_tags(cluster_stack_name).map do |tag|
189
+ if tag.key === "hostname_pattern_priority"
190
+ {
191
+ key: "hostname_pattern_priority",
192
+ value: hostname_pattern_priority
193
+ }
194
+ else
195
+ tag
196
+ end
197
+ end
198
+
199
+ stack_list = stack_list()
200
+
201
+ stack_list.each do |stack|
202
+ if stack.stack_name.match(/#{env_hash}$/)
203
+ stack_name = stack.stack_name
204
+ update_stack(stack_name, get_stack_template(stack_name), get_stack_parameters(stack_name), tags)
205
+ end
206
+ end
207
+
208
+ stack_list.each do |stack|
209
+ if stack.stack_name.match(/#{env_hash}$/)
210
+ wait_for_stack_ready(stack.stack_name) unless stack_ready?(stack.stack_name)
211
+ end
212
+ end
213
+
214
+ stack_name_web = "ecs-task-web-#{env_hash}"
215
+ parameters = get_stack_parameters(stack_name_web).map do |param|
216
+ if param.parameter_key === "HostnamePatternPriority"
217
+ {
218
+ parameter_key: "HostnamePatternPriority",
219
+ parameter_value: hostname_pattern_priority
220
+ }
221
+ elsif param.parameter_key === "HostnamePatternAggregatorPriority"
222
+ {
223
+ parameter_key: "HostnamePatternAggregatorPriority",
224
+ parameter_value: (hostname_pattern_priority.to_i + 1).to_s
225
+ }
226
+ else
227
+ param
228
+ end
229
+ end
230
+
231
+ update_stack(stack_name_web, get_stack_template(stack_name_web), parameters)
232
+
233
+ wait_for_stack_ready(stack_name_web) unless stack_ready?(stack_name_web)
234
+ end
235
+
236
+ def dns_to_staging(env_hash)
237
+ output "Recupero le informazioni relative al puntamento dei record DNS..."
238
+ dns_records = @cloudflare.get("zones/1fb634f19c43dfb0162cc4cb91915da2/dns_records", {per_page: 100, type: 'CNAME', content: get_alb_host(@base_stack_name_alb + env_hash[3..8])})
239
+ dns_records.body[:result].each do |dns|
240
+ if dns[:name] =~ /^\w+\-\w+\-staging\.prima\.it$/
241
+ output "Changing #{dns[:name]} DNS record"
242
+ @cloudflare.put("zones/1fb634f19c43dfb0162cc4cb91915da2/dns_records/#{dns[:id]}", {type: 'CNAME', name: dns[:name], content: 'staging.prima.it', proxied: true, ttl: 1})
243
+ end
244
+ end
245
+ end
246
+
59
247
  def finish_feature!
60
248
  current_branch_name = @prima.twig.current_branch_name
61
249
  stop_unless (current_branch_name =~ /^feature\//), "Non sei su un branch di feature, non posso mergiare nulla"
@@ -76,11 +264,8 @@ class Release
76
264
  end
77
265
 
78
266
  def deploy_shutdown!
79
- envs = {}
80
- stack_list.each do |stack|
81
- env_hash = stack.stack_name.match(/qa-(\w+)$/)[0]
82
- envs[env_hash] = stack.tags unless envs.has_key?(env_hash)
83
- end
267
+ output "Recupero le informazioni sui QA attivi..."
268
+ stack_list, envs = get_stacks
84
269
 
85
270
  env_hash = nil
86
271
  unless envs.empty?
@@ -89,693 +274,509 @@ class Release
89
274
  menu.shell = true
90
275
 
91
276
  envs.each do |key, env|
92
- title = @prima.reduce_size("#{env[0].key}: #{env[0].value} #{env[1].key}: #{env[1].value} #{env[2].key}: #{env[2].value} #{env[3].key}: #{env[3].value}", 100)
93
- msg = "#{title}".light_blue
277
+ title = ''
278
+ env.each do |e|
279
+ title << "\n#{e.key}: #{e.value} "
280
+ end
281
+ msg = @prima.reduce_size(title, 1000).to_s.light_blue
94
282
  menu.choice(msg) { key }
95
283
  end
96
284
  end
97
285
  else
98
- output "Nessun environment trovato".red
286
+ output 'Nessun environment trovato'.red
99
287
  exit
100
288
  end
101
289
 
102
290
  cluster_stack_name = nil
291
+ stacks_to_delete = []
103
292
  stack_list.each do |stack|
104
293
  if stack.stack_name.match(/#{env_hash}$/)
105
294
  if stack.stack_name.match(/ecs-cluster/)
106
295
  cluster_stack_name = stack.stack_name
107
296
  else
108
- delete_stack(stack.stack_name) if stack.stack_name.match(/#{env_hash}$/)
297
+ break unless stack.stack_name.match(/#{env_hash}$/)
298
+ stacks_to_delete.push(stack.stack_name)
299
+ delete_stack(stack.stack_name)
109
300
  end
110
301
  end
111
302
  end
112
303
 
304
+ cluster_stack_name = "ecs-cluster-#{env_hash}"
305
+ aggregator_enabled = get_stack_tags(cluster_stack_name).detect do |tag|
306
+ tag.key === "hostname_pattern_priority" and tag.value === "1"
307
+ end.is_a?(Aws::CloudFormation::Types::Tag)
308
+
309
+ if aggregator_enabled
310
+ dns_to_staging(env_hash)
311
+ end
312
+
113
313
  # Se non ha finito di cancellare le altre non si puo' cancellare il cluster
114
- output "Attendo 60 secondi per poter eliminare il cluster ECS"
115
- sleep 60
314
+ output "Attendo 10 secondi per poter eliminare il cluster ECS"
315
+
316
+ while stacks_to_delete.length > 0
317
+ sleep 13
318
+ stacks_to_delete.each do |stack_name|
319
+ stacks_to_delete = stacks_to_delete - [stack_name] unless stack_exists?(stack_name)
320
+ end
321
+ output "Stack ancora attivi: #{stacks_to_delete.length.to_s}. Attendo altri 10 secondi per eliminare il cluster ECS"
322
+ end
323
+
116
324
  delete_stack(cluster_stack_name)
325
+ delete_stack(@base_stack_name_alb + env_hash[3..8])
326
+ delete_stack(@base_stack_name_alb_ws + env_hash[3..8])
117
327
  output "Finito!".green
118
328
  end
119
329
 
120
- def deploy_feature!
121
- `sudo true` # cosi' non chiede la password dopo
122
- `git pull`
123
- prima_branch = choose_branch_to_deploy('prima')
124
- backoffice_branch = choose_branch_to_deploy('backoffice')
125
- urania_branch = choose_branch_to_deploy('urania')
126
- ermes_branch = choose_branch_to_deploy('ermes')
127
- socket_branch = {name: "master"}
128
- pamela_branch = {name: "master"}
129
-
130
- @dns_record_identifier = "#{@prima.clean_branch_name(prima_branch[:name])}-#{@prima.clean_branch_name(backoffice_branch[:name])}-#{@prima.clean_branch_name(urania_branch[:name])}-#{@prima.clean_branch_name(ermes_branch[:name])}".gsub(/feature./, '')[0..35].gsub(/(-+$)/, '')
131
-
132
- tags = [
133
- {
134
- key: "prima",
135
- value: prima_branch[:name]
136
- },
137
- {
138
- key: "urania",
139
- value: urania_branch[:name]
140
- },
141
- {
142
- key: "backoffice",
143
- value: backoffice_branch[:name]
144
- },
145
- {
146
- key: "ermes",
147
- value: ermes_branch[:name]
148
- }
149
- ]
150
-
151
- deploy_id = Digest::MD5.hexdigest(prima_branch[:name] + backoffice_branch[:name] + urania_branch[:name] + socket_branch[:name] + pamela_branch[:name] + ermes_branch[:name])
152
-
153
- cluster_stack_name = "ecs-cluster-qa-#{deploy_id}"
154
- create_cluster_stack(cluster_stack_name, tags) unless stack_exists?(cluster_stack_name)
155
- wait_for_stack_ready(cluster_stack_name) unless stack_ready?(cluster_stack_name)
156
-
157
- resp = @cf.describe_stack_resource({stack_name: cluster_stack_name, logical_resource_id: 'ECSCluster'})
158
- @ecs_cluster_name = resp.stack_resource_detail.physical_resource_id
159
-
160
- asg_stack_name = "ecs-asg-allinone-qa-#{deploy_id}"
161
- create_asg_stack(asg_stack_name, tags) unless stack_exists?(asg_stack_name)
162
-
163
- stack_name_db = "ecs-task-db-qa-#{deploy_id}"
164
- stack_body = IO.read('cloudformation/stacks/task/db.json')
165
- parameters = [
166
- {
167
- parameter_key: "Environment",
168
- parameter_value: "qa"
169
- },
170
- {
171
- parameter_key: "ECSClusterName",
172
- parameter_value: @ecs_cluster_name
173
- }
174
- ]
175
- create_stack(stack_name_db, stack_body, parameters, tags) unless stack_exists?(stack_name_db)
176
-
177
- create_prima_artifact(prima_branch[:revision], prima_branch[:name]) unless artifact_exists?('prima-artifacts', "prima/#{prima_branch[:revision]}")
178
- create_urania_artifact(urania_branch[:revision]) unless artifact_exists?('prima-artifacts', "microservices/urania/#{urania_branch[:revision]}-qa.tar.gz")
179
- create_ermes_artifact(ermes_branch[:revision]) unless artifact_exists?('prima-artifacts', "microservices/ermes/ermes_#{ermes_branch[:revision]}.tar.gz")
180
- create_backoffice_artifact(backoffice_branch[:revision], deploy_id) unless artifact_exists?('prima-artifacts', "backoffice/#{backoffice_branch[:revision]}-#{deploy_id}.zip")
181
-
182
- wait_for_stack_ready(stack_name_db) unless stack_ready?(stack_name_db)
183
-
184
- import_dbs(ec2_ip_address(asg_stack_name)) unless stack_exists?("ecs-task-web-qa-#{deploy_id}")
185
-
186
- stack_name_web = "ecs-task-web-qa-#{deploy_id}"
187
- git_checkout_version('prima', prima_branch[:revision])
188
- stack_body = IO.read('projects/prima/app/cloudformation/tasks/web.json')
189
- parameters = [
190
- {
191
- parameter_key: "Environment",
192
- parameter_value: "qa"
193
- },
194
- {
195
- parameter_key: "ReleaseVersion",
196
- parameter_value: prima_branch[:revision]
197
- },
198
- {
199
- parameter_key: "TaskDesiredCount",
200
- parameter_value: "1"
201
- },
202
- {
203
- parameter_key: "ECSClusterName",
204
- parameter_value: @ecs_cluster_name
205
- }
206
- ]
207
- if stack_exists?(stack_name_web)
208
- update_stack(stack_name_web, stack_body, parameters) if @prima_built
209
- else
210
- create_stack(stack_name_web, stack_body, parameters, tags)
211
- end
212
-
213
- stack_name_consumer = "ecs-task-consumer-qa-#{deploy_id}"
214
- git_checkout_version('prima', prima_branch[:revision])
215
- stack_body = IO.read('projects/prima/app/cloudformation/tasks/consumer.json')
216
- parameters = [
217
- {
218
- parameter_key: "Environment",
219
- parameter_value: "qa"
220
- },
221
- {
222
- parameter_key: "ReleaseVersion",
223
- parameter_value: prima_branch[:revision]
224
- },
225
- {
226
- parameter_key: "ECSClusterName",
227
- parameter_value: @ecs_cluster_name
228
- }
229
- ]
230
- if stack_exists?(stack_name_consumer)
231
- update_stack(stack_name_consumer, stack_body, parameters) if @prima_built
232
- else
233
- create_stack(stack_name_consumer, stack_body, parameters, tags)
234
- end
235
-
236
- stack_name_urania = "ecs-task-urania-qa-#{deploy_id}"
237
- git_checkout_version('urania', urania_branch[:revision])
238
- stack_body = IO.read('projects/urania/deploy/task.json')
239
- parameters = [
240
- {
241
- parameter_key: "Environment",
242
- parameter_value: "qa"
243
- },
244
- {
245
- parameter_key: "ReleaseVersion",
246
- parameter_value: urania_branch[:revision]
247
- },
248
- {
249
- parameter_key: "TaskDesiredCount",
250
- parameter_value: "1"
251
- },
252
- {
253
- parameter_key: "ECSClusterName",
254
- parameter_value: @ecs_cluster_name
255
- }
256
- ]
257
- if stack_exists?(stack_name_urania)
258
- update_stack(stack_name_urania, stack_body, parameters) if @urania_built
259
- else
260
- create_stack(stack_name_urania, stack_body, parameters, tags)
261
- end
262
-
263
- stack_name_ermes = "ecs-task-ermes-qa-#{deploy_id}"
264
- git_checkout_version('ermes', ermes_branch[:revision])
265
- stack_body = IO.read('projects/ermes/deploy/task.json')
266
- parameters = [
267
- {
268
- parameter_key: "Environment",
269
- parameter_value: "qa"
270
- },
271
- {
272
- parameter_key: "ReleaseVersion",
273
- parameter_value: ermes_branch[:revision]
274
- },
275
- {
276
- parameter_key: "ECSClusterName",
277
- parameter_value: @ecs_cluster_name
278
- }
279
- ]
280
- if stack_exists?(stack_name_ermes)
281
- update_stack(stack_name_ermes, stack_body, parameters) if @ermes_built
282
- else
283
- create_stack(stack_name_ermes, stack_body, parameters, tags)
284
- end
285
-
286
- git_checkout_version('backoffice', backoffice_branch[:revision])
287
- stack_name_backoffice = "ecs-task-backoffice-qa-#{deploy_id}"
288
- stack_body = IO.read('projects/backoffice/deploy/task.json')
289
- parameters = [
290
- {
291
- parameter_key: "Environment",
292
- parameter_value: "qa"
293
- },
294
- {
295
- parameter_key: "ReleaseVersion",
296
- parameter_value: "#{backoffice_branch[:revision]}-#{deploy_id}"
297
- },
298
- {
299
- parameter_key: "TaskDesiredCount",
300
- parameter_value: "1"
301
- },
302
- {
303
- parameter_key: "ECSClusterName",
304
- parameter_value: @ecs_cluster_name
305
- }
306
- ]
307
- if stack_exists?(stack_name_backoffice)
308
- update_stack(stack_name_backoffice, stack_body, parameters) if @backoffice_built
330
+ def deploy_lock!
331
+ output "Deploy update menu"
332
+ `git pull && git submodule init && git submodule update`
333
+
334
+ @deploy_update = true
335
+
336
+ output "Recupero le informazioni sui QA attivi..."
337
+ stack_list, envs = get_clusters()
338
+
339
+ env_hash = nil
340
+ unless envs.empty?
341
+ env_hash = choose do |menu|
342
+ menu.prompt = "Scegli il QA che vuoi proteggere dallo spegnimento automatico: ".cyan
343
+ menu.shell = true
344
+ envs.each do |key, env|
345
+ title = ""
346
+ env.each do |e|
347
+ title << "#{e.value}" if e.key == 'qainit'
348
+ end
349
+ msg = "#{@prima.reduce_size(title, 1000)}".light_blue
350
+ menu.choice(msg) { key }
351
+ end
352
+ end
309
353
  else
310
- create_stack(stack_name_backoffice, stack_body, parameters, tags)
354
+ output "Nessun QA trovato".red
355
+ exit
311
356
  end
312
357
 
313
- wait_for_stack_ready(stack_name_web) unless stack_ready?(stack_name_web)
314
- wait_for_stack_ready(stack_name_consumer) unless stack_ready?(stack_name_consumer)
315
- wait_for_stack_ready(stack_name_urania) unless stack_ready?(stack_name_urania)
316
- wait_for_stack_ready(stack_name_backoffice) unless stack_ready?(stack_name_backoffice)
317
- wait_for_stack_ready(stack_name_ermes) unless stack_ready?(stack_name_ermes)
318
-
319
- update_service_defaults(stack_name_web)
320
- update_service_defaults(stack_name_consumer)
321
- update_service_defaults(stack_name_urania)
322
- update_service_defaults(stack_name_backoffice)
323
- update_service_defaults(stack_name_ermes)
324
-
325
- stack_name_route53 = "ecs-route53-qa-#{deploy_id}"
326
- stack_body = IO.read('cloudformation/stacks/route53/qa.json')
327
- parameters = [
328
- {
329
- parameter_key: "DnsRecordIdentifier",
330
- parameter_value: @dns_record_identifier
331
- },
332
- {
333
- parameter_key: "PrimaElbHostname",
334
- parameter_value: get_elb_host(stack_name_web)
335
- },
336
- {
337
- parameter_key: "BackofficeElbHostname",
338
- parameter_value: get_elb_host(stack_name_backoffice)
339
- },
340
- {
341
- parameter_key: "UraniaElbHostname",
342
- parameter_value: get_elb_host(stack_name_urania)
343
- }
344
- ]
345
- create_stack(stack_name_route53, stack_body, parameters, tags) unless stack_exists?(stack_name_route53)
346
-
347
- prima_hostname = get_route53_hostname(stack_name_web)
348
- urania_hostname = get_route53_hostname(stack_name_urania)
349
- backoffice_hostname = get_route53_hostname(stack_name_backoffice)
350
-
351
- wait_for_stack_ready(stack_name_route53) unless stack_ready?(stack_name_route53)
352
-
353
- output "Prima url: #{prima_hostname}\n".cyan
354
- output "Urania url: #{urania_hostname}\n".cyan
355
- output "Backoffice url: #{backoffice_hostname}\n".cyan
356
- output "SSH connection: ssh ec2-user@#{ec2_ip_address(asg_stack_name)} -i ~/.ssh/ecs-cluster-qa.pem".cyan
357
- output "Deploy effettuato, everything is awesome!\n".green
358
- end
359
-
360
- def get_route53_hostname(stack_name)
361
- case
362
- when stack_name.include?('web')
363
- host = "www.#{@dns_record_identifier}.qa.colaster.com"
364
- when stack_name.include?('urania')
365
- host = "urania.#{@dns_record_identifier}.qa.colaster.com"
366
- when stack_name.include?('backoffice')
367
- host = "backoffice.#{@dns_record_identifier}.qa.colaster.com"
358
+ cluster_stack_name = "ecs-cluster-#{env_hash}"
359
+ if stack_exists?(cluster_stack_name)
360
+ tags = get_stack_tags(cluster_stack_name)
361
+ tag_keep_data = Aws::CloudFormation::Types::Tag.new({key:'AUTOMATIC_DELETION_PROTECTION', value:'true'})
362
+ tags.push tag_keep_data
368
363
  end
369
- host
370
- end
371
364
 
372
- def ec2_ip_address(asg_stack_name)
373
- resp = @cf.describe_stack_resource({
374
- stack_name: asg_stack_name,
375
- logical_resource_id: 'ECSAutoScalingGroup'
376
- })
377
- resp = @asg.describe_auto_scaling_groups({
378
- auto_scaling_group_names: [resp.stack_resource_detail.physical_resource_id],
379
- max_records: 1
380
- })
381
- instance_id = resp.auto_scaling_groups[0].instances[0].instance_id
382
- resp = @ec2.describe_instances({instance_ids: [instance_id]})
383
- resp.reservations[0].instances[0].private_ip_address
384
- end
365
+ update_cluster_stack(cluster_stack_name, tags)
385
366
 
386
- def get_elb_host(stack_name)
387
- case
388
- when stack_name.include?('web')
389
- logical_resource_id = 'EcsElasticLoadBalancerPublic'
390
- when stack_name.include?('urania')
391
- logical_resource_id = 'EcsElasticLoadBalancerInternal'
392
- when stack_name.include?('backoffice')
393
- logical_resource_id = 'EcsElasticLoadBalancerPublic'
394
- end
395
- resp = @cf.describe_stack_resource({
396
- stack_name: stack_name,
397
- logical_resource_id: logical_resource_id
398
- })
399
- resp = @elb.describe_load_balancers({
400
- load_balancer_names: [resp.stack_resource_detail.physical_resource_id],
401
- page_size: 1
402
- })
403
- resp.load_balancer_descriptions[0].dns_name
367
+ output "Finito!".green
404
368
  end
405
369
 
406
- def update_service_defaults(stack_name)
407
- case
408
- when stack_name.include?('web')
409
- logical_resource_id = 'ECSServiceWeb'
410
- when stack_name.include?('consumer')
411
- logical_resource_id = 'ECSServiceConsumer'
412
- when stack_name.include?('urania')
413
- logical_resource_id = 'ECSServiceUrania'
414
- when stack_name.include?('backoffice')
415
- logical_resource_id = 'ECSServiceBackoffice'
416
- when stack_name.include?('ermes')
417
- logical_resource_id = 'ECSServiceErmes'
418
- else
419
- raise "Service name non gestito per lo stack #{stack_name}"
420
- end
421
- resp = @cf.describe_stack_resource({
422
- stack_name: stack_name,
423
- logical_resource_id: logical_resource_id
424
- })
425
- resp = @ecs.update_service({
426
- cluster: @ecs_cluster_name,
427
- service: resp.stack_resource_detail.physical_resource_id,
428
- deployment_configuration: {
429
- minimum_healthy_percent: 0,
430
- maximum_percent: 100
431
- }
432
- })
433
- end
434
-
435
- def create_urania_artifact(revision)
436
- @urania_built = true
437
- output "Preparo l'artifact .zip\n".yellow
438
-
439
- git_checkout_version('urania', revision)
440
-
441
- Dir.chdir 'projects/urania'
442
-
443
- [
444
- "docker run -v $PWD:/code -w /code -e MIX_ENV=qa prima/urania:1.0.2 \
445
- 'mix local.hex --force && mix hex.info && \
446
- mix deps.get && mix compile && mix deps.compile && \
447
- mix release.clean --implode --no-confirm && mix release'",
448
- "sudo chown -R `whoami` ."
449
- ].each do |cmd|
450
- output "Eseguo #{cmd}".yellow
451
- res = %x[ #{cmd} ]
452
- if $?.exitstatus != 0
453
- color = 'red'
454
- else
455
- color = 'green'
370
+ def deploy_update!
371
+ output "Deploy update menu"
372
+ `git pull && git submodule init && git submodule update`
373
+
374
+ @deploy_update = true
375
+
376
+ output "Recupero le informazioni sui QA attivi..."
377
+ stack_list, envs = get_stacks()
378
+
379
+ env_hash = nil
380
+ unless envs.empty?
381
+ env_hash = choose do |menu|
382
+ menu.prompt = "Scegli il QA che vuoi aggiornare: ".cyan
383
+ menu.shell = true
384
+ envs.each do |key, env|
385
+ title = ""
386
+ env.each do |e|
387
+ title << "\n#{e.key.upcase}: #{e.value}"
388
+ end
389
+ msg = "#{@prima.reduce_size(title, 1000)}".light_blue
390
+ menu.choice(msg) { key }
391
+ end
456
392
  end
457
- output res.send color
458
- stop_if (color == 'red'), "Errore durante la build dell'artifact".red
393
+ else
394
+ output "Nessun QA trovato".red
395
+ exit
459
396
  end
460
397
 
461
- artifact_path = Dir.glob("rel/urania/releases/*/urania.tar.gz").first
462
- upload_artifact(artifact_path, "microservices/urania/#{revision}-qa.tar.gz")
398
+ envs[env_hash].each do |env|
399
+ unless ['hostname_pattern_priority', 'AUTOMATIC_DELETION_PROTECTION'].include? env.key
400
+ @projects[env.key] = select_branch_to_deploy(env.key, env.value)
401
+ end
402
+ end
403
+ deploy_feature!
463
404
 
464
- Dir.chdir '../../'
405
+ output "Finito!".green
465
406
  end
466
407
 
467
- def create_ermes_artifact(revision)
468
- @ermes_built = true
469
- output "Preparo l'artifact .zip\n".yellow
408
+ def get_default_branch_name(projects)
409
+ projects.each_key do |project|
410
+ return projects[project]['name'] if not projects[project]['default_branch']
411
+ end
412
+ end
470
413
 
471
- git_checkout_version('ermes', revision)
414
+ def suite_py_branches(args_json)
415
+ arg_projects = JSON.parse(args_json)
472
416
 
473
- Dir.chdir 'projects/ermes'
417
+ @projects.merge!(arg_projects)
474
418
 
475
- [
476
- "docker run -v $PWD:/code -w /code -e MIX_ENV=qa prima/ermes:0.0.4 \
477
- 'mix local.hex --force && mix hex.info && \
478
- mix deps.get && mix compile && mix deps.compile && \
479
- mix release.clean --implode --no-confirm && mix release'",
480
- "sudo chown -R `whoami` ."
481
- ].each do |cmd|
482
- output "Eseguo #{cmd}".yellow
483
- res = %x[ #{cmd} ]
484
- if $?.exitstatus != 0
485
- color = 'red'
486
- else
487
- color = 'green'
419
+ @projects.each_key do |project|
420
+ if @projects[project].empty?
421
+ @projects[project] = choose_branch_to_deploy(project, true)
488
422
  end
489
- output res.send color
490
- stop_if (color == 'red'), "Errore durante la build dell'artifact".red
491
423
  end
424
+ end
492
425
 
493
- artifact_path = Dir.glob("rel/ermes/releases/*/ermes.tar.gz").first
494
- upload_artifact(artifact_path, "microservices/ermes/ermes_#{revision}.tar.gz")
426
+ def get_git_user()
427
+ `git config user.name`.gsub(/[^A-Za-z]/, '').gsub("\n", '')
428
+ end
495
429
 
496
- Dir.chdir '../../'
430
+ def get_git_mail()
431
+ `git config user.email`.gsub("\n", '')
497
432
  end
498
433
 
499
- def create_backoffice_artifact(revision, deploy_id)
500
- @backoffice_built = true
501
- output "Preparo l'artifact .zip\n".yellow
434
+ def qainit_deploy!(quiet = false)
435
+ `git checkout master && git pull && git submodule update --init --recursive && git remote prune origin`
436
+
437
+ default_name = get_default_branch_name @projects
438
+ feature_number = ''
439
+ unless quiet
440
+ output "Inserisci la feature a cui si riferisce il QA: [#{default_name}]".cyan
441
+ feature_number = String(STDIN.gets.chomp)
442
+ end
443
+ feature_number = default_name if feature_number.empty?
444
+ branch_name = get_git_user + '_' + feature_number
445
+
446
+ if `git branch -l | grep #{branch_name}`.size > 0
447
+ `git checkout #{branch_name} && git pull`
448
+ else
449
+ `git checkout -b #{branch_name}`
450
+ end
502
451
 
503
- git_checkout_version('backoffice', revision)
452
+ @git_branch = branch_name
504
453
 
505
- Dir.chdir 'projects/backoffice'
454
+ File.open('branch_names', 'w') { |file| file.write(JSON.generate(@projects)) }
506
455
 
507
- ['node_modules'].each do |dir|
508
- unless File.directory?(dir)
509
- if File.directory?("../../../backoffice/#{dir}")
510
- exec_step "rsync -a ../../../backoffice/#{dir} ."
511
- end
456
+ update_drone_yml!
457
+
458
+ `git add projects && \
459
+ git add branch_names .drone.yml && \
460
+ git commit -m '#{branch_name}' && \
461
+ git push -f --set-upstream origin #{branch_name} && \
462
+ git checkout master`
463
+ end
464
+
465
+ def qainit_deploy_update!
466
+ `git checkout master && git pull`
467
+ # cancelliamo tutti i branch che non sono più sul repo remoto
468
+ `git fetch -p && for branch in \`git branch -vv | grep ': gone]' | awk '{print $1}'\`; do git branch -D $branch; done`
469
+ # leggiamo i nomi dei branch superstiti
470
+ former_branches = `git branch -a | grep remotes/ | grep -v HEAD | sed 's/ remotes\\/origin\\///g'`.split "\n"
471
+ git_user = get_git_user
472
+ # stampiamo la lista
473
+ chosen_branch = choose do |menu|
474
+ menu.prompt = "Scegli il QA che vuoi aggiornare: ".cyan
475
+ menu.shell = true
476
+ former_branches.delete('master')
477
+ former_branches.each_with_index do |branch, index|
478
+ msg = index.odd? ? branch.white : branch.light_yellow # uno bianco e uno giallo alternati
479
+ msg = branch.start_with?(git_user) ? msg.on_blue : msg.on_black # i branch creati da chi lancia l'update sono su sfondo più chiaro
480
+ menu.choice(msg) { branch }
512
481
  end
513
482
  end
483
+ # checkout master, checkout branch, pull branch
484
+ `git checkout master && git checkout #{chosen_branch} && git pull`
514
485
 
515
- stack_name_web = "ecs-task-web-qa-notneeded"
516
- web_qa_host = get_route53_hostname(stack_name_web)
486
+ # aggiornare il commit (revision a cui fa riferimento)
517
487
 
518
- [
519
- "docker-compose build workers",
520
- "cd ../../ && docker run -e GIT_DIR=$PWD -v $PWD:/usr/app/src -w /usr/app/src/projects/backoffice blinkmobile/bower install --allow-root",
521
- "docker run -v $PWD:/code -w /code -e PHANTOMJS_BIN=/code/node_modules/grunt-selenium-webdriver/node_modules/phantomjs/bin/phantomjs --entrypoint /bin/bash backoffice_workers '-c' 'sed -i \"s/web-qa-url/#{web_qa_host}/g\" Gruntfile.js && npm install && grunt qa'",
522
- "sudo chown -R `whoami` ."
523
- ].each do |cmd|
524
- output "Eseguo #{cmd}".yellow
525
- res = %x[ #{cmd} ]
526
- if $?.exitstatus != 0
527
- color = 'red'
528
- else
529
- color = 'green'
488
+ # leggo il file branch_names / recupero i nomi dei branch / riscrivo tutto
489
+ projects = ''
490
+ File.open('branch_names', 'r') do |file|
491
+ file.each_line do |line|
492
+ projects = JSON.parse(line)
530
493
  end
531
- output res.send color
532
- stop_if (color == 'red'), "Errore durante la build dell'artifact".red
533
494
  end
534
495
 
535
- artifact_path = '/tmp/backoffice.zip'
536
- exec_step "rm -f #{artifact_path} && zip -9 -r #{artifact_path} bin/"
537
- upload_artifact(artifact_path, "backoffice/#{revision}-#{deploy_id}.zip")
496
+ projects.each do |key, project|
497
+ @projects[key] = select_branch_to_deploy(key, project['name'])
498
+ @projects[key]['default_branch'] = project['default_branch']
499
+ end
500
+
501
+ File.open('branch_names', 'w') { |file| file.write(JSON.generate(@projects)) }
502
+
503
+ update_drone_yml!
538
504
 
539
- Dir.chdir '../../'
505
+ `git add branch_names .drone.yml`
506
+ `git commit -m 'update'`
507
+ `git push && git checkout master`
540
508
  end
541
509
 
542
- def create_prima_artifact(revision, branch_name)
543
- @prima_built = true
544
- output "Preparo l'artifact .zip\n".yellow
510
+ def qainit_deploy_shutdown!(selection = nil)
511
+ `git checkout master && git pull && git remote prune origin`
512
+ # leggiamo i nomi dei branch
513
+ former_branches = `git branch -a | grep remotes/ | grep -v HEAD | sed 's/ remotes\\/origin\\///g'`.split "\n"
514
+ if selection.nil?
515
+ # stampiamo la lista
516
+ chosen_branch = choose do |menu|
517
+ menu.prompt = "Scegli il QA che vuoi spegnere: ".cyan
518
+ menu.shell = true
519
+ git_user = get_git_user
520
+ former_branches.delete('master')
521
+ former_branches.each_with_index do |branch, index|
522
+ msg = index.odd? ? branch.white : branch.light_yellow # uno bianco e uno giallo alternati
523
+ msg = branch.start_with?(git_user) ? msg.on_blue : msg.on_black # i branch creati da chi lancia l'update sono su sfondo blu
524
+ menu.choice(msg) { branch }
525
+ end
526
+ end
527
+ else
528
+ chosen_branch = selection
529
+ end
530
+ # checkout master, checkout branch, pull branch, push sul branch con commit vuoto
531
+ `git checkout master && git checkout #{chosen_branch} && git pull`
532
+ `git commit --allow-empty -m 'shutdown' && git push && git checkout master`
533
+ end
545
534
 
546
- git_checkout_version('prima', revision)
535
+ def qainit_drone_shutdown!
536
+ output "Recupero le informazioni sui QA attivi..."
537
+ stack_list, envs = get_stacks
547
538
 
548
- Dir.chdir 'projects/prima'
539
+ env_hash = "qa-" + get_deploy_id
549
540
 
550
- ['vendor'].each do |dir|
551
- unless File.directory?(dir)
552
- if File.directory?("../../../prima/#{dir}")
553
- exec_step "rsync -a ../../../prima/#{dir} ."
541
+ cluster_stack_name = nil
542
+ stacks_to_delete = []
543
+ stack_list.each do |stack|
544
+ if stack.stack_name.match(/#{env_hash}$/)
545
+ if stack.stack_name.match(/ecs-cluster/)
546
+ cluster_stack_name = stack.stack_name
547
+ else
548
+ break unless stack.stack_name.match(/#{env_hash}$/)
549
+ stacks_to_delete.push(stack.stack_name)
550
+ delete_stack(stack.stack_name)
554
551
  end
555
552
  end
556
553
  end
557
554
 
558
- stack_name_backoffice = "ecs-task-backoffice-qa-notneeded"
559
- backoffice_qa_host = get_route53_hostname(stack_name_backoffice)
555
+ cluster_stack_name = "ecs-cluster-#{env_hash}"
556
+ if stack_exists?(cluster_stack_name)
557
+ aggregator_enabled = get_stack_tags(cluster_stack_name).detect do |tag|
558
+ tag.key === "hostname_pattern_priority" and tag.value === "1"
559
+ end.is_a?(Aws::CloudFormation::Types::Tag)
560
560
 
561
- [
562
- "bin/local_build_artifact.sh #{branch_name}"
563
- ].each do |cmd|
564
- output "Eseguo #{cmd}".yellow
565
- res = %x[ #{cmd} ]
566
- if $?.exitstatus != 0
567
- color = 'red'
568
- else
569
- color = 'green'
561
+ if aggregator_enabled
562
+ dns_to_staging(env_hash)
570
563
  end
571
- output res.send color
572
- exec_step "docker stop redis" if color == 'red'
573
- stop_if (color == 'red'), "Errore durante la build dell'artifact".red
574
564
  end
575
565
 
576
- Dir.chdir "../../"
577
- end
566
+ # Se non ha finito di cancellare le altre non si puo' cancellare il cluster
567
+ output "Attendo 10 secondi per poter eliminare il cluster ECS"
578
568
 
579
- def git_checkout_version(project, revision)
580
- Dir.chdir "projects/#{project}"
581
- exec_step "git checkout -- . && git clean -f -d && git checkout #{revision}"
582
- Dir.chdir "../../"
569
+ while stacks_to_delete.length > 0
570
+ sleep 13
571
+ stacks_to_delete.each do |stack_name|
572
+ stacks_to_delete = stacks_to_delete - [stack_name] unless stack_exists?(stack_name)
573
+ end
574
+ output "Stack ancora attivi: #{stacks_to_delete.length.to_s}. Attendo altri 10 secondi per eliminare il cluster ECS"
575
+ end
576
+
577
+ delete_stack(cluster_stack_name) if stack_exists?(cluster_stack_name)
578
+ delete_stack(@base_stack_name_alb + env_hash[3..8]) if stack_exists?(@base_stack_name_alb + env_hash[3..8])
579
+ delete_stack(@base_stack_name_alb_ws + env_hash[3..8]) if stack_exists?(@base_stack_name_alb_ws + env_hash[3..8])
580
+ `git checkout master && git push origin --delete ${DRONE_BRANCH}`
581
+ output "Cancello il record DNS utilizzato da Lighthouse"
582
+ delete_lighthouse_dns()
583
+ output "Finito!".green
583
584
  end
584
585
 
585
- def upload_artifact(source_path, destination_path)
586
- output "Upload dell'artifact in corso (#{(File.size(source_path).to_f / 2**20).round(2)} MiB)\n".yellow
587
- s3 = Aws::S3::Resource.new
588
- obj = s3.bucket(@s3_bucket).object(destination_path)
589
- obj.upload_file(source_path)
586
+ def qainit_write_output(file_message, output_message)
587
+ `mkdir -p /etc/qainit-output`
588
+ qa_file_name = "/etc/qainit-output/url_qa"
589
+ File.open(qa_file_name + '.txt', 'w') { |file| file.write(file_message) }
590
+ output "#{output_message} #{qa_file_name}".green
591
+ end
590
592
 
591
- output "#{@s3_bucket}/#{destination_path} uploadato con successo!\n".green
593
+ def update_drone_yml!()
594
+ drone_yml = File.read('.drone.yml')
595
+ @projects.each do |key, project|
596
+ drone_yml = drone_yml.gsub(/#{key}@.+\n/, "#{key}@#{project['revision']}\n")
597
+ end
598
+ File.open(".drone.yml", "w") do |f|
599
+ f.write(drone_yml)
600
+ end
592
601
  end
593
602
 
594
- def wait_for_stack_ready(stack_name)
595
- ready = false
596
- sleep_seconds = 10
597
- output "Attendo che lo stack #{stack_name} finisca di essere inizializzato...\n".yellow
598
- while !ready
599
- ready = true if stack_ready?(stack_name)
600
- seconds_elapsed = 0
601
- while true
602
- break if seconds_elapsed >= sleep_seconds
603
- print '.'.yellow; STDOUT.flush
604
- sleep 1
605
- seconds_elapsed += 1
606
- end
603
+ def get_deploy_id
604
+ if @deploy_id
605
+ @deploy_id
606
+ else
607
+ @deploy_id = Digest::MD5.hexdigest(ENV['DRONE_BRANCH'])
608
+ @deploy_id
607
609
  end
610
+ end
608
611
 
609
- output "\nStack #{stack_name} pronto!\n".green
610
- end
611
-
612
- def stack_list
613
- resp = @cf.describe_stacks
614
- stacks = resp.stacks
615
- stacks.keep_if { |stack| stack.stack_name.include? '-qa-' }
616
- stacks
617
- end
618
-
619
- def delete_stack(stack_name)
620
- @cf.delete_stack({stack_name: stack_name})
621
- output "Stack #{stack_name} spenta con successo\n".green
622
- end
623
-
624
- def stack_ready?(stack_name)
625
- resp = @cf.describe_stacks({
626
- stack_name: stack_name
627
- })
628
- ['CREATE_COMPLETE', 'UPDATE_COMPLETE'].include? resp.stacks[0].stack_status
629
- end
630
-
631
- def create_asg_stack(stack_name, tags = [])
632
- pp @ecs_cluster_name
633
-
634
- stack_body = IO.read('cloudformation/stacks/asg/ecs-asg-allinone.json')
635
- parameters = [
636
- {
637
- parameter_key: "Environment",
638
- parameter_value: "qa"
639
- },
640
- {
641
- parameter_key: "InstanceType",
642
- parameter_value: "t2.large"
643
- },
644
- {
645
- parameter_key: "ECSClusterName",
646
- parameter_value: @ecs_cluster_name
647
- }
648
- ]
649
- create_stack(stack_name, stack_body, parameters, tags)
650
- end
651
-
652
- def create_cluster_stack(stack_name, tags = [])
653
- stack_body = IO.read('cloudformation/stacks/ecs-cluster.json')
654
- create_stack(stack_name, stack_body, [], tags)
655
- end
656
-
657
- def import_dbs(ip_address)
658
- resp = @ecs.run_task({
659
- cluster: @ecs_cluster_name,
660
- task_definition: @import_db_task,
661
- overrides: {
662
- container_overrides: [
663
- {
664
- name: 'dbrestore',
665
- environment: [
666
- {
667
- name: 'EC2_IP_ADDRESS',
668
- value: ip_address,
669
- }
670
- ]
671
- }
672
- ]
673
- },
674
- count: 1
675
- })
676
- output "Attendo che i DB vengano importati...\n".yellow
677
- stopped_at = nil
678
- while stopped_at.nil?
679
- resp = @ecs.describe_tasks({
680
- cluster: @ecs_cluster_name,
681
- tasks: [resp.tasks[0].task_arn]
682
- })
683
- stopped_at = resp.tasks[0].stopped_at
684
- sleep_seconds = 10
685
- seconds_elapsed = 0
686
- while true && stopped_at.nil?
687
- break if seconds_elapsed >= sleep_seconds
688
- print '.'.yellow; STDOUT.flush
689
- sleep 1
690
- seconds_elapsed += 1
691
- end
612
+ def get_alb_host(stack_name)
613
+ case
614
+ when stack_name.include?('web')
615
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
616
+ when stack_name.include?('urania')
617
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
618
+ when stack_name.include?('backoffice')
619
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
620
+ when stack_name.include?('bburago')
621
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
622
+ when stack_name.include?('hal9000')
623
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
624
+ when stack_name.include?('fidaty')
625
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
626
+ when stack_name.include?('activia')
627
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
628
+ when stack_name.include?('skynet')
629
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
630
+ when stack_name.include?('roger')
631
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
632
+ when stack_name.include?('alb-http-public')
633
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
634
+ when stack_name.include?('alb-ws-public')
635
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
636
+ when stack_name.include?('peano')
637
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
638
+ when stack_name.include?('leftorium')
639
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
640
+ when stack_name.include?('assange')
641
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
642
+ when stack_name.include?('borat')
643
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
644
+ when stack_name.include?('crash')
645
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
646
+ when stack_name.include?('rachele')
647
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
648
+ when stack_name.include?('starsky')
649
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
650
+ when stack_name.include?('hutch')
651
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
652
+ when stack_name.include?('maia')
653
+ logical_resource_id = 'EcsApplicationLoadBalancerPublic'
654
+ when stack_name.include?('legion')
655
+ logical_resource_id = 'EcsApplicationLoadBalancerInternal'
692
656
  end
693
- print "\n"
657
+ resp = describe_stack_resource(stack_name, logical_resource_id)
658
+ resp = describe_load_balancers([resp.stack_resource_detail.physical_resource_id])
659
+ resp.load_balancers[0].dns_name
694
660
  end
695
661
 
696
- def stack_exists?(stack_name)
697
- begin
698
- res = @cf.describe_stacks({
699
- stack_name: stack_name
700
- })
701
- rescue Aws::CloudFormation::Errors::ValidationError => e
702
- if e.message.include? 'does not exist'
703
- false
704
- else
705
- raise e
706
- end
662
+ def deploy_pyxis?
663
+ if defined? @deploy_pyxis
664
+ @deploy_pyxis
707
665
  else
708
- true
709
- end
710
- end
711
-
712
- def create_stack(stack_name, stack_body, parameters = [], tags = [])
713
- @cf.create_stack({
714
- stack_name: stack_name,
715
- template_body: stack_body,
716
- parameters: parameters,
717
- tags: tags,
718
- capabilities: ["CAPABILITY_IAM"],
719
- on_failure: "ROLLBACK"
720
- })
721
- output "La creazione dello stack #{stack_name} è stata avviata".green
722
- end
723
-
724
- def update_stack(stack_name, stack_body, parameters = [])
725
- begin
726
- @cf.update_stack({
727
- stack_name: stack_name,
728
- template_body: stack_body,
729
- parameters: parameters,
730
- capabilities: ["CAPABILITY_IAM"]
731
- })
732
- rescue Aws::CloudFormation::Errors::ValidationError => e
733
- # if e.message.include? 'does not exist'
734
- # false
735
- # else
736
- # raise e
737
- # end
738
- raise e
739
- else
740
- output "L'update dello stack #{stack_name} è stato avviato".green
666
+ pyxis_updated = `git log -p -1 --unified=0 | grep pyxis-npm:`.length > 0
667
+
668
+ update_pyxis = !@projects['pyxis-npm'].empty? && @projects['pyxis-npm']['name'] != 'master' && pyxis_updated
669
+
670
+ @deploy_pyxis = update_pyxis
671
+ return update_pyxis
741
672
  end
742
673
  end
743
674
 
744
- def artifact_exists?(bucket, path)
745
- resp = @s3.list_objects({
746
- bucket: bucket,
747
- max_keys: 1,
748
- prefix: path
749
- })
750
- !resp.contents.empty?
675
+ def update_cluster_stack(stack_name, tags = [])
676
+ stack_body = IO.read('cloudformation/stacks/ecs-cluster.yml')
677
+ update_stack(stack_name, stack_body, [], tags)
751
678
  end
752
679
 
753
- def choose_branch_to_deploy(project_name)
680
+ def choose_branch_to_deploy(project_name, select_master = false)
754
681
  Dir.chdir "projects/#{project_name}"
755
682
  output "Recupero la lista dei branch del progetto #{project_name}..."
683
+ `git remote prune origin`
756
684
  out = %x[ git fetch ]
757
- branches = %x[ git for-each-ref --sort=-committerdate refs/remotes/ --format='%(refname) %(objectname)' | sed 's/refs\\/remotes\\/origin\\///g' ]
758
- .split("\n").delete_if { |b| b.include?('HEAD') || b.include?('dev') }[0..49]
685
+ branches = %x[ git for-each-ref --sort=-committerdate refs/remotes/ --format='%(refname) %(objectname) %(committeremail)' | sed 's/refs\\/remotes\\/origin\\///g' ]
686
+ .split("\n").delete_if { |b| b.include?('HEAD') }[0..49]
759
687
 
760
- branch_name = choose do |menu|
761
- menu.prompt = "Scegli il branch di #{project_name} da deployare: ".cyan
762
- menu.shell = true
688
+ master_branch = nil
763
689
 
764
- branches.each do |branch|
690
+ branches.each do |branch|
691
+ master_branch = branch if branch.match(/^master\s+/)
692
+ break unless master_branch.nil?
693
+ end
765
694
 
766
- title = @prima.reduce_size(branch, 100)
767
- msg = "#{title}".light_blue
768
- menu.choice(msg) { branch }
695
+ if select_master || branches.length == 1
696
+ branch_name = master_branch
697
+ else
698
+ branches.insert(0, branches.delete(master_branch))
699
+ branch_name = choose do |menu|
700
+ menu.prompt = "Scegli il branch di #{project_name} da deployare: ".cyan
701
+ menu.shell = true
702
+
703
+ git_mail = get_git_mail
704
+
705
+ branches.each_with_index do |branch, index|
706
+ title = @prima.reduce_size(branch, 100)
707
+ msg = index.odd? ? title.white : title.light_yellow # uno bianco e uno giallo alternati
708
+ msg = branch.include?(git_mail) ? msg.on_blue : msg.on_black # i branch aggiornati da chi lancia la creazione sono su sfondo blu
709
+ menu.choice(msg) { branch }
710
+ menu.default = branch if branch == master_branch
711
+ end
769
712
  end
770
713
  end
771
714
 
772
715
  Dir.chdir "../../"
773
716
 
774
- name = branch_name.split(' ').first
775
- revision = branch_name.split(' ').last
776
- { name: name, revision: revision[0..14] }
717
+ name = branch_name.split(' ')[0]
718
+ revision = branch_name.split(' ')[1]
719
+ committer_email = branch_name.split(' ')[2].tr('<>', '')
720
+ { 'name' => name, 'revision' => revision[0..14], 'committer' => committer_email, 'default_branch' => select_master }
777
721
  end
778
722
 
723
+ def select_branch_to_deploy(project_name, branch_name)
724
+ Dir.chdir "projects/#{project_name}"
725
+ output "Recupero il branch #{project_name}:#{branch_name} ..."
726
+ `git remote prune origin`
727
+ out = %x[ git fetch ]
728
+ branch_name = %x[ git for-each-ref --sort=-committerdate refs/remotes/ --format='%(refname) %(objectname) %(committeremail)' | sed 's/refs\\/remotes\\/origin\\///g' ]
729
+ .split("\n").delete_if { |b| !b.match("^#{Regexp.escape(branch_name)}") }[0..49]
730
+ .first
731
+
732
+ Dir.chdir "../../"
733
+ name = branch_name.split(' ')[0]
734
+ revision = branch_name.split(' ')[1]
735
+ committer_email = branch_name.split(' ')[2].tr('<>', '')
736
+ { 'name' => name, 'revision' => revision[0..14], 'committer' => committer_email }
737
+ end
738
+
739
+ def get_stacks()
740
+ envs = {}
741
+ stack_list = stack_list()
742
+ stack_list.each do |stack|
743
+ unless stack.stack_name.match(/spotfleet-allinone-qa-(\w+)$/)
744
+ env_hash = stack.stack_name.match(/qa-(\w+)$/)[0]
745
+ envs[env_hash] = stack.tags unless envs.has_key?(env_hash) || stack.tags.empty?
746
+ end
747
+ end
748
+ return stack_list, envs
749
+ end
750
+
751
+ def get_clusters()
752
+ envs = {}
753
+ cluster_list = cluster_list()
754
+ cluster_list.each do |stack|
755
+ unless stack.stack_name.match(/spotfleet-allinone-qa-(\w+)$/)
756
+ env_hash = stack.stack_name.match(/qa-(\w+)$/)[0]
757
+ envs[env_hash] = stack.tags unless envs.has_key?(env_hash) || stack.tags.empty?
758
+ end
759
+ end
760
+ return cluster_list, envs
761
+ end
762
+
763
+ def hostname_pattern_priority()
764
+ (Time.now.to_i.to_s[-4..-1].to_i + Random.rand(40000)).to_s
765
+ end
766
+
767
+ def select_branches(project_names = nil)
768
+ output "Deploy feature menu"
769
+ if project_names.nil?
770
+ @projects.each{ |key, value| @projects[key] = choose_branch_to_deploy(key) }
771
+ else
772
+ project_names.each do |project|
773
+ @projects[project] = choose_branch_to_deploy(project)
774
+ end
775
+ @projects.each_key do |branch_project|
776
+ @projects[branch_project] = choose_branch_to_deploy(branch_project, true) unless project_names.include? branch_project
777
+ end
778
+ end
779
+ end
779
780
  end
780
781
 
781
782
  def help_content
@@ -792,14 +793,24 @@ Synopsis
792
793
  twig release start
793
794
  twig release finish
794
795
  twig release deploy
796
+ twig release aggregator
795
797
 
796
798
  Description
797
799
  -----------
798
800
 
799
- start creates a new feature branch
800
- finish finishes the feature by merging to dev and master
801
- deploy deploys the feature branch to a temporary AWS Elastic Beanstalk env
802
- deploy stop destroys the AWS Elastic Beanstalk env
801
+ start creates a new feature branch
802
+ finish finishes the feature by merging to dev and master
803
+ qainit deploys a new environment with selected branches from every project
804
+ qainit $PROJECT_NAME deploys a new environment allowing to selected a branch from the input project (everything else is master)
805
+ qainit shutdown deletes a specific qa environment
806
+
807
+ Available only to devops (from artemide)
808
+ -----------
809
+ deploy deploys the feature branch to a temporary AWS Elastic Beanstalk env
810
+ deploy stop destroys the AWS Elastic Beanstalk env
811
+ deploy update updates a feature branch with current branches
812
+ deploy lock protects a qa environment from automatic deletion
813
+ aggregator enable/disable directs comparator's staging environments to a qa/staging
803
814
 
804
815
  Subcommand for Twig: <http://rondevera.github.io/twig/>
805
816
  Author: Andrea Usuelli <https://github.com/andreausu>
@@ -814,4 +825,11 @@ if args.include?('--help')
814
825
  exit
815
826
  end
816
827
 
817
- Release.new.execute!(args)
828
+ gem_update = true
829
+ if args.include?('no-gem-update')
830
+ gem_update = false
831
+ end
832
+
833
+ args.delete('no-gem-update')
834
+
835
+ Release.new(gem_update).execute!(args)