prima-twig 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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