multi_repo 0.4.0 → 0.5.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: bc809429c529e0f58d2274708e0785944edf7170ce7aa23858fc88031bb593e1
4
- data.tar.gz: 7d58ebc46fe2202b9e2e285e6a26fc4b4a40556181301a651994d41b9e4c1d5f
3
+ metadata.gz: 8505baba7399c81174faea1dcce56eb3d16687d1c08c88ac1fe18c2eeae6f26a
4
+ data.tar.gz: d513358adc717ca4582c6f29864926a0a23bfb01a88a0622b55ff358939f7d35
5
5
  SHA512:
6
- metadata.gz: 4828418ee29894ce72fd5d2ab2e705b99854f1aa5ba26f321a0235bfa7c7eadf45a5aada881897aa5df16fb6f83cdd1968113af80e0163d2a13a9e4dd354ee2d
7
- data.tar.gz: b4b2ed2d3c9677e658ad4c60ec615779882dee381bc5ed4b771602d56ca0a5b72ade124e140d50568a359c5e838d99ce3c51a8a475925a096d0582b7adc0cf9e
6
+ metadata.gz: 86f552f73954d01bbf06b31906170399eee68a60721538743dd5fdf2ce46832e918c89740d49e83c337a150f52dc9f8be3f73d0cb37f459fab3dcf317e244366
7
+ data.tar.gz: 86846ee0c472f5eb5b8ebade9bdafa87985db8ab114e210b6b0aa276e36466a56412260a6e503cc436dc874893f13baa140733542088816bae034c40ce7e3e5d
@@ -14,6 +14,8 @@ jobs:
14
14
  ruby-version:
15
15
  - '3.0'
16
16
  - '3.1'
17
+ - '3.2'
18
+ - '3.3'
17
19
  env:
18
20
  CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
19
21
  steps:
@@ -29,4 +31,4 @@ jobs:
29
31
  - name: Report code coverage
30
32
  if: ${{ github.ref == 'refs/heads/master' && matrix.ruby-version == '3.1' }}
31
33
  continue-on-error: true
32
- uses: paambaati/codeclimate-action@v5
34
+ uses: paambaati/codeclimate-action@v9
data/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.5.0] - 2024-11-12
8
+ ### Added
9
+ - [pull_request_labeler] Add ability to also add a comment about why the labels are changing [[#30](https://github.com/ManageIQ/multi_repo/pull/30)]
10
+ - [pull_request_labeler] Add normalization of PR formats to org/repo#pr format [[#30](https://github.com/ManageIQ/multi_repo/pull/30)]
11
+ - [pull_request_merger] Add URL support to pull_request_merger [[#37](https://github.com/ManageIQ/multi_repo/pull/37)]
12
+ - [Git Service, GitHub service] Move helper methods into services [[#31](https://github.com/ManageIQ/multi_repo/pull/31)]
13
+ - Add testing with ruby 3.2, 3.3 [[#35](https://github.com/ManageIQ/multi_repo/pull/35)]
14
+
15
+ ### Changed
16
+ - [pull_request_labeler] Make add and remove optional [[#30](https://github.com/ManageIQ/multi_repo/pull/30)]
17
+
18
+ ### Fixed
19
+ - [pull_request_labeler] Fix cli description of --prs [[#30](https://github.com/ManageIQ/multi_repo/pull/30)]
20
+ - [show_commit_history] Handle issue where PR may not be found [[#36](https://github.com/ManageIQ/multi_repo/pull/30)]
21
+
7
22
  ## [0.4.0] - 2024-03-29
8
23
  ### Changed
9
24
  - Allow overriding the path for a repo [[#28](https://github.com/ManageIQ/multi_repo/pull/28)]
@@ -18,6 +33,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
18
33
  - [show_commit_history] Prevent missing ranges from failing the entire run [[#20](https://github.com/ManageIQ/multi_repo/pull/20)]
19
34
  - [pull_request_merger] Fixing issue passing kwargs on Ruby 3 [[#23](https://github.com/ManageIQ/multi_repo/pull/23)]
20
35
 
21
- [Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v0.4.0...HEAD
36
+ [Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v0.5.0...HEAD
37
+ [0.5.0]: https://github.com/ManageIQ/more_core_extensions/compare/v0.4.0...v0.5.0
22
38
  [0.4.0]: https://github.com/ManageIQ/more_core_extensions/compare/v0.3.1...v0.4.0
23
39
  [0.3.1]: https://github.com/ManageIQ/more_core_extensions/compare/v0.3.0...v0.3.1
@@ -83,6 +83,17 @@ module MultiRepo::Service
83
83
  true
84
84
  end
85
85
 
86
+ def destroy_remote(remote)
87
+ if dry_run
88
+ puts "** dry-run: git remote rm #{remote}".light_black
89
+ else
90
+ client.remote("rm", remote)
91
+ end
92
+ rescue MiniGit::GitError
93
+ # Ignore missing remotes because we want them destroyed anyway
94
+ nil
95
+ end
96
+
86
97
  def remote_branch?(remote, branch)
87
98
  client.capturing.ls_remote(remote, branch).present?
88
99
  end
@@ -83,6 +83,24 @@ module MultiRepo::Service
83
83
  client.workflows(repo_name)[:workflows].select { |w| w.state == "disabled_inactivity" }
84
84
  end
85
85
 
86
+ PR_REGEX = %r{^([^/#]+/[^/#]+)#(\d+)$}
87
+
88
+ # Parse a list of PRs that are in URL or org/repo#pr format into a Array of
89
+ # [repo_name, pr_number] entries.
90
+ def self.parse_prs(*prs)
91
+ prs.flatten.map do |pr|
92
+ # Normalize to org/repo#pr
93
+ normalized_pr = pr.sub("https://github.com/", "").sub("/pull/", "#")
94
+
95
+ if (match = PR_REGEX.match(normalized_pr))
96
+ repo_name, pr_number = match.captures
97
+ [repo_name, pr_number.to_i]
98
+ else
99
+ raise ArgumentError, "Invalid PR '#{pr}'. PR must be a GitHub URL or in org/repo#pr format."
100
+ end
101
+ end
102
+ end
103
+
86
104
  attr_reader :dry_run
87
105
 
88
106
  def initialize(dry_run: false)
@@ -138,6 +156,44 @@ module MultiRepo::Service
138
156
  end
139
157
  end
140
158
 
159
+ def add_labels_to_an_issue(repo_name, issue_number, labels)
160
+ labels = Array(labels)
161
+ if dry_run
162
+ puts "** dry-run: github.add_labels_to_an_issue(#{repo_name.inspect}, #{issue_number.inspect}, #{labels.inspect})".light_black
163
+ else
164
+ client.add_labels_to_an_issue(repo_name, issue_number, labels)
165
+ end
166
+ end
167
+
168
+ def remove_labels_from_an_issue(repo_name, issue_number, labels)
169
+ Array(labels).each do |label|
170
+ if dry_run
171
+ puts "** dry-run: github.remove_label(#{repo_name.inspect}, #{issue_number.inspect}, #{label.inspect})".light_black
172
+ else
173
+ client.remove_label(repo_name, issue_number, label)
174
+ end
175
+ rescue Octokit::NotFound
176
+ # Ignore labels that are not found, because we want them removed anyway
177
+ end
178
+ end
179
+
180
+ def add_comment(repo_name, issue_number, body)
181
+ if dry_run
182
+ puts "** dry-run: github.add_comment(#{repo_name.inspect}, #{issue_number.inspect}, #{body.pretty_inspect.chomp})".light_black
183
+ else
184
+ client.add_comment(repo_name, issue_number, body)
185
+ end
186
+ end
187
+
188
+ def assign_user(repo_name, issue_number, assignee)
189
+ assignee = assignee[1..] if assignee.start_with?("@")
190
+ if dry_run
191
+ puts "** dry-run: github.update_issue(#{repo_name.inspect}, #{issue_number.inspect}, \"assignee\" => #{assignee.inspect})".light_black
192
+ else
193
+ client.update_issue(repo_name, issue_number, "assignee" => assignee)
194
+ end
195
+ end
196
+
141
197
  def create_milestone(repo_name, title, due_on)
142
198
  if dry_run
143
199
  puts "** dry-run: github.create_milestone(#{repo_name.inspect}, #{title.inspect}, :due_on => #{due_on.strftime("%Y-%m-%d").inspect})".light_black
@@ -208,6 +264,14 @@ module MultiRepo::Service
208
264
  end
209
265
  end
210
266
 
267
+ def merge_pull_request(repo_name, pr_number)
268
+ if dry_run
269
+ puts "** dry-run: github.merge_pull_request(#{repo_name.inspect}, #{pr_number.inspect})".light_black
270
+ else
271
+ client.merge_pull_request(repo_name, pr_number)
272
+ end
273
+ end
274
+
211
275
  def create_or_update_repository_secret(repo_name, key, value)
212
276
  payload = encode_secret(repo_name, value)
213
277
 
@@ -1,3 +1,3 @@
1
1
  module MultiRepo
2
- VERSION = "0.4.0".freeze
2
+ VERSION = "0.5.0".freeze
3
3
  end
@@ -20,9 +20,5 @@ MultiRepo::CLI.each_repo(**opts) do |repo|
20
20
  next
21
21
  end
22
22
 
23
- if opts[:dry_run]
24
- puts "** dry-run: git remote rm #{opts[:remote]}".light_black
25
- else
26
- repo.git.client.remote("rm", opts[:remote])
27
- end
23
+ repo.git.destroy_remote(opts[:remote])
28
24
  end
@@ -9,53 +9,32 @@ end
9
9
  opts = Optimist.options do
10
10
  synopsis "Add or remove labels on a set of pull requests."
11
11
 
12
- opt :prs, "The list of PRs to merge", :type => :strings, :required => true
13
- opt :add, "Labels to add", :type => :strings, :required => true
14
- opt :remove, "Labels to remove", :type => :strings, :required => true
12
+ opt :prs, "The list of PRs to label", :type => :strings, :required => true
13
+ opt :add, "Labels to add", :type => :strings
14
+ opt :remove, "Labels to remove", :type => :strings
15
15
 
16
- MultiRepo::CLI.common_options(self, :only => :dry_run)
17
- end
18
-
19
- # TODO: Normalize any PR format to `org/repo#pr`
20
- PR_REGEX = %r{^([^/#]+/[^/#]+)#([^/#]+)$}
21
- Optimist.die :prs, "must be in the form `org/repo#pr`" unless opts[:prs].all? { |pr| pr.match?(PR_REGEX) }
22
-
23
- def github
24
- MultiRepo::Service::Github.client
25
- end
16
+ opt :comment, "Comment explaining the label change", :type => :string
26
17
 
27
- def add_labels(repo_name, pr_number, labels:, dry_run:, **_)
28
- labels = Array(labels)
29
- if dry_run
30
- puts "** dry-run: github.add_labels_to_an_issue(#{repo_name.inspect}, #{pr_number.inspect}, #{labels.inspect})".light_black
31
- else
32
- github.add_labels_to_an_issue(repo_name, pr_number, labels)
33
- end
18
+ MultiRepo::CLI.common_options(self, :only => :dry_run)
34
19
  end
35
20
 
36
- def remove_labels(repo_name, pr_number, labels:, dry_run:, **_)
37
- Array(labels).each do |label|
38
- remove_label(repo_name, pr_number, label: label, dry_run: dry_run)
39
- end
40
- end
21
+ Optimist.die "at least one of --add or --remove is required" unless opts[:add_given] || opts[:remove_given]
41
22
 
42
- def remove_label(repo_name, pr_number, label:, dry_run:, **_)
43
- if dry_run
44
- puts "** dry-run: github.remove_label(#{repo_name.inspect}, #{pr_number.inspect}, #{label.inspect})".light_black
45
- else
46
- github.remove_label(repo_name, pr_number, label)
23
+ prs =
24
+ begin
25
+ MultiRepo::Service::Github.parse_prs(opts[:prs])
26
+ rescue ArgumentError => err
27
+ Optimist.die :prs, err.message
47
28
  end
48
- rescue Octokit::NotFound
49
- # Ignore labels that are not found, because we want them removed anyway
50
- end
51
29
 
52
- opts[:prs].each do |pr|
53
- puts MultiRepo::CLI.header(pr)
30
+ github = MultiRepo::Service::Github.new(:dry_run => opts[:dry_run])
54
31
 
55
- repo_name, pr_number = PR_REGEX.match(pr).captures
32
+ prs.each do |repo_name, pr_number|
33
+ puts MultiRepo::CLI.header("#{repo_name}##{pr_number}")
56
34
 
57
- add_labels(repo_name, pr_number, labels: opts[:add], **opts)
58
- remove_labels(repo_name, pr_number, labels: opts[:remove], **opts)
35
+ github.add_labels_to_an_issue(repo_name, pr_number, opts[:add]) if opts[:add].present?
36
+ github.remove_labels_from_an_issue(repo_name, pr_number, opts[:remove]) if opts[:remove].present?
37
+ github.add_comment(repo_name, pr_number, opts[:comment]) if opts[:comment].present?
59
38
 
60
39
  puts
61
40
  end
@@ -16,50 +16,28 @@ opts = Optimist.options do
16
16
  MultiRepo::CLI.common_options(self)
17
17
  end
18
18
 
19
- # TODO: Normalize any PR format to `org/repo#pr`
20
- PR_REGEX = %r{^([^/#]+/[^/#]+)#([^/#]+)$}
21
- Optimist.die :prs, "must be in the form `org/repo#pr`" unless opts[:prs].all? { |pr| pr.match?(PR_REGEX) }
22
-
23
- def merge_pull_request(repo_name, pr_number, dry_run:, **_)
24
- if dry_run
25
- puts "** dry-run: github.merge_pull_request(#{repo_name.inspect}, #{pr_number.inspect})".light_black
26
- else
27
- begin
28
- MultiRepo::Service::Github.client.merge_pull_request(repo_name, pr_number)
29
- rescue Octokit::MethodNotAllowed => err
30
- raise unless err.to_s.include?("Pull Request is not mergeable")
31
-
32
- puts "** WARN: Pull Request is not mergeable"
33
- end
19
+ prs =
20
+ begin
21
+ MultiRepo::Service::Github.parse_prs(opts[:prs])
22
+ rescue ArgumentError => err
23
+ Optimist.die :prs, err.message
34
24
  end
35
- end
36
25
 
37
- def add_labels(repo_name, pr_number, labels:, dry_run:, **_)
38
- labels = Array(labels)
39
- if dry_run
40
- puts "** dry-run: github.add_labels_to_an_issue(#{repo_name.inspect}, #{pr_number.inspect}, #{labels.inspect})".light_black
41
- else
42
- MultiRepo::Service::Github.client.add_labels_to_an_issue(repo_name, pr_number, labels)
43
- end
44
- end
26
+ github = MultiRepo::Service::Github.new(:dry_run => opts[:dry_run])
45
27
 
46
- def assign_user(repo_name, pr_number, assignee:, dry_run:, **_)
47
- assignee = assignee[1..] if assignee.start_with?("@")
48
- if dry_run
49
- puts "** dry-run: github.update_issue(#{repo_name.inspect}, #{pr_number.inspect}, \"assignee\" => #{assignee.inspect})".light_black
50
- else
51
- MultiRepo::Service::Github.client.update_issue(repo_name, pr_number, "assignee" => assignee)
52
- end
53
- end
28
+ prs.each do |repo_name, pr_number|
29
+ puts MultiRepo::CLI.header("#{repo_name}##{pr_number}")
54
30
 
55
- opts[:prs].each do |pr|
56
- puts MultiRepo::CLI.header(pr)
31
+ begin
32
+ github.merge_pull_request(repo_name, pr_number)
33
+ rescue Octokit::MethodNotAllowed => err
34
+ raise unless err.to_s.include?("Pull Request is not mergeable")
57
35
 
58
- repo_name, pr_number = PR_REGEX.match(pr).captures
36
+ puts "** WARN: Pull Request is not mergeable".light_yellow
37
+ end
59
38
 
60
- merge_pull_request(repo_name, pr_number, **opts)
61
- add_labels(repo_name, pr_number, **opts) if opts[:labels].present?
62
- assign_user(repo_name, pr_number, **opts)
39
+ github.add_labels_to_an_issue(repo_name, pr_number, opts[:labels]) if opts[:labels].present?
40
+ github.assign_user(repo_name, pr_number, opts[:assignee])
63
41
 
64
42
  puts
65
43
  end
@@ -60,7 +60,12 @@ MultiRepo::CLI.repos_for(**opts).each do |repo|
60
60
  log.lines.each do |line|
61
61
  next unless (match = line.match(/Merge pull request #(\d+)\b/))
62
62
 
63
- pr = github.pull_request(repo.name, match[1])
63
+ pr =
64
+ begin
65
+ github.pull_request(repo.name, match[1])
66
+ rescue Octokit::NotFound
67
+ next # PR not found could mean this was a cherry-pick from a different repo, so the PR doesn't exist.
68
+ end
64
69
  label = pr.labels.detect { |l| results.key?(l.name) }&.name || "other"
65
70
  results[label] << pr
66
71
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi_repo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ManageIQ Authors
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-29 00:00:00.000000000 Z
11
+ date: 2024-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -360,7 +360,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
360
360
  - !ruby/object:Gem::Version
361
361
  version: '0'
362
362
  requirements: []
363
- rubygems_version: 3.3.26
363
+ rubygems_version: 3.3.27
364
364
  signing_key:
365
365
  specification_version: 4
366
366
  summary: MultiRepo is a library for managing multiple repositiories and running scripts