Skip to content

Commit 6b3df4b

Browse files
authored
feat: add pr-auto-comments reusable Github Action (#1)
1 parent 2b10168 commit 6b3df4b

File tree

4 files changed

+545
-2
lines changed

4 files changed

+545
-2
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
name: PR Automated Comments Test
2+
3+
on:
4+
# Automatic triggers
5+
pull_request_target:
6+
types: [opened, ready_for_review, closed]
7+
8+
# Manual trigger for testing
9+
workflow_dispatch:
10+
inputs:
11+
test_event_type:
12+
description: 'Event type to simulate for testing'
13+
required: true
14+
type: choice
15+
options:
16+
- opened
17+
- ready_for_review
18+
- merged
19+
20+
jobs:
21+
# When manually triggered, we need to simulate the PR event context
22+
prepare-test-context:
23+
name: Prepare Test Context
24+
if: github.event_name == 'workflow_dispatch'
25+
runs-on: ubuntu-latest
26+
outputs:
27+
is_external: 'true'
28+
is_first_pr: ${{ steps.set-context.outputs.is_first_pr }}
29+
event_type: ${{ steps.set-context.outputs.event_type }}
30+
steps:
31+
- name: Set test context variables
32+
id: set-context
33+
run: |
34+
EVENT_TYPE="${{ github.event.inputs.test_event_type }}"
35+
echo "event_type=$EVENT_TYPE" >> $GITHUB_OUTPUT
36+
37+
# For the opened event, we need to simulate first PR status
38+
if [[ "$EVENT_TYPE" == "opened" ]]; then
39+
echo "is_first_pr=true" >> $GITHUB_OUTPUT
40+
else
41+
echo "is_first_pr=false" >> $GITHUB_OUTPUT
42+
fi
43+
44+
# Real workflow for actual PR events
45+
pr-comments-real:
46+
name: PR Comments (Real)
47+
if: github.event_name == 'pull_request_target'
48+
uses: ./.github/workflows/pr-auto-comments.yml@${{ github.ref_name }}
49+
with:
50+
org_name: "RequestNetwork"
51+
# You can specify additional internal users here if needed
52+
additional_internal_users: ""
53+
# Use default messages
54+
secrets:
55+
token: ${{ secrets.GITHUB_TOKEN }}
56+
57+
# Test workflow for manual triggering - using the actual reusable workflow
58+
first-pr-comment-test:
59+
name: First PR Comment (Test)
60+
needs: prepare-test-context
61+
if: github.event_name == 'workflow_dispatch' && needs.prepare-test-context.outputs.event_type == 'opened'
62+
uses: ./.github/workflows/pr-auto-comments.yml@${{ github.ref_name }}
63+
with:
64+
org_name: "RequestNetwork"
65+
first_pr_comment: "Hello @{{username}}, thank you for submitting your first pull request to the {{repository}} repository. We value your contribution and encourage you to review our contribution guidelines to ensure your submission meets our standards. Please note that every merged PR is automatically enrolled in our Best PR Initiative, offering a chance to win $500 each quarter. Our team is available via GitHub Discussions or Discord if you have any questions. Welcome aboard! (TEST)"
66+
ready_for_review_comment: ""
67+
merged_pr_comment: ""
68+
secrets:
69+
token: ${{ secrets.GITHUB_TOKEN }}
70+
71+
ready-for-review-comment-test:
72+
name: Ready for Review Comment (Test)
73+
needs: prepare-test-context
74+
if: github.event_name == 'workflow_dispatch' && needs.prepare-test-context.outputs.event_type == 'ready_for_review'
75+
uses: ./.github/workflows/pr-auto-comments.yml@${{ github.ref_name }}
76+
with:
77+
org_name: "RequestNetwork"
78+
first_pr_comment: ""
79+
ready_for_review_comment: "Thank you for your submission! As you prepare for the review process, please ensure that your PR title, description, and any linked issues fully comply with our contribution guidelines. A clear explanation of your changes and their context will help expedite the review process. Every merged PR is automatically entered into our Best PR Initiative, offering a chance to win $500 every quarter. We appreciate your attention to detail and look forward to reviewing your contribution! (TEST)"
80+
merged_pr_comment: ""
81+
secrets:
82+
token: ${{ secrets.GITHUB_TOKEN }}
83+
84+
merged-pr-comment-test:
85+
name: Merged PR Comment (Test)
86+
needs: prepare-test-context
87+
if: github.event_name == 'workflow_dispatch' && needs.prepare-test-context.outputs.event_type == 'merged'
88+
uses: ./.github/workflows/pr-auto-comments.yml@${{ github.ref_name }}
89+
with:
90+
org_name: "RequestNetwork"
91+
first_pr_comment: ""
92+
ready_for_review_comment: ""
93+
merged_pr_comment: "Congratulations, your pull request has been merged! Thank you for your valuable contribution to Request Network. As a reminder, every merged PR is automatically entered into our Best PR Initiative, offering a quarterly prize of $500. Your work significantly supports our project's growth, and we encourage you to continue engaging with our community. Additionally, if you want to build or add crypto payments and invoicing features, explore how our API can reduce deployment time from months to hours while offering advanced features. Book a call with our expert to learn more and fast-track your development. (TEST)"
94+
secrets:
95+
token: ${{ secrets.GITHUB_TOKEN }}
96+
97+
# Add completion notification
98+
notify-test-completion:
99+
name: Notify Test Completion
100+
needs: [prepare-test-context]
101+
if: github.event_name == 'workflow_dispatch'
102+
runs-on: ubuntu-latest
103+
steps:
104+
- name: Create notification issue comment
105+
uses: actions/github-script@v6
106+
with:
107+
github-token: ${{ secrets.GITHUB_TOKEN }}
108+
script: |
109+
const eventType = '${{ needs.prepare-test-context.outputs.event_type }}';
110+
const repoName = context.repo.repo;
111+
const orgName = context.repo.owner;
112+
113+
const issue_number = context.issue.number || 1;
114+
115+
await github.rest.issues.createComment({
116+
owner: context.repo.owner,
117+
repo: context.repo.repo,
118+
issue_number: issue_number,
119+
body: `## Test for "${eventType}" PR Event Initiated
120+
121+
A test of the \`${eventType}\` PR event comment has been initiated.
122+
123+
**Note:** Since this is a manual test, this will use hard-coded test variables:
124+
- Repository: ${repoName}
125+
- Organization: ${orgName}
126+
- Testing as an external contributor
127+
128+
Check the [Actions tab](https://github.com/${orgName}/${repoName}/actions/workflows/repo-pr-comments.yml) to see the workflow execution.
129+
130+
*This is a notification from the manual test trigger.*`
131+
});
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
name: PR Automated Comments
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
org_name:
7+
description: 'GitHub organization name to identify internal team members'
8+
required: true
9+
type: string
10+
additional_internal_users:
11+
description: 'Additional comma-separated list of usernames to consider as internal'
12+
required: false
13+
type: string
14+
default: ''
15+
first_pr_comment:
16+
description: 'Message for first PR comments (leave empty to disable first PR comments)'
17+
required: false
18+
type: string
19+
default: 'Hello @{{username}}, thank you for submitting your first pull request to the {{repository}} repository. We value your contribution and encourage you to review our contribution guidelines to ensure your submission meets our standards. Please note that every merged PR is automatically enrolled in our Best PR Initiative, offering a chance to win $500 each quarter. Our team is available via GitHub Discussions or Discord if you have any questions. Welcome aboard!'
20+
ready_for_review_comment:
21+
description: 'Message for PR ready for review comments (leave empty to disable ready for review comments)'
22+
required: false
23+
type: string
24+
default: 'Thank you for your submission! As you prepare for the review process, please ensure that your PR title, description, and any linked issues fully comply with our contribution guidelines. A clear explanation of your changes and their context will help expedite the review process. Every merged PR is automatically entered into our Best PR Initiative, offering a chance to win $500 every quarter. We appreciate your attention to detail and look forward to reviewing your contribution!'
25+
merged_pr_comment:
26+
description: 'Message for merged PR comments (leave empty to disable merged PR comments)'
27+
required: false
28+
type: string
29+
default: 'Congratulations, your pull request has been merged! Thank you for your valuable contribution to Request Network. As a reminder, every merged PR is automatically entered into our Best PR Initiative, offering a quarterly prize of $500. Your work significantly supports our project\'s growth, and we encourage you to continue engaging with our community. Additionally, if you want to build or add crypto payments and invoicing features, explore how our API can reduce deployment time from months to hours while offering advanced features. Book a call with our expert to learn more and fast-track your development.'
30+
secrets:
31+
token:
32+
description: 'GitHub token with org:read permission'
33+
required: false
34+
35+
jobs:
36+
# Central job to check if contributor is external and determine PR status
37+
check-contributor:
38+
name: Check Contributor Status
39+
runs-on: ubuntu-latest
40+
outputs:
41+
is_external: ${{ steps.check.outputs.is_external }}
42+
is_first_pr: ${{ steps.check.outputs.is_first_pr }}
43+
event_type: ${{ steps.event.outputs.type }}
44+
steps:
45+
- name: Determine event type
46+
id: event
47+
run: |
48+
if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then
49+
if [[ "${{ github.event.action }}" == "opened" ]]; then
50+
echo "type=opened" >> $GITHUB_OUTPUT
51+
elif [[ "${{ github.event.action }}" == "ready_for_review" ]]; then
52+
echo "type=ready_for_review" >> $GITHUB_OUTPUT
53+
elif [[ "${{ github.event.action }}" == "closed" && "${{ github.event.pull_request.merged }}" == "true" ]]; then
54+
echo "type=merged" >> $GITHUB_OUTPUT
55+
else
56+
echo "type=other" >> $GITHUB_OUTPUT
57+
fi
58+
else
59+
echo "type=other" >> $GITHUB_OUTPUT
60+
fi
61+
62+
- name: Check if external contributor
63+
id: check
64+
run: |
65+
# Get the PR author
66+
PR_AUTHOR="${{ github.event.pull_request.user.login }}"
67+
ORG_NAME="${{ inputs.org_name }}"
68+
ADDITIONAL_USERS="${{ inputs.additional_internal_users }}"
69+
70+
# First check if user is in the additional internal users list
71+
if [[ "$ADDITIONAL_USERS" == *"$PR_AUTHOR"* ]]; then
72+
echo "User is in additional internal users list, skipping comment"
73+
echo "is_external=false" >> $GITHUB_OUTPUT
74+
echo "is_first_pr=false" >> $GITHUB_OUTPUT
75+
exit 0
76+
fi
77+
78+
# Check if user is an org member
79+
echo "Checking if user is a member of organization $ORG_NAME"
80+
ORG_MEMBER=$(gh api -H "Accept: application/vnd.github+json" \
81+
"/orgs/$ORG_NAME/members/$PR_AUTHOR" --silent || echo "not_found")
82+
83+
if [[ "$ORG_MEMBER" != "not_found" ]]; then
84+
echo "User is an organization member, skipping comment"
85+
echo "is_external=false" >> $GITHUB_OUTPUT
86+
echo "is_first_pr=false" >> $GITHUB_OUTPUT
87+
exit 0
88+
fi
89+
90+
# User is external
91+
echo "is_external=true" >> $GITHUB_OUTPUT
92+
93+
# Only check if this is their first PR if needed
94+
if [[ "${{ steps.event.outputs.type }}" == "opened" ]]; then
95+
# Check if this is their first PR to the repo
96+
PR_COUNT=$(gh api graphql -f query='
97+
query($owner:String!, $repo:String!, $author:String!) {
98+
repository(owner:$owner, name:$repo) {
99+
pullRequests(first:100, states:[OPEN, CLOSED, MERGED], author:$author) {
100+
totalCount
101+
}
102+
}
103+
}' -f owner=${{ github.repository_owner }} -f repo=${{ github.event.repository.name }} -f author=$PR_AUTHOR | jq '.data.repository.pullRequests.totalCount')
104+
105+
if [ "$PR_COUNT" -eq 1 ]; then
106+
echo "First PR from this contributor"
107+
echo "is_first_pr=true" >> $GITHUB_OUTPUT
108+
else
109+
echo "Not the first PR from this contributor"
110+
echo "is_first_pr=false" >> $GITHUB_OUTPUT
111+
fi
112+
else
113+
echo "is_first_pr=false" >> $GITHUB_OUTPUT
114+
fi
115+
env:
116+
GH_TOKEN: ${{ secrets.token || github.token }}
117+
118+
# Leave a comment on first PRs
119+
first-pr-comment:
120+
name: First PR Comment
121+
needs: check-contributor
122+
if: needs.check-contributor.outputs.event_type == 'opened' && needs.check-contributor.outputs.is_external == 'true' && needs.check-contributor.outputs.is_first_pr == 'true' && inputs.first_pr_comment != ''
123+
runs-on: ubuntu-latest
124+
steps:
125+
- name: Leave first PR comment
126+
uses: actions/github-script@v6
127+
with:
128+
github-token: ${{ github.token }}
129+
script: |
130+
const variables = {
131+
username: context.payload.pull_request.user.login,
132+
repository: context.payload.repository.name,
133+
org: context.repo.owner,
134+
};
135+
136+
let commentBody = `${{ inputs.first_pr_comment }}`;
137+
Object.entries(variables).forEach(([key, value]) => {
138+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
139+
commentBody = commentBody.replace(regex, value);
140+
});
141+
142+
github.rest.issues.createComment({
143+
issue_number: context.issue.number,
144+
owner: context.repo.owner,
145+
repo: context.repo.repo,
146+
body: commentBody
147+
});
148+
149+
# Leave a comment when PR is marked ready for review
150+
ready-for-review-comment:
151+
name: Ready for Review Comment
152+
needs: check-contributor
153+
if: needs.check-contributor.outputs.event_type == 'ready_for_review' && needs.check-contributor.outputs.is_external == 'true' && inputs.ready_for_review_comment != ''
154+
runs-on: ubuntu-latest
155+
steps:
156+
- name: Leave ready for review comment
157+
uses: actions/github-script@v6
158+
with:
159+
github-token: ${{ github.token }}
160+
script: |
161+
const variables = {
162+
username: context.payload.pull_request.user.login,
163+
repository: context.payload.repository.name,
164+
org: context.repo.owner,
165+
};
166+
167+
let commentBody = `${{ inputs.ready_for_review_comment }}`;
168+
Object.entries(variables).forEach(([key, value]) => {
169+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
170+
commentBody = commentBody.replace(regex, value);
171+
});
172+
173+
github.rest.issues.createComment({
174+
issue_number: context.issue.number,
175+
owner: context.repo.owner,
176+
repo: context.repo.repo,
177+
body: commentBody
178+
});
179+
180+
# Leave a comment when PR is merged
181+
merged-pr-comment:
182+
name: Merged PR Comment
183+
needs: check-contributor
184+
if: needs.check-contributor.outputs.event_type == 'merged' && needs.check-contributor.outputs.is_external == 'true' && inputs.merged_pr_comment != ''
185+
runs-on: ubuntu-latest
186+
steps:
187+
- name: Leave merged PR comment
188+
uses: actions/github-script@v6
189+
with:
190+
github-token: ${{ github.token }}
191+
script: |
192+
const variables = {
193+
username: context.payload.pull_request.user.login,
194+
repository: context.payload.repository.name,
195+
org: context.repo.owner,
196+
};
197+
198+
let commentBody = `${{ inputs.merged_pr_comment }}`;
199+
Object.entries(variables).forEach(([key, value]) => {
200+
const regex = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
201+
commentBody = commentBody.replace(regex, value);
202+
});
203+
204+
github.rest.issues.createComment({
205+
issue_number: context.issue.number,
206+
owner: context.repo.owner,
207+
repo: context.repo.repo,
208+
body: commentBody
209+
});

0 commit comments

Comments
 (0)