heroku_deployer 0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 738576c9402da6ea58a47a34b432a9d1a8447f17
4
+ data.tar.gz: 7175f54727b6e9adedd2dc4a57c100c9d600a926
5
+ SHA512:
6
+ metadata.gz: 95f00f9e747d02ababc1af63bd8065aed134cc95d023a44fb57340efad7945e184919efd44d71a0919e1edd53e6cbe362e583f4a20ecd91739127eddcfa28754
7
+ data.tar.gz: 3691d23c33927c4bc6ad34adce55c6c9f0c325b4246abf2964d7504eb311535ff59129b157fdc4f8ee3e9d25ed0669abb7ee391887fad9c945b3eeafa04b3d92
@@ -0,0 +1,28 @@
1
+ require 'octokit'
2
+
3
+ module Amitree
4
+ class GitClient
5
+ def initialize(repository, username, password)
6
+ @repository = repository
7
+ @client = Octokit::Client.new login: username, password: password
8
+ end
9
+
10
+ def commits_between(rev1, rev2)
11
+ result = @client.compare @repository, rev1, rev2
12
+ result.commits
13
+ end
14
+
15
+ def commit_messages_between(rev1, rev2)
16
+ commits_between(rev1, rev2).map(&:commit).map(&:message)
17
+ end
18
+
19
+ def stories_worked_on_between(rev1, rev2)
20
+ messages = commit_messages_between(rev1, rev2)
21
+ messages.map{|msg| msg.scan /(?<=#)\d+/}.flatten.uniq
22
+ end
23
+
24
+ def link_to(rev)
25
+ "https://github.com/#{@repository}/commit/#{rev}"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,83 @@
1
+ require 'heroku-api'
2
+ require 'heroku/new_api'
3
+ require 'rendezvous'
4
+
5
+ module Amitree
6
+ class HerokuClient
7
+ class Error < StandardError
8
+ end
9
+
10
+ def initialize(api_key, staging_app_name, production_app_name)
11
+ @heroku = Heroku::API.new(:api_key => api_key)
12
+ # We need to use the new API (not currently supported by the heroku-api gem) for deploy_to_production
13
+ @heroku_new = Heroku::NewAPI.new(:api_key => api_key)
14
+ @staging_app_name = staging_app_name
15
+ @production_app_name = production_app_name
16
+ @promoted_release_regexp = /Promote #{@staging_app_name} (v\d+)/
17
+ end
18
+
19
+ def current_production_release
20
+ get_releases(@production_app_name)[-1]
21
+ end
22
+
23
+ def last_promoted_production_release
24
+ get_releases(@production_app_name).reverse.detect{|release| promoted_from_staging?(release)} or raise Error.new "Can't find a production release that was promoted from staging!"
25
+ end
26
+
27
+ def staging_release_name(production_release)
28
+ unless production_release['descr'] =~ @promoted_release_regexp
29
+ raise Error.new "Production release was not promoted from staging: #{production_release['descr']}"
30
+ end
31
+ $1
32
+ end
33
+
34
+ def promoted_from_staging?(release)
35
+ release['descr'] =~ @promoted_release_regexp
36
+ end
37
+
38
+ def staging_releases_since(staging_release_name)
39
+ staging_releases = get_releases(@staging_app_name)
40
+ index = staging_releases.index { |release| release['name'] == staging_release_name }
41
+ if index.nil?
42
+ raise Error.new "Could not find staging release #{staging_release_name}"
43
+ end
44
+ staging_releases.slice(index+1, staging_releases.length)
45
+ end
46
+
47
+ def deploy_to_production(staging_release_name, options={})
48
+ slug = staging_slug(staging_release_name)
49
+ puts "Deploying slug to production: #{slug}"
50
+ unless options[:dry_run]
51
+ @heroku_new.post_release(@production_app_name, {'slug' => slug, 'description' => "Promote #{@staging_app_name} #{staging_release_name}"})
52
+ db_migrate_on_production
53
+ end
54
+ end
55
+
56
+ def staging_slug(staging_release_name)
57
+ unless staging_release_name =~ /\Av(\d+)\z/
58
+ raise Error.new "Unexpected release name: #{staging_release_name}"
59
+ end
60
+ result = @heroku_new.get_release(@staging_app_name, $1)
61
+ result.body['slug']['id'] || raise(Error.new("Could not find slug in API response: #{result.inspect}"))
62
+ end
63
+
64
+ def db_migrate_on_production
65
+ heroku_run(@production_app_name, 'rake db:migrate db:seed')
66
+ end
67
+
68
+ private
69
+ def get_releases(app_name)
70
+ @heroku.get_releases(app_name).body
71
+ end
72
+
73
+ def heroku_run(app_name, command)
74
+ puts "Running command on #{app_name}: #{command}..."
75
+ data = @heroku.post_ps(app_name, command, { attach: true }).body
76
+ read, write = IO.pipe
77
+ Rendezvous.start(url: data['rendezvous_url'], input: read)
78
+ read.close
79
+ write.close
80
+ puts "Done."
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,21 @@
1
+ require 'multi_json'
2
+
3
+ module Heroku
4
+ class NewAPI < API
5
+ def initialize(options={})
6
+ options[:headers] ||= {}
7
+ options[:headers]['Accept'] = 'application/vnd.heroku+json; version=3'
8
+ super(options)
9
+ end
10
+
11
+ # POST /apps/:app/releases/:release
12
+ def post_release(app, query={})
13
+ request(
14
+ :expects => 201,
15
+ :method => :post,
16
+ :path => "/apps/#{app}/releases",
17
+ :body => MultiJson.dump(query)
18
+ )
19
+ end
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: heroku_deployer
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Nick Wargnier
8
+ - Tony Novak
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-05-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 2.14.1
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 2.14.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: octokit
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '='
33
+ - !ruby/object:Gem::Version
34
+ version: 2.7.1
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '='
40
+ - !ruby/object:Gem::Version
41
+ version: 2.7.1
42
+ - !ruby/object:Gem::Dependency
43
+ name: heroku-api
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '='
47
+ - !ruby/object:Gem::Version
48
+ version: 0.3.17
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '='
54
+ - !ruby/object:Gem::Version
55
+ version: 0.3.17
56
+ - !ruby/object:Gem::Dependency
57
+ name: rendezvous
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '='
61
+ - !ruby/object:Gem::Version
62
+ version: 0.0.2
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '='
68
+ - !ruby/object:Gem::Version
69
+ version: 0.0.2
70
+ - !ruby/object:Gem::Dependency
71
+ name: pivotal-tracker
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '='
75
+ - !ruby/object:Gem::Version
76
+ version: 0.5.12
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '='
82
+ - !ruby/object:Gem::Version
83
+ version: 0.5.12
84
+ description: Gem that handles automatic deployment of code to Heroku, integrating
85
+ with Pivotal Tracker and Git
86
+ email: engineering@amitree.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - lib/amitree/git_client.rb
92
+ - lib/amitree/heroku_client.rb
93
+ - lib/heroku/new_api.rb
94
+ homepage: http://rubygems.org/gems/heroku_deployer
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - "~>"
105
+ - !ruby/object:Gem::Version
106
+ version: '2.0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.2.2
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Heroku Deployer
118
+ test_files: []