multi_repo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +16 -0
  3. data/.github/workflows/ci.yaml +32 -0
  4. data/.gitignore +6 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +4 -0
  7. data/.rubocop_cc.yml +4 -0
  8. data/.rubocop_local.yml +0 -0
  9. data/.whitesource +3 -0
  10. data/Gemfile +6 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +90 -0
  13. data/Rakefile +6 -0
  14. data/bin/console +8 -0
  15. data/exe/multi_repo +29 -0
  16. data/lib/multi_repo/cli.rb +92 -0
  17. data/lib/multi_repo/helpers/git_mirror.rb +198 -0
  18. data/lib/multi_repo/helpers/license.rb +106 -0
  19. data/lib/multi_repo/helpers/pull_request_blaster_outer.rb +129 -0
  20. data/lib/multi_repo/helpers/readme_badges.rb +84 -0
  21. data/lib/multi_repo/helpers/rename_labels.rb +26 -0
  22. data/lib/multi_repo/helpers/update_branch_protection.rb +24 -0
  23. data/lib/multi_repo/helpers/update_labels.rb +34 -0
  24. data/lib/multi_repo/helpers/update_milestone.rb +33 -0
  25. data/lib/multi_repo/helpers/update_repo_settings.rb +23 -0
  26. data/lib/multi_repo/labels.rb +31 -0
  27. data/lib/multi_repo/repo.rb +56 -0
  28. data/lib/multi_repo/repo_set.rb +27 -0
  29. data/lib/multi_repo/service/artifactory.rb +122 -0
  30. data/lib/multi_repo/service/code_climate.rb +119 -0
  31. data/lib/multi_repo/service/docker.rb +178 -0
  32. data/lib/multi_repo/service/git/minigit_capturing_patch.rb +12 -0
  33. data/lib/multi_repo/service/git.rb +90 -0
  34. data/lib/multi_repo/service/github.rb +238 -0
  35. data/lib/multi_repo/service/rubygems_stub.rb +103 -0
  36. data/lib/multi_repo/service/travis.rb +68 -0
  37. data/lib/multi_repo/version.rb +3 -0
  38. data/lib/multi_repo.rb +44 -0
  39. data/multi_repo.gemspec +44 -0
  40. data/repos/.gitkeep +0 -0
  41. data/scripts/delete_labels +23 -0
  42. data/scripts/destroy_branch +23 -0
  43. data/scripts/destroy_remote +26 -0
  44. data/scripts/destroy_tag +31 -0
  45. data/scripts/each_repo +23 -0
  46. data/scripts/fetch_repos +18 -0
  47. data/scripts/git_mirror +9 -0
  48. data/scripts/github_rate_limit +10 -0
  49. data/scripts/hacktoberfest +138 -0
  50. data/scripts/make_alumni +50 -0
  51. data/scripts/new_rubygems_stub +17 -0
  52. data/scripts/pull_request_blaster_outer +24 -0
  53. data/scripts/pull_request_labeler +59 -0
  54. data/scripts/pull_request_merger +63 -0
  55. data/scripts/reenable_repo_workflows +33 -0
  56. data/scripts/rename_labels +22 -0
  57. data/scripts/restart_travis_builds +31 -0
  58. data/scripts/show_commit_history +86 -0
  59. data/scripts/show_org_members +19 -0
  60. data/scripts/show_org_repos +13 -0
  61. data/scripts/show_org_stats +82 -0
  62. data/scripts/show_project_cards +35 -0
  63. data/scripts/show_repo_set +13 -0
  64. data/scripts/show_tag +33 -0
  65. data/scripts/show_travis_status +63 -0
  66. data/scripts/update_branch_protection +22 -0
  67. data/scripts/update_labels +16 -0
  68. data/scripts/update_milestone +21 -0
  69. data/scripts/update_repo_settings +15 -0
  70. metadata +366 -0
@@ -0,0 +1,103 @@
1
+ module MultiRepo::Service
2
+ class RubygemsStub
3
+ attr_reader :repo, :owners, :dry_run
4
+
5
+ def initialize(repo, owners: [], dry_run: false, **_)
6
+ @repo = repo
7
+ @owners = owners
8
+ @dry_run = dry_run
9
+ end
10
+
11
+ def run
12
+ if stub_exists?
13
+ puts "A stub gem for #{repo.inspect} already exists."
14
+ return
15
+ end
16
+
17
+ if gem_exists?
18
+ puts "A gem for #{repo.inspect} already exists with the following versions:"
19
+ puts " #{gem_versions}"
20
+ puts
21
+ loop do
22
+ print "Would you still like to create a stub? (y/N) "
23
+ answer = gets.chomp.downcase[0] || "n"
24
+ break if answer == "y"
25
+ return if answer == "n"
26
+ end
27
+ puts
28
+ end
29
+
30
+ Dir.mktmpdir do |dir|
31
+ package = create_gem(dir)
32
+ push_gem(package)
33
+
34
+ owners.each do |o|
35
+ set_gem_owner(o)
36
+ end
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def stub_exists?
43
+ gem_versions.include?("0.0.1")
44
+ end
45
+
46
+ def gem_exists?
47
+ gem_string.presence
48
+ end
49
+
50
+ # Returns a gem's versions as listed by gem list
51
+ #
52
+ # Example (where @repo is the "foo" gem):
53
+ # # => ["2.1.0", "2.0.0", "1.1.0", "1.0.0"]
54
+ def gem_versions
55
+ gem_string.split(" ", 2).last.to_s[1..-2].to_s.split(", ")
56
+ end
57
+
58
+ # Returns a gem string as listed by gem list
59
+ #
60
+ # Example (where @repo is the "foo" gem):
61
+ # # => "foo (2.1.0, 2.0.0, 1.1.0, 1.0.0)"
62
+ def gem_string
63
+ @gem_string ||= `gem list #{repo} --exact --remote --all`.chomp.split("\n").last.to_s
64
+ end
65
+
66
+ def create_gem(dir)
67
+ path = File.join(dir, "#{repo}.gemspec")
68
+ File.write(path , <<~RUBY)
69
+ Gem::Specification.new do |s|
70
+ s.name = "#{repo}"
71
+ s.version = "0.0.1"
72
+ s.licenses = ["Apache-2.0"]
73
+ s.summary = "#{repo}"
74
+ s.description = s.summary
75
+ s.authors = ["ManageIQ Authors"]
76
+ s.homepage = "https://github.com/ManageIQ/#{repo}"
77
+ s.metadata = { "source_code_uri" => s.homepage }
78
+ end
79
+ RUBY
80
+
81
+ system("gem build #{path}", :chdir => dir)
82
+
83
+ File.join(dir, "#{repo}-0.0.1.gem")
84
+ end
85
+
86
+ def push_gem(package)
87
+ if dry_run
88
+ raise "#{package} not found" unless File.file?(package)
89
+ puts "** dry-run: gem push #{package}".light_black
90
+ else
91
+ system("gem push #{package}")
92
+ end
93
+ end
94
+
95
+ def set_gem_owner(owner)
96
+ if dry_run
97
+ puts "** dry-run: gem owner #{repo} --add #{owner}".light_black
98
+ else
99
+ system("gem owner #{repo} --add #{owner}")
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,68 @@
1
+ require 'yaml'
2
+
3
+ module MultiRepo::Service
4
+ class Travis
5
+ def self.api_token
6
+ @api_token ||= ENV["TRAVIS_API_TOKEN"]
7
+ end
8
+
9
+ def self.api_token=(token)
10
+ @api_token = token
11
+ end
12
+
13
+ def self.client
14
+ @client ||= begin
15
+ raise "Missing Travis API Token" if travis_api_token.nil?
16
+
17
+ require 'travis/client'
18
+ ::Travis::Client.new(
19
+ :uri => ::Travis::Client::COM_URI,
20
+ :access_token => api_token
21
+ )
22
+ end
23
+ end
24
+
25
+ def self.badge_name
26
+ "Build Status"
27
+ end
28
+
29
+ def self.badge_details(repo, branch)
30
+ {
31
+ "description" => badge_name,
32
+ "image" => "https://travis-ci.com/#{repo.name}.svg?branch=#{branch}",
33
+ "url" => "https://travis-ci.com/#{repo.name}"
34
+ }
35
+ end
36
+
37
+ attr_reader :repo, :dry_run
38
+
39
+ def initialize(repo, dry_run: false, **_)
40
+ @repo = repo
41
+ @dry_run = dry_run
42
+ end
43
+
44
+ def badge_details
45
+ self.class.badge_details(repo, "master")
46
+ end
47
+
48
+ def enable
49
+ if dry_run
50
+ puts "** dry-run: travis login --com --github-token $GITHUB_API_TOKEN".light_black
51
+ puts "** dry-run: travis enable --com".light_black
52
+ else
53
+ `travis login --com --github-token $GITHUB_API_TOKEN`
54
+ `travis enable --com`
55
+ end
56
+ end
57
+
58
+ def set_env(hash)
59
+ hash.each do |key, value|
60
+ if dry_run
61
+ puts "** dry-run: travis env set #{key} #{value}".light_black
62
+ else
63
+ `travis env set #{key} #{value}`
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module MultiRepo
2
+ VERSION = "0.1.0"
3
+ end
data/lib/multi_repo.rb ADDED
@@ -0,0 +1,44 @@
1
+ require 'pathname'
2
+ require 'pp'
3
+
4
+ require 'multi_repo/version'
5
+
6
+ require 'multi_repo/labels'
7
+ require 'multi_repo/repo'
8
+ require 'multi_repo/repo_set'
9
+
10
+ require 'multi_repo/service/artifactory'
11
+ require 'multi_repo/service/code_climate'
12
+ require 'multi_repo/service/docker'
13
+ require 'multi_repo/service/git'
14
+ require 'multi_repo/service/github'
15
+ require 'multi_repo/service/rubygems_stub'
16
+ require 'multi_repo/service/travis'
17
+
18
+ require 'multi_repo/helpers/git_mirror'
19
+ require 'multi_repo/helpers/license'
20
+ require 'multi_repo/helpers/pull_request_blaster_outer'
21
+ require 'multi_repo/helpers/readme_badges'
22
+ require 'multi_repo/helpers/rename_labels'
23
+ require 'multi_repo/helpers/update_branch_protection'
24
+ require 'multi_repo/helpers/update_labels'
25
+ require 'multi_repo/helpers/update_milestone'
26
+ require 'multi_repo/helpers/update_repo_settings'
27
+
28
+ module MultiRepo
29
+ def self.root_dir
30
+ @root_dir ||= Pathname.new(Dir.pwd).expand_path
31
+ end
32
+
33
+ def self.root_dir=(dir)
34
+ @root_dir = Pathname.new(dir).expand_path
35
+ end
36
+
37
+ def self.config_dir
38
+ @config_dir ||= root_dir.join("config")
39
+ end
40
+
41
+ def self.repos_dir
42
+ @repos_dir ||= root_dir.join("repos")
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'multi_repo/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "multi_repo"
8
+ spec.version = MultiRepo::VERSION
9
+ spec.authors = ["ManageIQ Authors"]
10
+ spec.email = ["contact@manageiq.org"]
11
+ spec.description = %q{MultiRepo is a library for managing multiple repositiories and running scripts against them.}
12
+ spec.summary = spec.description
13
+ spec.homepage = "http://github.com/ManageIQ/multi_repo"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.required_ruby_version = ">= 2.7.0"
24
+
25
+ spec.add_runtime_dependency "activesupport"
26
+ spec.add_runtime_dependency "colorize"
27
+ spec.add_runtime_dependency "config"
28
+ spec.add_runtime_dependency "licensee"
29
+ spec.add_runtime_dependency "minigit"
30
+ spec.add_runtime_dependency "more_core_extensions"
31
+ spec.add_runtime_dependency "octokit", ">=4.23.0"
32
+ spec.add_runtime_dependency "optimist"
33
+ spec.add_runtime_dependency "progressbar"
34
+ spec.add_runtime_dependency "psych", ">=3"
35
+ spec.add_runtime_dependency "rbnacl"
36
+ spec.add_runtime_dependency "rest-client"
37
+ spec.add_runtime_dependency "travis"
38
+
39
+ spec.add_development_dependency "bundler"
40
+ spec.add_development_dependency "manageiq-style"
41
+ spec.add_development_dependency "rake"
42
+ spec.add_development_dependency "rspec", ">= 3.0"
43
+ spec.add_development_dependency "simplecov", ">= 0.21.2"
44
+ end
data/repos/.gitkeep ADDED
File without changes
@@ -0,0 +1,23 @@
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 :labels, "The labels to delete.", :type => :strings, :required => true
11
+
12
+ MultiRepo::CLI.common_options(self, :repo_set_default => nil)
13
+ end
14
+ opts[:repo] = MultiRepo::Helpers::Labels.all.keys.sort unless opts[:repo] || opts[:repo_set]
15
+
16
+ github = MultiRepo::Service::Github.new(dry_run: opts[:dry_run])
17
+
18
+ MultiRepo::CLI.each_repo(**opts) do |repo|
19
+ opts[:labels].each do |label|
20
+ puts "Deleting #{label.inspect}"
21
+ github.delete_label!(repo.name, label)
22
+ end
23
+ end
@@ -0,0 +1,23 @@
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 destroy.", :type => :string, :required => true
11
+
12
+ MultiRepo::CLI.common_options(self, :except => :dry_run)
13
+ end
14
+
15
+ MultiRepo::CLI.each_repo(**opts) do |repo|
16
+ unless repo.git.branch?(opts[:branch])
17
+ puts "!! Skipping because #{opts[:branch]} branch doesn't exist".yellow
18
+ next
19
+ end
20
+
21
+ repo.git.client.checkout("master")
22
+ repo.git.client.branch("-D", opts[:branch])
23
+ end
@@ -0,0 +1,26 @@
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 :remote, "The remote to destroy", :type => :string, :required => true
11
+
12
+ MultiRepo::CLI.common_options(self)
13
+ end
14
+
15
+ MultiRepo::CLI.each_repo(**opts) do |repo|
16
+ unless repo.git.remote?(opts[:remote])
17
+ puts "!! Skipping because #{opts[:remote]} remote doesn't exist".yellow
18
+ next
19
+ end
20
+
21
+ if opts[:dry_run]
22
+ puts "** dry-run: git remote rm #{opts[:remote]}".light_black
23
+ else
24
+ repo.git.client.remote("rm", opts[:remote])
25
+ end
26
+ 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
+
9
+ opts = Optimist.options do
10
+ opt :tag, "The tag to destroy", :type => :string, :required => true
11
+
12
+ MultiRepo::CLI.common_options(self, :except => :dry_run)
13
+ end
14
+
15
+ require "stringio"
16
+ post_review = StringIO.new
17
+
18
+ MultiRepo::CLI.each_repo(**opts) do |repo|
19
+ unless repo.git.tag?(opts[:tag])
20
+ puts "!! Skipping because #{opts[:tag]} tag doesn't exist".yellow
21
+ next
22
+ end
23
+
24
+ repo.git.client.tag("-d", opts[:tag])
25
+ post_review.puts("pushd #{repo.path} && git push origin :#{opts[:tag]} && popd")
26
+ end
27
+
28
+ puts
29
+ puts "Run the following script to delete '#{opts[:tag]}' tag from all remote repos"
30
+ puts
31
+ puts post_review.string
data/scripts/each_repo ADDED
@@ -0,0 +1,23 @@
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 :command, "A command to run in each repo", :type => :string, :required => true
11
+ opt :ref, "Ref to checkout before running the command", :type => :string, :default => "master"
12
+
13
+ MultiRepo::CLI.common_options(self, :except => :dry_run)
14
+ end
15
+
16
+ MultiRepo::CLI.each_repo(**opts) do |repo|
17
+ repo.git.fetch
18
+ repo.git.hard_checkout(opts[:ref])
19
+ repo.chdir do
20
+ puts "+ #{opts[:command]}".light_black
21
+ system(opts[:command])
22
+ end
23
+ end
@@ -0,0 +1,18 @@
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 :checkout, "Branch to checkout after fetching.", :type => :string
11
+
12
+ MultiRepo::CLI.common_options(self, :except => :dry_run)
13
+ end
14
+
15
+ MultiRepo::CLI.each_repo(**opts) do |repo|
16
+ repo.git.fetch
17
+ repo.git.hard_checkout(opts[:checkout]) if opts[:checkout]
18
+ end
@@ -0,0 +1,9 @@
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
+ exit 1 unless MultiRepo::Helpers::GitMirror.new.mirror_all
@@ -0,0 +1,10 @@
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
+ puts [MultiRepo::Service::Github.client.rate_limit.to_h].tableize
@@ -0,0 +1,138 @@
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 apply the `hacktoberfest` label to", :type => :string, :required => true
11
+ opt :apply, "Apply the `hacktoberfest` label to `good first issue` labels. "\
12
+ "Pass --no-apply to remove the `hacktoberfest` label",
13
+ :type => :boolean, :default => true
14
+
15
+ MultiRepo::CLI.common_options(self, :only => :dry_run)
16
+ end
17
+
18
+ class MultiRepo::Hacktoberfest
19
+ attr_reader :org, :apply, :dry_run
20
+
21
+ def initialize(org:, apply:, dry_run: false, **_)
22
+ @org = org
23
+ @apply = apply
24
+ @dry_run = dry_run
25
+ end
26
+
27
+ def run
28
+ if apply
29
+ add_hacktoberfest_topics
30
+ good_first_issues.each { |issue| add_hacktoberfest_label(issue) }
31
+ else
32
+ remove_hacktoberfest_topics
33
+ hacktoberfest_issues.each { |issue| remove_hacktoberfest_label(issue) }
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def good_first_issues
40
+ sorted_issues("org:#{org} archived:false is:open label:\"good first issue\" -label:hacktoberfest")
41
+ end
42
+
43
+ def hacktoberfest_issues
44
+ sorted_issues("org:#{org} archived:false is:open label:hacktoberfest")
45
+ end
46
+
47
+ def sorted_issues(query)
48
+ github.client.search_issues(query).items.sort_by { |issue| issue_id(issue) }
49
+ end
50
+
51
+ def add_hacktoberfest_label(issue)
52
+ labels = ["hacktoberfest"]
53
+ repo, number = issue_id(issue)
54
+ puts "Adding #{labels.first.inspect} label to issue #{repo}##{number}"
55
+
56
+ if dry_run
57
+ puts "** dry-run: github.add_labels_to_an_issue(#{repo.inspect}, #{number.inspect}, #{labels.inspect})".light_black
58
+ else
59
+ github.client.add_labels_to_an_issue(repo, number, labels)
60
+ end
61
+ end
62
+
63
+ def remove_hacktoberfest_label(issue)
64
+ label = "hacktoberfest"
65
+ repo, number = issue_id(issue)
66
+ puts "Removing #{label.inspect} label from issue #{repo}##{number}"
67
+
68
+ if dry_run
69
+ puts "** dry-run: github.remove_label(#{repo.inspect}, #{number.inspect}, #{label.inspect})".light_black
70
+ else
71
+ github.client.remove_label(repo, number, label)
72
+ end
73
+ end
74
+
75
+ def add_hacktoberfest_topics
76
+ org_repos.each do |repo|
77
+ add_hacktoberfest_topic(repo)
78
+ end
79
+ end
80
+
81
+ def remove_hacktoberfest_topics
82
+ org_repos.each do |repo|
83
+ remove_hacktoberfest_topic(repo)
84
+ end
85
+ end
86
+
87
+ def add_hacktoberfest_topic(repo)
88
+ topic = "hacktoberfest"
89
+ topics = topic_names(repo)
90
+ return if topics.include?(topic)
91
+
92
+ puts "Adding #{topic.inspect} topic to repo #{repo}"
93
+
94
+ topics << topic
95
+ if dry_run
96
+ puts "** dry-run: github.replace_all_topics(#{repo.inspect}, #{topics.inspect})".light_black
97
+ else
98
+ github.client.replace_all_topics(repo, topics, :accept => "application/vnd.github.mercy-preview+json")
99
+ end
100
+ end
101
+
102
+ def remove_hacktoberfest_topic(repo)
103
+ topic = "hacktoberfest"
104
+ topics = topic_names(repo)
105
+ return unless topics.include?(topic)
106
+
107
+ puts "Removing #{topic.inspect} topic from repo #{repo}"
108
+
109
+ topics.delete(topic)
110
+ if dry_run
111
+ puts "** dry-run: github.replace_all_topics(#{repo.inspect}, #{topics.inspect})".light_black
112
+ else
113
+ github.client.replace_all_topics(repo, topics, :accept => "application/vnd.github.mercy-preview+json")
114
+ end
115
+ end
116
+
117
+ def issue_id(issue)
118
+ [issue_repo(issue), issue.number]
119
+ end
120
+
121
+ def issue_repo(issue)
122
+ issue.repository_url.split("/").last(2).join("/")
123
+ end
124
+
125
+ def topic_names(repo)
126
+ github.client.topics(repo, :accept => "application/vnd.github.mercy-preview+json")[:names]
127
+ end
128
+
129
+ def org_repos
130
+ github.org_repo_names(org)
131
+ end
132
+
133
+ def github
134
+ @github ||= MultiRepo::Service::Github.new(dry_run: dry_run)
135
+ end
136
+ end
137
+
138
+ MultiRepo::Hacktoberfest.new(**opts).run
@@ -0,0 +1,50 @@
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 :users, "The users to make alumni.", :type => :strings, :required => true
11
+ opt :org, "The org in which user belongs", :type => :string, :required => true
12
+
13
+ MultiRepo::CLI.common_options(self, :only => :dry_run)
14
+ end
15
+
16
+ class MultiRepo::MakeAlumni
17
+ attr_reader :org, :dry_run
18
+
19
+ def initialize(org:, dry_run:, **_)
20
+ @org = org
21
+ @dry_run = dry_run
22
+ @github = MultiRepo::Service::Github.new(dry_run: dry_run)
23
+ end
24
+
25
+ def run(user)
26
+ progress = MultiRepo.progress_bar(teams.size + repos.size)
27
+
28
+ github.add_team_membership(org, "alumni", user)
29
+ progress.increment
30
+
31
+ non_alumni_teams = github.team_names(org) - ["alumni"]
32
+ non_alumni_teams.each do |team|
33
+ github.remove_team_membership(org, team, user)
34
+ progress.increment
35
+ end
36
+
37
+ repos.each do |repo|
38
+ github.remove_collaborator(repo, user)
39
+ progress.increment
40
+ end
41
+
42
+ progress.finish
43
+ end
44
+ end
45
+
46
+ make_alumni = MultiRepo::MakeAlumni.new(**opts)
47
+ opts[:users].each do |user|
48
+ puts MultiRepo::CLI.header(user)
49
+ make_alumni.run(user)
50
+ end
@@ -0,0 +1,17 @@
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 :owners, "Owners to add to the gem stub", :type => :strings, :default => []
11
+
12
+ MultiRepo::CLI.common_options(self, :except => :repo_set)
13
+ end
14
+
15
+ MultiRepo::CLI.each_repo(**opts) do |repo|
16
+ MultiRepo::Service::RubygemsStub.new(repo.name, **opts).run
17
+ end
@@ -0,0 +1,24 @@
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 :base, "The target branch for the changes.", :type => :string, :required => true
11
+ opt :head, "The name of the branch to create on your fork.", :type => :string, :required => true
12
+ opt :script, "The path to the script that will update the desired files.", :type => :string, :required => true
13
+ opt :message, "The commit message for this change.", :type => :string, :required => true
14
+ opt :title, "The PR title for this change. (default is --message)", :type => :string
15
+
16
+ MultiRepo::CLI.common_options(self)
17
+ end
18
+
19
+ results = {}
20
+ MultiRepo::CLI.each_repo(**opts) do |repo|
21
+ results[repo.name] = MultiRepo::Helpers::PullRequestBlasterOuter.new(repo, **opts).blast
22
+ end
23
+
24
+ pp results