multi_repo 0.4.0 → 0.5.1

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: bfc3d56275cbe25e40cecabf411913805b1a83f59395ac0bf721b52130bc1795
4
+ data.tar.gz: b10b82500c86b84030488e687e86bfed2283b83de8911092211dae510c8eb22b
5
5
  SHA512:
6
- metadata.gz: 4828418ee29894ce72fd5d2ab2e705b99854f1aa5ba26f321a0235bfa7c7eadf45a5aada881897aa5df16fb6f83cdd1968113af80e0163d2a13a9e4dd354ee2d
7
- data.tar.gz: b4b2ed2d3c9677e658ad4c60ec615779882dee381bc5ed4b771602d56ca0a5b72ade124e140d50568a359c5e838d99ce3c51a8a475925a096d0582b7adc0cf9e
6
+ metadata.gz: 551aad598181333a741eeb5ab881642f8e455645acb9eea1870494c3f5ce83d5d7a2e7fcbfaf1fa797e652ac8a4c3513907b211db4c5d37560e229bb62c40064
7
+ data.tar.gz: 352099fa70f24b0bd5ecd5493fc7d62dd9ec3c2eb6cdad3b7dde9bef8803b69d1532e303dfe8e37b27a007f9b298a61b515437413e492b21e70eb0bf3eb25c83
@@ -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,28 @@ This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.5.1] - 2025-02-20
8
+ ### Added
9
+ - Add debugging of octokit request/response if DEBUG env var set [[#38](https://github.com/ManageIQ/multi_repo/pull/38)]
10
+
11
+ ### Fixed
12
+ - Pin json gem to 2.9.1 since 2.10.0+ is broken [[#41](https://github.com/ManageIQ/multi_repo/pull/41)]
13
+
14
+ ## [0.5.0] - 2024-11-12
15
+ ### Added
16
+ - [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)]
17
+ - [pull_request_labeler] Add normalization of PR formats to org/repo#pr format [[#30](https://github.com/ManageIQ/multi_repo/pull/30)]
18
+ - [pull_request_merger] Add URL support to pull_request_merger [[#37](https://github.com/ManageIQ/multi_repo/pull/37)]
19
+ - [Git Service, GitHub service] Move helper methods into services [[#31](https://github.com/ManageIQ/multi_repo/pull/31)]
20
+ - Add testing with ruby 3.2, 3.3 [[#35](https://github.com/ManageIQ/multi_repo/pull/35)]
21
+
22
+ ### Changed
23
+ - [pull_request_labeler] Make add and remove optional [[#30](https://github.com/ManageIQ/multi_repo/pull/30)]
24
+
25
+ ### Fixed
26
+ - [pull_request_labeler] Fix cli description of --prs [[#30](https://github.com/ManageIQ/multi_repo/pull/30)]
27
+ - [show_commit_history] Handle issue where PR may not be found [[#36](https://github.com/ManageIQ/multi_repo/pull/30)]
28
+
7
29
  ## [0.4.0] - 2024-03-29
8
30
  ### Changed
9
31
  - Allow overriding the path for a repo [[#28](https://github.com/ManageIQ/multi_repo/pull/28)]
@@ -18,6 +40,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
18
40
  - [show_commit_history] Prevent missing ranges from failing the entire run [[#20](https://github.com/ManageIQ/multi_repo/pull/20)]
19
41
  - [pull_request_merger] Fixing issue passing kwargs on Ruby 3 [[#23](https://github.com/ManageIQ/multi_repo/pull/23)]
20
42
 
21
- [Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v0.4.0...HEAD
43
+ [Unreleased]: https://github.com/ManageIQ/more_core_extensions/compare/v0.5.1...HEAD
44
+ [0.5.1]: https://github.com/ManageIQ/more_core_extensions/compare/v0.5.0...v0.5.1
45
+ [0.5.0]: https://github.com/ManageIQ/more_core_extensions/compare/v0.4.0...v0.5.0
22
46
  [0.4.0]: https://github.com/ManageIQ/more_core_extensions/compare/v0.3.1...v0.4.0
23
47
  [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
@@ -29,6 +29,13 @@ module MultiRepo::Service
29
29
  }.compact
30
30
 
31
31
  require 'octokit'
32
+
33
+ if ENV["DEBUG"]
34
+ middleware = Octokit.middleware.dup
35
+ middleware.response :logger
36
+ Octokit.middleware = middleware
37
+ end
38
+
32
39
  Octokit::Client.new(params)
33
40
  end
34
41
  end
@@ -83,6 +90,24 @@ module MultiRepo::Service
83
90
  client.workflows(repo_name)[:workflows].select { |w| w.state == "disabled_inactivity" }
84
91
  end
85
92
 
93
+ PR_REGEX = %r{^([^/#]+/[^/#]+)#(\d+)$}
94
+
95
+ # Parse a list of PRs that are in URL or org/repo#pr format into a Array of
96
+ # [repo_name, pr_number] entries.
97
+ def self.parse_prs(*prs)
98
+ prs.flatten.map do |pr|
99
+ # Normalize to org/repo#pr
100
+ normalized_pr = pr.sub("https://github.com/", "").sub("/pull/", "#")
101
+
102
+ if (match = PR_REGEX.match(normalized_pr))
103
+ repo_name, pr_number = match.captures
104
+ [repo_name, pr_number.to_i]
105
+ else
106
+ raise ArgumentError, "Invalid PR '#{pr}'. PR must be a GitHub URL or in org/repo#pr format."
107
+ end
108
+ end
109
+ end
110
+
86
111
  attr_reader :dry_run
87
112
 
88
113
  def initialize(dry_run: false)
@@ -138,6 +163,44 @@ module MultiRepo::Service
138
163
  end
139
164
  end
140
165
 
166
+ def add_labels_to_an_issue(repo_name, issue_number, labels)
167
+ labels = Array(labels)
168
+ if dry_run
169
+ puts "** dry-run: github.add_labels_to_an_issue(#{repo_name.inspect}, #{issue_number.inspect}, #{labels.inspect})".light_black
170
+ else
171
+ client.add_labels_to_an_issue(repo_name, issue_number, labels)
172
+ end
173
+ end
174
+
175
+ def remove_labels_from_an_issue(repo_name, issue_number, labels)
176
+ Array(labels).each do |label|
177
+ if dry_run
178
+ puts "** dry-run: github.remove_label(#{repo_name.inspect}, #{issue_number.inspect}, #{label.inspect})".light_black
179
+ else
180
+ client.remove_label(repo_name, issue_number, label)
181
+ end
182
+ rescue Octokit::NotFound
183
+ # Ignore labels that are not found, because we want them removed anyway
184
+ end
185
+ end
186
+
187
+ def add_comment(repo_name, issue_number, body)
188
+ if dry_run
189
+ puts "** dry-run: github.add_comment(#{repo_name.inspect}, #{issue_number.inspect}, #{body.pretty_inspect.chomp})".light_black
190
+ else
191
+ client.add_comment(repo_name, issue_number, body)
192
+ end
193
+ end
194
+
195
+ def assign_user(repo_name, issue_number, assignee)
196
+ assignee = assignee[1..] if assignee.start_with?("@")
197
+ if dry_run
198
+ puts "** dry-run: github.update_issue(#{repo_name.inspect}, #{issue_number.inspect}, \"assignee\" => #{assignee.inspect})".light_black
199
+ else
200
+ client.update_issue(repo_name, issue_number, "assignee" => assignee)
201
+ end
202
+ end
203
+
141
204
  def create_milestone(repo_name, title, due_on)
142
205
  if dry_run
143
206
  puts "** dry-run: github.create_milestone(#{repo_name.inspect}, #{title.inspect}, :due_on => #{due_on.strftime("%Y-%m-%d").inspect})".light_black
@@ -208,6 +271,14 @@ module MultiRepo::Service
208
271
  end
209
272
  end
210
273
 
274
+ def merge_pull_request(repo_name, pr_number)
275
+ if dry_run
276
+ puts "** dry-run: github.merge_pull_request(#{repo_name.inspect}, #{pr_number.inspect})".light_black
277
+ else
278
+ client.merge_pull_request(repo_name, pr_number)
279
+ end
280
+ end
281
+
211
282
  def create_or_update_repository_secret(repo_name, key, value)
212
283
  payload = encode_secret(repo_name, value)
213
284
 
@@ -1,3 +1,3 @@
1
1
  module MultiRepo
2
- VERSION = "0.4.0".freeze
2
+ VERSION = "0.5.1".freeze
3
3
  end
data/multi_repo.gemspec CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_runtime_dependency "activesupport"
26
26
  spec.add_runtime_dependency "colorize"
27
27
  spec.add_runtime_dependency "config"
28
+ spec.add_runtime_dependency "json", "~> 2.9.1" # Pin json due to https://github.com/ruby/json/issues/752
28
29
  spec.add_runtime_dependency "licensee"
29
30
  spec.add_runtime_dependency "minigit"
30
31
  spec.add_runtime_dependency "more_core_extensions"
data/renovate.json CHANGED
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
- "extends": [
4
- "config:recommended"
5
- ]
3
+ "inheritConfig": true,
4
+ "inheritConfigRepoName": "manageiq/renovate-config"
6
5
  }
@@ -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,13 @@
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.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ManageIQ Authors
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-03-29 00:00:00.000000000 Z
10
+ date: 2025-02-20 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -52,6 +51,20 @@ dependencies:
52
51
  - - ">="
53
52
  - !ruby/object:Gem::Version
54
53
  version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: json
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 2.9.1
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 2.9.1
55
68
  - !ruby/object:Gem::Dependency
56
69
  name: licensee
57
70
  requirement: !ruby/object:Gem::Requirement
@@ -345,7 +358,6 @@ homepage: http://github.com/ManageIQ/multi_repo
345
358
  licenses:
346
359
  - MIT
347
360
  metadata: {}
348
- post_install_message:
349
361
  rdoc_options: []
350
362
  require_paths:
351
363
  - lib
@@ -360,8 +372,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
360
372
  - !ruby/object:Gem::Version
361
373
  version: '0'
362
374
  requirements: []
363
- rubygems_version: 3.3.26
364
- signing_key:
375
+ rubygems_version: 3.6.5
365
376
  specification_version: 4
366
377
  summary: MultiRepo is a library for managing multiple repositiories and running scripts
367
378
  against them.