git-pr-release 1.1.0 → 1.2.0

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
  SHA256:
3
- metadata.gz: 0ff787e6c979a6958c8be9e429eb7c089095a55fd20ac3ac497592564c9a9355
4
- data.tar.gz: 4db4523c50aa12ba8b7f51450197b6e00dc3560d40356cdfac035fa0a036d871
3
+ metadata.gz: c62affe0022fbc68eb4fb5d6f3ac2ad27c6bb37779c2977619ac7636bfed8340
4
+ data.tar.gz: 66793e7118f37575b3121ca87c5575322a1b7ec406e94c929165bce4698fdc4c
5
5
  SHA512:
6
- metadata.gz: ac75e33bbf1c2c8808ee0f22ebf397678401f12e384eae7042a82a5ec350ab3039f55a72d5d093da5242a5ee4a7d8bd892b717feca97f9deb58cc818039e98da
7
- data.tar.gz: f0e1566526389611d3e94da79fb74dd3df6495a2d5242866a69e796fe02ca3053cb1a70ffe226f34540d7b684c2f2d4ee25bd1b55cd10591e86d7315c68af16c
6
+ metadata.gz: 6b89116177f0b77ff0ac6aec85b123117cf1aedc84843581e88d84d54106a3cc2f5c400ad072976c4764691336947f6c036b8bc01454929f64dcb6bf0028a2b2
7
+ data.tar.gz: 3e31b988775f96af5f619f23cb28ce29a5096ad8a785b7e592f8241c40e0326c24abbd6ae50114934c53fda97fbc164477cdc52e97fb07cc690a633638895530
@@ -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)
@@ -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.1.0'
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
@@ -6,20 +6,14 @@ module Git
6
6
  module Release
7
7
  class CLI
8
8
  include Git::Pr::Release::Util
9
- extend Git::Pr::Release::Util
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
- Octokit.configure do |c|
18
- c.api_endpoint = "#{scheme}://#{host}/api/v3"
19
- c.web_endpoint = "#{scheme}://#{host}/"
20
- end
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
- production_branch = ENV.fetch('GIT_PR_RELEASE_BRANCH_PRODUCTION') { git_config('branch.production') } || 'master'
38
- staging_branch = ENV.fetch('GIT_PR_RELEASE_BRANCH_STAGING') { git_config('branch.staging') } || 'staging'
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
- client = Octokit::Client.new :access_token => obtain_token!
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
- ### Create a release PR
110
+ merged_prs
111
+ end
88
112
 
89
- say 'Searching for existing release pull requests...', :info
90
- found_release_pr = client.pull_requests(repository).find do |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
- # Fetch changed files of a release PR
96
- changed_files = pull_request_files(client, found_release_pr)
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
- if @dry_run
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( found_release_pr, merged_prs, changed_files ) if @json
106
- exit 0
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 = nil, nil
110
- release_pr = nil
140
+ update_release_pr(release_pr, pr_title, pr_body)
111
141
 
112
- if create_mode
113
- created_pr = client.create_pull_request(
114
- repository, production_branch, staging_branch, 'Preparing release pull request...', ''
115
- )
116
- unless created_pr
117
- say 'Failed to create a new pull request', :error
118
- exit 2
119
- end
120
- changed_files = pull_request_files(client, created_pr) # Refetch changed files from created_pr
121
- pr_title, pr_body = build_pr_title_and_body created_pr, merged_prs, changed_files
122
- release_pr = created_pr
123
- else
124
- pr_title, new_body = build_pr_title_and_body found_release_pr, merged_prs, changed_files
125
- pr_body = merge_pr_body(found_release_pr.body, new_body)
126
- release_pr = found_release_pr
127
- end
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
- updated_pull_request = client.update_pull_request(
169
+ client.update_pull_request(
133
170
  repository, release_pr.number, :title => pr_title, :body => pr_body
134
171
  )
135
172
 
136
- unless updated_pull_request
137
- say 'Failed to update a pull request', :error
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
- say "#{create_mode ? 'Created' : 'Updated'} pull request: #{updated_pull_request.rels[:html].href}", :notice
155
- dump_result_as_json( release_pr, merged_prs, changed_files ) if @json
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
@@ -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 = DEFAULT_PR_TEMPLATE
91
-
92
- if path = ENV.fetch('GIT_PR_RELEASE_TEMPLATE') { git_config('template') }
93
- template_path = File.join(git('rev-parse', '--show-toplevel').first.chomp, path)
94
- template = File.read(template_path)
95
- end
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
@@ -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 any options" do
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 ENV" do
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
@@ -1,6 +1,7 @@
1
1
  require "timecop"
2
2
  require "yaml"
3
3
  require "git/pr/release"
4
+ require "webmock/rspec"
4
5
 
5
6
  RSpec.configure do |config|
6
7
  config.expect_with :rspec do |expectations|
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.1.0
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-01-02 00:00:00.000000000 Z
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.0.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