mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00

- This doesn't require "all" to be specified as part of the command, it's the default, so usage is now just: ``` $ brew contributions "Issy Long" $ brew contributions "Issy Long" --repositories=brew,core $ brew contributions me@issyl0.co.uk --repositories=cask,bundle ``` - As we discussed in the PR review before, `comma_array` doesn't allow two names, so we can't (yet) do `comma_array "--repositories", "--repos"` like we can with `flag`. That's an enhancement for the future if we want to make the flags here less verbose. But now that "all" is the default, maybe less necessary.
110 lines
3.4 KiB
Ruby
Executable File
110 lines
3.4 KiB
Ruby
Executable File
# typed: true
|
|
# frozen_string_literal: true
|
|
|
|
require "cli/parser"
|
|
|
|
module Homebrew
|
|
extend T::Sig
|
|
|
|
module_function
|
|
|
|
SUPPORTED_REPOS = [
|
|
%w[brew core cask],
|
|
OFFICIAL_CMD_TAPS.keys.map { |t| t.delete_prefix("homebrew/") },
|
|
OFFICIAL_CASK_TAPS.reject { |t| t == "cask" },
|
|
].flatten.freeze
|
|
|
|
sig { returns(CLI::Parser) }
|
|
def contributions_args
|
|
Homebrew::CLI::Parser.new do
|
|
usage_banner "`contributions` <email|name>"
|
|
description <<~EOS
|
|
Contributions to Homebrew repos for a user.
|
|
|
|
The first argument is a name (e.g. "BrewTestBot") or an email address (e.g. "brewtestbot@brew.sh").
|
|
EOS
|
|
|
|
comma_array "--repositories",
|
|
description: "Specify a comma-separated (no spaces) list of repositories to search. " \
|
|
"Supported repositories: #{SUPPORTED_REPOS.join(", ")}. " \
|
|
"Omitting this flag, or specifying `--repositories=all`, will search all repositories."
|
|
flag "--from=",
|
|
description: "Date (ISO-8601 format) to start searching contributions."
|
|
|
|
flag "--to=",
|
|
description: "Date (ISO-8601 format) to stop searching contributions."
|
|
|
|
named_args min: 1, max: 1
|
|
end
|
|
end
|
|
|
|
sig { void }
|
|
def contributions
|
|
args = contributions_args.parse
|
|
|
|
commits = 0
|
|
coauthorships = 0
|
|
|
|
all_repos = args.repositories.nil? || args.repositories.include?("all")
|
|
repos = all_repos ? SUPPORTED_REPOS : args.repositories
|
|
|
|
repos.each do |repo|
|
|
if SUPPORTED_REPOS.exclude?(repo)
|
|
return ofail "Unsupported repository: #{repo}. Try one of #{SUPPORTED_REPOS.join(", ")}."
|
|
end
|
|
|
|
repo_path = find_repo_path_for_repo(repo)
|
|
unless repo_path.exist?
|
|
|
|
opoo "Repository #{repo} not yet tapped! Tapping it now..."
|
|
Tap.fetch("homebrew", repo).install
|
|
end
|
|
|
|
commits += git_log_author_cmd(T.must(repo_path), args)
|
|
coauthorships += git_log_coauthor_cmd(T.must(repo_path), args)
|
|
end
|
|
|
|
sentence = "#{args.named.first} directly authored #{commits} commits " \
|
|
"and co-authored #{coauthorships} commits " \
|
|
"across #{all_repos ? "all Homebrew repos" : repos.to_sentence}"
|
|
sentence += if args.from && args.to
|
|
" between #{args.from} and #{args.to}"
|
|
elsif args.from
|
|
" after #{args.from}"
|
|
elsif args.to
|
|
" before #{args.to}"
|
|
else
|
|
" in all time"
|
|
end
|
|
sentence += "."
|
|
|
|
puts sentence
|
|
end
|
|
|
|
sig { params(repo: String).returns(Pathname) }
|
|
def find_repo_path_for_repo(repo)
|
|
return HOMEBREW_REPOSITORY if repo == "brew"
|
|
|
|
Tap.fetch("homebrew", repo).path
|
|
end
|
|
|
|
sig { params(repo_path: Pathname, args: Homebrew::CLI::Args).returns(Integer) }
|
|
def git_log_author_cmd(repo_path, args)
|
|
cmd = ["git", "-C", repo_path, "log", "--oneline", "--author=#{args.named.first}"]
|
|
cmd << "--before=#{args.to}" if args.to
|
|
cmd << "--after=#{args.from}" if args.from
|
|
|
|
Utils.safe_popen_read(*cmd).lines.count
|
|
end
|
|
|
|
sig { params(repo_path: Pathname, args: Homebrew::CLI::Args).returns(Integer) }
|
|
def git_log_coauthor_cmd(repo_path, args)
|
|
cmd = ["git", "-C", repo_path, "log", "--oneline"]
|
|
cmd << "--format='%(trailers:key=Co-authored-by:)'"
|
|
cmd << "--before=#{args.to}" if args.to
|
|
cmd << "--after=#{args.from}" if args.from
|
|
|
|
Utils.safe_popen_read(*cmd).lines.count { |l| l.include?(args.named.first) }
|
|
end
|
|
end
|