Skip to content

Commit ced7ebb

Browse files
committed
ci: automatically add Reviewed-by trailer when Accepted label is set
This introduce new workflow that is run when Accepted label is set. It appends Reviewed-by trailers to all commits in the pull request for all reviewers that ack-ed it. * It is skipped if Accepted label is missing/removed * It is no-op success if PR was synchronized after label was set (this is required to make it green as it is automatically re-run when the job finishes as a side effect to pushing to this repository) * It adds the trailers when Accepted label is added It uses secrets.BOT_TOKEN and SSSD_AUTHORS variable that contains mapping from github account to name and email. Since PR CI is restarted when commits with Reviewed-by are pushed, the job also submits comment with current PR CI status, so it is not lost and we do not have to necessarily wait for new PR CI run to finish.
1 parent f84bc33 commit ced7ebb

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed

.github/workflows/accepted.yml

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
name: Accepted
2+
on:
3+
pull_request_target:
4+
types:
5+
- synchronize
6+
- labeled
7+
- unlabeled
8+
env:
9+
PR_ID: ${{ github.event.pull_request.number }}
10+
GH_TOKEN: ${{ secrets.BOT_TOKEN }}
11+
AUTHORS: ${{ vars.SSSD_AUTHORS }}
12+
ACTOR: ${{ github.actor }}
13+
jobs:
14+
15+
accepted-label-set:
16+
# Make the job appear as skipped if Accepted label is missing
17+
if: >
18+
(
19+
github.event.action == 'labeled'
20+
&& github.event.label.name == 'Accepted'
21+
) || (
22+
github.event.action == 'synchronize'
23+
&& contains(github.event.pull_request.labels.*.name, 'Accepted')
24+
)
25+
runs-on: ubuntu-latest
26+
permissions:
27+
contents: write
28+
pull-requests: write
29+
30+
steps:
31+
- name: Checkout Repository
32+
uses: actions/checkout@v4
33+
with:
34+
# Fetch the entire history of the repository
35+
# This is necessary for a successful git push
36+
fetch-depth: 0
37+
# The pull request head branch is checked out
38+
# This is the branch that was merged or closed
39+
ref: ${{ github.event.pull_request.head.ref }}
40+
token: ${{ secrets.BOT_TOKEN }}
41+
42+
- name: Reviewed-by trailer was already added and pull request is accepted
43+
if: github.event.action == 'synchronize'
44+
run: |
45+
# Just succeed, as the pull request was updated by this job
46+
exit 0
47+
48+
- name: Set git user identity
49+
if: github.event.action == 'labeled'
50+
run: |
51+
git config --global user.name "sssd-bot"
52+
git config --global user.email "sssd-maintainers@lists.fedoraproject.org"
53+
54+
- name: Add 'Reviewed-by' trailer
55+
if: github.event.action == 'labeled'
56+
run: |
57+
set -e -o pipefail
58+
59+
PR_REVIEWERS=`gh pr view "$PR_ID" --json reviews --jq '.reviews.[] | select(.state == "APPROVED") | .author.login' | sort`
60+
PR_COMMITS_SHA=`gh pr view "$PR_ID" --json commits --jq .commits.[].oid`
61+
PR_COMMITS_FIRST=`echo "$PR_COMMITS_SHA" | head -1`
62+
63+
git config trailer.where end
64+
git config trailer.ifexists addIfDifferent
65+
66+
trailers=""
67+
for name in $PR_REVIEWERS; do
68+
value=$(echo "$AUTHORS" | jq -r \
69+
--arg user "$name" \
70+
'
71+
# Iterate over the array and select the object with a matching github_username.
72+
.[] | select(.github_username == $user) |
73+
74+
# If a match is found, format the output as "Name <email>".
75+
# The `//` operator provides a fallback.
76+
"\(.name) <\(.email)>" //
77+
78+
# If no match is found, use the default fallback string.
79+
"\($user) <https://github.com/\($user)>"
80+
'
81+
)
82+
83+
trailers+="--trailer 'Reviewed-by: $value' "
84+
done
85+
86+
if [ ! -z "$trailers" ]; then
87+
git rebase "$PR_COMMITS_FIRST~1" -x "git commit --allow-empty --amend --no-edit $trailers"
88+
fi
89+
90+
- name: Add comment to print current CI status
91+
if: github.event.action == 'labeled'
92+
run: |
93+
set -e -o pipefail
94+
95+
COMMENT_FILE=.accepted-add-reviewed-by.comment
96+
97+
echo "**The pull request was accepted by @$ACTOR with the following PR CI status:**" > $COMMENT_FILE
98+
echo "" >> $COMMENT_FILE
99+
echo "---" >> $COMMENT_FILE
100+
echo "" >> $COMMENT_FILE
101+
102+
CHECKS=`gh pr checks "$PR_ID" --json state,workflow,name,link`
103+
104+
echo $CHECKS | jq -r '
105+
# Filter the array to exclude accepted and backport workflows
106+
# these will be always in_progress or skipped at this point
107+
map(select(
108+
.workflow != "Accepted" and .workflow != "Backport"
109+
)) |
110+
111+
# First, sort the entire array by the "workflow" and "name" keys.
112+
sort_by(.workflow, .name | ascii_downcase) |
113+
114+
# Then, iterate over each element in the sorted array.
115+
.[] |
116+
117+
# A conditional check to determine the icon based on the state.
118+
(if .state == "FAILURE" then "🔴"
119+
elif .state == "SUCCESS" then "🟢"
120+
elif .state == "CANCELLED" then "⚪"
121+
elif .state == "IN_PROGRESS" then "🟡"
122+
elif .state == "PENDING" then "⏳"
123+
elif .state == "SKIPPED" then "➖"
124+
else .state
125+
end
126+
) as $icon |
127+
128+
# Another conditional check to format the output.
129+
# If the workflow is an empty string, print a simplified format.
130+
# Otherwise, print the full format including the workflow.
131+
if .workflow == "" then
132+
"\($icon)&ensp;[\(.name)](\(.link)) (\(.state | ascii_downcase))"
133+
else
134+
"\($icon)&ensp;[\(.workflow) / \(.name)](\(.link)) (\(.state | ascii_downcase))"
135+
end
136+
' >> "$COMMENT_FILE"
137+
138+
echo "" >> $COMMENT_FILE
139+
echo "---" >> $COMMENT_FILE
140+
echo "" >> $COMMENT_FILE
141+
142+
unfinished=`echo $CHECKS | jq '.[] | select(.state != "SUCCESS")'`
143+
if [ -z "$unfinished" ]; then
144+
echo "All checks passed. It is safe to merge this pull request." >> $COMMENT_FILE
145+
else
146+
echo "**There are unsuccessful or unfinished checks.** Make sure that the failures are not related to this pull request before merging." >> $COMMENT_FILE
147+
fi
148+
149+
gh pr comment "$PR_ID" --body-file "$COMMENT_FILE"
150+
151+
- name: Push changes
152+
if: github.event.action == 'labeled'
153+
run: git push origin HEAD --force

0 commit comments

Comments
 (0)