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 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