prima-twig 0.2.6 → 0.2.8

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
  SHA1:
3
- metadata.gz: c7b49a95c43b880947a37b296a3ff8b6be29047e
4
- data.tar.gz: 76da46ef24f1ff4ef4e32fb438346b61d26054c7
3
+ metadata.gz: 7988c66d94da4a89f9b0f4e355f839377e399932
4
+ data.tar.gz: 1eac804cf0d0a260823c0e5188b14c69c311e30d
5
5
  SHA512:
6
- metadata.gz: 2abbb30d0b36d3b6347b815850ac3cb8da00217558320d9d391621e9d9beaca68edcd9525dbcdcdf4540bebb454810071d2259560a1253f105fc2d8c4042229a
7
- data.tar.gz: f4d092aca806c4eb20363fa77358aba72be4df27e62be51a7f48a45211826d418d929c2d10777d096fdb700e3f3e6f750c00b8a8e91a54d0e3f45e18e1c9aae6
6
+ metadata.gz: f30302ca0f5c462314f1feec9a5da6993034dfa389fcb05da3ab0df515a11a14fd4aee098e8dc3a6b612b263f95e225e567d4be587abef4055fbf1eca02f3a7a
7
+ data.tar.gz: ed5e356f70c54777163ca6f92295b33ea82597a2f3b710d8e23a3886612d441bde842232808d2ea87c60b75ff5f7960d9a2c29b46cc682953da00d414a6de219
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require_relative '../lib/prima_twig.rb'
5
+ require 'colorize'
6
+ require 'highline/import'
7
+ require 'aws-sdk'
8
+ require 'redcarpet'
9
+ require 'mail'
10
+ require 'erb'
11
+
12
+ def help_content
13
+ <<-HELP
14
+
15
+ twig-deploy
16
+ ===========
17
+
18
+ Updates master and push to origin
19
+
20
+ Synopsis
21
+ --------
22
+
23
+ twig deploy
24
+
25
+ Description
26
+ -----------
27
+
28
+ Merges dev in master and push dev and master to origin, than returns to the actual branch
29
+
30
+ Subcommand for Twig: <http://rondevera.github.io/twig/>
31
+ Author: Andrea Usuelli <https://github.com/andreausu>
32
+
33
+ HELP
34
+ end
35
+
36
+ args = ARGV.dup
37
+
38
+ if args.include?('--help')
39
+ puts help_content
40
+ exit
41
+ end
42
+
43
+ class Review
44
+ include Command
45
+
46
+ def initialize
47
+ @prima = Prima.new
48
+ end
49
+
50
+ def execute!
51
+ output "Recupero degli artifacts in corso, attendi qualche secondo...".yellow
52
+ artifacts = get_artifacts
53
+
54
+ artifact = choose do |menu|
55
+ menu.prompt = 'Scegli la release da deployare: '.cyan
56
+ menu.shell = true
57
+
58
+ artifacts.each do |k, v|
59
+ branch = k
60
+ title = @prima.reduce_size(branch, 100).light_blue
61
+ msg = "#{title}"
62
+ menu.choice(msg) {k}
63
+ end
64
+ end
65
+
66
+ deploy_command = "bin/deploy #{artifacts[artifact]}"
67
+
68
+ output "Il comando per il deploy sara': #{deploy_command}".yellow
69
+
70
+ exec_step deploy_command if @prima.yesno "Sei sicuro di voler effettuare il deploy in produzione?".blue
71
+
72
+ user = `git config user.name`
73
+
74
+ mail = Mail.new do
75
+ from 'developers@prima.it'
76
+ to 'developers@prima.it'
77
+ subject "#{user} ha effettuato il deploy della release #{artifact}"
78
+ end
79
+
80
+ body = "# Deploy in produzione avvenuto con successo!\n\n"
81
+ body << "### Data: #{Time.now.strftime('%d/%m/%Y %H:%M:%S')}\n"
82
+ body << "### Utente: #{user}\n"
83
+ body << "### Release: [#{artifact}](https://github.com/primait/prima/releases/tag/#{ERB::Util.url_encode(artifact)})\n"
84
+
85
+ htmlBody = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new).render body
86
+
87
+ html_part = Mail::Part.new do
88
+ content_type 'text/html; charset=UTF-8'
89
+ body htmlBody
90
+ end
91
+ text_part = Mail::Part.new do
92
+ body htmlBody.gsub(/<br\s?\/?>/, "\r\n").gsub(/<\/?[^>]*>/, '')
93
+ end
94
+
95
+ mail.html_part = html_part
96
+ mail.text_part = text_part
97
+
98
+ opts = {address: 'smtp.mandrillapp.com', port: '587'}
99
+ opts[:user_name] = 'developers@prima.it'
100
+ opts[:password] = @prima.config['mandrill']
101
+
102
+ mail.delivery_method(:smtp, opts)
103
+ mail.deliver
104
+
105
+ end
106
+
107
+ def get_artifacts
108
+ rev_already_downloaded = []
109
+ artifacts = {}
110
+ s3 = Aws::S3::Client.new
111
+ resp = s3.list_objects(bucket: 'prima-deploy', prefix: 'artifacts')
112
+ resp.contents.each do |l|
113
+ rev = l.key.match(/_(\w{15}).zip$/).captures.first if l.key.match(/_(\w{15}).zip$/)
114
+ if rev && l.key.include?('prod_') && !rev_already_downloaded.include?(rev)
115
+ rev_already_downloaded << rev
116
+ object = s3.head_object(bucket: 'prima-deploy', key: l.key)
117
+ artifacts[object.metadata['branch']] = rev if object.metadata.has_key? 'branch'
118
+ end
119
+ end
120
+ artifacts
121
+ end
122
+
123
+ end
124
+
125
+ Review.new.execute!
@@ -0,0 +1,403 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require_relative '../lib/prima_twig.rb'
5
+ require 'launchy'
6
+
7
+ class Release
8
+ include Command
9
+
10
+ def initialize
11
+ @prima = Prima.new
12
+ @eb = Aws::ElasticBeanstalk::Client.new
13
+ @ec2 = Aws::EC2::Client.new
14
+ @s3_bucket = 'elasticbeanstalk-eu-west-1-001575623345'
15
+ @current_branch_name = @prima.twig.current_branch_name
16
+ @s3_key = @current_branch_name.gsub('/', '-') + '.zip'
17
+ @application_name = 'prima-qa'
18
+ @environment_name = sanitize_environment_name(@s3_key.gsub('.zip', ''))
19
+ @git_rev = `git rev-parse HEAD`
20
+ @version_label = @environment_name + '-' + @git_rev[0,5]
21
+ @user = `git config user.name`.downcase
22
+ @user = @user[0,1] + @user.split(' ').last
23
+ end
24
+
25
+ def execute! args
26
+ possible_args = ["start", "finish", "deploy"]
27
+ stop_if args.empty?, [:wrong_args, possible_args]
28
+ stop_if args.length > 2, [:wrong_args, possible_args]
29
+
30
+ stop_if @prima.head_detached?, :detached_head
31
+
32
+ case args[0]
33
+ when "start"
34
+ start_feature!
35
+ when "finish"
36
+ finish_feature!
37
+ when "deploy"
38
+ if ['terminate', 'stop', 'shutdown', 'halt', 'destroy'].include? args[1]
39
+ deploy_shutdown!
40
+ else
41
+ deploy_feature!
42
+ end
43
+ else
44
+ stop_if true, [:wrong_args, possible_args]
45
+ end
46
+ end
47
+
48
+ def start_feature!
49
+ end
50
+
51
+ def finish_feature!
52
+ end
53
+
54
+ def deploy_feature!
55
+ app_name = 'prima-qa'
56
+
57
+ ssh_key_path = "~/.ssh/eb_#{@user}"
58
+ ec2_key_name = "eb_#{@user}"
59
+ artifact_path = '/tmp/prima-artifact.zip'
60
+
61
+ stop_if application_version_exists?(@application_name, @version_label), "La versione #{@version_label} esiste gia', ti sei ricordato di committare?".red
62
+
63
+ manage_ec2_keypair(ec2_key_name, ssh_key_path)
64
+
65
+ build_release!
66
+
67
+ exec_step 'rsync -avd --exclude-from app/deploy/aws_docker/qa/.rsync-exclude-qa . /tmp/prima'
68
+ exec_step 'cd /tmp/prima && cp app/deploy/aws_docker/qa/Dockerrun.aws.json .'
69
+ exec_step "rm -f #{artifact_path}; cd /tmp/prima && zip -ryq #{artifact_path} ."
70
+ output "Upload dell'artifact in corso (#{(File.size(artifact_path).to_f / 2**20).round(2)} MiB)\n".yellow
71
+ s3 = Aws::S3::Resource.new
72
+ obj = s3.bucket(@s3_bucket).object(@s3_key)
73
+ obj.upload_file(artifact_path)
74
+
75
+ output "#{@s3_bucket}/#{@s3_key} uploadato con successo!\n".green
76
+
77
+ resp = @eb.create_application_version({
78
+ application_name: @application_name,
79
+ version_label: @version_label,
80
+ description: @current_branch_name,
81
+ source_bundle: {
82
+ s3_bucket: @s3_bucket,
83
+ s3_key: @s3_key,
84
+ },
85
+ auto_create_application: false,
86
+ })
87
+
88
+ output "Application version #{@version_label} creata con successo!\n".green
89
+
90
+ if environment_exists?(@application_name, @environment_name)
91
+ is_eb_ready = is_eb_ready?(@application_name, @environment_name)
92
+ wait_for_eb_ready(@application_name, @environment_name) unless is_eb_ready
93
+ @eb.update_application_version({
94
+ application_name: @application_name,
95
+ version_label: @version_label
96
+ })
97
+ run_commands(@environment_name, ssh_key_path)
98
+ else
99
+ output "Environment #{@environment_name} non presente, inizio la creazione...\n".yellow
100
+ create_eb_environment(@application_name, @environment_name, @version_label, @git_rev, ec2_key_name)
101
+ output "Environment #{@environment_name} creato!\n".green
102
+ is_eb_ready = is_eb_ready?(@application_name, @environment_name)
103
+ wait_for_eb_ready(@application_name, @environment_name) unless is_eb_ready
104
+ run_commands(@environment_name, ssh_key_path)
105
+ end
106
+
107
+ endpoint_url = get_eb_endpoint_url(@application_name, @environment_name)
108
+ output "Endpoint url: #{endpoint_url}\n".cyan
109
+ Launchy.open(endpoint_url) if @prima.yesno 'Vuoi aprirlo nel browser?'.blue
110
+ output "Deploy effettuato, everything is awesome!\n".green
111
+ end
112
+
113
+ def deploy_shutdown!
114
+ stop_unless environment_exists?(@application_name, @environment_name), "L'environment #{@environment_name} non esiste!"
115
+ shutdown_environment(@environment_name) if @prima.yesno("Sei sicuro di voler spegnere l'env?".blue)
116
+ output "L'environment #{@environment_name} e' stato disrutto con successo!\n".green
117
+ output "Potrebbe comunque passare qualche minuto prima che l'operazione finisca\n".yellow
118
+ end
119
+
120
+ def build_release!
121
+ output "Preparo l'artifact .zip\n".yellow
122
+
123
+ base_cmd = 'docker exec -it prima_'
124
+ [
125
+ "docker run -v $PWD:/usr/app/src -w /usr/app/src blinkmobile/bower install --allow-root",
126
+ "#{base_cmd}web_1 composer install",
127
+ "#{base_cmd}php_1 ./app/console -e=prod assets:install web",
128
+ "#{base_cmd}php_1 ./app/console -e=prod fos:js-routing:dump",
129
+ "#{base_cmd}php_1 ./app/console -e=prod cypress:ng-routing:dump",
130
+ "#{base_cmd}php_1 ./app/console -e=prod bazinga:js-translation:dump web",
131
+ "#{base_cmd}php_1 ./node_modules/.bin/brunch build --production",
132
+ "#{base_cmd}web_1 composer dump-autoload --optimize --no-dev",
133
+ "#{base_cmd}compass_1 compass compile --force -c compass/config_prod.rb compass/"
134
+ ].each do |cmd|
135
+ output "Eseguo #{cmd}".yellow
136
+ res = %x[ #{cmd} ]
137
+ if $?.exitstatus != 0
138
+ color = 'red'
139
+ else
140
+ color = 'green'
141
+ end
142
+ output res.send color
143
+ stop_if (color == 'red'), "Errore durante la build dell'artifact".red
144
+ end
145
+ end
146
+
147
+ def environment_exists?(application_name, environment_name)
148
+ resp = @eb.describe_environments({
149
+ application_name: application_name,
150
+ environment_names: [environment_name],
151
+ include_deleted: false
152
+ })
153
+ !resp.environments[0].nil?
154
+ end
155
+
156
+ def shutdown_environment(environment_name)
157
+ @eb.terminate_environment({
158
+ environment_name: environment_name,
159
+ terminate_resources: true
160
+ })
161
+ end
162
+
163
+ def manage_ec2_keypair(ec2_key_name, path)
164
+ path = File.expand_path(path)
165
+ return if File.exist?(path)
166
+ stop_unless @prima.yesno("Sei sicuro di voler creare la chiave SSH in #{path}?".blue), "Non puoi continuare senza chiave SSH".red
167
+ %x[ ssh-keygen -b 2048 -t rsa -f #{path} -q -N '' ]
168
+ upload_ssh_public_key(ec2_key_name, path + '.pub')
169
+ output "Chiave SSH creata e uploadata con successo!\n".green
170
+ end
171
+
172
+ def upload_ssh_public_key(ec2_key_name, path)
173
+ @ec2.import_key_pair({
174
+ dry_run: false,
175
+ key_name: ec2_key_name,
176
+ public_key_material: IO.read(path)
177
+ })
178
+ end
179
+
180
+ def create_eb_environment(application_name, environment_name, version_label, git_rev, ec2_key_name)
181
+ resp = @eb.create_environment({
182
+ application_name: application_name,
183
+ environment_name: environment_name,
184
+ version_label: version_label,
185
+ solution_stack_name: "64bit Amazon Linux 2015.09 v2.0.4 running Multi-container Docker 1.7.1 (Generic)",
186
+ option_settings: [
187
+ {
188
+ namespace: "aws:autoscaling:launchconfiguration",
189
+ option_name: "IamInstanceProfile",
190
+ value: "prima-qa",
191
+ },
192
+ {
193
+ namespace: "aws:autoscaling:launchconfiguration",
194
+ option_name: "EC2KeyName",
195
+ value: ec2_key_name,
196
+ },
197
+ {
198
+ namespace: "aws:autoscaling:launchconfiguration",
199
+ option_name: "InstanceType",
200
+ value: "t2.medium",
201
+ },
202
+ {
203
+ namespace: "aws:autoscaling:asg",
204
+ option_name: "MaxSize",
205
+ value: "1",
206
+ },
207
+ {
208
+ namespace: "aws:autoscaling:asg",
209
+ option_name: "MinSize",
210
+ value: "1",
211
+ },
212
+ {
213
+ namespace: "aws:cloudformation:template:parameter",
214
+ option_name: "EnvironmentVariables",
215
+ value: "SYMFONY__PRIMA__GIT__REVISION=#{git_rev},PRIMA_ENV_NAME=web-qa,PARAMETERS_FILE=prima-deploy/parameters_qa.yml",
216
+ },
217
+ {
218
+ namespace: "aws:elasticbeanstalk:application:environment",
219
+ option_name: "PARAMETERS_FILE",
220
+ value: "prima-deploy/parameters_qa.yml",
221
+ },
222
+ {
223
+ namespace: "aws:elasticbeanstalk:application:environment",
224
+ option_name: "PRIMA_ENV_NAME",
225
+ value: "web-qa",
226
+ },
227
+ {
228
+ namespace: "aws:elasticbeanstalk:application:environment",
229
+ option_name: "SYMFONY__PRIMA__GIT__REVISION",
230
+ value: git_rev,
231
+ }
232
+ ],
233
+ tags: [
234
+ {
235
+ key: "user",
236
+ value: @user
237
+ }
238
+ ]
239
+ })
240
+ end
241
+
242
+ def is_eb_ready?(application_name, environment_name)
243
+ resp = @eb.describe_environments({
244
+ application_name: application_name,
245
+ environment_names: [environment_name],
246
+ include_deleted: false
247
+ })
248
+ resp.environments[0].status != 'Launching'
249
+ end
250
+
251
+ def get_eb_endpoint_url(application_name, environment_name)
252
+ resp = @eb.describe_environments({
253
+ application_name: application_name,
254
+ environment_names: [environment_name],
255
+ include_deleted: false
256
+ })
257
+ "http://#{resp.environments[0].endpoint_url}"
258
+ end
259
+
260
+ def get_eb_events(application_name, environment_name, start_time=nil, end_time=nil)
261
+ start_time ||= Time.utc(1980,"jan",1,0,0,0)
262
+ end_time ||= Time.now + 1
263
+ resp = @eb.describe_events({
264
+ application_name: application_name,
265
+ environment_name: environment_name,
266
+ start_time: start_time,
267
+ end_time: end_time
268
+ })
269
+ resp.events.reverse
270
+ end
271
+
272
+ def wait_for_eb_ready(application_name, environment_name)
273
+ ready = false
274
+ start_time = Time.now - 60
275
+ output "Attendo che l'environment finisca di essere inizializzato...\n".yellow
276
+ while !ready
277
+ print '...'.yellow; STDOUT.flush
278
+
279
+ events = get_eb_events(application_name, environment_name, start_time)
280
+ start_time = Time.now
281
+
282
+ print "\n" if events.length > 0
283
+ STDOUT.flush
284
+
285
+ events.each do |event|
286
+ if ["WARN", "ERROR", "FATAL"].include? event.severity
287
+ color = 'red'
288
+ else
289
+ color = 'cyan'
290
+ end
291
+ output "#{event.event_date} - #{event.severity} #{event.message}".send color
292
+ end
293
+
294
+ ready = true if is_eb_ready?(application_name, environment_name)
295
+ sleep 10 unless ready
296
+ end
297
+
298
+ output "Environment inizializzato!\n".green
299
+ end
300
+
301
+ def run_commands(environment_name, ssh_key_path)
302
+ instance_id = @eb.describe_environment_resources({
303
+ environment_name: environment_name,
304
+ }).environment_resources.instances[0].id
305
+
306
+ resp = @ec2.describe_instances({instance_ids: [instance_id]})
307
+
308
+ public_ip_address = resp.reservations[0].instances[0].public_ip_address
309
+
310
+ output "L'IP pubblico della macchina e': #{public_ip_address}\n".cyan
311
+
312
+ base_cmd = "ssh -q -tt -o StrictHostKeyChecking=no -i #{ssh_key_path} ec2-user@#{public_ip_address}"
313
+ cmd = "#{base_cmd} sudo -i docker ps -a --filter='name=php' | awk '{print $1 }' | grep -v CONTAINER"
314
+ container_id = %x[ #{cmd} | grep -v 'Warning:' ].chomp
315
+
316
+ base_docker_cmd = "sudo -i docker exec #{container_id}"
317
+
318
+ [
319
+ "#{base_cmd} #{base_docker_cmd} ./app/console doctrine:database:drop --no-interaction --force",
320
+ "#{base_cmd} #{base_docker_cmd} ./app/console doctrine:database:create --no-interaction",
321
+ "#{base_cmd} #{base_docker_cmd} ./app/console doctrine:database:drop --no-interaction --connection=msa --force; true",
322
+ "#{base_cmd} #{base_docker_cmd} ./app/console doctrine:database:create --no-interaction --connection=msa",
323
+ "#{base_cmd} #{base_docker_cmd} ./app/console doctrine:schema:create --no-interaction",
324
+ "#{base_cmd} #{base_docker_cmd} ./app/console doctrine:fixtures:load --no-interaction --fixtures=src/Prima/DataFixtures/"
325
+ ].each do |cmd|
326
+ output "Eseguo #{cmd}".yellow
327
+ res = %x[ #{cmd} ]
328
+ if $?.exitstatus != 0
329
+ color = 'red'
330
+ else
331
+ color = 'green'
332
+ end
333
+ output res.send color
334
+ end
335
+ end
336
+
337
+ def application_version_exists?(application_name, version_label)
338
+ resp = @eb.describe_application_versions({
339
+ application_name: application_name,
340
+ version_labels: [ version_label ]
341
+ })
342
+ !resp.application_versions[0].nil?
343
+ end
344
+
345
+ def sanitize_environment_name(environment_name)
346
+ environment_name.gsub!(/([^\w]|_)/, '-')
347
+ if environment_name.length > 23
348
+ if environment_name.start_with?('feature')
349
+ environment_name = environment_name[8,23]
350
+ elsif environment_name.start_with?('hotfix')
351
+ environment_name = environment_name[7,23]
352
+ else
353
+ environment_name = environment_name[0,23]
354
+ end
355
+ end
356
+ if environment_name[0] == '-'
357
+ environment_name = environment_name[1..-1]
358
+ end
359
+ if environment_name[-1] == '-'
360
+ environment_name = environment_name[0..-2]
361
+ end
362
+ environment_name
363
+ end
364
+
365
+ end
366
+
367
+ def help_content
368
+ <<-HELP
369
+
370
+ twig-feature
371
+ ===========
372
+
373
+ Manage feature branches
374
+
375
+ Synopsis
376
+ --------
377
+
378
+ twig release start
379
+ twig release finish
380
+ twig release deploy
381
+
382
+ Description
383
+ -----------
384
+
385
+ start creates a new feature branch
386
+ finish finishes the feature by merging to dev and master
387
+ deploy deploys the feature branch to a temporary AWS Elastic Beanstalk env
388
+ deploy stop destroys the AWS Elastic Beanstalk env
389
+
390
+ Subcommand for Twig: <http://rondevera.github.io/twig/>
391
+ Author: Andrea Usuelli <https://github.com/andreausu>
392
+
393
+ HELP
394
+ end
395
+
396
+ args = ARGV.dup
397
+
398
+ if args.include?('--help')
399
+ puts help_content
400
+ exit
401
+ end
402
+
403
+ Release.new.execute!(args)
@@ -31,8 +31,8 @@ class Hotfix
31
31
  def start_hotfix!
32
32
 
33
33
  branch_name = @prima.clean_branch_name(ask('Inserisci il nome del branch (puoi omettere hotfix/): '.cyan))
34
- stop_if branch_name.length, 'Devi inserire il nome del branch'
35
- branch_name.prepend issue_type + '/' unless branch_name.include? issue_type
34
+ stop_unless branch_name.length > 0, 'Devi inserire il nome del branch'
35
+ branch_name.prepend 'hotfix/' unless branch_name.include? 'hotfix'
36
36
 
37
37
  output "Il nome del branch sarà " + branch_name.yellow
38
38
 
@@ -61,7 +61,8 @@ class Hotfix
61
61
  exec_step 'git push origin dev' if @prima.yesno 'Vuoi effettuare il push di dev?'.blue
62
62
 
63
63
  # Chiude la issue
64
- @prima.close_issue(@prima.twig.get_branch_property(current_branch_name, 'issue'))
64
+ issue_number = @prima.twig.get_branch_property(current_branch_name, 'issue')
65
+ @prima.close_issue(issue_number) if issue_number
65
66
 
66
67
  # Rimuove il branch remoto
67
68
  exec_step "git push origin :#{current_branch_name}" if @prima.yesno "Vuoi eliminare il branch remoto #{current_branch_name}?".blue
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'redcarpet'
5
+ require 'mail'
6
+ require_relative '../lib/prima_twig.rb'
7
+
8
+ class Release
9
+ include Command
10
+
11
+ def initialize
12
+ @prima = Prima.new
13
+ end
14
+
15
+ def execute! args
16
+ possible_args = ["start", "finish"]
17
+ stop_if args.empty?, [:wrong_args, possible_args]
18
+ stop_if args.length > 1, [:wrong_args, possible_args]
19
+
20
+ stop_if @prima.head_detached?, :detached_head
21
+ stop_unless @prima.is_clean?, :clean
22
+
23
+ case args[0]
24
+ when "start"
25
+ start_release!
26
+ when "finish"
27
+ finish_release!
28
+ else
29
+ stop_if true, [:wrong_args, possible_args]
30
+ end
31
+ end
32
+
33
+ def start_release!
34
+
35
+ release_name = @prima.clean_branch_name(ask('Inserisci il nome della release (senza prefisso release/): '.cyan))
36
+
37
+ branch_name = "release/#{release_name}/#{Time.now.strftime('%Y%m%d')}"
38
+
39
+ output "Il nome del branch sarà #{branch_name.yellow}"
40
+
41
+ exec_step "git checkout dev"
42
+ exec_step "git pull origin dev"
43
+ exec_step "git checkout -b #{branch_name}"
44
+ exec_step "git push -u origin #{branch_name}"
45
+
46
+ pr = @prima.create_pull_request('master', branch_name, branch_name, '')
47
+ @prima.twig.set_branch_property(branch_name, 'pr', pr.number)
48
+ @prima.twig.set_branch_property(branch_name, 'diff-branch', 'dev')
49
+
50
+ commits = get_commits(pr.number)
51
+ issues = get_issues(pr.number)
52
+
53
+ issues.each do |issue|
54
+ @prima.delete_label_from_issue(issue.number, Prima::LABEL_NEXT_RELEASE)
55
+ @prima.update_issue_with_label(issue.number, Prima::LABEL_IN_STAGING)
56
+ end
57
+
58
+ pr_body = build_pr_body(issues, commits)
59
+ @prima.update_pr pr.number, {:body => pr_body}
60
+
61
+ mail = Mail.new do
62
+ from 'developers@prima.it'
63
+ to 'developers@prima.it'
64
+ subject "#{`git config user.name`} ha iniziato la creazione della release #{branch_name}"
65
+ end
66
+
67
+ htmlBody = build_pr_body(issues, commits, 'html')
68
+
69
+ html_part = Mail::Part.new do
70
+ content_type 'text/html; charset=UTF-8'
71
+ body htmlBody
72
+ end
73
+ text_part = Mail::Part.new do
74
+ body htmlBody.gsub(/<br\s?\/?>/, "\r\n").gsub(/<\/?[^>]*>/, '')
75
+ end
76
+
77
+ mail.html_part = html_part
78
+ mail.text_part = text_part
79
+
80
+ opts = {address: 'smtp.mandrillapp.com', port: '587'}
81
+ opts[:user_name] = 'developers@prima.it'
82
+ opts[:password] = @prima.config['mandrill']
83
+
84
+ mail.delivery_method(:smtp, opts)
85
+ mail.deliver
86
+ end
87
+
88
+ def finish_release!
89
+ current_branch_name = @prima.twig.current_branch_name
90
+ stop_unless (current_branch_name =~ /^release\//), "Non sei su un branch di release, non posso mergiare nulla"
91
+
92
+ # Mergia la PR
93
+ pr = @prima.get_pr
94
+ stop_unless pr, 'Pull Request not found'
95
+ @prima.merge_pull_request pr
96
+
97
+ output "La Pull Request e' stata mergiata!".green
98
+
99
+ # Mergia il branch su dev e pusha
100
+ exec_step 'git fetch'
101
+ exec_step 'git checkout dev'
102
+ exec_step 'git merge origin/dev'
103
+ exec_step "git merge --no-ff #{current_branch_name}"
104
+
105
+ exec_step 'git push origin dev' if @prima.yesno 'Vuoi effettuare il push di dev?'.blue
106
+
107
+ # Aggiorno le issue
108
+ issues = get_issues(pr.number)
109
+ issues.each do |issue|
110
+ @prima.delete_label_from_issue(issue.number, Prima::LABEL_IN_STAGING)
111
+ @prima.close_issue issue.number
112
+ end
113
+
114
+ # Rimuove il branch remoto
115
+ exec_step "git push origin :#{current_branch_name}" if @prima.yesno "Vuoi eliminare il branch remoto #{current_branch_name}?".blue
116
+
117
+ # Crea il tag e la release con la description figa
118
+ exec_step 'git checkout master'
119
+ exec_step 'git pull'
120
+ res = @prima.rugged.tags.create(current_branch_name, @prima.rugged.head.target_id)
121
+
122
+ exec_step 'git push --tags'
123
+
124
+ commits = get_commits(pr.number)
125
+ pr_body = build_pr_body(issues, commits)
126
+
127
+ @prima.create_release(current_branch_name, {:name => current_branch_name, :body => pr_body})
128
+
129
+ output 'Release creata con successo!'.green
130
+ end
131
+
132
+ def get_commits(pr_number)
133
+ commits = []
134
+
135
+ @prima.get_pr_commits(pr_number).each do |item|
136
+ commits << item
137
+ end
138
+
139
+ commits
140
+ end
141
+
142
+ def get_issues(pr_number)
143
+ issues = []
144
+ issues_ids = []
145
+
146
+ self.get_commits(pr_number).each do |item|
147
+ issues_ids << item.commit.message.match(/^#(\d+)\s-/).captures.first if item.commit.message =~ /^#(\d+)\s-/
148
+ end
149
+
150
+ issues_ids.each do |id|
151
+ issues << @prima.get_issue(id)
152
+ end
153
+
154
+ issues
155
+ end
156
+
157
+ def build_pr_body(issues, commits, output_format = 'markdown')
158
+ body = ''
159
+
160
+ body << "# Issues\n\n"
161
+
162
+ issues.each do |issue|
163
+ body << "### [##{issue.number} - #{issue.title}](#{get_issue_url(issue.number)})\n\n"
164
+ body << "#{issue.body}\n\n"
165
+ end
166
+
167
+ body << "# Commits\n\n"
168
+
169
+ commits.each do |commit|
170
+ body << "* [#{commit.commit.message}](#{get_commit_url(commit.sha)})\n"
171
+ end
172
+
173
+ if output_format == 'html'
174
+ markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new)
175
+ body = markdown.render body
176
+ end
177
+
178
+ body
179
+
180
+ end
181
+
182
+ def get_commit_url(sha)
183
+ "https://github.com/#{@prima.repo_name}/commit/#{sha}"
184
+ end
185
+
186
+ def get_issue_url(number)
187
+ "https://github.com/#{@prima.repo_name}/issues/#{number}"
188
+ end
189
+ end
190
+
191
+ def help_content
192
+ <<-HELP
193
+
194
+ twig-release
195
+ ===========
196
+
197
+ Manage release creation
198
+
199
+ Synopsis
200
+ --------
201
+
202
+ twig release start
203
+ twig release finish
204
+
205
+ Description
206
+ -----------
207
+
208
+ start creates an release from dev branch
209
+ finish finishes the actual release by merging to dev and master
210
+
211
+ Subcommand for Twig: <http://rondevera.github.io/twig/>
212
+ Author: Andrea Usuelli <https://github.com/andreausu>
213
+
214
+ HELP
215
+ end
216
+
217
+ args = ARGV.dup
218
+
219
+ if args.include?('--help')
220
+ puts help_content
221
+ exit
222
+ end
223
+
224
+ Release.new.execute!(args)
@@ -4,19 +4,25 @@ require 'octokit'
4
4
  require 'yaml'
5
5
  require 'rugged'
6
6
  require 'highline/import'
7
+ require 'aws-sdk'
7
8
 
8
9
  class Prima
9
10
  LABEL_REVIEW='review'
10
11
  LABEL_WIP='wip'
11
12
  LABEL_HOTFIX='hotfix'
12
- GITHUB='github'
13
- attr_reader :gh, :twig, :config, :rugged
13
+ LABEL_NEXT_RELEASE='next release'
14
+ LABEL_IN_STAGING='in staging'
15
+ CONFIG_KEYS=['github', 'mandrill', 'aws_key_id', 'aws_key_secret']
16
+ attr_reader :gh, :twig, :config, :rugged, :aws
14
17
 
15
18
  def initialize
16
19
  @twig = Twig.new(:read_options => true)
17
20
  unless has_config?
18
21
  generate_config
19
22
  end
23
+ unless has_latest_config?
24
+ update_config
25
+ end
20
26
  @config = YAML.load_file 'twig.yml'
21
27
  @rugged = Rugged::Repository.new('.')
22
28
  create_clients
@@ -26,21 +32,51 @@ class Prima
26
32
  File.exist? 'twig.yml'
27
33
  end
28
34
 
35
+ def has_latest_config?
36
+ existing_config = YAML.load_file 'twig.yml'
37
+ CONFIG_KEYS.each do |k|
38
+ unless existing_config.has_key? k
39
+ return false
40
+ end
41
+ end
42
+ end
43
+
29
44
  def generate_config
30
45
  puts 'Progetto non inizializzato'.red
31
46
  puts 'Creazione del file di configurazione'.yellow
32
- github_token = ask 'github token: '
33
- conf = {
34
- GITHUB => github_token.to_s
35
- }
47
+ conf = {}
48
+ CONFIG_KEYS.each do |k|
49
+ token = ask "#{k} token: "
50
+ conf[k] = token
51
+ end
52
+ write_config conf
53
+ end
54
+
55
+ def update_config
56
+ puts 'Mancano alcuni parametri nella tua configurazione'.yellow
57
+ existing_config = YAML.load_file 'twig.yml'
58
+ CONFIG_KEYS.each do |k|
59
+ unless existing_config.has_key? k
60
+ token = ask "#{k} token: "
61
+ existing_config[k] = token
62
+ end
63
+ end
64
+ write_config existing_config
65
+ end
66
+
67
+ def write_config(conf = {})
36
68
  File.open('twig.yml', 'w') { |file|
37
69
  file.write conf.to_yaml
38
- puts 'File di configurazione creato'.green
70
+ puts 'File di configurazione aggiornato'.green
39
71
  }
40
72
  end
41
73
 
42
74
  def create_clients
43
75
  @gh = Octokit::Client.new(:access_token => @config['github'])
76
+ Aws.config.update({
77
+ region: 'eu-west-1',
78
+ credentials: Aws::Credentials.new(@config['aws_key_id'], @config['aws_key_secret']),
79
+ })
44
80
  end
45
81
 
46
82
  def disabled_branches
@@ -145,6 +181,12 @@ class Prima
145
181
  end
146
182
  end
147
183
 
184
+ def delete_label_from_issue(issue_number, label)
185
+ if issue_has_label?(issue_number, label)
186
+ @gh.remove_label repo_name, issue_number, label
187
+ end
188
+ end
189
+
148
190
  def user_login
149
191
  user = @gh.user
150
192
  user.login
@@ -165,6 +207,22 @@ class Prima
165
207
  results
166
208
  end
167
209
 
210
+ def update_pr(pr_number, options = {})
211
+ @gh.update_pull_request repo_name, pr_number, options
212
+ end
213
+
214
+ def get_issue(issue_number)
215
+ @gh.issue repo_name, issue_number
216
+ end
217
+
218
+ def get_pr_commits(pr_number)
219
+ @gh.pull_request_commits repo_name, pr_number
220
+ end
221
+
222
+ def create_pull_request(base_branch, head, title, body = '')
223
+ @gh.create_pull_request repo_name, base_branch, head, title, body
224
+ end
225
+
168
226
  def merge_pull_request(pr, commit_message='')
169
227
  raise "Invalid Pull Request" unless pr
170
228
  pr_number = pr[:number]
@@ -179,6 +237,10 @@ class Prima
179
237
  `git config remote.origin.url`
180
238
  end
181
239
 
240
+ def create_release(tag_name, options = {})
241
+ @gh.create_release repo_name, tag_name, options
242
+ end
243
+
182
244
  def yesno(prompt = 'Continue?', default = true)
183
245
  a = ''
184
246
  s = default ? '[Y/n]' : '[y/N]'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prima-twig
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.6
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matteo Giachino
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2015-11-19 00:00:00.000000000 Z
14
+ date: 2015-11-30 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: twig
@@ -97,21 +97,69 @@ dependencies:
97
97
  - - "~>"
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0.22'
100
+ - !ruby/object:Gem::Dependency
101
+ name: redcarpet
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - "~>"
105
+ - !ruby/object:Gem::Version
106
+ version: '3.3'
107
+ type: :runtime
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '3.3'
114
+ - !ruby/object:Gem::Dependency
115
+ name: mail
116
+ requirement: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - "~>"
119
+ - !ruby/object:Gem::Version
120
+ version: '2.6'
121
+ type: :runtime
122
+ prerelease: false
123
+ version_requirements: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - "~>"
126
+ - !ruby/object:Gem::Version
127
+ version: '2.6'
128
+ - !ruby/object:Gem::Dependency
129
+ name: aws-sdk
130
+ requirement: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - "~>"
133
+ - !ruby/object:Gem::Version
134
+ version: '2'
135
+ type: :runtime
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - "~>"
140
+ - !ruby/object:Gem::Version
141
+ version: '2'
100
142
  description: Our tools to manage git and github
101
143
  email: matteo.giachino@prima.it
102
144
  executables:
103
145
  - twig-circle
146
+ - twig-deploy
147
+ - twig-feature
104
148
  - twig-hotfix
105
149
  - twig-open-pr
106
150
  - twig-pick-issue
151
+ - twig-release
107
152
  - twig-review
108
153
  extensions: []
109
154
  extra_rdoc_files: []
110
155
  files:
111
156
  - bin/twig-circle
157
+ - bin/twig-deploy
158
+ - bin/twig-feature
112
159
  - bin/twig-hotfix
113
160
  - bin/twig-open-pr
114
161
  - bin/twig-pick-issue
162
+ - bin/twig-release
115
163
  - bin/twig-review
116
164
  - lib/command.rb
117
165
  - lib/prima_twig.rb
@@ -135,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
183
  version: '0'
136
184
  requirements: []
137
185
  rubyforge_project:
138
- rubygems_version: 2.4.6
186
+ rubygems_version: 2.4.7
139
187
  signing_key:
140
188
  specification_version: 4
141
189
  summary: The Prima twig toolbelt