Skip to content

Commit 761523a

Browse files
ci: add codeowners and contributor verification workflow
1 parent 43fe3ab commit 761523a

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @thinkparq/rust

.github/workflows/contributors.yml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: Contributor Verification
2+
3+
# This workflow serves two purposes:
4+
# * Verifies all commit authors/committers have signed the ThinkParQ CLA.
5+
# * Verified all commits are made using expected names+email addresses to avoid a contributor
6+
# accidentally leaking their private information (i.e., forgetting to use a GitHub noreply email).
7+
8+
on:
9+
pull_request:
10+
types: [opened, synchronize]
11+
12+
jobs:
13+
verify:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Check out code
17+
uses: actions/checkout@v3
18+
with:
19+
fetch-depth: 0 # Ensure we have the full commit history for this PR
20+
- name: Verify the creator of this PR has signed the ThinkParQ contributor license agreement (CLA)
21+
env:
22+
APPROVED_CONTRIBUTORS: ${{ vars.APPROVED_CONTRIBUTORS }}
23+
run: |
24+
PR_USER="${{ github.event.pull_request.user.login }}"
25+
echo "Pull request created by '$PR_USER'"
26+
27+
# APPROVED_CONTRIBUTORS is expected as a space-separated list (name1, name2, ...)
28+
ALLOWED_USERS="$APPROVED_CONTRIBUTORS"
29+
IS_ALLOWED=false
30+
31+
for user in $ALLOWED_USERS; do
32+
if [ "$user" = "$PR_USER" ]; then
33+
IS_ALLOWED=true
34+
break
35+
fi
36+
done
37+
38+
if [ "$IS_ALLOWED" = "false" ]; then
39+
echo "::error::User '$PR_USER' has not yet signed the ThinkParQ contributor license agreement. Please contact [email protected] to get started."
40+
exit 1
41+
else
42+
echo "::notice::User '$PR_USER' has signed the ThinkParQ contributor license agreement."
43+
fi
44+
- name: Verify all commits were made by known committers using their expected names and emails
45+
env:
46+
# Fine to print the list of approved committers in the logs because it only contains a
47+
# list of names and emails that should be allowed in commits.
48+
APPROVED_COMMITTERS: ${{ vars.APPROVED_COMMITTERS }}
49+
run: |
50+
# Determine base branch for this PR
51+
BASE_REF="${{ github.event.pull_request.base.ref }}"
52+
echo "Base branch is $BASE_REF"
53+
54+
# Gather the commits that are unique to this PR
55+
COMMITS=$(git log "origin/$BASE_REF..HEAD" --pretty=format:"%H")
56+
57+
if [ -z "$COMMITS" ]; then
58+
echo "No new commits found (maybe this PR is empty?)."
59+
exit 0
60+
fi
61+
62+
echo "Analyzing commits in this PR:"
63+
echo "$COMMITS"
64+
65+
# Parse the JSON from $APPROVED_COMMITTERS using 'jq'
66+
# Expected JSON structure is { "Name1": "Email1", "Name2": "Email2", ... }
67+
68+
EXIT_CODE=0
69+
70+
for c in $COMMITS; do
71+
AUTH_NAME=$(git show -s --format="%an" "$c")
72+
AUTH_EMAIL=$(git show -s --format="%ae" "$c")
73+
COMM_NAME=$(git show -s --format="%cn" "$c")
74+
COMM_EMAIL=$(git show -s --format="%ce" "$c")
75+
76+
# Mask both emails so they won't appear in cleartext logs
77+
echo "::add-mask::$AUTH_EMAIL"
78+
echo "::add-mask::$COMM_EMAIL"
79+
80+
echo "Checking commit $c by $AUTH_NAME / committer $COMM_NAME"
81+
82+
# Lookup the expected email for the AUTHOR name
83+
EXPECTED_AUTHOR_EMAIL=$(echo "${APPROVED_COMMITTERS}" | jq -r ".\"$AUTH_NAME\"")
84+
if [ "$EXPECTED_AUTHOR_EMAIL" = "null" ] || [ -z "$EXPECTED_AUTHOR_EMAIL" ]; then
85+
echo "::error::Author name '$AUTH_NAME' is not an approved name. Did they forget to set the right Git user.name?"
86+
EXIT_CODE=1
87+
else
88+
# Compare actual email to the expected email
89+
if [ "$AUTH_EMAIL" != "$EXPECTED_AUTHOR_EMAIL" ]; then
90+
echo "::error::Author '$AUTH_NAME' used an unapproved email. Did they forget to set the right Git user.email?"
91+
EXIT_CODE=1
92+
fi
93+
fi
94+
95+
# Lookup the expected email for the COMMITTER name
96+
EXPECTED_COMMITTER_EMAIL=$(echo "${APPROVED_COMMITTERS}" | jq -r ".\"$COMM_NAME\"")
97+
if [ "$EXPECTED_COMMITTER_EMAIL" = "null" ] || [ -z "$EXPECTED_COMMITTER_EMAIL" ]; then
98+
echo "::error::Committer name '$COMM_NAME' is not an approved name. Did they forget to set the right Git user.name?"
99+
EXIT_CODE=1
100+
else
101+
if [ "$COMM_EMAIL" != "$EXPECTED_COMMITTER_EMAIL" ]; then
102+
echo "::error::Committer '$COMM_NAME' used an unapproved email. Did they forget to set the right Git user.email"
103+
EXIT_CODE=1
104+
fi
105+
fi
106+
done
107+
108+
if [ "$EXIT_CODE" -ne 0 ]; then
109+
echo "::error::One or more commits failed the policy check."
110+
exit $EXIT_CODE
111+
fi
112+
113+
echo "::notice::All commits were made by known committers with their expected names and emails."

0 commit comments

Comments
 (0)