Skip to content

Commit 0493903

Browse files
committed
build: resolve co-authors from commits
1 parent 3095c9a commit 0493903

File tree

1 file changed

+101
-13
lines changed

1 file changed

+101
-13
lines changed

.github/workflows/scripts/generate_pr_commit_message

Lines changed: 101 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,23 @@ on_error() {
5656
exit "$1"
5757
}
5858

59+
# Resolves a name and email using .mailmap via git check-mailmap, falling back to the provided values if no match is found.
60+
#
61+
# $1 - name
62+
# $2 - email
63+
resolve_name_email() {
64+
local name="$1"
65+
local email="$2"
66+
local resolved
67+
68+
resolved=$(git check-mailmap "$name <$email>" 2>/dev/null)
69+
if [ -n "$resolved" ]; then
70+
echo "$resolved"
71+
else
72+
echo "$name <$email>"
73+
fi
74+
}
75+
5976
# Resolves GitHub handle to name and email using .mailmap.
6077
#
6178
# $1 - GitHub handle
@@ -76,24 +93,47 @@ resolve_user() {
7693
fi
7794
}
7895

79-
# Makes authenticated GitHub API requests.
96+
# Makes GitHub API requests.
8097
#
8198
# $1 - HTTP method (GET or POST)
8299
# $2 - API endpoint
83-
# $3 - Data for POST requests
100+
# $3 - data for POST requests
84101
github_api() {
85102
local method="$1"
86103
local endpoint="$2"
87104
local data="$3"
88105

89-
if [ "$method" == "GET" ]; then
90-
curl -s -H "Authorization: token $GITHUB_TOKEN" "$GITHUB_API_URL$endpoint"
91-
elif [ "$method" == "POST" ]; then
92-
curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" -H "Content-Type: application/json" -d "$data" "$GITHUB_API_URL$endpoint"
93-
else
94-
echo "Invalid HTTP method: $method"
95-
on_error 1
106+
# Initialize an array to hold curl headers:
107+
local headers=()
108+
109+
# If GITHUB_TOKEN is set, add the Authorization header:
110+
if [ -n "$GITHUB_TOKEN" ]; then
111+
headers+=("-H" "Authorization: token $GITHUB_TOKEN")
96112
fi
113+
114+
# Determine the HTTP method and construct the curl command accordingly...
115+
case "$method" in
116+
GET)
117+
curl -s "${headers[@]}" "$GITHUB_API_URL$endpoint"
118+
;;
119+
POST)
120+
# For POST requests, always set the Content-Type header>
121+
headers+=("-H" "Content-Type: application/json")
122+
123+
# If data is provided, include it in the request:
124+
if [ -n "$data" ]; then
125+
curl -s -X POST "${headers[@]}" -d "$data" "$GITHUB_API_URL$endpoint"
126+
else
127+
# Handle cases where POST data is required but not provided:
128+
echo "POST request requires data."
129+
on_error 1
130+
fi
131+
;;
132+
*)
133+
echo "Invalid HTTP method: $method"
134+
on_error 1
135+
;;
136+
esac
97137
}
98138

99139
# Main execution sequence.
@@ -103,6 +143,10 @@ main() {
103143
pr_title=$(echo "$pr_details" | jq -r '.title')
104144
pr_body=$(echo "$pr_details" | jq -r '.body // ""')
105145
pr_url=$(echo "$pr_details" | jq -r '.html_url')
146+
pr_author_login=$(echo "$pr_details" | jq -r '.user.login')
147+
148+
# Resolve the PR author's name and email using .mailmap:
149+
pr_author_resolved=$(resolve_user "$pr_author_login")
106150

107151
# Extract reviewers:
108152
pr_reviews=$(github_api "GET" "/repos/$REPO_OWNER/$REPO_NAME/pulls/$pr_number/reviews")
@@ -111,8 +155,51 @@ main() {
111155
# Fetch commits in the PR:
112156
pr_commits=$(github_api "GET" "/repos/$REPO_OWNER/$REPO_NAME/pulls/$pr_number/commits")
113157

114-
# Extract co-authors from commits:
115-
co_authors=$(echo "$pr_commits" | jq -r '.[].commit.message' | grep -Eio "Co-authored-by:.*" | sort -u)
158+
# Extract co-authors from commit messages:
159+
processed_co_authors=""
160+
while IFS= read -r co_author_line; do
161+
name_email=$(echo "$co_author_line" | sed -E 's/Co-authored-by:[[:space:]]*(.*)/\1/')
162+
name=$(echo "$name_email" | sed -E 's/^(.*)<.*>$/\1/' | xargs)
163+
email=$(echo "$name_email" | sed -E 's/^.*<(.*)>$/\1/' | xargs)
164+
resolved_author=$(resolve_name_email "$name" "$email")
165+
166+
processed_co_authors+="Co-authored-by: $resolved_author"$'\n'
167+
done <<< "$co_authors"
168+
169+
# Extract commit authors:
170+
authors_info=$(echo "$pr_commits" | jq -r '.[] | .commit.author | "\(.name) <\(.email)>"' | sort -u | sed '/^ *<.*>/d' | sed '/^$/d')
171+
172+
# Process commit authors:
173+
commit_authors=""
174+
while IFS= read -r author_line; do
175+
# Skip empty lines:
176+
if [ -z "$author_line" ]; then
177+
continue
178+
fi
179+
180+
# Extract name and email:
181+
name=$(echo "$author_line" | sed -E 's/^(.*)<.*>$/\1/' | xargs)
182+
email=$(echo "$author_line" | sed -E 's/^.*<(.*)>$/\1/' | xargs)
183+
184+
# Resolve name and email using .mailmap:
185+
resolved_author=$(resolve_name_email "$name" "$email")
186+
187+
# Skip if the resolved author matches the resolved PR author:
188+
if [ "$resolved_author" == "$pr_author_resolved" ]; then
189+
continue
190+
fi
191+
192+
commit_authors+="$resolved_author"$'\n'
193+
done <<< "$authors_info"
194+
195+
# Remove any empty lines and duplicates:
196+
commit_authors=$(echo "$commit_authors" | sort -u | sed '/^$/d')
197+
198+
# Prefix with 'Co-authored-by: ':
199+
commit_authors_formatted=$(echo "$commit_authors" | sed 's/^/Co-authored-by: /' | sort -u)
200+
201+
# Combine co-authors and commit authors:
202+
all_co_authors=$(echo -e "$co_authors\n$commit_authors_formatted" | sort -u | sed '/^$/d')
116203

117204
# Extract 'Signed-off-by' lines from commits:
118205
signed_off_bys=$(echo "$pr_commits" | jq -r '.[].commit.message' | grep -Eio 'Signed-off-by:.*' | sort -u)
@@ -124,6 +211,7 @@ main() {
124211

125212
# GitHub-supported closing keywords:
126213
closing_keywords=("close" "closes" "closed" "fix" "fixes" "fixed" "resolve" "resolves" "resolved")
214+
127215
# Create a regex pattern from the keywords:
128216
keywords_pattern=$(IFS='|'; echo "${closing_keywords[*]}")
129217

@@ -148,8 +236,8 @@ main() {
148236
commit_body+="\n$ref_issues"
149237
fi
150238
commit_body+="\n"
151-
if [ -n "$co_authors" ]; then
152-
commit_body+="\n$co_authors"
239+
if [ -n "$all_co_authors" ]; then
240+
commit_body+="\n$all_co_authors"
153241
fi
154242
for reviewer in $reviewers; do
155243
resolved_reviewer=$(resolve_user "$reviewer")

0 commit comments

Comments
 (0)