git-pr-release 1.1.0 → 1.2.0
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/git-pr-release.gemspec +2 -1
- data/lib/git/pr/release/cli.rb +103 -70
- data/lib/git/pr/release/util.rb +7 -20
- data/spec/git/pr/release/cli_spec.rb +487 -0
- data/spec/git/pr/release_spec.rb +4 -26
- data/spec/spec_helper.rb +1 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c62affe0022fbc68eb4fb5d6f3ac2ad27c6bb37779c2977619ac7636bfed8340
|
4
|
+
data.tar.gz: 66793e7118f37575b3121ca87c5575322a1b7ec406e94c929165bce4698fdc4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b89116177f0b77ff0ac6aec85b123117cf1aedc84843581e88d84d54106a3cc2f5c400ad072976c4764691336947f6c036b8bc01454929f64dcb6bf0028a2b2
|
7
|
+
data.tar.gz: 3e31b988775f96af5f619f23cb28ce29a5096ad8a785b7e592f8241c40e0326c24abbd6ae50114934c53fda97fbc164477cdc52e97fb07cc690a633638895530
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# git-pr-release
|
2
2
|
|
3
|
+
## v1.2.0 (2020-02-07)
|
4
|
+
|
5
|
+
[full changelog](https://github.com/motemen/git-pr-release/compare/v1.1.0...v1.2.0)
|
6
|
+
|
7
|
+
* (#44) Use API option when detecting existing release PR (@onk)
|
8
|
+
* (#41, #42) Refactor (@onk)
|
9
|
+
- Some local variables are removed. This will break if you have customized the template ERB.
|
10
|
+
|
3
11
|
## v1.1.0 (2020-01-02)
|
4
12
|
|
5
13
|
[full changelog](https://github.com/motemen/git-pr-release/compare/v1.0.1...v1.1.0)
|
data/git-pr-release.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "git-pr-release"
|
7
|
-
spec.version = '1.
|
7
|
+
spec.version = '1.2.0'
|
8
8
|
spec.authors = ["motemen"]
|
9
9
|
spec.email = ["motemen@gmail.com"]
|
10
10
|
spec.summary = 'Creates a release pull request'
|
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.add_development_dependency 'rspec'
|
26
26
|
spec.add_development_dependency 'timecop'
|
27
|
+
spec.add_development_dependency 'webmock'
|
27
28
|
|
28
29
|
spec.license = 'MIT'
|
29
30
|
end
|
data/lib/git/pr/release/cli.rb
CHANGED
@@ -6,20 +6,14 @@ module Git
|
|
6
6
|
module Release
|
7
7
|
class CLI
|
8
8
|
include Git::Pr::Release::Util
|
9
|
-
|
10
|
-
def self.start
|
11
|
-
host, repository, scheme = host_and_repository_and_scheme
|
12
|
-
|
13
|
-
if host
|
14
|
-
# GitHub:Enterprise
|
15
|
-
OpenSSL::SSL.const_set :VERIFY_PEER, OpenSSL::SSL::VERIFY_NONE # XXX
|
9
|
+
attr_reader :repository, :production_branch, :staging_branch, :template_path, :labels
|
16
10
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
11
|
+
def self.start
|
12
|
+
result = self.new.start
|
13
|
+
exit result
|
14
|
+
end
|
22
15
|
|
16
|
+
def start
|
23
17
|
OptionParser.new do |opts|
|
24
18
|
opts.on('-n', '--dry-run', 'Do not create/update a PR. Just prints out') do |v|
|
25
19
|
@dry_run = v
|
@@ -33,20 +27,54 @@ module Git
|
|
33
27
|
end.parse!
|
34
28
|
|
35
29
|
### Set up configuration
|
30
|
+
configure
|
31
|
+
|
32
|
+
### Fetch merged PRs
|
33
|
+
merged_prs = fetch_merged_prs
|
34
|
+
if merged_prs.empty?
|
35
|
+
say 'No pull requests to be released', :error
|
36
|
+
return 1
|
37
|
+
end
|
38
|
+
|
39
|
+
### Create a release PR
|
40
|
+
create_release_pr(merged_prs)
|
41
|
+
return 0
|
42
|
+
end
|
36
43
|
|
37
|
-
|
38
|
-
|
44
|
+
def client
|
45
|
+
@client ||= Octokit::Client.new :access_token => obtain_token!
|
46
|
+
end
|
47
|
+
|
48
|
+
def configure
|
49
|
+
host, @repository, scheme = host_and_repository_and_scheme
|
50
|
+
|
51
|
+
if host
|
52
|
+
# GitHub:Enterprise
|
53
|
+
OpenSSL::SSL.const_set :VERIFY_PEER, OpenSSL::SSL::VERIFY_NONE # XXX
|
54
|
+
|
55
|
+
Octokit.configure do |c|
|
56
|
+
c.api_endpoint = "#{scheme}://#{host}/api/v3"
|
57
|
+
c.web_endpoint = "#{scheme}://#{host}/"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
@production_branch = ENV.fetch('GIT_PR_RELEASE_BRANCH_PRODUCTION') { git_config('branch.production') } || 'master'
|
62
|
+
@staging_branch = ENV.fetch('GIT_PR_RELEASE_BRANCH_STAGING') { git_config('branch.staging') } || 'staging'
|
63
|
+
@template_path = ENV.fetch('GIT_PR_RELEASE_TEMPLATE') { git_config('template') }
|
64
|
+
|
65
|
+
_labels = ENV.fetch('GIT_PR_RELEASE_LABELS') { git_config('labels') }
|
66
|
+
@labels = _labels && _labels.split(/\s*,\s*/) || []
|
39
67
|
|
40
68
|
say "Repository: #{repository}", :debug
|
41
69
|
say "Production branch: #{production_branch}", :debug
|
42
70
|
say "Staging branch: #{staging_branch}", :debug
|
71
|
+
say "Template path: #{template_path}", :debug
|
72
|
+
say "Labels #{labels}", :debug
|
73
|
+
end
|
43
74
|
|
44
|
-
|
45
|
-
|
75
|
+
def fetch_merged_prs
|
46
76
|
git :remote, 'update', 'origin' unless @no_fetch
|
47
77
|
|
48
|
-
### Fetch merged PRs
|
49
|
-
|
50
78
|
merged_feature_head_sha1s = git(
|
51
79
|
:log, '--merges', '--pretty=format:%P', "origin/#{production_branch}..origin/#{staging_branch}"
|
52
80
|
).map do |line|
|
@@ -73,86 +101,91 @@ module Git
|
|
73
101
|
end
|
74
102
|
end.compact
|
75
103
|
|
76
|
-
if merged_pull_request_numbers.empty?
|
77
|
-
say 'No pull requests to be released', :error
|
78
|
-
exit 1
|
79
|
-
end
|
80
|
-
|
81
104
|
merged_prs = merged_pull_request_numbers.map do |nr|
|
82
105
|
pr = client.pull_request repository, nr
|
83
106
|
say "To be released: ##{pr.number} #{pr.title}", :notice
|
84
107
|
pr
|
85
108
|
end
|
86
109
|
|
87
|
-
|
110
|
+
merged_prs
|
111
|
+
end
|
88
112
|
|
89
|
-
|
90
|
-
found_release_pr =
|
91
|
-
pr.head.ref == staging_branch && pr.base.ref == production_branch
|
92
|
-
end
|
113
|
+
def create_release_pr(merged_prs)
|
114
|
+
found_release_pr = detect_existing_release_pr
|
93
115
|
create_mode = found_release_pr.nil?
|
94
116
|
|
95
|
-
|
96
|
-
|
117
|
+
if create_mode
|
118
|
+
if @dry_run
|
119
|
+
release_pr = nil
|
120
|
+
changed_files = []
|
121
|
+
else
|
122
|
+
release_pr = prepare_release_pr
|
123
|
+
changed_files = pull_request_files(release_pr)
|
124
|
+
end
|
125
|
+
else
|
126
|
+
release_pr = found_release_pr
|
127
|
+
changed_files = pull_request_files(release_pr)
|
128
|
+
end
|
97
129
|
|
98
|
-
|
99
|
-
pr_title, new_body = build_pr_title_and_body found_release_pr, merged_prs, changed_files
|
100
|
-
pr_body = create_mode ? new_body : merge_pr_body(found_release_pr.body, new_body)
|
130
|
+
pr_title, pr_body = build_and_merge_pr_title_and_body(release_pr, merged_prs, changed_files)
|
101
131
|
|
132
|
+
if @dry_run
|
102
133
|
say 'Dry-run. Not updating PR', :info
|
103
134
|
say pr_title, :notice
|
104
135
|
say pr_body, :notice
|
105
|
-
dump_result_as_json(
|
106
|
-
|
136
|
+
dump_result_as_json( release_pr, merged_prs, changed_files ) if @json
|
137
|
+
return
|
107
138
|
end
|
108
139
|
|
109
|
-
pr_title, pr_body
|
110
|
-
release_pr = nil
|
140
|
+
update_release_pr(release_pr, pr_title, pr_body)
|
111
141
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
142
|
+
say "#{create_mode ? 'Created' : 'Updated'} pull request: #{release_pr.rels[:html].href}", :notice
|
143
|
+
dump_result_as_json( release_pr, merged_prs, changed_files ) if @json
|
144
|
+
end
|
145
|
+
|
146
|
+
def detect_existing_release_pr
|
147
|
+
say 'Searching for existing release pull requests...', :info
|
148
|
+
client.pull_requests(repository, head: staging_branch, base: production_branch).first
|
149
|
+
end
|
150
|
+
|
151
|
+
def prepare_release_pr
|
152
|
+
client.create_pull_request(
|
153
|
+
repository, production_branch, staging_branch, 'Preparing release pull request...', ''
|
154
|
+
)
|
155
|
+
end
|
156
|
+
|
157
|
+
def build_and_merge_pr_title_and_body(release_pr, merged_prs, changed_files)
|
158
|
+
# release_pr is nil when dry_run && create_mode
|
159
|
+
old_body = release_pr ? release_pr.body : ""
|
160
|
+
pr_title, new_body = build_pr_title_and_body(release_pr, merged_prs, changed_files, template_path)
|
128
161
|
|
162
|
+
[pr_title, merge_pr_body(old_body, new_body)]
|
163
|
+
end
|
164
|
+
|
165
|
+
def update_release_pr(release_pr, pr_title, pr_body)
|
129
166
|
say 'Pull request body:', :debug
|
130
167
|
say pr_body, :debug
|
131
168
|
|
132
|
-
|
169
|
+
client.update_pull_request(
|
133
170
|
repository, release_pr.number, :title => pr_title, :body => pr_body
|
134
171
|
)
|
135
172
|
|
136
|
-
unless
|
137
|
-
|
138
|
-
exit 3
|
139
|
-
end
|
140
|
-
|
141
|
-
labels = ENV.fetch('GIT_PR_RELEASE_LABELS') { git_config('labels') }
|
142
|
-
if not labels.nil? and not labels.empty?
|
143
|
-
labels = labels.split(/\s*,\s*/)
|
144
|
-
labeled_pull_request = client.add_labels_to_an_issue(
|
173
|
+
unless labels.empty?
|
174
|
+
client.add_labels_to_an_issue(
|
145
175
|
repository, release_pr.number, labels
|
146
176
|
)
|
147
|
-
|
148
|
-
unless labeled_pull_request
|
149
|
-
say 'Failed to add labels to a pull request', :error
|
150
|
-
exit 4
|
151
|
-
end
|
152
177
|
end
|
178
|
+
end
|
153
179
|
|
154
|
-
|
155
|
-
|
180
|
+
# Fetch PR files of specified pull_request
|
181
|
+
def pull_request_files(pull_request)
|
182
|
+
return [] if pull_request.nil?
|
183
|
+
|
184
|
+
# Fetch files as many as possible
|
185
|
+
client.auto_paginate = true
|
186
|
+
files = client.pull_request_files repository, pull_request.number
|
187
|
+
client.auto_paginate = false
|
188
|
+
return files
|
156
189
|
end
|
157
190
|
end
|
158
191
|
end
|
data/lib/git/pr/release/util.rb
CHANGED
@@ -83,16 +83,16 @@ Release <%= Time.now %>
|
|
83
83
|
<% end -%>
|
84
84
|
ERB
|
85
85
|
|
86
|
-
def build_pr_title_and_body(release_pr, merged_prs, changed_files)
|
86
|
+
def build_pr_title_and_body(release_pr, merged_prs, changed_files, template_path)
|
87
87
|
release_pull_request = target_pull_request = release_pr ? PullRequest.new(release_pr) : DummyPullRequest.new
|
88
88
|
merged_pull_requests = pull_requests = merged_prs.map { |pr| PullRequest.new(pr) }
|
89
89
|
|
90
|
-
template =
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
90
|
+
template = if template_path
|
91
|
+
template_fullpath = File.join(git('rev-parse', '--show-toplevel').first.chomp, template_path)
|
92
|
+
File.read(template_path)
|
93
|
+
else
|
94
|
+
DEFAULT_PR_TEMPLATE
|
95
|
+
end
|
96
96
|
|
97
97
|
erb = ERB.new template, nil, '-'
|
98
98
|
content = erb.result binding
|
@@ -195,19 +195,6 @@ ERB
|
|
195
195
|
|
196
196
|
auth
|
197
197
|
end
|
198
|
-
|
199
|
-
# Fetch PR files of specified pull_request
|
200
|
-
def pull_request_files(client, pull_request)
|
201
|
-
return [] if pull_request.nil?
|
202
|
-
|
203
|
-
host, repository, scheme = host_and_repository_and_scheme
|
204
|
-
|
205
|
-
# Fetch files as many as possible
|
206
|
-
client.auto_paginate = true
|
207
|
-
files = client.pull_request_files repository, pull_request.number
|
208
|
-
client.auto_paginate = false
|
209
|
-
return files
|
210
|
-
end
|
211
198
|
end
|
212
199
|
end
|
213
200
|
end
|
@@ -0,0 +1,487 @@
|
|
1
|
+
RSpec.describe Git::Pr::Release::CLI do
|
2
|
+
let(:configured_cli) {
|
3
|
+
cli = Git::Pr::Release::CLI.new
|
4
|
+
allow(cli).to receive(:host_and_repository_and_scheme) {
|
5
|
+
[nil, "motemen/git-pr-release", "https"]
|
6
|
+
}
|
7
|
+
allow(cli).to receive(:git_config).with(anything) { nil }
|
8
|
+
cli.configure
|
9
|
+
cli
|
10
|
+
}
|
11
|
+
|
12
|
+
describe "#start" do
|
13
|
+
subject { @cli.start }
|
14
|
+
|
15
|
+
before {
|
16
|
+
@cli = Git::Pr::Release::CLI.new
|
17
|
+
|
18
|
+
allow(@cli).to receive(:configure)
|
19
|
+
allow(@cli).to receive(:fetch_merged_prs) { merged_prs }
|
20
|
+
allow(@cli).to receive(:create_release_pr)
|
21
|
+
}
|
22
|
+
|
23
|
+
context "When merged_prs is empty" do
|
24
|
+
let(:merged_prs) { [] }
|
25
|
+
it {
|
26
|
+
is_expected.to eq 1
|
27
|
+
expect(@cli).to have_received(:configure)
|
28
|
+
expect(@cli).to have_received(:fetch_merged_prs)
|
29
|
+
expect(@cli).not_to have_received(:create_release_pr)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
context "When merged_prs exists" do
|
34
|
+
let(:merged_prs) {
|
35
|
+
agent = Sawyer::Agent.new("http://example.com/") do |conn|
|
36
|
+
conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
|
37
|
+
conn.adapter(:test, Faraday::Adapter::Test::Stubs.new)
|
38
|
+
end
|
39
|
+
pr_3 = Sawyer::Resource.new(agent, YAML.load_file(file_fixture("pr_3.yml")))
|
40
|
+
pr_4 = Sawyer::Resource.new(agent, YAML.load_file(file_fixture("pr_4.yml")))
|
41
|
+
[pr_3, pr_4]
|
42
|
+
}
|
43
|
+
it {
|
44
|
+
is_expected.to eq 0
|
45
|
+
expect(@cli).to have_received(:configure)
|
46
|
+
expect(@cli).to have_received(:fetch_merged_prs)
|
47
|
+
expect(@cli).to have_received(:create_release_pr).with(merged_prs)
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#configure" do
|
53
|
+
subject { @cli.configure }
|
54
|
+
|
55
|
+
before {
|
56
|
+
@cli = Git::Pr::Release::CLI.new
|
57
|
+
|
58
|
+
allow(@cli).to receive(:git_config).with(anything) { nil }
|
59
|
+
}
|
60
|
+
|
61
|
+
context "When default" do
|
62
|
+
before {
|
63
|
+
allow(@cli).to receive(:host_and_repository_and_scheme) {
|
64
|
+
[nil, "motemen/git-pr-release", "https"]
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
it "configured as default" do
|
69
|
+
subject
|
70
|
+
|
71
|
+
expect(Octokit.api_endpoint).to eq "https://api.github.com/"
|
72
|
+
expect(Octokit.web_endpoint).to eq "https://github.com/"
|
73
|
+
|
74
|
+
expect(@cli.repository).to eq "motemen/git-pr-release"
|
75
|
+
expect(@cli.production_branch).to eq "master"
|
76
|
+
expect(@cli.staging_branch).to eq "staging"
|
77
|
+
expect(@cli.template_path).to eq nil
|
78
|
+
expect(@cli.labels).to eq []
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "When GitHub Enterprise Server" do
|
83
|
+
before {
|
84
|
+
allow(@cli).to receive(:host_and_repository_and_scheme) {
|
85
|
+
["example.com", "motemen/git-pr-release", "https"]
|
86
|
+
}
|
87
|
+
}
|
88
|
+
after {
|
89
|
+
Octokit.reset!
|
90
|
+
}
|
91
|
+
|
92
|
+
it "octokit is configured" do
|
93
|
+
subject
|
94
|
+
|
95
|
+
expect(Octokit.api_endpoint).to eq "https://example.com/api/v3/"
|
96
|
+
expect(Octokit.web_endpoint).to eq "https://example.com/"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "branches" do
|
101
|
+
context "When branches are set by ENV" do
|
102
|
+
around do |example|
|
103
|
+
original = ENV.to_hash
|
104
|
+
begin
|
105
|
+
ENV["GIT_PR_RELEASE_BRANCH_PRODUCTION"] = "prod"
|
106
|
+
ENV["GIT_PR_RELEASE_BRANCH_STAGING"] = "dev"
|
107
|
+
example.run
|
108
|
+
ensure
|
109
|
+
ENV.replace(original)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
it "branches are configured" do
|
114
|
+
subject
|
115
|
+
|
116
|
+
expect(@cli.production_branch).to eq "prod"
|
117
|
+
expect(@cli.staging_branch).to eq "dev"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "When branches are set by git_config" do
|
122
|
+
before {
|
123
|
+
allow(@cli).to receive(:git_config).with("branch.production") { "production" }
|
124
|
+
allow(@cli).to receive(:git_config).with("branch.staging") { "develop" }
|
125
|
+
}
|
126
|
+
|
127
|
+
it "branches are configured" do
|
128
|
+
subject
|
129
|
+
|
130
|
+
expect(@cli.production_branch).to eq "production"
|
131
|
+
expect(@cli.staging_branch).to eq "develop"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "labels" do
|
137
|
+
context "With ENV" do
|
138
|
+
around do |example|
|
139
|
+
original = ENV.to_hash
|
140
|
+
begin
|
141
|
+
ENV["GIT_PR_RELEASE_LABELS"] = env_labels
|
142
|
+
example.run
|
143
|
+
ensure
|
144
|
+
ENV.replace(original)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context "string" do
|
149
|
+
let(:env_labels) { "release" }
|
150
|
+
it "set labels" do
|
151
|
+
subject
|
152
|
+
expect(@cli.labels).to eq ["release"]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "comma separated string" do
|
157
|
+
let(:env_labels) { "release,release2" }
|
158
|
+
it "set labels" do
|
159
|
+
subject
|
160
|
+
expect(@cli.labels).to eq ["release", "release2"]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context "empty string" do
|
165
|
+
let(:env_labels) { "" }
|
166
|
+
it "set labels as default" do
|
167
|
+
subject
|
168
|
+
expect(@cli.labels).to eq []
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "With git_config" do
|
174
|
+
before {
|
175
|
+
allow(@cli).to receive(:git_config).with("labels") { "release" }
|
176
|
+
}
|
177
|
+
|
178
|
+
it "set labels" do
|
179
|
+
subject
|
180
|
+
expect(@cli.labels).to eq ["release"]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "#fetch_merged_prs" do
|
187
|
+
subject { @cli.fetch_merged_prs }
|
188
|
+
|
189
|
+
before {
|
190
|
+
@cli = configured_cli
|
191
|
+
|
192
|
+
agent = Sawyer::Agent.new("http://example.com/") do |conn|
|
193
|
+
conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
|
194
|
+
conn.adapter(:test, Faraday::Adapter::Test::Stubs.new)
|
195
|
+
end
|
196
|
+
|
197
|
+
expect(@cli).to receive(:git).with(:remote, "update", "origin") {
|
198
|
+
[]
|
199
|
+
}
|
200
|
+
|
201
|
+
expect(@cli).to receive(:git).with(:log, "--merges", "--pretty=format:%P", "origin/master..origin/staging") {
|
202
|
+
<<~GIT_LOG.each_line
|
203
|
+
ad694b9c2b868e8801f9209f0ad5dd5458c49854 42bd43b80c973c8f348df3521745201be05bf194
|
204
|
+
b620bead10831d2e4e15be392e0a435d3470a0ad 5c977a1827387ac7b7a85c7b827ee119165f1823
|
205
|
+
GIT_LOG
|
206
|
+
}
|
207
|
+
expect(@cli).to receive(:git).with("ls-remote", "origin", "refs/pull/*/head") {
|
208
|
+
<<~GIT_LS_REMOTE.each_line
|
209
|
+
bbcd2a04ef394e91be44c24e93e52fdbca944060 refs/pull/1/head
|
210
|
+
5c977a1827387ac7b7a85c7b827ee119165f1823 refs/pull/3/head
|
211
|
+
42bd43b80c973c8f348df3521745201be05bf194 refs/pull/4/head
|
212
|
+
GIT_LS_REMOTE
|
213
|
+
}
|
214
|
+
expect(@cli).to receive(:git).with("merge-base", "5c977a1827387ac7b7a85c7b827ee119165f1823", "origin/master") {
|
215
|
+
"b620bead10831d2e4e15be392e0a435d3470a0ad".each_line
|
216
|
+
}
|
217
|
+
expect(@cli).to receive(:git).with("merge-base", "42bd43b80c973c8f348df3521745201be05bf194", "origin/master") {
|
218
|
+
"b620bead10831d2e4e15be392e0a435d3470a0ad".each_line
|
219
|
+
}
|
220
|
+
|
221
|
+
client = double(Octokit::Client)
|
222
|
+
@pr_3 = Sawyer::Resource.new(agent, YAML.load_file(file_fixture("pr_3.yml")))
|
223
|
+
@pr_4 = Sawyer::Resource.new(agent, YAML.load_file(file_fixture("pr_4.yml")))
|
224
|
+
expect(client).to receive(:pull_request).with("motemen/git-pr-release", 3) { @pr_3 }
|
225
|
+
expect(client).to receive(:pull_request).with("motemen/git-pr-release", 4) { @pr_4 }
|
226
|
+
allow(@cli).to receive(:client).with(no_args) { client }
|
227
|
+
}
|
228
|
+
|
229
|
+
it { is_expected.to eq [@pr_3, @pr_4] }
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "#create_release_pr" do
|
233
|
+
subject { @cli.create_release_pr(@merged_prs) }
|
234
|
+
|
235
|
+
before {
|
236
|
+
@cli = configured_cli
|
237
|
+
|
238
|
+
@agent = Sawyer::Agent.new("http://example.com/") do |conn|
|
239
|
+
conn.builder.handlers.delete(Faraday::Adapter::NetHttp)
|
240
|
+
conn.adapter(:test, Faraday::Adapter::Test::Stubs.new)
|
241
|
+
end
|
242
|
+
|
243
|
+
@merged_prs = [
|
244
|
+
Sawyer::Resource.new(@agent, YAML.load_file(file_fixture("pr_3.yml"))),
|
245
|
+
Sawyer::Resource.new(@agent, YAML.load_file(file_fixture("pr_4.yml"))),
|
246
|
+
]
|
247
|
+
|
248
|
+
allow(@cli).to receive(:detect_existing_release_pr) { existing_release_pr }
|
249
|
+
@pr_title = "Release 2020-01-04 16:51:09 +0900"
|
250
|
+
@pr_body = <<~BODY.chomp
|
251
|
+
- [ ] #3 Provides a creating release pull-request object for template @hakobe
|
252
|
+
- [ ] #4 use user who create PR if there is no assignee @motemen
|
253
|
+
BODY
|
254
|
+
allow(@cli).to receive(:build_and_merge_pr_title_and_body) {
|
255
|
+
[@pr_title, @pr_body]
|
256
|
+
}
|
257
|
+
allow(@cli).to receive(:update_release_pr)
|
258
|
+
@changed_files = [double(Sawyer::Resource)]
|
259
|
+
allow(@cli).to receive(:pull_request_files) { @changed_files }
|
260
|
+
}
|
261
|
+
|
262
|
+
context "When create_mode" do
|
263
|
+
before {
|
264
|
+
@created_pr = Sawyer::Resource.new(@agent, YAML.load_file(file_fixture("pr_1.yml")))
|
265
|
+
allow(@cli).to receive(:prepare_release_pr) { @created_pr }
|
266
|
+
}
|
267
|
+
|
268
|
+
let(:existing_release_pr) { nil }
|
269
|
+
|
270
|
+
it {
|
271
|
+
subject
|
272
|
+
|
273
|
+
expect(@cli).to have_received(:detect_existing_release_pr)
|
274
|
+
expect(@cli).to have_received(:prepare_release_pr)
|
275
|
+
expect(@cli).to have_received(:pull_request_files)
|
276
|
+
expect(@cli).to have_received(:build_and_merge_pr_title_and_body).with(@created_pr, @merged_prs, @changed_files)
|
277
|
+
expect(@cli).to have_received(:update_release_pr).with(@created_pr, @pr_title, @pr_body)
|
278
|
+
}
|
279
|
+
end
|
280
|
+
|
281
|
+
context "When not create_mode" do
|
282
|
+
before {
|
283
|
+
allow(@cli).to receive(:prepare_release_pr)
|
284
|
+
}
|
285
|
+
|
286
|
+
let(:existing_release_pr) { double(
|
287
|
+
number: 1023,
|
288
|
+
rels: { html: double(href: "https://github.com/motemen/git-pr-release/pull/1023") },
|
289
|
+
)}
|
290
|
+
|
291
|
+
it {
|
292
|
+
subject
|
293
|
+
|
294
|
+
expect(@cli).to have_received(:detect_existing_release_pr)
|
295
|
+
expect(@cli).to have_received(:pull_request_files).with(existing_release_pr)
|
296
|
+
expect(@cli).not_to have_received(:prepare_release_pr)
|
297
|
+
expect(@cli).to have_received(:build_and_merge_pr_title_and_body).with(existing_release_pr, @merged_prs, @changed_files)
|
298
|
+
expect(@cli).to have_received(:update_release_pr).with(existing_release_pr, @pr_title, @pr_body)
|
299
|
+
}
|
300
|
+
end
|
301
|
+
|
302
|
+
context "When dry_run with create_mode" do
|
303
|
+
before {
|
304
|
+
@created_pr = Sawyer::Resource.new(@agent, YAML.load_file(file_fixture("pr_1.yml")))
|
305
|
+
allow(@cli).to receive(:prepare_release_pr) { @created_pr }
|
306
|
+
|
307
|
+
@cli.instance_variable_set(:@dry_run, true)
|
308
|
+
}
|
309
|
+
|
310
|
+
let(:existing_release_pr) { nil }
|
311
|
+
|
312
|
+
it {
|
313
|
+
subject
|
314
|
+
|
315
|
+
expect(@cli).to have_received(:detect_existing_release_pr)
|
316
|
+
expect(@cli).not_to have_received(:prepare_release_pr)
|
317
|
+
expect(@cli).not_to have_received(:pull_request_files)
|
318
|
+
expect(@cli).to have_received(:build_and_merge_pr_title_and_body).with(nil, @merged_prs, [])
|
319
|
+
expect(@cli).not_to have_received(:update_release_pr).with(@created_pr, @pr_title, @pr_body)
|
320
|
+
}
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
describe "#prepare_release_pr" do
|
325
|
+
subject { @cli.prepare_release_pr }
|
326
|
+
|
327
|
+
before {
|
328
|
+
@cli = configured_cli
|
329
|
+
|
330
|
+
@client = double(Octokit::Client)
|
331
|
+
allow(@client).to receive(:create_pull_request)
|
332
|
+
allow(@cli).to receive(:client) { @client }
|
333
|
+
}
|
334
|
+
|
335
|
+
it {
|
336
|
+
subject
|
337
|
+
|
338
|
+
expect(@client).to have_received(:create_pull_request).with(
|
339
|
+
"motemen/git-pr-release",
|
340
|
+
"master",
|
341
|
+
"staging",
|
342
|
+
"Preparing release pull request...",
|
343
|
+
"", # empby body
|
344
|
+
)
|
345
|
+
}
|
346
|
+
end
|
347
|
+
|
348
|
+
describe "#build_and_merge_pr_title_and_body" do
|
349
|
+
subject { @cli.build_and_merge_pr_title_and_body(release_pr, @merged_prs, changed_files) }
|
350
|
+
|
351
|
+
before {
|
352
|
+
@cli = configured_cli
|
353
|
+
|
354
|
+
@merged_prs = [double(Sawyer::Resource)]
|
355
|
+
allow(@cli).to receive(:build_pr_title_and_body) { ["PR Title", "PR Body"] }
|
356
|
+
allow(@cli).to receive(:merge_pr_body) { "Merged Body" }
|
357
|
+
}
|
358
|
+
|
359
|
+
context "When release_pr exists" do
|
360
|
+
let(:release_pr) { double(body: "Old Body") }
|
361
|
+
let(:changed_files) { [double(Sawyer::Resource)] }
|
362
|
+
|
363
|
+
it {
|
364
|
+
is_expected.to eq ["PR Title", "Merged Body"]
|
365
|
+
|
366
|
+
expect(@cli).to have_received(:build_pr_title_and_body).with(release_pr, @merged_prs, changed_files, nil)
|
367
|
+
expect(@cli).to have_received(:merge_pr_body).with("Old Body", "PR Body")
|
368
|
+
}
|
369
|
+
end
|
370
|
+
|
371
|
+
context "When release_pr is nil" do
|
372
|
+
# = When dry_run with create_mode
|
373
|
+
let(:release_pr) { nil }
|
374
|
+
let(:changed_files) { [] }
|
375
|
+
|
376
|
+
it {
|
377
|
+
is_expected.to eq ["PR Title", "Merged Body"]
|
378
|
+
|
379
|
+
expect(@cli).to have_received(:build_pr_title_and_body).with(release_pr, @merged_prs, changed_files, nil)
|
380
|
+
expect(@cli).to have_received(:merge_pr_body).with("", "PR Body")
|
381
|
+
}
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
describe "#update_release_pr" do
|
386
|
+
subject { @cli.update_release_pr(@release_pr, "PR Title", "PR Body") }
|
387
|
+
|
388
|
+
before {
|
389
|
+
@cli = configured_cli
|
390
|
+
|
391
|
+
@release_pr = double(number: 1023)
|
392
|
+
|
393
|
+
@client = double(Octokit::Client)
|
394
|
+
allow(@client).to receive(:update_pull_request) { @release_pr }
|
395
|
+
allow(@client).to receive(:add_labels_to_an_issue)
|
396
|
+
allow(@cli).to receive(:client) { @client }
|
397
|
+
}
|
398
|
+
|
399
|
+
context "Without labels" do
|
400
|
+
it {
|
401
|
+
subject
|
402
|
+
|
403
|
+
expect(@client).to have_received(:update_pull_request).with(
|
404
|
+
"motemen/git-pr-release",
|
405
|
+
1023,
|
406
|
+
{
|
407
|
+
title: "PR Title",
|
408
|
+
body: "PR Body",
|
409
|
+
}
|
410
|
+
)
|
411
|
+
expect(@client).not_to have_received(:add_labels_to_an_issue)
|
412
|
+
}
|
413
|
+
end
|
414
|
+
|
415
|
+
context "With labels" do
|
416
|
+
before {
|
417
|
+
allow(@cli).to receive(:labels) { ["release"] }
|
418
|
+
}
|
419
|
+
it {
|
420
|
+
subject
|
421
|
+
|
422
|
+
expect(@client).to have_received(:update_pull_request).with(
|
423
|
+
"motemen/git-pr-release",
|
424
|
+
1023,
|
425
|
+
{
|
426
|
+
title: "PR Title",
|
427
|
+
body: "PR Body",
|
428
|
+
}
|
429
|
+
)
|
430
|
+
expect(@client).to have_received(:add_labels_to_an_issue).with(
|
431
|
+
"motemen/git-pr-release", 1023, ["release"]
|
432
|
+
)
|
433
|
+
}
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
describe "#detect_existing_release_pr" do
|
438
|
+
subject { @cli.detect_existing_release_pr }
|
439
|
+
|
440
|
+
before {
|
441
|
+
@cli = configured_cli
|
442
|
+
|
443
|
+
@client = double(Octokit::Client)
|
444
|
+
allow(@cli).to receive(:client).with(no_args) { @client }
|
445
|
+
}
|
446
|
+
|
447
|
+
context "When exists" do
|
448
|
+
before {
|
449
|
+
@release_pr = double(head: double(ref: "staging"), base: double(ref: "master"))
|
450
|
+
allow(@client).to receive(:pull_requests) { [@release_pr] }
|
451
|
+
}
|
452
|
+
|
453
|
+
it { is_expected.to eq @release_pr }
|
454
|
+
end
|
455
|
+
|
456
|
+
context "When not exists" do
|
457
|
+
before {
|
458
|
+
allow(@client).to receive(:pull_requests) { [] }
|
459
|
+
}
|
460
|
+
|
461
|
+
it { is_expected.to be_nil }
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
describe "#pull_request_files" do
|
466
|
+
subject { @cli.pull_request_files(@release_pr) }
|
467
|
+
|
468
|
+
before {
|
469
|
+
@cli = configured_cli
|
470
|
+
|
471
|
+
@release_pr = double(number: 1023)
|
472
|
+
@client = double(Octokit::Client)
|
473
|
+
@changed_files = [double(Sawyer::Resource)]
|
474
|
+
allow(@client).to receive(:pull_request_files) { @changed_files }
|
475
|
+
allow(@client).to receive(:auto_paginate=)
|
476
|
+
allow(@cli).to receive(:client) { @client }
|
477
|
+
}
|
478
|
+
|
479
|
+
it {
|
480
|
+
is_expected.to eq @changed_files
|
481
|
+
|
482
|
+
expect(@client).to have_received(:auto_paginate=).with(true)
|
483
|
+
expect(@client).to have_received(:pull_request_files).with("motemen/git-pr-release", 1023)
|
484
|
+
expect(@client).to have_received(:auto_paginate=).with(false)
|
485
|
+
}
|
486
|
+
end
|
487
|
+
end
|
data/spec/git/pr/release_spec.rb
CHANGED
@@ -19,9 +19,9 @@ RSpec.describe Git::Pr::Release do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
describe "#build_pr_title_and_body" do
|
22
|
-
context "without
|
22
|
+
context "without template_path" do
|
23
23
|
it {
|
24
|
-
pr_title, new_body = build_pr_title_and_body(@release_pr, @merged_prs, @changed_files)
|
24
|
+
pr_title, new_body = build_pr_title_and_body(@release_pr, @merged_prs, @changed_files, nil)
|
25
25
|
expect(pr_title).to eq "Release 2019-02-20 22:58:35 +0900"
|
26
26
|
expect(new_body).to eq <<~MARKDOWN
|
27
27
|
- [ ] #3 Provides a creating release pull-request object for template @hakobe
|
@@ -30,37 +30,15 @@ RSpec.describe Git::Pr::Release do
|
|
30
30
|
}
|
31
31
|
end
|
32
32
|
|
33
|
-
context "with
|
34
|
-
before {
|
35
|
-
ENV["GIT_PR_RELEASE_TEMPLATE"] = "spec/fixtures/file/template_1.erb"
|
36
|
-
}
|
37
|
-
|
38
|
-
after {
|
39
|
-
ENV["GIT_PR_RELEASE_TEMPLATE"] = nil
|
40
|
-
}
|
41
|
-
|
33
|
+
context "with template_path" do
|
42
34
|
it {
|
43
|
-
pr_title, new_body = build_pr_title_and_body(@release_pr, @merged_prs, @changed_files)
|
35
|
+
pr_title, new_body = build_pr_title_and_body(@release_pr, @merged_prs, @changed_files, "spec/fixtures/file/template_1.erb")
|
44
36
|
expect(pr_title).to eq "a"
|
45
37
|
expect(new_body).to eq <<~MARKDOWN
|
46
38
|
b
|
47
39
|
MARKDOWN
|
48
40
|
}
|
49
41
|
end
|
50
|
-
|
51
|
-
context "with git_config template" do
|
52
|
-
before {
|
53
|
-
expect(self).to receive(:git_config).with("template") { "spec/fixtures/file/template_2.erb" }
|
54
|
-
}
|
55
|
-
|
56
|
-
it {
|
57
|
-
pr_title, new_body = build_pr_title_and_body(@release_pr, @merged_prs, @changed_files)
|
58
|
-
expect(pr_title).to eq "c"
|
59
|
-
expect(new_body).to eq <<~MARKDOWN
|
60
|
-
d
|
61
|
-
MARKDOWN
|
62
|
-
}
|
63
|
-
end
|
64
42
|
end
|
65
43
|
|
66
44
|
describe "#dump_result_as_json" do
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-pr-release
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- motemen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: octokit
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
description: git-pr-release creates a pull request which summarizes feature branches
|
98
112
|
that are to be released into production
|
99
113
|
email:
|
@@ -124,6 +138,7 @@ files:
|
|
124
138
|
- spec/fixtures/file/pr_6.yml
|
125
139
|
- spec/fixtures/file/template_1.erb
|
126
140
|
- spec/fixtures/file/template_2.erb
|
141
|
+
- spec/git/pr/release/cli_spec.rb
|
127
142
|
- spec/git/pr/release_spec.rb
|
128
143
|
- spec/spec_helper.rb
|
129
144
|
- spec/support/capture_support.rb
|
@@ -147,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
162
|
- !ruby/object:Gem::Version
|
148
163
|
version: '0'
|
149
164
|
requirements: []
|
150
|
-
rubygems_version: 3.
|
165
|
+
rubygems_version: 3.1.2
|
151
166
|
signing_key:
|
152
167
|
specification_version: 4
|
153
168
|
summary: Creates a release pull request
|
@@ -159,6 +174,7 @@ test_files:
|
|
159
174
|
- spec/fixtures/file/pr_6.yml
|
160
175
|
- spec/fixtures/file/template_1.erb
|
161
176
|
- spec/fixtures/file/template_2.erb
|
177
|
+
- spec/git/pr/release/cli_spec.rb
|
162
178
|
- spec/git/pr/release_spec.rb
|
163
179
|
- spec/spec_helper.rb
|
164
180
|
- spec/support/capture_support.rb
|