|
| 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