multi_repo 1.0.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 +4 -4
- data/.github/workflows/ci.yaml +13 -12
- data/CHANGELOG.md +28 -2
- data/README.md +2 -3
- data/lib/multi_repo/cli.rb +6 -2
- data/lib/multi_repo/helpers/pull_request_blaster_outer.rb +45 -12
- data/lib/multi_repo/repo.rb +8 -0
- data/lib/multi_repo/service/artifactory.rb +14 -0
- data/lib/multi_repo/service/git.rb +11 -4
- data/lib/multi_repo/service/github.rb +6 -0
- data/lib/multi_repo/version.rb +1 -1
- data/lib/multi_repo.rb +0 -1
- data/multi_repo.gemspec +2 -2
- data/scripts/delete_labels +1 -1
- data/scripts/each_repo +4 -2
- data/scripts/pull_request_blaster_outer +16 -3
- data/scripts/show_commit_history +31 -20
- data/scripts/show_org_repos +4 -1
- metadata +7 -13
- data/.codeclimate.yml +0 -16
- data/.rubocop_cc.yml +0 -4
- data/lib/multi_repo/service/code_climate.rb +0 -119
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff97c5d89d0a12946bcfeedc113427407e9858f72f687cad2c6c133db1bb41b4
|
|
4
|
+
data.tar.gz: 12f0b8884470a4dd1430cdc1b4bb131f3f93e5957bf66c5400ffa67d3fdbce78
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e562d3f593d9b5f3481cc8d1aafdc67aa0c938bd266f2ab939d07ebdd8fde31dbebf26026760451fcb0127613f0f356bf9f03ee7d264851f8b77d0747882f385
|
|
7
|
+
data.tar.gz: 03b147b28464d5179423794d5e96ee42feb3b8edc586d0407d9560769ba42ece76d498090692bebac3d339948defd498fe9e2820fc8e39dc24b8318fa512f6f8
|
data/.github/workflows/ci.yaml
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
name: CI
|
|
2
|
-
|
|
3
2
|
on:
|
|
4
|
-
push:
|
|
5
3
|
pull_request:
|
|
4
|
+
push:
|
|
5
|
+
branches-ignore:
|
|
6
|
+
- dependabot/*
|
|
7
|
+
- renovate/*
|
|
6
8
|
schedule:
|
|
7
|
-
- cron:
|
|
8
|
-
|
|
9
|
+
- cron: 0 0 * * 0
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
concurrency:
|
|
12
|
+
group: "${{ github.workflow }}-${{ github.ref }}"
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
9
16
|
jobs:
|
|
10
17
|
ci:
|
|
11
18
|
runs-on: ubuntu-latest
|
|
@@ -16,19 +23,13 @@ jobs:
|
|
|
16
23
|
- '3.1'
|
|
17
24
|
- '3.2'
|
|
18
25
|
- '3.3'
|
|
19
|
-
env:
|
|
20
|
-
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
|
|
21
26
|
steps:
|
|
22
|
-
- uses: actions/checkout@
|
|
27
|
+
- uses: actions/checkout@v6
|
|
23
28
|
- name: Set up Ruby
|
|
24
29
|
uses: ruby/setup-ruby@v1
|
|
25
30
|
with:
|
|
26
|
-
ruby-version: ${{ matrix.ruby-version }}
|
|
31
|
+
ruby-version: "${{ matrix.ruby-version }}"
|
|
27
32
|
bundler-cache: true
|
|
28
33
|
timeout-minutes: 30
|
|
29
34
|
- name: Run tests
|
|
30
35
|
run: bundle exec rake
|
|
31
|
-
- name: Report code coverage
|
|
32
|
-
if: ${{ github.ref == 'refs/heads/master' && matrix.ruby-version == '3.1' }}
|
|
33
|
-
continue-on-error: true
|
|
34
|
-
uses: paambaati/codeclimate-action@v9
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,30 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.2.0] - 2026-04-14
|
|
8
|
+
### Added
|
|
9
|
+
- [Artifactory service] Add head and exists? methods [[#97](https://github.com/ManageIQ/multi_repo/pull/97)]
|
|
10
|
+
- [pull_request_blaster_outer] Add ability to override message in the script [[#70](https://github.com/ManageIQ/multi_repo/pull/70)]
|
|
11
|
+
- [pull_request_blaster_outer] Add ability to specify a different fork name [[#71](https://github.com/ManageIQ/multi_repo/pull/71)]
|
|
12
|
+
- [show_org_repos] Add options include_forks and include_archived [[#73](https://github.com/ManageIQ/multi_repo/pull/73)]
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- [Git service] Handle when tags move during a git fetch which would otherwise fail [[#75](https://github.com/ManageIQ/multi_repo/pull/75)]
|
|
16
|
+
- [each_repo] Fix each_repo when the script needs to bundle [[#72](https://github.com/ManageIQ/multi_repo/pull/72)]
|
|
17
|
+
- [delete_labels] Fix a constant problem [[#67](https://github.com/ManageIQ/multi_repo/pull/67)]
|
|
18
|
+
|
|
19
|
+
### Removed
|
|
20
|
+
- **BREAKING** Drop CodeClimate [[#74](https://github.com/ManageIQ/multi_repo/pull/74)]
|
|
21
|
+
|
|
22
|
+
## [1.1.0] - 2025-10-01
|
|
23
|
+
### Added
|
|
24
|
+
- [show_commit_history] Add pr-changelog display format [[#49](https://github.com/ManageIQ/multi_repo/pull/49)]
|
|
25
|
+
- [pull_request_blaster_outer] Prevent git show paging when using --force [[#53](https://github.com/ManageIQ/multi_repo/pull/53)]
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- Update licensee to at least 9.7.0 [[#54](https://github.com/ManageIQ/multi_repo/pull/54)]
|
|
29
|
+
- Separate progress bar options from creation of the progress bar [[#55](https://github.com/ManageIQ/multi_repo/pull/55)]
|
|
30
|
+
|
|
7
31
|
## [1.0.0] - 2025-04-24
|
|
8
32
|
### Added
|
|
9
33
|
- Allow blank overrides on the command line [[#46](https://github.com/ManageIQ/multi_repo/pull/46)]
|
|
@@ -35,7 +59,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
35
59
|
|
|
36
60
|
### Fixed
|
|
37
61
|
- [pull_request_labeler] Fix cli description of --prs [[#30](https://github.com/ManageIQ/multi_repo/pull/30)]
|
|
38
|
-
- [show_commit_history] Handle issue where PR may not be found [[#36](https://github.com/ManageIQ/multi_repo/pull/
|
|
62
|
+
- [show_commit_history] Handle issue where PR may not be found [[#36](https://github.com/ManageIQ/multi_repo/pull/36)]
|
|
39
63
|
|
|
40
64
|
## [0.4.0] - 2024-03-29
|
|
41
65
|
### Changed
|
|
@@ -51,7 +75,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
51
75
|
- [show_commit_history] Prevent missing ranges from failing the entire run [[#20](https://github.com/ManageIQ/multi_repo/pull/20)]
|
|
52
76
|
- [pull_request_merger] Fixing issue passing kwargs on Ruby 3 [[#23](https://github.com/ManageIQ/multi_repo/pull/23)]
|
|
53
77
|
|
|
54
|
-
[Unreleased]: https://github.com/ManageIQ/multi_repo/compare/v1.
|
|
78
|
+
[Unreleased]: https://github.com/ManageIQ/multi_repo/compare/v1.2.0...HEAD
|
|
79
|
+
[1.2.0]: https://github.com/ManageIQ/multi_repo/compare/v1.1.0...v1.2.0
|
|
80
|
+
[1.1.0]: https://github.com/ManageIQ/multi_repo/compare/v1.0.0...v1.1.0
|
|
55
81
|
[1.0.0]: https://github.com/ManageIQ/multi_repo/compare/v0.6.0...v1.0.0
|
|
56
82
|
[0.6.0]: https://github.com/ManageIQ/multi_repo/compare/v0.5.1...v0.6.0
|
|
57
83
|
[0.5.1]: https://github.com/ManageIQ/multi_repo/compare/v0.5.0...v0.5.1
|
data/README.md
CHANGED
|
@@ -4,7 +4,6 @@ MultiRepo is a tool for managing multiple git repositories.
|
|
|
4
4
|
|
|
5
5
|
[](http://badge.fury.io/rb/multi_repo)
|
|
6
6
|
[](https://github.com/ManageIQ/multi_repo/actions/workflows/ci.yaml)
|
|
7
|
-
[](https://codeclimate.com/github/ManageIQ/multi_repo)
|
|
8
7
|
|
|
9
8
|
## Installation
|
|
10
9
|
|
|
@@ -19,7 +18,7 @@ gem install multi_repo
|
|
|
19
18
|
Typical usage will be from single scripts. In order to keep each script manageable, it can be preferable to use bundler/inline to define the gems needed by that script. To do this, add the following to the top of the script:
|
|
20
19
|
|
|
21
20
|
```ruby
|
|
22
|
-
|
|
21
|
+
#!/usr/bin/env ruby
|
|
23
22
|
|
|
24
23
|
require "bundler/inline"
|
|
25
24
|
gemfile do
|
|
@@ -69,7 +68,7 @@ purposes
|
|
|
69
68
|
- Go to https://github.com/settings/tokens
|
|
70
69
|
- Choose "Generate New Token"
|
|
71
70
|
- Give the token a description
|
|
72
|
-
- At a
|
|
71
|
+
- At a minimum, choose "repo" for the permissions.
|
|
73
72
|
- Click "Generate Token"
|
|
74
73
|
- Copy the token given to you, and keep it in a safe location, as once you leave
|
|
75
74
|
the page, the token is no longer accessible
|
data/lib/multi_repo/cli.rb
CHANGED
|
@@ -84,11 +84,15 @@ module MultiRepo
|
|
|
84
84
|
|
|
85
85
|
def self.progress_bar(total = 100)
|
|
86
86
|
require "progressbar"
|
|
87
|
-
ProgressBar.create(
|
|
87
|
+
ProgressBar.create(progress_bar_options(total))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.progress_bar_options(total = 100)
|
|
91
|
+
{
|
|
88
92
|
:format => "%j%% |%B| %E",
|
|
89
93
|
:length => HEADER_SIZE,
|
|
90
94
|
:total => total
|
|
91
|
-
|
|
95
|
+
}
|
|
92
96
|
end
|
|
93
97
|
end
|
|
94
98
|
end
|
|
@@ -2,9 +2,9 @@ require 'pathname'
|
|
|
2
2
|
|
|
3
3
|
module MultiRepo::Helpers
|
|
4
4
|
class PullRequestBlasterOuter
|
|
5
|
-
attr_reader :repo, :base, :head, :script, :dry_run, :
|
|
5
|
+
attr_reader :repo, :base, :head, :script, :dry_run, :source_message, :source_title, :source_body, :force
|
|
6
6
|
|
|
7
|
-
def initialize(repo, base:, head:, script:, dry_run:, message:, title: nil, force: false, **)
|
|
7
|
+
def initialize(repo, base:, head:, script:, dry_run:, message:, title: nil, body: nil, force: false, **)
|
|
8
8
|
@repo = repo
|
|
9
9
|
@base = base
|
|
10
10
|
@head = head
|
|
@@ -14,9 +14,11 @@ module MultiRepo::Helpers
|
|
|
14
14
|
s.to_s
|
|
15
15
|
end
|
|
16
16
|
@dry_run = dry_run
|
|
17
|
-
@message = message
|
|
18
|
-
@title = (title || message)[0, 72]
|
|
19
17
|
@force = force
|
|
18
|
+
|
|
19
|
+
@source_message = message&.gsub("\\n", "\n")
|
|
20
|
+
@source_title = title
|
|
21
|
+
@source_body = body&.gsub("\\n", "\n")
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def blast
|
|
@@ -41,7 +43,14 @@ module MultiRepo::Helpers
|
|
|
41
43
|
puts
|
|
42
44
|
|
|
43
45
|
if dry_run
|
|
44
|
-
puts "** dry-run: Skipping opening pull request".light_black
|
|
46
|
+
puts "** dry-run: Skipping opening pull request. The pull request would look like:".light_black
|
|
47
|
+
puts
|
|
48
|
+
puts "Pull Request Title:".light_black
|
|
49
|
+
puts title.light_black
|
|
50
|
+
puts
|
|
51
|
+
puts "Pull Request Body:".light_black
|
|
52
|
+
puts body.light_black
|
|
53
|
+
|
|
45
54
|
result = "dry run".light_black
|
|
46
55
|
else
|
|
47
56
|
answer =
|
|
@@ -67,19 +76,31 @@ module MultiRepo::Helpers
|
|
|
67
76
|
|
|
68
77
|
private
|
|
69
78
|
|
|
79
|
+
attr_accessor :override_message
|
|
80
|
+
|
|
81
|
+
def message
|
|
82
|
+
override_message || source_message
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def title
|
|
86
|
+
source_title || message.lines.first.chomp[0, 72]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def body
|
|
90
|
+
source_body || message.lines.drop(1).join.strip
|
|
91
|
+
end
|
|
92
|
+
|
|
70
93
|
def github
|
|
71
94
|
@github ||= MultiRepo::Service::Github.new(dry_run: dry_run)
|
|
72
95
|
end
|
|
73
96
|
|
|
74
|
-
def forked?
|
|
75
|
-
|
|
76
|
-
# Ideally there would be a "forked from" field in the repo metadata, but there isn't.
|
|
77
|
-
github.client.repos(github.client.login, :type => "forks").any? { |m| m.name == repo.short_name }
|
|
97
|
+
def forked?(cache: true)
|
|
98
|
+
github.forks(cache: cache).any? { |f| f.name == repo.fork_short_name }
|
|
78
99
|
end
|
|
79
100
|
|
|
80
101
|
def fork_repo
|
|
81
102
|
github.client.fork(repo.name)
|
|
82
|
-
until forked?
|
|
103
|
+
until forked?(cache: false)
|
|
83
104
|
print "."
|
|
84
105
|
sleep 3
|
|
85
106
|
end
|
|
@@ -88,6 +109,10 @@ module MultiRepo::Helpers
|
|
|
88
109
|
def run_script
|
|
89
110
|
repo.chdir do
|
|
90
111
|
Bundler.with_unbundled_env do
|
|
112
|
+
# Ensure any previous override commit message is removed
|
|
113
|
+
FileUtils.rm_f(".git/COMMIT_EDITMSG")
|
|
114
|
+
self.override_message = nil
|
|
115
|
+
|
|
91
116
|
parts = []
|
|
92
117
|
parts << "GITHUB_REPO=#{repo.name}"
|
|
93
118
|
parts << "DRY_RUN=true" if dry_run
|
|
@@ -98,6 +123,10 @@ module MultiRepo::Helpers
|
|
|
98
123
|
puts "!! Script execution failed.".light_red
|
|
99
124
|
exit $?.exitstatus
|
|
100
125
|
end
|
|
126
|
+
|
|
127
|
+
if File.exist?(".git/COMMIT_EDITMSG")
|
|
128
|
+
self.override_message = File.read(".git/COMMIT_EDITMSG")
|
|
129
|
+
end
|
|
101
130
|
end
|
|
102
131
|
end
|
|
103
132
|
end
|
|
@@ -112,7 +141,11 @@ module MultiRepo::Helpers
|
|
|
112
141
|
end
|
|
113
142
|
|
|
114
143
|
def show_commit
|
|
115
|
-
|
|
144
|
+
if force
|
|
145
|
+
repo.git.raw("--no-pager", "show")
|
|
146
|
+
else
|
|
147
|
+
repo.git.client.show
|
|
148
|
+
end
|
|
116
149
|
end
|
|
117
150
|
|
|
118
151
|
def blast_remote
|
|
@@ -134,7 +167,7 @@ module MultiRepo::Helpers
|
|
|
134
167
|
end
|
|
135
168
|
|
|
136
169
|
def open_pull_request
|
|
137
|
-
pr = github.client.create_pull_request(repo.name, base, pr_head, title,
|
|
170
|
+
pr = github.client.create_pull_request(repo.name, base, pr_head, title, body)
|
|
138
171
|
pr.html_url
|
|
139
172
|
rescue => err
|
|
140
173
|
raise unless err.message.include?("A pull request already exists")
|
data/lib/multi_repo/repo.rb
CHANGED
|
@@ -27,6 +27,14 @@ module MultiRepo
|
|
|
27
27
|
name.split("/").last
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def fork_name
|
|
31
|
+
config.fork_name
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def fork_short_name
|
|
35
|
+
fork_name&.split("/")&.last || short_name
|
|
36
|
+
end
|
|
37
|
+
|
|
30
38
|
def write_file(file, content, **kwargs)
|
|
31
39
|
if dry_run
|
|
32
40
|
puts "** dry-run: Writing #{path.join(file).expand_path}".light_black
|
|
@@ -40,6 +40,18 @@ module MultiRepo::Service
|
|
|
40
40
|
request(:get, path, **kwargs)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
def head(path, **kwargs)
|
|
44
|
+
path = path.to_s
|
|
45
|
+
request(:head, path, **kwargs)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def exists?(path, **kwargs)
|
|
49
|
+
head(path, **kwargs)
|
|
50
|
+
true
|
|
51
|
+
rescue RestClient::NotFound
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
|
|
43
55
|
def list(folder, cache: @cache, **kwargs)
|
|
44
56
|
folder = folder.to_s
|
|
45
57
|
cache_file = "/tmp/artifactory-#{folder.tr("/", "_")}-#{Date.today}.txt"
|
|
@@ -94,6 +106,8 @@ module MultiRepo::Service
|
|
|
94
106
|
"Accept" => "application/json",
|
|
95
107
|
"Content-Type" => "application/json"
|
|
96
108
|
)
|
|
109
|
+
headers = headers.except("Accept") if verb == :head
|
|
110
|
+
|
|
97
111
|
path = File.join(self.class.api_endpoint, path)
|
|
98
112
|
|
|
99
113
|
puts "+ #{verb.to_s.upcase} #{path}".light_black if verbose
|
|
@@ -18,18 +18,21 @@ module MultiRepo::Service
|
|
|
18
18
|
retry
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def self.
|
|
21
|
+
def self.raw(*args, quiet: false)
|
|
22
22
|
require "minigit"
|
|
23
23
|
require "shellwords"
|
|
24
24
|
|
|
25
|
-
args = ["clone", clone_source, path]
|
|
26
25
|
command = Shellwords.join(["git", *args])
|
|
27
|
-
command << " &>/dev/null"
|
|
26
|
+
command << " &>/dev/null" if quiet && !ENV["GIT_DEBUG"]
|
|
28
27
|
puts "+ #{command}" if ENV["GIT_DEBUG"] # Matches the output of MiniGit
|
|
29
28
|
|
|
30
29
|
raise MiniGit::GitError.new(args, $?) unless system(command)
|
|
31
30
|
end
|
|
32
31
|
|
|
32
|
+
def self.clone(clone_source:, path:)
|
|
33
|
+
raw("clone", clone_source, path, quiet: true)
|
|
34
|
+
end
|
|
35
|
+
|
|
33
36
|
attr_reader :dry_run, :client
|
|
34
37
|
|
|
35
38
|
def initialize(path:, clone_source:, dry_run: false)
|
|
@@ -39,10 +42,14 @@ module MultiRepo::Service
|
|
|
39
42
|
@client = self.class.client(path: path, clone_source: clone_source)
|
|
40
43
|
end
|
|
41
44
|
|
|
45
|
+
def raw(*args)
|
|
46
|
+
Dir.chdir(client.git_dir) { self.class.raw(*args) }
|
|
47
|
+
end
|
|
48
|
+
|
|
42
49
|
def fetch(output: false)
|
|
43
50
|
client = output ? self.client : self.client.capturing
|
|
44
51
|
|
|
45
|
-
client.fetch(:all => true, :tags => true)
|
|
52
|
+
client.fetch(:all => true, :tags => true, :force => true)
|
|
46
53
|
end
|
|
47
54
|
|
|
48
55
|
def hard_checkout(branch, source = "origin/#{branch}", output: false)
|
|
@@ -90,6 +90,11 @@ module MultiRepo::Service
|
|
|
90
90
|
client.workflows(repo_name)[:workflows].select { |w| w.state == "disabled_inactivity" }
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
+
def self.forks(cache: true)
|
|
94
|
+
@forks = nil unless cache
|
|
95
|
+
@forks ||= client.repos(client.login, :type => "forks")
|
|
96
|
+
end
|
|
97
|
+
|
|
93
98
|
PR_REGEX = %r{^([^/#]+/[^/#]+)#(\d+)$}
|
|
94
99
|
|
|
95
100
|
# Parse a list of PRs that are in URL or org/repo#pr format into a Array of
|
|
@@ -125,6 +130,7 @@ module MultiRepo::Service
|
|
|
125
130
|
:team_member_names,
|
|
126
131
|
:team_ids_by_name,
|
|
127
132
|
:team_names,
|
|
133
|
+
:forks,
|
|
128
134
|
:disabled_workflows,
|
|
129
135
|
:to => :class
|
|
130
136
|
|
data/lib/multi_repo/version.rb
CHANGED
data/lib/multi_repo.rb
CHANGED
|
@@ -11,7 +11,6 @@ require 'multi_repo/repo'
|
|
|
11
11
|
require 'multi_repo/repo_set'
|
|
12
12
|
|
|
13
13
|
require 'multi_repo/service/artifactory'
|
|
14
|
-
require 'multi_repo/service/code_climate'
|
|
15
14
|
require 'multi_repo/service/docker'
|
|
16
15
|
require 'multi_repo/service/git'
|
|
17
16
|
require 'multi_repo/service/github'
|
data/multi_repo.gemspec
CHANGED
|
@@ -25,7 +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 "licensee"
|
|
28
|
+
spec.add_runtime_dependency "licensee", ">= 9.7.0"
|
|
29
29
|
spec.add_runtime_dependency "minigit"
|
|
30
30
|
spec.add_runtime_dependency "more_core_extensions"
|
|
31
31
|
spec.add_runtime_dependency "octokit", ">= 7.0.0"
|
|
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
|
|
|
36
36
|
spec.add_runtime_dependency "rest-client"
|
|
37
37
|
|
|
38
38
|
spec.add_development_dependency "bundler"
|
|
39
|
-
spec.add_development_dependency "manageiq-style"
|
|
39
|
+
spec.add_development_dependency "manageiq-style"
|
|
40
40
|
spec.add_development_dependency "rake"
|
|
41
41
|
spec.add_development_dependency "rspec", ">= 3.0"
|
|
42
42
|
spec.add_development_dependency "simplecov", ">= 0.21.2"
|
data/scripts/delete_labels
CHANGED
|
@@ -13,7 +13,7 @@ opts = Optimist.options do
|
|
|
13
13
|
|
|
14
14
|
MultiRepo::CLI.common_options(self, :repo_set_default => nil)
|
|
15
15
|
end
|
|
16
|
-
opts[:repo] = MultiRepo::
|
|
16
|
+
opts[:repo] = MultiRepo::Labels.all.keys.sort unless opts[:repo] || opts[:repo_set]
|
|
17
17
|
|
|
18
18
|
github = MultiRepo::Service::Github.new(dry_run: opts[:dry_run])
|
|
19
19
|
|
data/scripts/each_repo
CHANGED
|
@@ -19,7 +19,9 @@ MultiRepo::CLI.each_repo(**opts) do |repo|
|
|
|
19
19
|
repo.git.fetch
|
|
20
20
|
repo.git.hard_checkout(opts[:ref])
|
|
21
21
|
repo.chdir do
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
Bundler.with_unbundled_env do
|
|
23
|
+
puts "+ #{opts[:command]}".light_black
|
|
24
|
+
system(opts[:command])
|
|
25
|
+
end
|
|
24
26
|
end
|
|
25
27
|
end
|
|
@@ -14,12 +14,25 @@ opts = Optimist.options do
|
|
|
14
14
|
opt :base, "The target branch for the changes.", :type => :string, :required => true
|
|
15
15
|
opt :head, "The name of the branch to create on your fork.", :type => :string, :required => true
|
|
16
16
|
opt :script, "The path to the script that will update the desired files.", :type => :string, :required => true
|
|
17
|
-
opt :
|
|
18
|
-
opt :title, "The PR title for this change. (default is --message)", :type => :string
|
|
17
|
+
opt :force, "Force creation of the pull request without asking.", :default => false
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
see_below = "See \"Notes on commit messages\" section below."
|
|
20
|
+
opt :message, "The commit message for this change. #{see_below}", :type => :string, :required => true
|
|
21
|
+
opt :title, "The PR title for this change. #{see_below}", :type => :string
|
|
22
|
+
opt :body, "The PR body for this change. #{see_below}", :type => :string
|
|
21
23
|
|
|
22
24
|
MultiRepo::CLI.common_options(self)
|
|
25
|
+
opt :help, "Show this message" # Ensure help appears above the notes sections
|
|
26
|
+
|
|
27
|
+
banner ""
|
|
28
|
+
banner <<~EOS
|
|
29
|
+
Notes on commit messages:
|
|
30
|
+
* The --message and --body options can accept '\\n' characters to support multiline messages.
|
|
31
|
+
* In a script, you can override --message by writing the commit message contents to .git/COMMIT_EDITMSG.
|
|
32
|
+
* The --title will default to the first line of the message.
|
|
33
|
+
* The --body will default to the rest of the message.
|
|
34
|
+
* If you want to override the title or body, you can do so with the --title and --body options, respectively.
|
|
35
|
+
EOS
|
|
23
36
|
end
|
|
24
37
|
|
|
25
38
|
results = {}
|
data/scripts/show_commit_history
CHANGED
|
@@ -7,14 +7,15 @@ gemfile do
|
|
|
7
7
|
end
|
|
8
8
|
require "active_support/core_ext/object/blank"
|
|
9
9
|
require "active_support/core_ext/string/inflections"
|
|
10
|
+
require "more_core_extensions/core_ext/hash/deletes"
|
|
10
11
|
|
|
11
|
-
DISPLAY_FORMATS = %w[commit pr-title pr-label]
|
|
12
|
+
DISPLAY_FORMATS = %w[commit pr-title pr-label pr-changelog]
|
|
12
13
|
|
|
13
14
|
opts = Optimist.options do
|
|
14
15
|
synopsis "Show the git commit log between two refs for all git repos."
|
|
15
16
|
|
|
16
17
|
opt :from, "The commit log 'from' ref", :type => :string, :required => true
|
|
17
|
-
opt :to, "The commit log 'to' ref"
|
|
18
|
+
opt :to, "The commit log 'to' ref", :type => :string, :required => true
|
|
18
19
|
opt :display, "How to display the history. Valid values are: #{DISPLAY_FORMATS.join(", ")}", :default => "commit"
|
|
19
20
|
opt :summary, "Display a summary of the repos.", :default => false
|
|
20
21
|
|
|
@@ -33,30 +34,32 @@ repos_with_changes = []
|
|
|
33
34
|
MultiRepo::CLI.repos_for(**opts).each do |repo|
|
|
34
35
|
next if opts[:skip].include?(repo.name)
|
|
35
36
|
|
|
36
|
-
puts MultiRepo::CLI.header(repo.name)
|
|
37
|
+
puts MultiRepo::CLI.header(repo.name) unless opts[:display] == "pr-changelog"
|
|
37
38
|
repo.git.fetch(output: false)
|
|
38
39
|
|
|
39
40
|
case opts[:display]
|
|
40
|
-
when "pr-label", "pr-title"
|
|
41
|
+
when "pr-label", "pr-title", "pr-changelog"
|
|
41
42
|
github ||= MultiRepo::Service::Github.client
|
|
42
|
-
pr_label_display = opts[:display] == "pr-label"
|
|
43
43
|
|
|
44
44
|
results = {}
|
|
45
|
-
if
|
|
46
|
-
results["bug"] =
|
|
47
|
-
results["enhancement"] =
|
|
45
|
+
if %w[pr-label pr-changelog].include?(opts[:display])
|
|
46
|
+
results["bug"] = Set.new
|
|
47
|
+
results["enhancement"] = Set.new
|
|
48
48
|
end
|
|
49
|
-
results["other"] =
|
|
49
|
+
results["other"] = Set.new
|
|
50
50
|
|
|
51
51
|
log =
|
|
52
52
|
begin
|
|
53
53
|
repo.git.client.capturing.log({:oneline => true}, range)
|
|
54
54
|
rescue MiniGit::GitError
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
unless opts[:display] == "pr-changelog"
|
|
56
|
+
puts "ERROR: commit range not found.".light_red
|
|
57
|
+
puts
|
|
58
|
+
end
|
|
57
59
|
next
|
|
58
60
|
end
|
|
59
61
|
|
|
62
|
+
pr_index = {}
|
|
60
63
|
log.lines.each do |line|
|
|
61
64
|
next unless (match = line.match(/Merge pull request #(\d+)\b/))
|
|
62
65
|
|
|
@@ -66,23 +69,31 @@ MultiRepo::CLI.repos_for(**opts).each do |repo|
|
|
|
66
69
|
rescue Octokit::NotFound
|
|
67
70
|
next # PR not found could mean this was a cherry-pick from a different repo, so the PR doesn't exist.
|
|
68
71
|
end
|
|
72
|
+
|
|
73
|
+
pr_index[pr.number] = pr
|
|
69
74
|
label = pr.labels.detect { |l| results.key?(l.name) }&.name || "other"
|
|
70
|
-
results[label] << pr
|
|
75
|
+
results[label] << pr.number
|
|
71
76
|
end
|
|
77
|
+
results.delete_blanks
|
|
72
78
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
next if prs.blank?
|
|
77
|
-
changes_found = true
|
|
79
|
+
if results.present? && opts[:display] == "pr-changelog"
|
|
80
|
+
puts "\n## <i class=\"fa-brands fa-github\"></i> [#{repo.name}](https://github.com/#{repo.name}/compare/#{opts[:from]}...#{opts[:to]})"
|
|
81
|
+
end
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
results.each do |label, pr_numbers|
|
|
84
|
+
case opts[:display]
|
|
85
|
+
when "pr-label"
|
|
86
|
+
puts "\n## #{label.titleize}\n\n"
|
|
87
|
+
when "pr-changelog"
|
|
88
|
+
puts "\n### #{label.titleize}\n\n"
|
|
89
|
+
end
|
|
90
|
+
pr_numbers.each do |pr_number|
|
|
91
|
+
pr = pr_index[pr_number]
|
|
81
92
|
puts "* #{pr.title} [[##{pr.number}]](#{pr.html_url})"
|
|
82
93
|
end
|
|
83
94
|
end
|
|
84
95
|
|
|
85
|
-
repos_with_changes << repo if
|
|
96
|
+
repos_with_changes << repo if results.present?
|
|
86
97
|
when "commit"
|
|
87
98
|
output =
|
|
88
99
|
begin
|
data/scripts/show_org_repos
CHANGED
|
@@ -10,6 +10,9 @@ opts = Optimist.options do
|
|
|
10
10
|
synopsis "List all repos in an org."
|
|
11
11
|
|
|
12
12
|
opt :org, "The org to list the repos for", :type => :string, :required => true
|
|
13
|
+
|
|
14
|
+
opt :include_forks, "Include forked repos", :default => false
|
|
15
|
+
opt :include_archived, "Include archived repos", :default => false
|
|
13
16
|
end
|
|
14
17
|
|
|
15
|
-
puts MultiRepo::Service::Github.org_repo_names(opts[:org])
|
|
18
|
+
puts MultiRepo::Service::Github.org_repo_names(opts[:org], **opts.slice(:include_forks, :include_archived))
|
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: 1.
|
|
4
|
+
version: 1.2.0
|
|
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: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activesupport
|
|
@@ -58,14 +57,14 @@ dependencies:
|
|
|
58
57
|
requirements:
|
|
59
58
|
- - ">="
|
|
60
59
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
60
|
+
version: 9.7.0
|
|
62
61
|
type: :runtime
|
|
63
62
|
prerelease: false
|
|
64
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
64
|
requirements:
|
|
66
65
|
- - ">="
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
67
|
+
version: 9.7.0
|
|
69
68
|
- !ruby/object:Gem::Dependency
|
|
70
69
|
name: minigit
|
|
71
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -198,14 +197,14 @@ dependencies:
|
|
|
198
197
|
requirements:
|
|
199
198
|
- - ">="
|
|
200
199
|
- !ruby/object:Gem::Version
|
|
201
|
-
version:
|
|
200
|
+
version: '0'
|
|
202
201
|
type: :development
|
|
203
202
|
prerelease: false
|
|
204
203
|
version_requirements: !ruby/object:Gem::Requirement
|
|
205
204
|
requirements:
|
|
206
205
|
- - ">="
|
|
207
206
|
- !ruby/object:Gem::Version
|
|
208
|
-
version:
|
|
207
|
+
version: '0'
|
|
209
208
|
- !ruby/object:Gem::Dependency
|
|
210
209
|
name: rake
|
|
211
210
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -257,12 +256,10 @@ executables:
|
|
|
257
256
|
extensions: []
|
|
258
257
|
extra_rdoc_files: []
|
|
259
258
|
files:
|
|
260
|
-
- ".codeclimate.yml"
|
|
261
259
|
- ".github/workflows/ci.yaml"
|
|
262
260
|
- ".gitignore"
|
|
263
261
|
- ".rspec"
|
|
264
262
|
- ".rubocop.yml"
|
|
265
|
-
- ".rubocop_cc.yml"
|
|
266
263
|
- ".rubocop_local.yml"
|
|
267
264
|
- ".whitesource"
|
|
268
265
|
- CHANGELOG.md
|
|
@@ -287,7 +284,6 @@ files:
|
|
|
287
284
|
- lib/multi_repo/repo.rb
|
|
288
285
|
- lib/multi_repo/repo_set.rb
|
|
289
286
|
- lib/multi_repo/service/artifactory.rb
|
|
290
|
-
- lib/multi_repo/service/code_climate.rb
|
|
291
287
|
- lib/multi_repo/service/docker.rb
|
|
292
288
|
- lib/multi_repo/service/git.rb
|
|
293
289
|
- lib/multi_repo/service/git/minigit_capturing_patch.rb
|
|
@@ -330,7 +326,6 @@ homepage: http://github.com/ManageIQ/multi_repo
|
|
|
330
326
|
licenses:
|
|
331
327
|
- MIT
|
|
332
328
|
metadata: {}
|
|
333
|
-
post_install_message:
|
|
334
329
|
rdoc_options: []
|
|
335
330
|
require_paths:
|
|
336
331
|
- lib
|
|
@@ -345,8 +340,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
345
340
|
- !ruby/object:Gem::Version
|
|
346
341
|
version: '0'
|
|
347
342
|
requirements: []
|
|
348
|
-
rubygems_version:
|
|
349
|
-
signing_key:
|
|
343
|
+
rubygems_version: 4.0.7
|
|
350
344
|
specification_version: 4
|
|
351
345
|
summary: MultiRepo is a library for managing multiple repositiories and running scripts
|
|
352
346
|
against them.
|
data/.codeclimate.yml
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
prepare:
|
|
2
|
-
fetch:
|
|
3
|
-
- url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/.rubocop_base.yml
|
|
4
|
-
path: ".rubocop_base.yml"
|
|
5
|
-
- url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/.rubocop_cc_base.yml
|
|
6
|
-
path: ".rubocop_cc_base.yml"
|
|
7
|
-
- url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/styles/base.yml
|
|
8
|
-
path: styles/base.yml
|
|
9
|
-
- url: https://raw.githubusercontent.com/ManageIQ/manageiq-style/master/styles/cc_base.yml
|
|
10
|
-
path: styles/cc_base.yml
|
|
11
|
-
plugins:
|
|
12
|
-
rubocop:
|
|
13
|
-
enabled: true
|
|
14
|
-
config: ".rubocop_cc.yml"
|
|
15
|
-
channel: rubocop-1-56-3
|
|
16
|
-
version: '2'
|
data/.rubocop_cc.yml
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
module MultiRepo::Service
|
|
2
|
-
class CodeClimate
|
|
3
|
-
def self.api_token
|
|
4
|
-
@api_token ||= ENV["CODECLIMATE_API_TOKEN"]
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
def self.api_token=(token)
|
|
8
|
-
@api_token = token
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def self.badge_name
|
|
12
|
-
"Code Climate"
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.badge_details(repo)
|
|
16
|
-
{
|
|
17
|
-
"description" => badge_name,
|
|
18
|
-
"image" => "https://codeclimate.com/github/#{repo.name}.svg",
|
|
19
|
-
"url" => "https://codeclimate.com/github/#{repo.name}"
|
|
20
|
-
}
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def self.coverage_badge_name
|
|
24
|
-
"Test Coverage"
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def self.coverage_badge_details(repo)
|
|
28
|
-
{
|
|
29
|
-
"description" => coverage_badge_name,
|
|
30
|
-
"image" => "https://codeclimate.com/github/#{repo.name}/badges/coverage.svg",
|
|
31
|
-
"url" => "https://codeclimate.com/github/#{repo.name}/coverage"
|
|
32
|
-
}
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
attr_reader :repo, :dry_run
|
|
36
|
-
|
|
37
|
-
def initialize(repo, dry_run: false, **_)
|
|
38
|
-
@repo = repo
|
|
39
|
-
@dry_run = dry_run
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def save!
|
|
43
|
-
write_codeclimate_yaml
|
|
44
|
-
write_rubocop_yamls
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def enable
|
|
48
|
-
ensure_enabled
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def badge_details
|
|
52
|
-
self.class.badge_details(repo)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def coverage_badge_details
|
|
56
|
-
self.class.coverage_badge_details(repo)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def test_reporter_id
|
|
60
|
-
ensure_enabled
|
|
61
|
-
@response.dig("data", 0, "attributes", "test_reporter_id")
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def create_repo_secret
|
|
65
|
-
Github.new(dry_run: dry_run).create_or_update_repository_secret(repo.name, "CC_TEST_REPORTER_ID", test_reporter_id)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
private
|
|
69
|
-
|
|
70
|
-
def ensure_enabled
|
|
71
|
-
return if @enabled
|
|
72
|
-
|
|
73
|
-
require 'rest-client'
|
|
74
|
-
require 'json'
|
|
75
|
-
|
|
76
|
-
@response =
|
|
77
|
-
if dry_run
|
|
78
|
-
puts "** dry-run: RestClient.get(\"https://api.codeclimate.com/v1/repos?github_slug=#{repo.name}\", #{headers})".light_black
|
|
79
|
-
{"data" => [{"attributes" => {"badge_token" => "0123456789abdef01234", "test_reporter_id" => "0123456789abcedef0123456789abcedef0123456789abcedef0123456789abc"}}]}
|
|
80
|
-
else
|
|
81
|
-
JSON.parse(RestClient.get("https://api.codeclimate.com/v1/repos?github_slug=#{repo.name}", headers))
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
if @response["data"].empty?
|
|
85
|
-
payload = {"data" => {"type" => "repos", "attributes" => {"url" => "https://github.com/#{repo.name}"}}}.to_json
|
|
86
|
-
@response = JSON.parse(RestClient.post("https://api.codeclimate.com/v1/github/repos", payload, headers))
|
|
87
|
-
@response["data"] = [@response["data"]]
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
@enabled = true
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def headers
|
|
94
|
-
token = self.class.api_token
|
|
95
|
-
raise "Missing CodeClimate API Token" if token.nil?
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
:accept => "application/vnd.api+json",
|
|
99
|
-
:content_type => "application/vnd.api+json",
|
|
100
|
-
:authorization => "Token token=#{token}"
|
|
101
|
-
}
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def write_codeclimate_yaml
|
|
105
|
-
write_generator_file(".codeclimate.yml")
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def write_rubocop_yamls
|
|
109
|
-
%w[.rubocop.yml .rubocop_cc.yml .rubocop_local.yml].each do |file|
|
|
110
|
-
write_generator_file(file)
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def write_generator_file(file)
|
|
115
|
-
content = RestClient.get("https://raw.githubusercontent.com/ManageIQ/manageiq/master/lib/generators/manageiq/plugin/templates/#{file}").body
|
|
116
|
-
repo.write_file(file, content, dry_run: dry_run)
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|