dev-cmd/contributions: Use GitHub APIs for commit author info
- Using `git log` was brittle with name changes and email address changes for contributors over the years unless we made a Git `mailmap` file which brings with it its own updatedness overhead. - Let's use the GitHub commits API (importantly _not_ the search API) so that we can give it a username and it will return contributions associated with every email address on that user's account: https://docs.github.com/en/rest/commits/commits?apiVersion=2022-11-28#list-commits--parameters. - This is quite significantly slower, but it's worth it for correctness especially when we get to all maintainers' contributions (in a separate PR). - The commits API does not (yet?) support trailers or commit "committer"s, just authors.
This commit is contained in:
parent
6b7ecd18e9
commit
d3827b12f2
@ -19,11 +19,11 @@ module Homebrew
|
||||
sig { returns(CLI::Parser) }
|
||||
def contributions_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
usage_banner "`contributions` <email|name> [<--repositories>`=`] [<--csv>]"
|
||||
usage_banner "`contributions` <email|username> [<--repositories>`=`] [<--csv>]"
|
||||
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").
|
||||
The first argument is a GitHub username (e.g. "BrewTestBot") or an email address (e.g. "brewtestbot@brew.sh").
|
||||
EOS
|
||||
|
||||
comma_array "--repositories",
|
||||
@ -64,14 +64,15 @@ module Homebrew
|
||||
return ofail "Unsupported repository: #{repo}. Try one of #{SUPPORTED_REPOS.join(", ")}."
|
||||
end
|
||||
|
||||
tap = Tap.fetch("Homebrew", repo)
|
||||
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
|
||||
tap.install
|
||||
end
|
||||
|
||||
results[repo] = {
|
||||
commits: git_log_author_cmd(T.must(repo_path), args),
|
||||
commits: GitHub.repo_commit_count_for_user(tap.full_name, args.named.first),
|
||||
coauthorships: git_log_trailers_cmd(T.must(repo_path), "Co-authored-by", args),
|
||||
signoffs: git_log_trailers_cmd(T.must(repo_path), "Signed-off-by", args),
|
||||
}
|
||||
@ -127,15 +128,6 @@ module Homebrew
|
||||
.sum(&:sum) # 956
|
||||
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, trailer: String, args: Homebrew::CLI::Args).returns(Integer) }
|
||||
def git_log_trailers_cmd(repo_path, trailer, args)
|
||||
cmd = ["git", "-C", repo_path, "log", "--oneline"]
|
||||
|
@ -86,7 +86,7 @@ class Tap
|
||||
# e.g. `user/repo`
|
||||
attr_reader :name
|
||||
|
||||
# The full name of this {Tap}, including the `homebrew-` prefix.
|
||||
# The full name of this {Tap}, including the `homebrew-` prefix unless repo == "brew".
|
||||
# It combines {#user} and 'homebrew-'-prefixed {#repo} with a slash.
|
||||
# e.g. `user/homebrew-repo`
|
||||
attr_reader :full_name
|
||||
@ -100,7 +100,7 @@ class Tap
|
||||
@user = user
|
||||
@repo = repo
|
||||
@name = "#{@user}/#{@repo}".downcase
|
||||
@full_name = "#{@user}/homebrew-#{@repo}"
|
||||
@full_name = (@repo == "brew") ? "#{user}/#{repo}" : "#{@user}/homebrew-#{@repo}"
|
||||
@path = TAP_DIRECTORY/@full_name.downcase
|
||||
@path.extend(GitRepositoryExtension)
|
||||
@alias_table = nil
|
||||
|
@ -699,4 +699,14 @@ module GitHub # rubocop:disable Metrics/ModuleLength
|
||||
|
||||
output[/^Status: (200)/, 1] != "200"
|
||||
end
|
||||
|
||||
def repo_commit_count_for_user(nwo, user)
|
||||
return if Homebrew::EnvConfig.no_github_api?
|
||||
|
||||
commits = 0
|
||||
API.paginate_rest("#{API_URL}/repos/#{nwo}/commits", query: "&author=#{user}") do |result|
|
||||
commits += result.length
|
||||
end
|
||||
commits
|
||||
end
|
||||
end
|
||||
|
@ -253,9 +253,9 @@ module GitHub
|
||||
end
|
||||
end
|
||||
|
||||
def paginate_rest(url, per_page: 100)
|
||||
def paginate_rest(url, query: nil, per_page: 100)
|
||||
(1..API_MAX_PAGES).each do |page|
|
||||
result = API.open_rest("#{url}?per_page=#{per_page}&page=#{page}")
|
||||
result = API.open_rest("#{url}?per_page=#{per_page}&page=#{page}#{query}")
|
||||
yield(result, page)
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user