ci: attribute release contributors
This commit is contained in:
@@ -8,6 +8,7 @@ on:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
pull-requests: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
@@ -20,6 +21,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate changelog
|
- name: Generate changelog
|
||||||
id: changelog
|
id: changelog
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
TAG="${GITHUB_REF_NAME}"
|
TAG="${GITHUB_REF_NAME}"
|
||||||
@@ -38,27 +41,103 @@ jobs:
|
|||||||
|
|
||||||
FEATS=""
|
FEATS=""
|
||||||
FIXES=""
|
FIXES=""
|
||||||
|
CONTRIBUTORS=""
|
||||||
|
declare -A SEEN_PRS=()
|
||||||
|
declare -A SEEN_CONTRIBUTORS=()
|
||||||
|
|
||||||
|
add_contributor() {
|
||||||
|
local login="$1"
|
||||||
|
local avatar="$2"
|
||||||
|
local profile="$3"
|
||||||
|
[ -z "$login" ] && return
|
||||||
|
[ -n "${SEEN_CONTRIBUTORS[$login]+x}" ] && return
|
||||||
|
SEEN_CONTRIBUTORS["$login"]=1
|
||||||
|
avatar="${avatar:-https://github.com/${login}.png?size=96}"
|
||||||
|
profile="${profile:-https://github.com/${login}}"
|
||||||
|
CONTRIBUTORS="${CONTRIBUTORS}<a href=\"${profile}\"><img src=\"${avatar}\" width=\"48\" height=\"48\" alt=\"@${login}\"></a> "
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_conventional() {
|
||||||
|
local text="$1"
|
||||||
|
ENTRY_TYPE=""
|
||||||
|
ENTRY_TITLE=""
|
||||||
|
local pattern='^(feat|fix)(\([^)]*\))?!?:[[:space:]](.+)$'
|
||||||
|
if [[ "$text" =~ $pattern ]]; then
|
||||||
|
ENTRY_TYPE="${BASH_REMATCH[1]}"
|
||||||
|
ENTRY_TITLE="${BASH_REMATCH[3]}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
author_suffix() {
|
||||||
|
local login="$1"
|
||||||
|
local profile="$2"
|
||||||
|
local name="$3"
|
||||||
|
if [ -n "$login" ]; then
|
||||||
|
printf ' by [@%s](%s)' "$login" "${profile:-https://github.com/${login}}"
|
||||||
|
elif [ -n "$name" ]; then
|
||||||
|
printf ' by %s' "$name"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# %H = hash, %s = subject (first line)
|
# %H = hash, %s = subject (first line)
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
[ -z "$line" ] && continue
|
[ -z "$line" ] && continue
|
||||||
sha="${line%% *}"
|
sha="${line%%$'\t'*}"
|
||||||
subject="${line#* }"
|
subject="${line#*$'\t'}"
|
||||||
# match conventional commits: feat, fix (with optional scope and breaking !)
|
|
||||||
if echo "$subject" | grep -qE '^(feat|fix)(\([^)]+\))?!?: '; then
|
commit_login="$(gh api "repos/${REPO}/commits/${sha}" --jq '.author.login // empty')"
|
||||||
type="$(echo "$subject" | sed -E 's/^([a-z]+)(\([^)]+\))?!?:.*/\1/')"
|
commit_name="$(gh api "repos/${REPO}/commits/${sha}" --jq '.commit.author.name // empty')"
|
||||||
# strip type prefix for display, keep rest as title
|
commit_avatar=""
|
||||||
title="$(echo "$subject" | sed -E 's/^[a-z]+(\([^)]+\))?!?: //')"
|
commit_profile=""
|
||||||
short="$(echo "$sha" | cut -c1-7)"
|
if [ -n "$commit_login" ]; then
|
||||||
url="https://github.com/${REPO}/commit/${sha}"
|
commit_avatar="$(gh api "repos/${REPO}/commits/${sha}" --jq '.author.avatar_url // empty')"
|
||||||
entry="- ${title} ([\`${short}\`](${url}))"
|
commit_profile="$(gh api "repos/${REPO}/commits/${sha}" --jq '.author.html_url // empty')"
|
||||||
if [ "$type" = "feat" ]; then
|
add_contributor "$commit_login" "$commit_avatar" "$commit_profile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
pr="$(gh api "repos/${REPO}/commits/${sha}/pulls" --jq '.[0].number // empty')"
|
||||||
|
if [ -n "$pr" ]; then
|
||||||
|
pr_title="$(gh api "repos/${REPO}/pulls/${pr}" --jq '.title // empty')"
|
||||||
|
pr_login="$(gh api "repos/${REPO}/pulls/${pr}" --jq '.user.login // empty')"
|
||||||
|
pr_avatar="$(gh api "repos/${REPO}/pulls/${pr}" --jq '.user.avatar_url // empty')"
|
||||||
|
pr_profile="$(gh api "repos/${REPO}/pulls/${pr}" --jq '.user.html_url // empty')"
|
||||||
|
pr_url="$(gh api "repos/${REPO}/pulls/${pr}" --jq '.html_url // empty')"
|
||||||
|
add_contributor "$pr_login" "$pr_avatar" "$pr_profile"
|
||||||
|
|
||||||
|
# A conflict-resolution commit and the original PR commit can
|
||||||
|
# both be reachable from a release. Render the PR only once and
|
||||||
|
# attribute it to the PR author, never to the merge author.
|
||||||
|
if [ -z "${SEEN_PRS[$pr]+x}" ]; then
|
||||||
|
candidate="$pr_title"
|
||||||
|
if ! parse_conventional "$candidate"; then
|
||||||
|
candidate="$subject"
|
||||||
|
parse_conventional "$candidate" || true
|
||||||
|
fi
|
||||||
|
if [ -n "$ENTRY_TYPE" ]; then
|
||||||
|
SEEN_PRS["$pr"]=1
|
||||||
|
entry="- ${ENTRY_TITLE} ([#${pr}](${pr_url}))"
|
||||||
|
entry="${entry}$(author_suffix "$pr_login" "$pr_profile" "$commit_name")"
|
||||||
|
if [ "$ENTRY_TYPE" = "feat" ]; then
|
||||||
FEATS="${FEATS}${entry}"$'\n'
|
FEATS="${FEATS}${entry}"$'\n'
|
||||||
elif [ "$type" = "fix" ]; then
|
elif [ "$ENTRY_TYPE" = "fix" ]; then
|
||||||
FIXES="${FIXES}${entry}"$'\n'
|
FIXES="${FIXES}${entry}"$'\n'
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done < <(git log "$RANGE" --format="%H %s" --no-merges)
|
fi
|
||||||
|
elif parse_conventional "$subject"; then
|
||||||
|
short="${sha:0:7}"
|
||||||
|
url="https://github.com/${REPO}/commit/${sha}"
|
||||||
|
entry="- ${ENTRY_TITLE} ([\`${short}\`](${url}))"
|
||||||
|
entry="${entry}$(author_suffix "$commit_login" "$commit_profile" "$commit_name")"
|
||||||
|
if [ "$ENTRY_TYPE" = "feat" ]; then
|
||||||
|
FEATS="${FEATS}${entry}"$'\n'
|
||||||
|
elif [ "$ENTRY_TYPE" = "fix" ]; then
|
||||||
|
FIXES="${FIXES}${entry}"$'\n'
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < <(git log "$RANGE" --format="%H%x09%s" --no-merges)
|
||||||
|
|
||||||
{
|
{
|
||||||
echo "# ${TAG}"
|
echo "# ${TAG}"
|
||||||
@@ -79,6 +158,12 @@ jobs:
|
|||||||
echo "_No relevant conventional commits (feat/fix) in this release._"
|
echo "_No relevant conventional commits (feat/fix) in this release._"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
if [ -n "$CONTRIBUTORS" ]; then
|
||||||
|
echo "## Contributors"
|
||||||
|
echo ""
|
||||||
|
printf "%s\n" "$CONTRIBUTORS"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
echo "---"
|
echo "---"
|
||||||
echo ""
|
echo ""
|
||||||
if [ -n "$PREV_TAG" ]; then
|
if [ -n "$PREV_TAG" ]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user