From b0b769890c94bb70505127fad07fd657dc233dbd Mon Sep 17 00:00:00 2001 From: dblock Date: Fri, 22 Dec 2023 11:23:45 -0500 Subject: [PATCH 1/4] Fix: fix cache_format_version deprecation. Signed-off-by: dblock --- bin/project | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/project b/bin/project index 14cb21b..9749664 100755 --- a/bin/project +++ b/bin/project @@ -50,6 +50,7 @@ module Bin client_options = { access_token: global_options[:token] } if global_options.key?(:token) unless global_options['no-cache'] stack = Faraday::RackBuilder.new do |builder| + ActiveSupport.cache_format_version = 7.0 cache_store = ActiveSupport::Cache.lookup_store(:file_store, File.expand_path(File.join(__dir__, '..', '.cache'))) logger = global_options['debug'] ? Logger.new($stdout) : nil builder.use Faraday::HttpCache, serializer: Marshal, shared_cache: false, store: cache_store, logger: logger From 97efb5c7d604fe45a0036bf2a682c57ab386d32b Mon Sep 17 00:00:00 2001 From: dblock Date: Fri, 22 Dec 2023 11:26:07 -0500 Subject: [PATCH 2/4] Bundle update. Signed-off-by: dblock --- .rubocop_todo.yml | 43 ++++++++++---- Gemfile.lock | 112 +++++++++++++++++++++-------------- bin/commands/contributors.rb | 2 +- bin/commands/pr.rb | 6 ++ lib/github/commits.rb | 2 +- lib/github/contributors.rb | 2 +- lib/github/issues.rb | 2 +- lib/github/item.rb | 4 +- lib/github/items.rb | 4 +- lib/github/pull_requests.rb | 2 +- lib/github/repo.rb | 4 +- lib/github/repos.rb | 4 +- lib/github/searchable.rb | 6 +- lib/github/signers.rb | 2 +- lib/github/team.rb | 2 +- lib/github/teams.rb | 4 +- lib/github/user.rb | 2 +- lib/github/users.rb | 4 +- 18 files changed, 125 insertions(+), 82 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 59eea55..f5508d7 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2023-10-09 16:15:45 UTC using RuboCop version 1.36.0. +# on 2023-12-22 16:23:09 UTC using RuboCop version 1.59.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -42,6 +42,7 @@ Lint/UnderscorePrefixedVariableName: - 'lib/github/maintainers.rb' # Offense count: 3 +# This cop supports unsafe autocorrection (--autocorrect-all). Lint/UselessAssignment: Exclude: - 'lib/github/repo.rb' @@ -53,18 +54,18 @@ Metrics/ClassLength: Max: 105 # Offense count: 3 -# Configuration parameters: AllowedMethods, AllowedPatterns, IgnoredMethods. +# Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/CyclomaticComplexity: Max: 9 # Offense count: 2 -# Configuration parameters: AllowedMethods, AllowedPatterns, IgnoredMethods. +# Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/PerceivedComplexity: Max: 10 # Offense count: 5 # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. -# AllowedNames: as, at, by, db, id, in, io, ip, of, on, os, pp, to +# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to Naming/MethodParameterName: Exclude: - 'lib/github/item.rb' @@ -150,7 +151,8 @@ RSpec/MultipleExpectations: Max: 5 # Offense count: 31 -# Configuration parameters: IgnoreSharedExamples. +# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. +# SupportedStyles: always, named_only RSpec/NamedSubject: Exclude: - 'spec/github/issues_spec.rb' @@ -163,11 +165,11 @@ RSpec/NamedSubject: RSpec/NestedGroups: Max: 5 -# Offense count: 1 -# This cop supports unsafe autocorrection (--autocorrect-all). -Style/CaseLikeIf: - Exclude: - - 'lib/github/items.rb' +# Offense count: 17 +# Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata. +# Include: **/*_spec.rb +RSpec/SpecFilePathFormat: + Enabled: false # Offense count: 1 # This cop supports unsafe autocorrection (--autocorrect-all). @@ -177,6 +179,13 @@ Style/ClassAndModuleChildren: Exclude: - 'spec/support/without_data_files.rb' +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/ConcatArrayLiterals: + Exclude: + - 'lib/github/commits.rb' + - 'lib/github/issues.rb' + # Offense count: 4 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: EnforcedStyle. @@ -191,6 +200,7 @@ Style/FrozenStringLiteralComment: # Offense count: 2 # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AllowedReceivers. +# AllowedReceivers: Thread.current Style/HashEachMethods: Exclude: - 'bin/commands/pr.rb' @@ -202,6 +212,13 @@ Style/IdenticalConditionalBranches: Exclude: - 'lib/github/repo.rb' +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: InverseMethods, InverseBlocks. +Style/InverseMethods: + Exclude: + - 'lib/github/repo.rb' + # Offense count: 1 # This cop supports unsafe autocorrection (--autocorrect-all). Style/MapToHash: @@ -210,7 +227,7 @@ Style/MapToHash: # Offense count: 1 # This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns, IgnoredMethods. +# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns. # SupportedStyles: predicate, comparison Style/NumericPredicate: Exclude: @@ -255,8 +272,8 @@ Style/StringConcatenation: # Offense count: 2 # This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, IgnoredMethods, AllowComments. -# AllowedMethods: respond_to, define_method +# Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments. +# AllowedMethods: define_method Style/SymbolProc: Exclude: - 'bin/commands/issues.rb' diff --git a/Gemfile.lock b/Gemfile.lock index a1111ca..f6f25fb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,19 +1,26 @@ GEM remote: http://rubygems.org/ specs: - activesupport (6.1.7.5) + activesupport (7.1.2) + base64 + bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) minitest (>= 5.1) + mutex_m tzinfo (~> 2.0) - zeitwerk (~> 2.3) - addressable (2.8.1) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) ast (2.4.2) + base64 (0.2.0) + bigdecimal (3.1.5) chronic (0.10.2) codecov (0.6.0) simplecov (>= 0.15, < 0.22) concurrent-ruby (1.2.2) + connection_pool (2.4.1) crack (0.4.5) rexml diff-lcs (1.5.0) @@ -21,65 +28,79 @@ GEM dotiw (5.3.3) activesupport i18n - faraday (2.6.0) + drb (2.2.0) + ruby2_keywords + faraday (2.8.1) + base64 faraday-net_http (>= 2.0, < 3.1) ruby2_keywords (>= 0.0.4) - faraday-http-cache (2.4.1) + faraday-http-cache (2.5.0) faraday (>= 0.8) - faraday-net_http (3.0.1) - faraday-retry (2.0.0) + faraday-net_http (3.0.2) + faraday-retry (2.2.0) faraday (~> 2.0) - gli (2.21.0) - hashdiff (1.0.1) + gli (2.21.1) + hashdiff (1.1.0) i18n (1.14.1) concurrent-ruby (~> 1.0) - json (2.6.2) - minitest (5.19.0) - octokit (4.25.1) + json (2.7.1) + language_server-protocol (3.17.0.3) + minitest (5.20.0) + mutex_m (0.2.0) + octokit (8.0.0) faraday (>= 1, < 3) sawyer (~> 0.9) - parallel (1.22.1) - parser (3.1.2.1) + parallel (1.24.0) + parser (3.2.2.4) ast (~> 2.4.1) - public_suffix (5.0.0) + racc + public_suffix (5.0.4) + racc (1.7.3) rainbow (3.1.1) - rake (13.0.6) - redcarpet (3.5.1) - regexp_parser (2.6.0) - rexml (3.2.5) - rspec (3.11.0) - rspec-core (~> 3.11.0) - rspec-expectations (~> 3.11.0) - rspec-mocks (~> 3.11.0) - rspec-core (3.11.0) - rspec-support (~> 3.11.0) - rspec-expectations (3.11.1) + rake (13.1.0) + redcarpet (3.6.0) + regexp_parser (2.8.3) + rexml (3.2.6) + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-mocks (3.11.1) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.6) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-support (3.11.1) - rubocop (1.36.0) + rspec-support (~> 3.12.0) + rspec-support (3.12.1) + rubocop (1.59.0) json (~> 2.3) + language_server-protocol (>= 3.17.0) parallel (~> 1.10) - parser (>= 3.1.2.1) + parser (>= 3.2.2.4) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.20.1, < 2.0) + rubocop-ast (>= 1.30.0, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.21.0) - parser (>= 3.1.1.0) - rubocop-performance (1.15.0) - rubocop (>= 1.7.0, < 2.0) - rubocop-ast (>= 0.4.0) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.30.0) + parser (>= 3.2.1.0) + rubocop-capybara (2.19.0) + rubocop (~> 1.41) + rubocop-factory_bot (2.24.0) + rubocop (~> 1.33) + rubocop-performance (1.20.0) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.30.0, < 2.0) rubocop-rake (0.6.0) rubocop (~> 1.0) - rubocop-rspec (2.13.2) - rubocop (~> 1.33) - ruby-progressbar (1.11.0) + rubocop-rspec (2.25.0) + rubocop (~> 1.40) + rubocop-capybara (~> 2.17) + rubocop-factory_bot (~> 2.22) + ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) sawyer (0.9.2) addressable (>= 2.3.5) @@ -92,13 +113,12 @@ GEM simplecov_json_formatter (0.1.4) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicode-display_width (2.3.0) - vcr (6.1.0) - webmock (3.14.0) + unicode-display_width (2.5.0) + vcr (6.2.0) + webmock (3.19.1) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - zeitwerk (2.6.11) PLATFORMS ruby diff --git a/bin/commands/contributors.rb b/bin/commands/contributors.rb index 4c03ae9..1e95877 100644 --- a/bin/commands/contributors.rb +++ b/bin/commands/contributors.rb @@ -41,7 +41,7 @@ class Commands org = GitHub::Organization.new(options) signers = org.commits(options).dco_signers signers.sort_for_display.each do |signer| - puts signer.to_s + puts signer end end end diff --git a/bin/commands/pr.rb b/bin/commands/pr.rb index 825d531..6424039 100644 --- a/bin/commands/pr.rb +++ b/bin/commands/pr.rb @@ -41,6 +41,12 @@ class Commands puts "#{k}: #{v}% (prs=#{prs.buckets[k].size}, people=#{prs.contributors.buckets[k].size})" end + prs.buckets.each_pair do |key, prs| + puts "\n# #{key}" + prs.each do |pr| + puts pr + end + end end end end diff --git a/lib/github/commits.rb b/lib/github/commits.rb index 420981d..95d9116 100644 --- a/lib/github/commits.rb +++ b/lib/github/commits.rb @@ -3,7 +3,7 @@ module GitHub class Commits < Items def initialize(arr_or_options) - super arr_or_options, GitHub::Commit + super(arr_or_options, GitHub::Commit) end # Gets all unique DCO signers (by email address) from all commits diff --git a/lib/github/contributors.rb b/lib/github/contributors.rb index f0829f1..82c9eb5 100644 --- a/lib/github/contributors.rb +++ b/lib/github/contributors.rb @@ -6,7 +6,7 @@ class Contributors < Items include GitHub::Buckets def initialize(arr) - super arr, Contributor + super(arr, Contributor) end def humans diff --git a/lib/github/issues.rb b/lib/github/issues.rb index c364e4a..8d4ca5a 100644 --- a/lib/github/issues.rb +++ b/lib/github/issues.rb @@ -3,7 +3,7 @@ module GitHub class Issues < Items def initialize(id_or_options) - super id_or_options, GitHub::Issue + super(id_or_options, GitHub::Issue) end def version_labels diff --git a/lib/github/item.rb b/lib/github/item.rb index 4665e60..74c140c 100644 --- a/lib/github/item.rb +++ b/lib/github/item.rb @@ -6,9 +6,9 @@ class Item < SimpleDelegator def initialize(id_or_obj, m = nil) if id_or_obj.is_a?(Sawyer::Resource) - super id_or_obj + super(id_or_obj) elsif m - super $github.send(m, id_or_obj) + super($github.send(m, id_or_obj)) else raise "Missing Octokit method for #{id_or_obj}" end diff --git a/lib/github/items.rb b/lib/github/items.rb index 457349b..eb95906 100644 --- a/lib/github/items.rb +++ b/lib/github/items.rb @@ -7,9 +7,9 @@ class Items < Array def initialize(arr_or_options, klass) if arr_or_options.is_a?(Array) - super klass.wrap(arr_or_options) + super(klass.wrap(arr_or_options)) elsif arr_or_options.is_a?(Hash) - super fetch(arr_or_options, klass) + super(fetch(arr_or_options, klass)) else raise ArgumentError, "Unexpected #{arr_or_options.class}" end diff --git a/lib/github/pull_requests.rb b/lib/github/pull_requests.rb index 5ab8562..913fac8 100644 --- a/lib/github/pull_requests.rb +++ b/lib/github/pull_requests.rb @@ -5,7 +5,7 @@ class PullRequests < Items include GitHub::Buckets def initialize(arr_or_options) - super arr_or_options, GitHub::PullRequest + super(arr_or_options, GitHub::PullRequest) end def contributors diff --git a/lib/github/repo.rb b/lib/github/repo.rb index 5d78f39..db4689d 100644 --- a/lib/github/repo.rb +++ b/lib/github/repo.rb @@ -4,9 +4,9 @@ module GitHub class Repo < Item def initialize(id_or_obj) if id_or_obj.is_a?(Sawyer::Resource) - super id_or_obj + super(id_or_obj) else - super $github.repo(id_or_obj) + super($github.repo(id_or_obj)) end rescue Octokit::NotFound => e raise "Invalid repo: #{id_or_obj}: #{e.message}" diff --git a/lib/github/repos.rb b/lib/github/repos.rb index 50611b9..9a17277 100644 --- a/lib/github/repos.rb +++ b/lib/github/repos.rb @@ -7,9 +7,9 @@ class Repos < Items def initialize(obj_or_options = {}) if obj_or_options.is_a?(Hash) @org = obj_or_options[:org] - super $github.org_repos(org), GitHub::Repo + super($github.org_repos(org), GitHub::Repo) else - super obj_or_options, GitHub::Repo + super(obj_or_options, GitHub::Repo) end end diff --git a/lib/github/searchable.rb b/lib/github/searchable.rb index ccac525..47deba3 100644 --- a/lib/github/searchable.rb +++ b/lib/github/searchable.rb @@ -19,19 +19,19 @@ def to_s class SearchableRepo < Searchable def initialize(name, org = nil) - super 'repo', [org, name].compact.join('/') + super('repo', [org, name].compact.join('/')) end end class SearchableOrg < Searchable def initialize(name) - super 'org', name + super('org', name) end end class Searchables < Array def initialize(options = {}) - super [] + super([]) orgs = Array(options[:org]) repos = Array(options[:repo]) repo_in_org = false diff --git a/lib/github/signers.rb b/lib/github/signers.rb index 78dab5f..581f896 100644 --- a/lib/github/signers.rb +++ b/lib/github/signers.rb @@ -8,7 +8,7 @@ def initialize(arr) arr.each do |signer| by_email[signer.email] = best_signer(by_email[signer.email], signer) end - super by_email.values + super(by_email.values) end # Sort all "noreply" email addresses to the bottom (for manual curation), then sort by name diff --git a/lib/github/team.rb b/lib/github/team.rb index 376f7e4..21e2a1f 100644 --- a/lib/github/team.rb +++ b/lib/github/team.rb @@ -5,7 +5,7 @@ class Team < Item include Comparable def initialize(id_or_obj) - super id_or_obj, :team + super(id_or_obj, :team) end def repos diff --git a/lib/github/teams.rb b/lib/github/teams.rb index 9b8ee96..84bc42d 100644 --- a/lib/github/teams.rb +++ b/lib/github/teams.rb @@ -7,9 +7,9 @@ class Teams < Items def initialize(obj_or_options = {}) if obj_or_options.is_a?(Hash) @org = obj_or_options[:org] - super $github.organization_teams(org), GitHub::Team + super($github.organization_teams(org), GitHub::Team) else - super obj_or_options, GitHub::Team + super(obj_or_options, GitHub::Team) end end end diff --git a/lib/github/user.rb b/lib/github/user.rb index 1900355..3d1ddef 100644 --- a/lib/github/user.rb +++ b/lib/github/user.rb @@ -5,7 +5,7 @@ class User < Item include Comparable def initialize(id_or_obj) - super id_or_obj, :user + super(id_or_obj, :user) rescue Octokit::NotFound => e raise "Invalid user: #{id_or_obj}: #{e.message}" end diff --git a/lib/github/users.rb b/lib/github/users.rb index fd66dcb..40844b1 100644 --- a/lib/github/users.rb +++ b/lib/github/users.rb @@ -7,9 +7,9 @@ class Users < Items def initialize(obj_or_options = {}) if obj_or_options.is_a?(Hash) @org = obj_or_options[:org] - super $github.org_members(org), GitHub::Users + super($github.org_members(org), GitHub::Users) else - super obj_or_options, GitHub::Users + super(obj_or_options, GitHub::Users) end end From 95c7789f8ed937f47f5736e0dd640e448bf15211 Mon Sep 17 00:00:00 2001 From: dblock Date: Fri, 22 Dec 2023 11:34:42 -0500 Subject: [PATCH 3/4] Fix: skip blank lines in CODEOWNERS. Signed-off-by: dblock --- .rubocop_todo.yml | 6 +++--- lib/github/repo.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index f5508d7..4164216 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2023-12-22 16:23:09 UTC using RuboCop version 1.59.0. +# on 2023-12-22 16:34:02 UTC using RuboCop version 1.59.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -51,9 +51,9 @@ Lint/UselessAssignment: # Offense count: 1 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: - Max: 105 + Max: 106 -# Offense count: 3 +# Offense count: 4 # Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/CyclomaticComplexity: Max: 9 diff --git a/lib/github/repo.rb b/lib/github/repo.rb index db4689d..04917c2 100644 --- a/lib/github/repo.rb +++ b/lib/github/repo.rb @@ -57,7 +57,7 @@ def codeowners data = $github.contents(full_name, path: '.github/CODEOWNERS') content = Base64.decode64(data.content) lines = content.split("\n").reject { |part| part[0] == '#' } - lines.map do |line| + lines.reject(&:blank?).map do |line| users = line.split(' ')[1..] users&.map { |user| user[1..] } end.flatten From 96b8529ddbd031ff870b05f8e05ac605744ea4e0 Mon Sep 17 00:00:00 2001 From: dblock Date: Tue, 19 Mar 2024 13:00:34 -0400 Subject: [PATCH 4/4] Added suport for maintainers stats --repo. Signed-off-by: dblock --- .rubocop_todo.yml | 4 +-- README.md | 6 +++++ bin/commands/maintainers.rb | 53 ++++++++++++++++++++++++------------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 4164216..812fe83 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2023-12-22 16:34:02 UTC using RuboCop version 1.59.0. +# on 2024-03-19 16:59:49 UTC using RuboCop version 1.59.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -51,7 +51,7 @@ Lint/UselessAssignment: # Offense count: 1 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: - Max: 106 + Max: 122 # Offense count: 4 # Configuration parameters: AllowedMethods, AllowedPatterns. diff --git a/README.md b/README.md index b082ffc..933bc05 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,12 @@ You can pass a date to find out stats for a given point in time. As of 2023-06-01, 103 repos have 202 maintainers, including 18% (19/103) of repos with at least one of 17 external maintainers. ``` +You can limit to a list of repos using `--repo`. + +``` +./bin/project maintainers stats --repo=opensearch-project/OpenSearch --repo=opensearch-project/opensearch-py +``` + Shows missing MAINTAINERS.md. ``` diff --git a/bin/commands/maintainers.rb b/bin/commands/maintainers.rb index 97125c4..c5034d6 100644 --- a/bin/commands/maintainers.rb +++ b/bin/commands/maintainers.rb @@ -7,28 +7,33 @@ class Commands g.desc 'Show MAINTAINERS.md stats.' g.command 'stats' do |c| c.flag %i[date], desc: 'Date at.', default_value: nil + g.flag %i[repo], multiple: true, desc: 'Search a specific repo within the org.' c.action do |_global_options, options, _args| - org = GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')) dt = options[:date] ? Chronic.parse(options[:date]).to_date : nil - maintainers = org.repos.maintainers(dt) - puts "As of #{dt || Date.today}, #{org.repos.count} repos have #{maintainers.unique_count} maintainers, including #{org.repos.external_maintainers_percent}% (#{org.repos.external_maintained_size}/#{org.repos.count}) of repos with at least one of #{maintainers.external_unique_count} external maintainers." + repos = if options[:repo]&.any? + GitHub::Repos.new(options[:repo]) + else + GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')).repos + end + maintainers = repos.maintainers(dt) + puts "As of #{dt || Date.today}, #{repos.count} repos have #{maintainers.unique_count} maintainers, including #{repos.external_maintainers_percent}% (#{repos.external_maintained_size}/#{repos.count}) of repos with at least one of #{maintainers.external_unique_count} external maintainers." puts "\n# Maintainers\n" puts "unique: #{maintainers.unique_count}" maintainers.each_pair do |bucket, logins| puts "#{bucket}: #{logins.size} (#{logins.map(&:to_s).join(', ')})" end puts "\n# External Maintainers\n" - org.repos.maintained[:external]&.sort_by(&:name)&.each do |repo| + repos.maintained[:external]&.sort_by(&:name)&.each do |repo| puts "#{repo.html_url}: #{repo.maintainers[:external]}" end puts "\n# Student Maintainers\n" - org.repos.maintained[:students]&.sort_by(&:name)&.each do |repo| + repos.maintained[:students]&.sort_by(&:name)&.each do |repo| puts "#{repo.html_url}: #{repo.maintainers[:students]}" end puts "\n# Unknown Maintainers\n" - org.repos.maintained[:unknown]&.sort_by(&:name)&.each do |repo| + repos.maintained[:unknown]&.sort_by(&:name)&.each do |repo| puts "#{repo.html_url}: #{repo.maintainers[:unknown]}" end end @@ -37,9 +42,12 @@ class Commands g.desc 'Audit repos for missing MAINTAINERS.md.' g.command 'missing' do |c| c.action do |_global_options, options, _args| - org = GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')) - repos = org.repos.sort_by(&:name) - repos.select { |repo| repo.maintainers.nil? }.each do |repo| + repos = if options[:repo]&.any? + GitHub::Repos.new(options[:repo]) + else + GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')).repos + end + repos.sort_by(&:name).select { |repo| repo.maintainers.nil? }.each do |repo| puts repo.html_url end end @@ -48,9 +56,12 @@ class Commands g.desc 'Audit MAINTAINERS.md and CODEOWNERS.' g.command 'audit' do |c| c.action do |_global_options, options, _args| - org = GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')) - repos = org.repos.sort_by(&:name) - repos.each do |repo| + repos = if options[:repo]&.any? + GitHub::Repos.new(options[:repo]) + else + GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')).repos + end + repos.sort_by(&:name).each do |repo| problems = {} repo.maintainers&.each do |user| next if repo.codeowners&.include?(user) @@ -77,12 +88,15 @@ class Commands g.desc 'Audit MAINTAINERS.md that have never contributed.' g.command 'contributors' do |c| c.action do |_global_options, options, _args| - org = GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')) - repos = org.repos.sort_by(&:name) + repos = if options[:repo]&.any? + GitHub::Repos.new(options[:repo]) + else + GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')).repos + end total_users = 0 total_repos = 0 unique_users = Set.new - repos.each do |repo| + repos.sort_by(&:name).each do |repo| users = repo.maintainers&.map do |user| commits = $github.commits(repo.full_name, author: user) next if commits.any? @@ -103,9 +117,12 @@ class Commands g.desc 'Compare MAINTAINERS.md and CODEOWNERS with repo permissions.' g.command 'permissions' do |c| c.action do |_global_options, options, _args| - org = GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')) - repos = org.repos.sort_by(&:name) - repos.each do |repo| + repos = if options[:repo]&.any? + GitHub::Repos.new(options[:repo]) + else + GitHub::Organization.new(options.merge(org: options['org'] || 'opensearch-project')).repos + end + repos.sort_by(&:name).each do |repo| if repo.oss_problems.any? puts "#{repo.html_url}" repo.oss_problems.each_pair do |problem, desc|