From 6026c7c74d18a110d2bafe303a1a83534ff2d832 Mon Sep 17 00:00:00 2001 From: nandahkrishna Date: Thu, 4 Feb 2021 17:00:50 +0530 Subject: [PATCH 1/5] `brew update-maintainers`: dev-cmd to update maintainers in README --- Library/Homebrew/.rubocop.yml | 2 +- .../Homebrew/dev-cmd/update-maintainers.rb | 64 +++++++++++++++++++ Library/Homebrew/utils/github.rb | 29 +++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 Library/Homebrew/dev-cmd/update-maintainers.rb diff --git a/Library/Homebrew/.rubocop.yml b/Library/Homebrew/.rubocop.yml index 6a49053b64..799d1baf79 100644 --- a/Library/Homebrew/.rubocop.yml +++ b/Library/Homebrew/.rubocop.yml @@ -37,7 +37,7 @@ Metrics/PerceivedComplexity: Metrics/MethodLength: Max: 260 Metrics/ModuleLength: - Max: 600 + Max: 650 Exclude: - "test/**/*" diff --git a/Library/Homebrew/dev-cmd/update-maintainers.rb b/Library/Homebrew/dev-cmd/update-maintainers.rb new file mode 100644 index 0000000000..32c690d779 --- /dev/null +++ b/Library/Homebrew/dev-cmd/update-maintainers.rb @@ -0,0 +1,64 @@ +# typed: false +# frozen_string_literal: true + +require "cli/parser" +require "utils/github" + +module Homebrew + extend T::Sig + + module_function + + sig { returns(CLI::Parser) } + def update_maintainers_args + Homebrew::CLI::Parser.new do + description <<~EOS + Update the list of maintainers in the `Homebrew/brew` README. + EOS + + named_args :none + end + end + + def update_maintainers + update_maintainers_args.parse + + # We assume that only public members wish to be included in the README + public_members = GitHub.public_member_usernames("Homebrew") + + plc = GitHub.members_by_team("Homebrew", "plc") + tsc = GitHub.members_by_team("Homebrew", "tsc") + linux = GitHub.members_by_team("Homebrew", "linux") + other = GitHub.members_by_team("Homebrew", "maintainers") + other.except!(*[plc, tsc, linux].map(&:keys).flatten.uniq) + + sentences = [plc, tsc, linux, other].map do |h| + h.slice!(*public_members) + h.each { |k, v| h[k] = "[#{v}](https://github.com/#{k})" } + h.values.sort.to_sentence + end + + readme = HOMEBREW_REPOSITORY/"README.md" + + content = readme.read + content.gsub!(/(Homebrew's \[Project Leadership Committee.*) is .*\./, + "\\1 is #{sentences[0]}.") + content.gsub!(/(Homebrew's \[Technical Steering Committee.*) is .*\./, + "\\1 is #{sentences[1]}.") + content.gsub!(%r{(Homebrew/brew's Linux maintainers are).*\.}, + "\\1 #{sentences[2]}.") + content.gsub!(/(Homebrew's other current maintainers are).*\./, + "\\1 #{sentences[3]}.") + + File.open(readme, "w+") { |f| f.write(content) } + + diff = system_command "git", args: [ + "-C", HOMEBREW_REPOSITORY, "diff", "--exit-code", "README.md" + ] + if diff.status.success? + puts "No changes to list of maintainers." + else + puts "List of maintainers updated in README." + end + end +end diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index 293ae71d1d..feec12c973 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -572,6 +572,35 @@ module GitHub artifact.first["archive_download_url"] end + def public_member_usernames(org, per_page: 100) + url = "#{API_URL}/orgs/#{org}/public_members?per_page=#{per_page}" + members = [] + + (1..API_MAX_PAGES).each do |page| + result = open_api(url + "&page=#{page}").map { |m| m["login"] } + members.concat(result) + + return members if result.length < per_page + end + end + + def members_by_team(org, team) + query = <<~EOS + { organization(login: "#{org}") { + team(slug: "#{team}") { + members(first: 100) { + nodes { + ... on User { login name } + } + } + } + } + } + EOS + result = open_graphql(query, scopes: ["read:org", "user"]) + result["organization"]["team"]["members"]["nodes"].map { |m| [m["login"], m["name"]] }.to_h + end + def sponsors_by_tier(user) query = <<~EOS { organization(login: "#{user}") { From 7bb059b523827d49cc8f56f1d1c7d02befd29222 Mon Sep 17 00:00:00 2001 From: nandahkrishna Date: Thu, 4 Feb 2021 17:49:38 +0530 Subject: [PATCH 2/5] Update manpage and completions --- completions/bash/brew | 16 ++++++++++++++++ completions/fish/brew.fish | 7 +++++++ completions/internal_commands_list.txt | 1 + completions/zsh/_brew | 10 ++++++++++ docs/Manpage.md | 4 ++++ manpages/brew.1 | 3 +++ 6 files changed, 41 insertions(+) diff --git a/completions/bash/brew b/completions/bash/brew index 71098288b9..abd7782871 100644 --- a/completions/bash/brew +++ b/completions/bash/brew @@ -2108,6 +2108,21 @@ _brew_update_license_data() { esac } +_brew_update_maintainers() { + local cur="${COMP_WORDS[COMP_CWORD]}" + case "$cur" in + -*) + __brewcomp " + --debug + --help + --quiet + --verbose + " + return + ;; + esac +} + _brew_update_python_resources() { local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in @@ -2382,6 +2397,7 @@ _brew() { up) _brew_up ;; update) _brew_update ;; update-license-data) _brew_update_license_data ;; + update-maintainers) _brew_update_maintainers ;; update-python-resources) _brew_update_python_resources ;; update-report) _brew_update_report ;; update-test) _brew_update_test ;; diff --git a/completions/fish/brew.fish b/completions/fish/brew.fish index d146d6ce6c..a2c251d9b9 100644 --- a/completions/fish/brew.fish +++ b/completions/fish/brew.fish @@ -1439,6 +1439,13 @@ __fish_brew_complete_arg 'update-license-data' -l quiet -d 'Make some output mor __fish_brew_complete_arg 'update-license-data' -l verbose -d 'Make some output more verbose' +__fish_brew_complete_cmd 'update-maintainers' 'Update the list of maintainers in the `Homebrew/brew` README' +__fish_brew_complete_arg 'update-maintainers' -l debug -d 'Display any debugging information' +__fish_brew_complete_arg 'update-maintainers' -l help -d 'Show this message' +__fish_brew_complete_arg 'update-maintainers' -l quiet -d 'Make some output more quiet' +__fish_brew_complete_arg 'update-maintainers' -l verbose -d 'Make some output more verbose' + + __fish_brew_complete_cmd 'update-python-resources' 'Update versions for PyPI resource blocks in formula' __fish_brew_complete_arg 'update-python-resources' -l debug -d 'Display any debugging information' __fish_brew_complete_arg 'update-python-resources' -l exclude-packages -d 'Exclude these packages when finding resources' diff --git a/completions/internal_commands_list.txt b/completions/internal_commands_list.txt index b1d36a5ddc..0b5931a16e 100644 --- a/completions/internal_commands_list.txt +++ b/completions/internal_commands_list.txt @@ -97,6 +97,7 @@ untap up update update-license-data +update-maintainers update-python-resources update-reset update-test diff --git a/completions/zsh/_brew b/completions/zsh/_brew index 7792c24eed..22c4e2e749 100644 --- a/completions/zsh/_brew +++ b/completions/zsh/_brew @@ -212,6 +212,7 @@ __brew_internal_commands() { 'untap:Remove a tapped formula repository' 'update:Fetch the newest version of Homebrew and all formulae from GitHub using `git`(1) and perform any necessary migrations' 'update-license-data:Update SPDX license data in the Homebrew repository' + 'update-maintainers:Update the list of maintainers in the `Homebrew/brew` README' 'update-python-resources:Update versions for PyPI resource blocks in formula' 'update-report:The Ruby implementation of `brew update`' 'update-reset:Fetch and reset Homebrew and all tap repositories (or any specified repository) using `git`(1) to their latest `origin/HEAD`' @@ -1677,6 +1678,15 @@ _brew_update_license_data() { '--verbose[Make some output more verbose]' } +# brew update-maintainers +_brew_update_maintainers() { + _arguments \ + '--debug[Display any debugging information]' \ + '--help[Show this message]' \ + '--quiet[Make some output more quiet]' \ + '--verbose[Make some output more verbose]' +} + # brew update-python-resources _brew_update_python_resources() { _arguments \ diff --git a/docs/Manpage.md b/docs/Manpage.md index 2581d00e34..c7a72bd5ff 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -1384,6 +1384,10 @@ Update SPDX license data in the Homebrew repository. * `--fail-if-not-changed`: Return a failing status code if current license data's version is the same as the upstream. This can be used to notify CI when the SPDX license data is out of date. +### `update-maintainers` + +Update the list of maintainers in the `Homebrew/brew` README. + ### `update-python-resources` [*`options`*] *`formula`* [...] Update versions for PyPI resource blocks in *`formula`*. diff --git a/manpages/brew.1 b/manpages/brew.1 index 81c06baee8..759b9edbad 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1916,6 +1916,9 @@ Update SPDX license data in the Homebrew repository\. \fB\-\-fail\-if\-not\-changed\fR Return a failing status code if current license data\'s version is the same as the upstream\. This can be used to notify CI when the SPDX license data is out of date\. . +.SS "\fBupdate\-maintainers\fR" +Update the list of maintainers in the \fBHomebrew/brew\fR README\. +. .SS "\fBupdate\-python\-resources\fR [\fIoptions\fR] \fIformula\fR [\.\.\.]" Update versions for PyPI resource blocks in \fIformula\fR\. . From 0474fe60933d604575c4fab5a95f27cf333863e8 Mon Sep 17 00:00:00 2001 From: nandahkrishna Date: Thu, 4 Feb 2021 23:48:03 +0530 Subject: [PATCH 3/5] dev-cmd/update-maintainers: add tests --- Library/Homebrew/test/dev-cmd/update-maintainers_spec.rb | 8 ++++++++ Library/Homebrew/test/utils/github_spec.rb | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 Library/Homebrew/test/dev-cmd/update-maintainers_spec.rb diff --git a/Library/Homebrew/test/dev-cmd/update-maintainers_spec.rb b/Library/Homebrew/test/dev-cmd/update-maintainers_spec.rb new file mode 100644 index 0000000000..8e8ad57369 --- /dev/null +++ b/Library/Homebrew/test/dev-cmd/update-maintainers_spec.rb @@ -0,0 +1,8 @@ +# typed: false +# frozen_string_literal: true + +require "cmd/shared_examples/args_parse" + +describe "brew update-maintainers" do + it_behaves_like "parseable arguments" +end diff --git a/Library/Homebrew/test/utils/github_spec.rb b/Library/Homebrew/test/utils/github_spec.rb index b1de7fd7f4..10067e9359 100644 --- a/Library/Homebrew/test/utils/github_spec.rb +++ b/Library/Homebrew/test/utils/github_spec.rb @@ -50,6 +50,13 @@ describe GitHub do end end + describe "::public_member_usernames", :needs_network do + it "gets the usernames of all publicly visible members of the organisation" do + response = described_class.public_member_usernames("Homebrew") + expect(response).to be_a(Array) + end + end + describe "::sponsors_by_tier", :needs_network do it "errors on an unauthenticated token" do expect { From 90632ce274be1718e6688962119bbae9ee3aaa7d Mon Sep 17 00:00:00 2001 From: nandahkrishna Date: Fri, 5 Feb 2021 01:43:07 +0530 Subject: [PATCH 4/5] dev-cmd/update-maintainers: modify Linux maintainer wording in README --- Library/Homebrew/dev-cmd/man.rb | 2 +- Library/Homebrew/dev-cmd/update-maintainers.rb | 2 +- README.md | 2 +- docs/Manpage.md | 2 +- manpages/brew.1 | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Library/Homebrew/dev-cmd/man.rb b/Library/Homebrew/dev-cmd/man.rb index 999916dfc9..2d375eaa6a 100644 --- a/Library/Homebrew/dev-cmd/man.rb +++ b/Library/Homebrew/dev-cmd/man.rb @@ -88,7 +88,7 @@ module Homebrew readme.read[/(Homebrew's \[Technical Steering Committee.*\.)/, 1] .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1') variables[:linux] = - readme.read[%r{(Homebrew/brew's Linux maintainers .*\.)}, 1] + readme.read[/(Homebrew's Linux maintainers .*\.)/, 1] .gsub(/\[([^\]]+)\]\([^)]+\)/, '\1') variables[:maintainers] = readme.read[/(Homebrew's other current maintainers .*\.)/, 1] diff --git a/Library/Homebrew/dev-cmd/update-maintainers.rb b/Library/Homebrew/dev-cmd/update-maintainers.rb index 32c690d779..2701fc800b 100644 --- a/Library/Homebrew/dev-cmd/update-maintainers.rb +++ b/Library/Homebrew/dev-cmd/update-maintainers.rb @@ -45,7 +45,7 @@ module Homebrew "\\1 is #{sentences[0]}.") content.gsub!(/(Homebrew's \[Technical Steering Committee.*) is .*\./, "\\1 is #{sentences[1]}.") - content.gsub!(%r{(Homebrew/brew's Linux maintainers are).*\.}, + content.gsub!(/(Homebrew's Linux maintainers are).*\./, "\\1 #{sentences[2]}.") content.gsub!(/(Homebrew's other current maintainers are).*\./, "\\1 #{sentences[3]}.") diff --git a/README.md b/README.md index 800ad90083..e6e8ed99d7 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Homebrew's [Project Leadership Committee](https://docs.brew.sh/Homebrew-Governan Homebrew's [Technical Steering Committee](https://docs.brew.sh/Homebrew-Governance#7-technical-steering-committee) is [Michka Popoff](https://github.com/imichka), [FX Coudert](https://github.com/fxcoudert), [Markus Reiter](https://github.com/reitermarkus), [Misty De Meo](https://github.com/mistydemeo) and [Mike McQuaid](https://github.com/MikeMcQuaid). -Homebrew/brew's Linux maintainers are [Michka Popoff](https://github.com/imichka), [Shaun Jackman](https://github.com/sjackman), [Dawid Dziurla](https://github.com/dawidd6), [Issy Long](https://github.com/issyl0) and [Maxim Belkin](https://github.com/maxim-belkin). +Homebrew's Linux maintainers are [Michka Popoff](https://github.com/imichka), [Shaun Jackman](https://github.com/sjackman), [Dawid Dziurla](https://github.com/dawidd6), [Issy Long](https://github.com/issyl0) and [Maxim Belkin](https://github.com/maxim-belkin). Homebrew's other current maintainers are [Claudia Pellegrino](https://github.com/claui), [Zach Auten](https://github.com/zachauten), [Rui Chen](https://github.com/chenrui333), [Vitor Galvao](https://github.com/vitorgalvao), [Caleb Xu](https://github.com/alebcay), [Gautham Goli](https://github.com/GauthamGoli), [Steven Peters](https://github.com/scpeters), [Bo Anderson](https://github.com/Bo98), [William Woodruff](https://github.com/woodruffw), [Igor Kapkov](https://github.com/igas), [Sam Ford](https://github.com/samford), [Alexander Bayandin](https://github.com/bayandin), [Izaak Beekman](https://github.com/zbeekman), [Eric Knibbe](https://github.com/EricFromCanada), [Viktor Szakats](https://github.com/vszakats), [Thierry Moisan](https://github.com/moisan), [Steven Peters](https://github.com/scpeters), [Tom Schoonjans](https://github.com/tschoonj), [Issy Long](https://github.com/issyl0), [CoreCode](https://github.com/core-code), [Randall](https://github.com/ran-dall), [Rylan Polster](https://github.com/Rylan12), [SeekingMeaning](https://github.com/SeekingMeaning), [William Ma](https://github.com/whoiswillma) and [Dustin Rodrigues](https://github.com/dtrodrigues). diff --git a/docs/Manpage.md b/docs/Manpage.md index c7a72bd5ff..e38f47c8fb 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -1965,7 +1965,7 @@ Homebrew's Project Leadership Committee is Misty De Meo, Shaun Jackman, Jonathan Homebrew's Technical Steering Committee is Michka Popoff, FX Coudert, Markus Reiter, Misty De Meo and Mike McQuaid. -Homebrew/brew's Linux maintainers are Michka Popoff, Shaun Jackman, Dawid Dziurla, Issy Long and Maxim Belkin. +Homebrew's Linux maintainers are Michka Popoff, Shaun Jackman, Dawid Dziurla, Issy Long and Maxim Belkin. Homebrew's other current maintainers are Claudia Pellegrino, Zach Auten, Rui Chen, Vitor Galvao, Caleb Xu, Gautham Goli, Steven Peters, Bo Anderson, William Woodruff, Igor Kapkov, Sam Ford, Alexander Bayandin, Izaak Beekman, Eric Knibbe, Viktor Szakats, Thierry Moisan, Steven Peters, Tom Schoonjans, Issy Long, CoreCode, Randall, Rylan Polster, SeekingMeaning, William Ma and Dustin Rodrigues. diff --git a/manpages/brew.1 b/manpages/brew.1 index 759b9edbad..1c7ae3c6b2 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -2849,7 +2849,7 @@ Homebrew\'s Project Leadership Committee is Misty De Meo, Shaun Jackman, Jonatha Homebrew\'s Technical Steering Committee is Michka Popoff, FX Coudert, Markus Reiter, Misty De Meo and Mike McQuaid\. . .P -Homebrew/brew\'s Linux maintainers are Michka Popoff, Shaun Jackman, Dawid Dziurla, Issy Long and Maxim Belkin\. +Homebrew\'s Linux maintainers are Michka Popoff, Shaun Jackman, Dawid Dziurla, Issy Long and Maxim Belkin\. . .P Homebrew\'s other current maintainers are Claudia Pellegrino, Zach Auten, Rui Chen, Vitor Galvao, Caleb Xu, Gautham Goli, Steven Peters, Bo Anderson, William Woodruff, Igor Kapkov, Sam Ford, Alexander Bayandin, Izaak Beekman, Eric Knibbe, Viktor Szakats, Thierry Moisan, Steven Peters, Tom Schoonjans, Issy Long, CoreCode, Randall, Rylan Polster, SeekingMeaning, William Ma and Dustin Rodrigues\. From 15f936a22a228f01482ce6819fefccdf73045afb Mon Sep 17 00:00:00 2001 From: nandahkrishna Date: Sat, 6 Feb 2021 02:58:17 +0530 Subject: [PATCH 5/5] dev-cmd/update-maintainers: implement suggestions from code review --- Library/Homebrew/.rubocop.yml | 3 +- .../Homebrew/dev-cmd/update-maintainers.rb | 29 ++++++++++--------- Library/Homebrew/utils/github.rb | 16 ++++++++-- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Library/Homebrew/.rubocop.yml b/Library/Homebrew/.rubocop.yml index 799d1baf79..b5cdb52bf7 100644 --- a/Library/Homebrew/.rubocop.yml +++ b/Library/Homebrew/.rubocop.yml @@ -36,8 +36,9 @@ Metrics/PerceivedComplexity: Max: 90 Metrics/MethodLength: Max: 260 +# TODO: Reduce to 600 after refactoring utils/github Metrics/ModuleLength: - Max: 650 + Max: 620 Exclude: - "test/**/*" diff --git a/Library/Homebrew/dev-cmd/update-maintainers.rb b/Library/Homebrew/dev-cmd/update-maintainers.rb index 2701fc800b..1ce882b7b5 100644 --- a/Library/Homebrew/dev-cmd/update-maintainers.rb +++ b/Library/Homebrew/dev-cmd/update-maintainers.rb @@ -26,29 +26,32 @@ module Homebrew # We assume that only public members wish to be included in the README public_members = GitHub.public_member_usernames("Homebrew") - plc = GitHub.members_by_team("Homebrew", "plc") - tsc = GitHub.members_by_team("Homebrew", "tsc") - linux = GitHub.members_by_team("Homebrew", "linux") - other = GitHub.members_by_team("Homebrew", "maintainers") - other.except!(*[plc, tsc, linux].map(&:keys).flatten.uniq) + members = { + plc: GitHub.members_by_team("Homebrew", "plc"), + tsc: GitHub.members_by_team("Homebrew", "tsc"), + linux: GitHub.members_by_team("Homebrew", "linux"), + } + members[:other] = GitHub.members_by_team("Homebrew", "maintainers") + .except(*members.values.map(&:keys).flatten.uniq) - sentences = [plc, tsc, linux, other].map do |h| - h.slice!(*public_members) - h.each { |k, v| h[k] = "[#{v}](https://github.com/#{k})" } - h.values.sort.to_sentence + sentences = {} + members.each do |group, hash| + hash.slice!(*public_members) + hash.each { |login, name| hash[login] = "[#{name}](https://github.com/#{login})" } + sentences[group] = hash.values.sort.to_sentence end readme = HOMEBREW_REPOSITORY/"README.md" content = readme.read content.gsub!(/(Homebrew's \[Project Leadership Committee.*) is .*\./, - "\\1 is #{sentences[0]}.") + "\\1 is #{sentences[:plc]}.") content.gsub!(/(Homebrew's \[Technical Steering Committee.*) is .*\./, - "\\1 is #{sentences[1]}.") + "\\1 is #{sentences[:tsc]}.") content.gsub!(/(Homebrew's Linux maintainers are).*\./, - "\\1 #{sentences[2]}.") + "\\1 #{sentences[:linux]}.") content.gsub!(/(Homebrew's other current maintainers are).*\./, - "\\1 #{sentences[3]}.") + "\\1 #{sentences[:other]}.") File.open(readme, "w+") { |f| f.write(content) } diff --git a/Library/Homebrew/utils/github.rb b/Library/Homebrew/utils/github.rb index feec12c973..a18b146200 100644 --- a/Library/Homebrew/utils/github.rb +++ b/Library/Homebrew/utils/github.rb @@ -577,7 +577,7 @@ module GitHub members = [] (1..API_MAX_PAGES).each do |page| - result = open_api(url + "&page=#{page}").map { |m| m["login"] } + result = open_api("#{url}&page=#{page}").map { |member| member["login"] } members.concat(result) return members if result.length < per_page @@ -587,6 +587,11 @@ module GitHub def members_by_team(org, team) query = <<~EOS { organization(login: "#{org}") { + teams(first: 100) { + nodes { + ... on Team { name } + } + } team(slug: "#{team}") { members(first: 100) { nodes { @@ -598,7 +603,14 @@ module GitHub } EOS result = open_graphql(query, scopes: ["read:org", "user"]) - result["organization"]["team"]["members"]["nodes"].map { |m| [m["login"], m["name"]] }.to_h + + if result["organization"]["teams"]["nodes"].blank? + raise Error, + "Your token needs the 'read:org' scope to access this API" + end + raise Error, "The team #{org}/#{team} does not exist" if result["organization"]["team"].blank? + + result["organization"]["team"]["members"]["nodes"].map { |member| [member["login"], member["name"]] }.to_h end def sponsors_by_tier(user)