multi_repo 0.4.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yaml +3 -1
- data/CHANGELOG.md +25 -1
- data/lib/multi_repo/service/git.rb +11 -0
- data/lib/multi_repo/service/github.rb +71 -0
- data/lib/multi_repo/version.rb +1 -1
- data/multi_repo.gemspec +1 -0
- data/renovate.json +2 -3
- data/scripts/destroy_remote +1 -5
- data/scripts/pull_request_labeler +17 -38
- data/scripts/pull_request_merger +16 -38
- data/scripts/show_commit_history +6 -1
- metadata +17 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfc3d56275cbe25e40cecabf411913805b1a83f59395ac0bf721b52130bc1795
|
4
|
+
data.tar.gz: b10b82500c86b84030488e687e86bfed2283b83de8911092211dae510c8eb22b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 551aad598181333a741eeb5ab881642f8e455645acb9eea1870494c3f5ce83d5d7a2e7fcbfaf1fa797e652ac8a4c3513907b211db4c5d37560e229bb62c40064
|
7
|
+
data.tar.gz: 352099fa70f24b0bd5ecd5493fc7d62dd9ec3c2eb6cdad3b7dde9bef8803b69d1532e303dfe8e37b27a007f9b298a61b515437413e492b21e70eb0bf3eb25c83
|
data/.github/workflows/ci.yaml
CHANGED
@@ -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@
|
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.
|
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
|
|
data/lib/multi_repo/version.rb
CHANGED
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
data/scripts/destroy_remote
CHANGED
@@ -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
|
13
|
-
opt :add, "Labels to add", :type => :strings
|
14
|
-
opt :remove, "Labels to remove", :type => :strings
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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[:
|
53
|
-
puts MultiRepo::CLI.header(pr)
|
30
|
+
github = MultiRepo::Service::Github.new(:dry_run => opts[:dry_run])
|
54
31
|
|
55
|
-
|
32
|
+
prs.each do |repo_name, pr_number|
|
33
|
+
puts MultiRepo::CLI.header("#{repo_name}##{pr_number}")
|
56
34
|
|
57
|
-
|
58
|
-
|
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
|
data/scripts/pull_request_merger
CHANGED
@@ -16,50 +16,28 @@ opts = Optimist.options do
|
|
16
16
|
MultiRepo::CLI.common_options(self)
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
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
|
-
|
47
|
-
|
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
|
-
|
56
|
-
|
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
|
-
|
36
|
+
puts "** WARN: Pull Request is not mergeable".light_yellow
|
37
|
+
end
|
59
38
|
|
60
|
-
|
61
|
-
|
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
|
data/scripts/show_commit_history
CHANGED
@@ -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 =
|
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
|
+
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:
|
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.
|
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.
|