git-pr-release 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 98451853b6d661fc267e971bc26da386c77db073
4
+ data.tar.gz: 2437ff8212312fae03bbdfc28f2bae9e1b2806a7
5
+ SHA512:
6
+ metadata.gz: e03be692ee0bbb5a4ac1dd4cffd68fb625a39601cda7171d2c93770f4162b162e6cd5ae287877f4030ca2c4d65dafd442e8bd42803f0389c9f58178f5171aec5
7
+ data.tar.gz: d8831448a215b076fdd69782ccfdcbc5c22eeb979623f7cb0818754dbdc311fb07bb681eae75f0608af00dfdb89e592e8c0529746ecf3180dc5828966f8dcf3f
@@ -0,0 +1,2 @@
1
+ /.bundle/
2
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ git-pr-release (0.0.1)
5
+ colorize (~> 0.6)
6
+ highline (~> 1.6)
7
+ octokit (~> 2.7)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.3.5)
13
+ colorize (0.6.0)
14
+ faraday (0.9.0)
15
+ multipart-post (>= 1.2, < 3)
16
+ highline (1.6.20)
17
+ multipart-post (2.0.0)
18
+ octokit (2.7.0)
19
+ sawyer (~> 0.5.2)
20
+ sawyer (0.5.2)
21
+ addressable (~> 2.3.5)
22
+ faraday (~> 0.8, < 0.10)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ git-pr-release!
@@ -0,0 +1,35 @@
1
+ git-pr-release
2
+ ==============
3
+
4
+ Creates a pull request which summarizes feature branches that are to be
5
+ released into production. Useful if your branching storategy is like below:
6
+
7
+ * Feature branches are first merged into "staging" (or release, development)
8
+ branch.
9
+ * Then the staging branch is merged into "production" branch, which is for
10
+ production release.
11
+
12
+ Configuration
13
+ -------------
14
+
15
+ All configuration are taken using `git config`.
16
+
17
+ ### `pr-release.token`
18
+
19
+ Token for GitHub API.
20
+
21
+ If not set, you will be asked to input username/password for one time only,
22
+ and this configuration variable will be stored.
23
+
24
+ ### `pr-release.branch.production`
25
+
26
+ The branch name that is deployed in production environment.
27
+
28
+ Default value: `master`.
29
+
30
+ ### `pr-release.branch.staging`
31
+
32
+ The branch name that the feature branches are merged into and is going to be
33
+ merged into the "production" branch.
34
+
35
+ Default value: `staging`.
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'uri'
5
+ require 'open3'
6
+ require 'octokit'
7
+ require 'colorize'
8
+
9
+ def say(message, level)
10
+ color = case level
11
+ when :trace
12
+ return unless ENV['DEBUG']
13
+ nil
14
+ when :debug
15
+ return unless ENV['DEBUG']
16
+ :blue
17
+ when :info
18
+ :green
19
+ when :notice
20
+ :yellow
21
+ when :warn
22
+ :magenta
23
+ when :error
24
+ :red
25
+ end
26
+
27
+ puts message.colorize(color)
28
+ end
29
+
30
+ def git(*command)
31
+ command = [ 'git', *command.map(&:to_s) ]
32
+ say "Executing `#{command.join(' ')}`", :trace
33
+ out, status = Open3.capture2(*command)
34
+ unless status.success?
35
+ raise "Executing `#{command.join(' ')}` failed: #{status}"
36
+ end
37
+ out.each_line
38
+ end
39
+
40
+
41
+ def git_config(key)
42
+ begin
43
+ git('config', key).first.chomp
44
+ rescue
45
+ nil
46
+ end
47
+ end
48
+
49
+ def generate_description(pull_requests)
50
+ pull_requests.map do |pr|
51
+ "- [ ] ##{pr.number} #{pr.title}" + (pr.assignee ? " @#{pr.assignee.login}" : '')
52
+ end.join("\n")
53
+ end
54
+
55
+ def obtain_token!
56
+ token = git_config('pr-release.token')
57
+
58
+ unless token
59
+ require 'highline/import'
60
+ STDERR.puts 'Could not obtain config variable pr-release.token.'
61
+ STDERR.puts 'Trying to generate token...'
62
+
63
+ username = ask('username? ') { |q| q.default = ENV['USER'] }
64
+ password = ask('password? (not saved) ') { |q| q.echo = '*' }
65
+
66
+ temporary_client = Octokit::Client.new :login => username, :password => password
67
+
68
+ auth = temporary_client.create_authorization({ :scopes => [ 'public_repo', 'repo' ], :note => 'summerize-release' })
69
+ token = auth.token
70
+ git :config, '--global', 'pr-release.token', token
71
+ end
72
+
73
+ token
74
+ end
75
+
76
+ remote = git_config 'remote.origin.url'
77
+ unless %r(^\w+://) === remote
78
+ remote = "ssh://#{remote.sub(':', '/')}"
79
+ end
80
+
81
+ remote_url = URI.parse(remote)
82
+ repository = remote_url.path.sub(%r(^/), '').sub(/\.git$/, '')
83
+
84
+ if remote_url.host != 'github.com'
85
+ # GitHub:Enterprise
86
+ OpenSSL::SSL.const_set :VERIFY_PEER, OpenSSL::SSL::VERIFY_NONE # XXX
87
+
88
+ Octokit.configure do |c|
89
+ c.api_endpoint = "https://#{remote_url.host}/api/v3"
90
+ c.web_endpoint = "https://#{remote_url.host}/"
91
+ end
92
+ end
93
+
94
+ ## Project specific configuration
95
+ production_branch = git_config('pr-release.branch.production') || 'master'
96
+ staging_branch = git_config('pr-release.branch.staging') || 'staging'
97
+
98
+ say "Repository: #{repository}", :debug
99
+ say "Production branch: #{production_branch}", :debug
100
+ say "Staging branch: #{staging_branch}", :debug
101
+
102
+ client = Octokit::Client.new :access_token => obtain_token!
103
+
104
+ git :remote, 'update', 'origin'
105
+
106
+ merged_feature_head_sha1s = git(
107
+ :log, '--merges', '--pretty=format:%P', "origin/#{production_branch}..origin/#{staging_branch}"
108
+ ).map do |line|
109
+ main_sha1, feature_sha1 = line.chomp.split /\s+/
110
+ feature_sha1
111
+ end
112
+
113
+ merged_pull_request_numbers = git('ls-remote', 'origin', 'refs/pull/*/head').map do |line|
114
+ sha1, ref = line.chomp.split /\s+/
115
+
116
+ if merged_feature_head_sha1s.include? sha1
117
+ if %r<^refs/pull/(\d+)/head$>.match ref
118
+ pr_number = $1.to_i
119
+
120
+ if git('merge-base', sha1, "origin/#{production_branch}").first.chomp == sha1
121
+ say "##{pr_number} (#{sha1}) is already merged into #{production_branch}", :debug
122
+ else
123
+ pr_number
124
+ end
125
+ else
126
+ say "Bad pull request head ref format: #{ref}", :warn
127
+ nil
128
+ end
129
+ end
130
+ end.compact
131
+
132
+ if merged_pull_request_numbers.empty?
133
+ say 'No pull requests to be released', :error
134
+ exit 1
135
+ end
136
+
137
+ pull_requests = merged_pull_request_numbers.map do |nr|
138
+ pr = client.pull_request repository, nr
139
+ say "To be released: ##{pr.number} #{pr.title}", :notice
140
+ pr
141
+ end
142
+
143
+ say 'Searching for existing release pull requests...', :info
144
+ release_pr = client.pull_requests(repository).find do |pr|
145
+ pr.head.ref == staging_branch && pr.base.ref == production_branch
146
+ end
147
+
148
+ created = false
149
+
150
+ if release_pr
151
+ say "Updating release pull request ##{release_pr.number}...", :info
152
+ client.update_pull_request(
153
+ repository, release_pr.number, :body => generate_description(pull_requests)
154
+ )
155
+ else
156
+ say 'Creating release pull request...', :info
157
+ release_pr = client.create_pull_request(
158
+ repository, production_branch, staging_branch, "release #{Time.now}", generate_description(pull_requests)
159
+ )
160
+ created = true
161
+ end
162
+
163
+ unless release_pr
164
+ say 'No pull request found/created', :error
165
+ exit 1
166
+ end
167
+
168
+ say "#{created ? 'Created' : 'Updated'} pull request: #{release_pr.rels[:html].href}", :notice
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "git-pr-release"
7
+ spec.version = '0.0.1'
8
+ spec.authors = ["motemen"]
9
+ spec.email = ["motemen@gmail.com"]
10
+ spec.summary = 'Creates a release pull request'
11
+ spec.description = 'git-pr-release creates a pull request which summarizes feature branches that are to be released into production'
12
+ spec.homepage = 'https://github.com/motemen/git-pr-release'
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_dependency 'octokit', '~> 2.7'
20
+ spec.add_dependency 'highline', '~> 1.6'
21
+ spec.add_dependency 'colorize', '~> 0.6'
22
+
23
+ spec.license = 'MIT'
24
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-pr-release
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - motemen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: octokit
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: highline
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: colorize
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
55
+ description: git-pr-release creates a pull request which summarizes feature branches
56
+ that are to be released into production
57
+ email:
58
+ - motemen@gmail.com
59
+ executables:
60
+ - git-pr-release
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - .gitignore
65
+ - Gemfile
66
+ - Gemfile.lock
67
+ - README.md
68
+ - bin/git-pr-release
69
+ - git-pr-release.gemspec
70
+ homepage: https://github.com/motemen/git-pr-release
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.0.3
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Creates a release pull request
94
+ test_files: []
95
+ has_rdoc: