multi_repo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +16 -0
- data/.github/workflows/ci.yaml +32 -0
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/.rubocop.yml +4 -0
- data/.rubocop_cc.yml +4 -0
- data/.rubocop_local.yml +0 -0
- data/.whitesource +3 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +90 -0
- data/Rakefile +6 -0
- data/bin/console +8 -0
- data/exe/multi_repo +29 -0
- data/lib/multi_repo/cli.rb +92 -0
- data/lib/multi_repo/helpers/git_mirror.rb +198 -0
- data/lib/multi_repo/helpers/license.rb +106 -0
- data/lib/multi_repo/helpers/pull_request_blaster_outer.rb +129 -0
- data/lib/multi_repo/helpers/readme_badges.rb +84 -0
- data/lib/multi_repo/helpers/rename_labels.rb +26 -0
- data/lib/multi_repo/helpers/update_branch_protection.rb +24 -0
- data/lib/multi_repo/helpers/update_labels.rb +34 -0
- data/lib/multi_repo/helpers/update_milestone.rb +33 -0
- data/lib/multi_repo/helpers/update_repo_settings.rb +23 -0
- data/lib/multi_repo/labels.rb +31 -0
- data/lib/multi_repo/repo.rb +56 -0
- data/lib/multi_repo/repo_set.rb +27 -0
- data/lib/multi_repo/service/artifactory.rb +122 -0
- data/lib/multi_repo/service/code_climate.rb +119 -0
- data/lib/multi_repo/service/docker.rb +178 -0
- data/lib/multi_repo/service/git/minigit_capturing_patch.rb +12 -0
- data/lib/multi_repo/service/git.rb +90 -0
- data/lib/multi_repo/service/github.rb +238 -0
- data/lib/multi_repo/service/rubygems_stub.rb +103 -0
- data/lib/multi_repo/service/travis.rb +68 -0
- data/lib/multi_repo/version.rb +3 -0
- data/lib/multi_repo.rb +44 -0
- data/multi_repo.gemspec +44 -0
- data/repos/.gitkeep +0 -0
- data/scripts/delete_labels +23 -0
- data/scripts/destroy_branch +23 -0
- data/scripts/destroy_remote +26 -0
- data/scripts/destroy_tag +31 -0
- data/scripts/each_repo +23 -0
- data/scripts/fetch_repos +18 -0
- data/scripts/git_mirror +9 -0
- data/scripts/github_rate_limit +10 -0
- data/scripts/hacktoberfest +138 -0
- data/scripts/make_alumni +50 -0
- data/scripts/new_rubygems_stub +17 -0
- data/scripts/pull_request_blaster_outer +24 -0
- data/scripts/pull_request_labeler +59 -0
- data/scripts/pull_request_merger +63 -0
- data/scripts/reenable_repo_workflows +33 -0
- data/scripts/rename_labels +22 -0
- data/scripts/restart_travis_builds +31 -0
- data/scripts/show_commit_history +86 -0
- data/scripts/show_org_members +19 -0
- data/scripts/show_org_repos +13 -0
- data/scripts/show_org_stats +82 -0
- data/scripts/show_project_cards +35 -0
- data/scripts/show_repo_set +13 -0
- data/scripts/show_tag +33 -0
- data/scripts/show_travis_status +63 -0
- data/scripts/update_branch_protection +22 -0
- data/scripts/update_labels +16 -0
- data/scripts/update_milestone +21 -0
- data/scripts/update_repo_settings +15 -0
- metadata +366 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :prs, "The list of PRs to merge", :type => :strings, :required => true
|
11
|
+
opt :add, "Labels to add", :type => :strings, :required => true
|
12
|
+
opt :remove, "Labels to remove", :type => :strings, :required => true
|
13
|
+
|
14
|
+
MultiRepo::CLI.common_options(self, :only => :dry_run)
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: Normalize any PR format to `org/repo#pr`
|
18
|
+
PR_REGEX = %r{^([^/#]+/[^/#]+)#([^/#]+)$}
|
19
|
+
Optimist.die :prs, "must be in the form `org/repo#pr`" unless opts[:prs].all? { |pr| pr.match?(PR_REGEX) }
|
20
|
+
|
21
|
+
def github
|
22
|
+
MultiRepo::Service::Github.client
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_labels(repo_name, pr_number, labels:, dry_run:, **_)
|
26
|
+
labels = Array(labels)
|
27
|
+
if dry_run
|
28
|
+
puts "** dry-run: github.add_labels_to_an_issue(#{repo_name.inspect}, #{pr_number.inspect}, #{labels.inspect})".light_black
|
29
|
+
else
|
30
|
+
github.add_labels_to_an_issue(repo_name, pr_number, labels)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def remove_labels(repo_name, pr_number, labels:, dry_run:, **_)
|
35
|
+
Array(labels).each do |label|
|
36
|
+
remove_label(repo_name, pr_number, label: label, dry_run: dry_run)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def remove_label(repo_name, pr_number, label:, dry_run:, **_)
|
41
|
+
if dry_run
|
42
|
+
puts "** dry-run: github.remove_label(#{repo_name.inspect}, #{pr_number.inspect}, #{label.inspect})".light_black
|
43
|
+
else
|
44
|
+
github.remove_label(repo_name, pr_number, label)
|
45
|
+
end
|
46
|
+
rescue Octokit::NotFound
|
47
|
+
# Ignore labels that are not found, because we want them removed anyway
|
48
|
+
end
|
49
|
+
|
50
|
+
opts[:prs].each do |pr|
|
51
|
+
puts MultiRepo::CLI.header(pr)
|
52
|
+
|
53
|
+
repo_name, pr_number = PR_REGEX.match(pr).captures
|
54
|
+
|
55
|
+
add_labels(repo_name, pr_number, labels: opts[:add], **opts)
|
56
|
+
remove_labels(repo_name, pr_number, labels: opts[:remove], **opts)
|
57
|
+
|
58
|
+
puts
|
59
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :prs, "The list of PRs to merge", :type => :strings, :required => true
|
11
|
+
opt :assignee, "GitHub user to assign when merging", :type => :string, :required => true
|
12
|
+
opt :labels, "Labels to apply when merging", :type => :strings
|
13
|
+
|
14
|
+
MultiRepo::CLI.common_options(self)
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: Normalize any PR format to `org/repo#pr`
|
18
|
+
PR_REGEX = %r{^([^/#]+/[^/#]+)#([^/#]+)$}
|
19
|
+
Optimist.die :prs, "must be in the form `org/repo#pr`" unless opts[:prs].all? { |pr| pr.match?(PR_REGEX) }
|
20
|
+
|
21
|
+
def merge_pull_request(repo_name, pr_number, dry_run:, **_)
|
22
|
+
if dry_run
|
23
|
+
puts "** dry-run: github.merge_pull_request(#{repo_name.inspect}, #{pr_number.inspect})".light_black
|
24
|
+
else
|
25
|
+
begin
|
26
|
+
MultiRepo::Service::Github.client.merge_pull_request(repo_name, pr_number)
|
27
|
+
rescue Octokit::MethodNotAllowed => err
|
28
|
+
raise unless err.to_s.include?("Pull Request is not mergeable")
|
29
|
+
|
30
|
+
puts "** WARN: Pull Request is not mergeable"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_labels(repo_name, pr_number, labels:, dry_run:, **_)
|
36
|
+
labels = Array(labels)
|
37
|
+
if dry_run
|
38
|
+
puts "** dry-run: github.add_labels_to_an_issue(#{repo_name.inspect}, #{pr_number.inspect}, #{labels.inspect})".light_black
|
39
|
+
else
|
40
|
+
MultiRepo::Service::Github.client.add_labels_to_an_issue(repo_name, pr_number, labels)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def assign_user(repo_name, pr_number, assignee:, dry_run:, **_)
|
45
|
+
assignee = assignee[1..] if assignee.start_with?("@")
|
46
|
+
if dry_run
|
47
|
+
puts "** dry-run: github.update_issue(#{repo_name.inspect}, #{pr_number.inspect}, \"assignee\" => #{assignee.inspect})".light_black
|
48
|
+
else
|
49
|
+
MultiRepo::Service::Github.client.update_issue(repo_name, pr_number, "assignee" => assignee)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
opts[:prs].each do |pr|
|
54
|
+
puts MultiRepo::CLI.header(pr)
|
55
|
+
|
56
|
+
repo_name, pr_number = PR_REGEX.match(pr).captures
|
57
|
+
|
58
|
+
merge_pull_request(repo_name, pr_number, opts)
|
59
|
+
add_labels(repo_name, pr_number, opts) if opts[:labels].present?
|
60
|
+
assign_user(repo_name, pr_number, opts)
|
61
|
+
|
62
|
+
puts
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :org, "The organization to reenable workflows in", :type => :string, :required => true
|
11
|
+
opt :extra_repos, "Extra repos to reenable workflows in", :type => :strings, :default => []
|
12
|
+
|
13
|
+
MultiRepo::CLI.common_options(self, :only => :dry_run)
|
14
|
+
ende
|
15
|
+
|
16
|
+
github = MultiRepo::Service::Github.new(**opts.slice(:dry_run))
|
17
|
+
|
18
|
+
repos = (github.org_repo_names(opts[:org]) + opts[:extra_repos]).sort
|
19
|
+
repos.each do |repo_name|
|
20
|
+
puts MultiRepo::CLI.header(repo_name)
|
21
|
+
|
22
|
+
disabled_workflows = github.disabled_workflows
|
23
|
+
if disabled_workflows.any?
|
24
|
+
disabled_workflows.each do |w|
|
25
|
+
puts "** Enabling #{w.html_url} (#{w.id})"
|
26
|
+
github.enable_workflow(github, repo_name, w.html_url, w.id)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
puts "** No disabled workflows found"
|
30
|
+
end
|
31
|
+
|
32
|
+
puts
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :old, "The old label names.", :type => :strings, :required => true
|
11
|
+
opt :new, "The new label names.", :type => :strings, :required => true
|
12
|
+
|
13
|
+
MultiRepo::CLI.common_options(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
rename_hash = opts[:old].zip(opts[:new]).to_h
|
17
|
+
puts "Renaming: #{rename_hash.pretty_inspect}"
|
18
|
+
puts
|
19
|
+
|
20
|
+
MultiRepo::CLI.each_repo(**opts) do |repo|
|
21
|
+
MultiRepo::Helpers::RenameLabels.new(repo.name, rename_hash, **opts).run
|
22
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
require 'travis'
|
9
|
+
require 'travis/pro/auto_login'
|
10
|
+
|
11
|
+
opts = Optimist.options do
|
12
|
+
opt :ref, "The branch or release tag to rebuild.", :type => :string, :required => true
|
13
|
+
|
14
|
+
MultiRepo::CLI.common_options(self, :except => :dry_run, :repo_set_default => nil)
|
15
|
+
end
|
16
|
+
opts[:repo_set] = opts[:ref].split("-").first unless opts[:repo] || opts[:repo_set]
|
17
|
+
|
18
|
+
puts "Restarting Travis builds for #{opts[:ref]}:"
|
19
|
+
|
20
|
+
MultiRepo::CLI.repos_for(**opts).collect do |repo|
|
21
|
+
repo = Travis::Pro::Repository.find(repo.name)
|
22
|
+
begin
|
23
|
+
last_build = repo.last_on_branch(opts[:ref])
|
24
|
+
rescue Travis::Client::NotFound
|
25
|
+
# Ignore repo which doesn't have Travis enabled for that branch
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
puts "- #{repo.name}..."
|
30
|
+
last_build.restart
|
31
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
require "active_support/core_ext/object/blank"
|
9
|
+
require "active_support/core_ext/string/inflections"
|
10
|
+
|
11
|
+
DISPLAY_FORMATS = %w[commit pr-title pr-label]
|
12
|
+
|
13
|
+
opts = Optimist.options do
|
14
|
+
opt :from, "The commit log 'from' ref", :type => :string, :required => true
|
15
|
+
opt :to, "The commit log 'to' ref" , :type => :string, :required => true
|
16
|
+
opt :display, "How to display the history. Valid values are: #{DISPLAY_FORMATS.join(", ")}", :default => "commit"
|
17
|
+
opt :summary, "Display a summary of the repos.", :default => false
|
18
|
+
|
19
|
+
opt :skip, "The repos to skip", :type => :strings, :default => []
|
20
|
+
|
21
|
+
MultiRepo::CLI.common_options(self, :except => :dry_run)
|
22
|
+
end
|
23
|
+
Optimist.die :display, "must be one of: #{DISPLAY_FORMATS.join(", ")}" unless DISPLAY_FORMATS.include?(opts[:display])
|
24
|
+
|
25
|
+
range = "#{opts[:from]}..#{opts[:to]}"
|
26
|
+
|
27
|
+
puts "Git commit log between #{opts[:from]} and #{opts[:to]}\n\n"
|
28
|
+
|
29
|
+
repos_with_changes = []
|
30
|
+
|
31
|
+
MultiRepo::CLI.repos_for(**opts).each do |repo|
|
32
|
+
next if opts[:skip].include?(repo.name)
|
33
|
+
|
34
|
+
puts MultiRepo::CLI.header(repo.name)
|
35
|
+
repo.git.fetch(output: false)
|
36
|
+
|
37
|
+
case opts[:display]
|
38
|
+
when "pr-label", "pr-title"
|
39
|
+
github ||= MultiRepo::Service::Github.client
|
40
|
+
pr_label_display = opts[:display] == "pr-label"
|
41
|
+
|
42
|
+
results = {}
|
43
|
+
if pr_label_display
|
44
|
+
results["bug"] = []
|
45
|
+
results["enhancement"] = []
|
46
|
+
end
|
47
|
+
results["other"] = []
|
48
|
+
|
49
|
+
log = repo.git.client.capturing.log({:oneline => true}, range)
|
50
|
+
log.lines.each do |line|
|
51
|
+
next unless (match = line.match(/Merge pull request #(\d+)\b/))
|
52
|
+
|
53
|
+
pr = github.pull_request(repo.name, match[1])
|
54
|
+
label = pr.labels.detect { |l| results.key?(l.name) }&.name || "other"
|
55
|
+
results[label] << pr
|
56
|
+
end
|
57
|
+
|
58
|
+
changes_found = false
|
59
|
+
|
60
|
+
results.each do |label, prs|
|
61
|
+
next if prs.blank?
|
62
|
+
changes_found = true
|
63
|
+
|
64
|
+
puts "\n## #{label.titleize}\n\n" if pr_label_display
|
65
|
+
prs.each do |pr|
|
66
|
+
puts "* #{pr.title} [[##{pr.number}]](#{pr.html_url})"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
repos_with_changes << repo if changes_found
|
71
|
+
when "commit"
|
72
|
+
output = repo.git.client.capturing.log({:oneline => true, :decorate => true, :graph => true}, range)
|
73
|
+
puts output
|
74
|
+
repos_with_changes << repo if output.present?
|
75
|
+
end
|
76
|
+
puts
|
77
|
+
end
|
78
|
+
|
79
|
+
if opts[:summary] && repos_with_changes.any?
|
80
|
+
puts
|
81
|
+
puts "Here are the changes per affected repository in GitHub:"
|
82
|
+
repos_with_changes.each do |repo|
|
83
|
+
puts "* [#{repo.name}](https://github.com/#{repo.name}/compare/#{opts[:from]}...#{opts[:to]})"
|
84
|
+
end
|
85
|
+
puts
|
86
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :org, "The org to list the users for", :type => :string, :required => true
|
11
|
+
opt :team, "Show members of a specific team", :type => :string
|
12
|
+
opt :alumni, "Whether or not to include alumni", :default => false
|
13
|
+
end
|
14
|
+
|
15
|
+
github = MultiRepo::Service::Github.new
|
16
|
+
members = opts[:team] ? github.team_member_names(opts[:org], opts[:team]) : github.org_member_names(opts[:org])
|
17
|
+
members -= github.team_member_names(opts[:org], "alumni") unless opts[:alumni]
|
18
|
+
|
19
|
+
puts members
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :org, "The org to list the repos for", :type => :string, :required => true
|
11
|
+
end
|
12
|
+
|
13
|
+
puts MultiRepo::Service::Github.org_repo_names(opts[:org])
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :since, "Since what date.", :type => :string, :required => true
|
11
|
+
|
12
|
+
MultiRepo::CLI.common_options(self, :except => :dry_run)
|
13
|
+
end
|
14
|
+
|
15
|
+
class OrgStats
|
16
|
+
def initialize(since:, **opts)
|
17
|
+
@since = since
|
18
|
+
@opts = opts
|
19
|
+
|
20
|
+
@total_commits = Hash.new(0)
|
21
|
+
@total_merges = Hash.new(0)
|
22
|
+
@names = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
MultiRepo::CLI.each_repo(**@opts) { |repo| run_one(repo) }
|
27
|
+
|
28
|
+
puts
|
29
|
+
puts "Total Commits:"
|
30
|
+
print_totals(@total_commits)
|
31
|
+
|
32
|
+
puts
|
33
|
+
puts "Grand Total Commits: #{@total_commits.values.sum}"
|
34
|
+
|
35
|
+
puts
|
36
|
+
puts "Total Merges:"
|
37
|
+
print_totals(@total_merges)
|
38
|
+
|
39
|
+
puts
|
40
|
+
puts "Grand Total Merges: #{@total_merges.values.sum}"
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def run_one(repo)
|
46
|
+
repo.git.fetch
|
47
|
+
repo.git.hard_checkout("master")
|
48
|
+
|
49
|
+
puts "Commits:"
|
50
|
+
commits = repo.git.client.capturing.shortlog("--summary", "--numbered", "--email", "--no-merges", "--since", @since)
|
51
|
+
puts commits
|
52
|
+
|
53
|
+
parse_data(commits).each do |number, name, email|
|
54
|
+
@total_commits[email] += number.to_i
|
55
|
+
@names[email] ||= name
|
56
|
+
end
|
57
|
+
|
58
|
+
puts "Merges:"
|
59
|
+
merges = repo.git.client.capturing.shortlog("--summary", "--numbered", "--email", "--merges", "--since", @since, "--grep", "Merge pull request #")
|
60
|
+
puts merges
|
61
|
+
|
62
|
+
parse_data(merges).each do |number, name, email|
|
63
|
+
@total_merges[email] += number.to_i
|
64
|
+
@names[email] ||= name
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def parse_data(data)
|
69
|
+
data
|
70
|
+
.chomp
|
71
|
+
.lines(:chomp => true)
|
72
|
+
.map { |l| l.match(/^\s*(\d+)\s+([^<]+)<([^>]+)>/).captures }
|
73
|
+
end
|
74
|
+
|
75
|
+
def print_totals(totals)
|
76
|
+
totals.sort_by { |_email, number| -number }.each do |email, number|
|
77
|
+
puts "#{number.to_s.rjust(8)} #{@names[email]} <#{email}>"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
OrgStats.new(**opts).run
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :project_id, "The project ID", :type => :integer, :required => true
|
11
|
+
opt :column, "The column within the project", :type => :string, :required => true
|
12
|
+
|
13
|
+
MultiRepo::CLI.common_options(self, :only => :repo)
|
14
|
+
end
|
15
|
+
|
16
|
+
github = MultiRepo::Service::Github.client
|
17
|
+
repo = opts[:repo].first
|
18
|
+
projects_headers = {:accept => "application/vnd.github.inertia-preview+json"}
|
19
|
+
|
20
|
+
projects = github.send(repo.include?("/") ? :projects : :org_projects, repo, projects_headers)
|
21
|
+
project = projects.detect { |p| p.number == opts[:project_id] }
|
22
|
+
Optimist.die :project_id, "not found" if project.nil?
|
23
|
+
|
24
|
+
column = github.project_columns(project.id, projects_headers).detect { |c| c.name == opts[:column] }
|
25
|
+
Optimist.die :column, "not found" if column.nil?
|
26
|
+
|
27
|
+
cards = github.column_cards(column.id, projects_headers)
|
28
|
+
issues = cards.map do |card|
|
29
|
+
org, repo, _issues, id = URI.parse(card.content_url).path.split("/").last(4)
|
30
|
+
github.issue("#{org}/#{repo}", id)
|
31
|
+
end
|
32
|
+
|
33
|
+
issues.each do |issue|
|
34
|
+
puts "* #{issue.title} [[##{issue.number}]](#{issue.html_url})"
|
35
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
MultiRepo::CLI.common_options(self, :only => :repo_set)
|
11
|
+
end
|
12
|
+
|
13
|
+
puts MultiRepo::CLI.repos_for(**opts).collect(&:name)
|
data/scripts/show_tag
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
require 'more_core_extensions/core_ext/array/tableize'
|
9
|
+
|
10
|
+
opts = Optimist.options do
|
11
|
+
opt :tag, "The tag name.", :type => :string, :required => true
|
12
|
+
|
13
|
+
MultiRepo::CLI.common_options(self, :except => :dry_run, :repo_set_default => nil)
|
14
|
+
end
|
15
|
+
opts[:repo_set] = opts[:tag].split("-").first unless opts[:repo] || opts[:repo_set]
|
16
|
+
|
17
|
+
HEADER = %w(Repo SHA Message).freeze
|
18
|
+
|
19
|
+
def show_tag(repo, tag)
|
20
|
+
line =
|
21
|
+
begin
|
22
|
+
repo.git.client.capturing.show({:summary => true, :oneline => true}, tag)
|
23
|
+
rescue MiniGit::GitError => err
|
24
|
+
""
|
25
|
+
end
|
26
|
+
|
27
|
+
sha, message = line.split(" ", 2)
|
28
|
+
[repo.name, sha, message]
|
29
|
+
end
|
30
|
+
|
31
|
+
repos = MultiRepo::CLI.repos_for(**opts)
|
32
|
+
table = [HEADER] + repos.collect { |repo| show_tag(repo, opts[:tag]) }
|
33
|
+
puts table.tableize(:max_width => 75)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
gem "action_view"
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'more_core_extensions/core_ext/array/tableize'
|
11
|
+
require 'action_view' # For ActionView::Helpers::DateHelper
|
12
|
+
require 'travis'
|
13
|
+
require 'travis/pro/auto_login'
|
14
|
+
|
15
|
+
opts = Optimist.options do
|
16
|
+
opt :ref, "The branch or release tag to check status for.", :type => :string, :required => true
|
17
|
+
|
18
|
+
MultiRepo::CLI.common_options(self, :except => :dry_run, :repo_set_default => nil)
|
19
|
+
end
|
20
|
+
opts[:repo_set] = opts[:ref].split("-").first unless opts[:repo] || opts[:repo_set]
|
21
|
+
|
22
|
+
date_helper = Class.new { include ActionView::Helpers::DateHelper }.new
|
23
|
+
|
24
|
+
travis_repos = MultiRepo::CLI.repos_for(**opts).collect do |repo|
|
25
|
+
repo = Travis::Pro::Repository.find(repo.name)
|
26
|
+
begin
|
27
|
+
last_build = repo.last_on_branch(opts[:ref])
|
28
|
+
rescue Travis::Client::NotFound
|
29
|
+
# Ignore repo which doesn't have Travis enabled for that branch
|
30
|
+
next
|
31
|
+
end
|
32
|
+
|
33
|
+
status, status_sort =
|
34
|
+
case last_build.state
|
35
|
+
when "errored", "failed"
|
36
|
+
[last_build.state.red, 0]
|
37
|
+
when "created", "started"
|
38
|
+
[last_build.state.yellow, 1]
|
39
|
+
when "passed"
|
40
|
+
[last_build.state.green, 2]
|
41
|
+
else
|
42
|
+
[last_build.state, 3]
|
43
|
+
end
|
44
|
+
|
45
|
+
date_sort = last_build.finished_at
|
46
|
+
date = "#{date_helper.time_ago_in_words(date_sort)} ago" if date_sort
|
47
|
+
|
48
|
+
last_build_url = "https://travis-ci.com/github/#{last_build.repository.slug}/builds/#{last_build.id}"
|
49
|
+
|
50
|
+
{
|
51
|
+
"Repo" => repo.name,
|
52
|
+
"Status" => status,
|
53
|
+
"Status Sort" => status_sort,
|
54
|
+
"Date" => date,
|
55
|
+
"Date Sort" => date_sort,
|
56
|
+
"URL" => last_build_url
|
57
|
+
}
|
58
|
+
end.compact
|
59
|
+
|
60
|
+
# Reverse sort by date then stable sort by status
|
61
|
+
travis_repos = travis_repos.sort_by { |v| v["Date Sort"].to_s }.reverse.sort_by.with_index { |v, n| [v["Status Sort"], n] }
|
62
|
+
|
63
|
+
puts travis_repos.tableize(:columns => ["Repo", "Status", "Date", "URL"])
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :branch, "The branch to protect.", :type => :string, :required => true
|
11
|
+
|
12
|
+
MultiRepo::CLI.common_options(self, :repo_set_default => nil)
|
13
|
+
end
|
14
|
+
opts[:repo_set] = opts[:branch] unless opts[:repo] || opts[:repo_set]
|
15
|
+
|
16
|
+
MultiRepo::CLI.repos_for(**opts).each do |repo|
|
17
|
+
next if opts[:branch] != "master" && repo.config.has_real_releases
|
18
|
+
|
19
|
+
puts MultiRepo::CLI.header(repo.name)
|
20
|
+
MultiRepo::Helpers::UpdateBranchProtection.new(repo.name, **opts).run
|
21
|
+
puts
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
MultiRepo::CLI.common_options(self, :repo_set_default => nil)
|
11
|
+
end
|
12
|
+
opts[:repo] = MultiRepo::Labels.all.keys.sort unless opts[:repo] || opts[:repo_set]
|
13
|
+
|
14
|
+
MultiRepo::CLI.each_repo(**opts) do |repo|
|
15
|
+
MultiRepo::Helpers::UpdateLabels.new(repo.name, **opts).run
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
opt :title, "The milestone title.", :type => :string, :required => true
|
11
|
+
opt :due_on, "The due date.", :type => :string
|
12
|
+
opt :close, "Whether to close the milestone.", :default => false
|
13
|
+
|
14
|
+
MultiRepo::CLI.common_options(self)
|
15
|
+
end
|
16
|
+
Optimist.die(:due_on, "is required") if !opts[:close] && !opts[:due_on]
|
17
|
+
Optimist.die(:due_on, "must be a date format") if opts[:due_on] && !MultiRepo::Service::GitHub.valid_milestone_date?(opts[:due_on])
|
18
|
+
|
19
|
+
MultiRepo::CLI.each_repo(**opts) do |repo|
|
20
|
+
MultiRepo::Helpers::UpdateMilestone.new(repo.name, **opts).run
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/inline"
|
4
|
+
gemfile do
|
5
|
+
source "https://rubygems.org"
|
6
|
+
gem "multi_repo", require: "multi_repo/cli", path: File.expand_path("..", __dir__)
|
7
|
+
end
|
8
|
+
|
9
|
+
opts = Optimist.options do
|
10
|
+
MultiRepo::CLI.common_options(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
MultiRepo::CLI.each_repo(**opts) do |repo|
|
14
|
+
MultiRepo::Helpers::UpdateRepoSettings.new(repo.name, **opts).run
|
15
|
+
end
|