diff --git a/Library/Homebrew/dev-cmd/sponsors.rb b/Library/Homebrew/dev-cmd/sponsors.rb new file mode 100644 index 0000000000..568daa9452 --- /dev/null +++ b/Library/Homebrew/dev-cmd/sponsors.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require "cli/parser" +require "utils/github" + +module Homebrew + module_function + + def sponsors_args + Homebrew::CLI::Parser.new do + usage_banner <<~EOS + `sponsors` + + Print a Markdown summary of Homebrew's GitHub Sponsors, suitable for pasting into a README. + EOS + end + end + + def sponsors + sponsors_args.parse + + sponsors = { + "named" => [], + "users" => 0, + "orgs" => 0, + } + + GitHub.sponsors_by_tier("Homebrew").each do |tier| + sponsors["named"] += tier["sponsors"] if tier["tier"] >= 100 + sponsors["users"] += tier["count"] + sponsors["orgs"] += tier["sponsors"].count { |s| s["type"] == "organization" } + end + + items = [] + items += sponsors["named"].map { |s| "[#{s["name"]}](https://github.com/#{s["login"]})" } + + anon_users = sponsors["users"] - sponsors["named"].length - sponsors["orgs"] + + items << if items.length > 1 + "#{anon_users} other users" + else + "#{anon_users} users" + end + + if sponsors["orgs"] == 1 + items << "#{sponsors["orgs"]} organization" + elsif sponsors["orgs"] > 1 + items << "#{sponsors["orgs"]} organizations" + end + + sponsor_text = if items.length > 2 + items[0..-2].join(", ") + " and #{items.last}" + else + items.join(" and ") + end + + puts "Homebrew is generously supported by #{sponsor_text} via [GitHub Sponsors](https://github.com/sponsors/Homebrew)." + end +end diff --git a/Library/Homebrew/test/dev-cmd/sponsors_spec.rb b/Library/Homebrew/test/dev-cmd/sponsors_spec.rb new file mode 100644 index 0000000000..667dff55b6 --- /dev/null +++ b/Library/Homebrew/test/dev-cmd/sponsors_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "cmd/shared_examples/args_parse" + +describe "Homebrew.sponsors_args" 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 354c2585c4..37f2fd0483 100644 --- a/Library/Homebrew/test/utils/github_spec.rb +++ b/Library/Homebrew/test/utils/github_spec.rb @@ -49,6 +49,14 @@ describe GitHub do end end + describe "::sponsors_by_tier", :needs_network do + it "errors on an unauthenticated token" do + expect { + subject.sponsors_by_tier("Homebrew") + }.to raise_error(/INSUFFICIENT_SCOPES|FORBIDDEN/) + end + end + describe "::get_artifact_url", :needs_network do it "fails to find a nonexistant workflow" do expect { diff --git a/completions/internal_commands_list.txt b/completions/internal_commands_list.txt index 69f6c41c2a..3beacf0b09 100644 --- a/completions/internal_commands_list.txt +++ b/completions/internal_commands_list.txt @@ -71,6 +71,7 @@ ruby search sh shellenv +sponsors style switch tap diff --git a/docs/Manpage.md b/docs/Manpage.md index 2709a17839..aaabdb46e6 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -967,6 +967,11 @@ build systems would not find otherwise. * `--env`: Use the standard `PATH` instead of superenv's when `std` is passed. +### `sponsors` + +Print a Markdown summary of Homebrew's GitHub Sponsors, suitable for pasting +into a README. + ### `style` [*`options`*] [*`file`*|*`tap`*|*`formula`*] Check formulae or files for conformance to Homebrew style guidelines. diff --git a/manpages/brew.1 b/manpages/brew.1 index a653c4df12..4972791289 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -1254,6 +1254,9 @@ Start a Homebrew build environment shell\. Uses our years\-battle\-hardened Home \fB\-\-env\fR Use the standard \fBPATH\fR instead of superenv\'s when \fBstd\fR is passed\. . +.SS "\fBsponsors\fR" +Print a Markdown summary of Homebrew\'s GitHub Sponsors, suitable for pasting into a README\. +. .SS "\fBstyle\fR [\fIoptions\fR] [\fIfile\fR|\fItap\fR|\fIformula\fR]" Check formulae or files for conformance to Homebrew style guidelines\. .