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) }
|
sig { returns(CLI::Parser) }
|
||||||
def contributions_args
|
def contributions_args
|
||||||
Homebrew::CLI::Parser.new do
|
Homebrew::CLI::Parser.new do
|
||||||
usage_banner "`contributions` <email|name> [<--repositories>`=`] [<--csv>]"
|
usage_banner "`contributions` <email|username> [<--repositories>`=`] [<--csv>]"
|
||||||
description <<~EOS
|
description <<~EOS
|
||||||
Contributions to Homebrew repos for a user.
|
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
|
EOS
|
||||||
|
|
||||||
comma_array "--repositories",
|
comma_array "--repositories",
|
||||||
@ -64,14 +64,15 @@ module Homebrew
|
|||||||
return ofail "Unsupported repository: #{repo}. Try one of #{SUPPORTED_REPOS.join(", ")}."
|
return ofail "Unsupported repository: #{repo}. Try one of #{SUPPORTED_REPOS.join(", ")}."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
tap = Tap.fetch("Homebrew", repo)
|
||||||
repo_path = find_repo_path_for_repo(repo)
|
repo_path = find_repo_path_for_repo(repo)
|
||||||
unless repo_path.exist?
|
unless repo_path.exist?
|
||||||
opoo "Repository #{repo} not yet tapped! Tapping it now..."
|
opoo "Repository #{repo} not yet tapped! Tapping it now..."
|
||||||
Tap.fetch("homebrew", repo).install
|
tap.install
|
||||||
end
|
end
|
||||||
|
|
||||||
results[repo] = {
|
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),
|
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),
|
signoffs: git_log_trailers_cmd(T.must(repo_path), "Signed-off-by", args),
|
||||||
}
|
}
|
||||||
@ -127,15 +128,6 @@ module Homebrew
|
|||||||
.sum(&:sum) # 956
|
.sum(&:sum) # 956
|
||||||
end
|
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) }
|
sig { params(repo_path: Pathname, trailer: String, args: Homebrew::CLI::Args).returns(Integer) }
|
||||||
def git_log_trailers_cmd(repo_path, trailer, args)
|
def git_log_trailers_cmd(repo_path, trailer, args)
|
||||||
cmd = ["git", "-C", repo_path, "log", "--oneline"]
|
cmd = ["git", "-C", repo_path, "log", "--oneline"]
|
||||||
|
@ -86,7 +86,7 @@ class Tap
|
|||||||
# e.g. `user/repo`
|
# e.g. `user/repo`
|
||||||
attr_reader :name
|
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.
|
# It combines {#user} and 'homebrew-'-prefixed {#repo} with a slash.
|
||||||
# e.g. `user/homebrew-repo`
|
# e.g. `user/homebrew-repo`
|
||||||
attr_reader :full_name
|
attr_reader :full_name
|
||||||
@ -100,7 +100,7 @@ class Tap
|
|||||||
@user = user
|
@user = user
|
||||||
@repo = repo
|
@repo = repo
|
||||||
@name = "#{@user}/#{@repo}".downcase
|
@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 = TAP_DIRECTORY/@full_name.downcase
|
||||||
@path.extend(GitRepositoryExtension)
|
@path.extend(GitRepositoryExtension)
|
||||||
@alias_table = nil
|
@alias_table = nil
|
||||||
|
@ -699,4 +699,14 @@ module GitHub # rubocop:disable Metrics/ModuleLength
|
|||||||
|
|
||||||
output[/^Status: (200)/, 1] != "200"
|
output[/^Status: (200)/, 1] != "200"
|
||||||
end
|
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
|
end
|
||||||
|
@ -253,9 +253,9 @@ module GitHub
|
|||||||
end
|
end
|
||||||
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|
|
(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)
|
yield(result, page)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user