name: PR Template on: pull_request_target: types: - opened - edited - synchronize permissions: contents: read pull-requests: write issues: write jobs: validate: name: Validate runs-on: ubuntu-latest steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: ref: ${{ github.event.repository.default_branch }} - name: Validate PR template id: validate continue-on-error: true env: PR_BODY: ${{ github.event.pull_request.body }} run: node util/check-pr-template.js - name: Handle incomplete PR if: steps.validate.outcome == 'failure' uses: actions/github-script@v8 with: github-token: ${{ secrets.BOT }} script: | const label = "reason: incomplete pr"; try { await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label }); } catch (error) { if (error.status === 404) { await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: "D93F0B", description: "Your PR template is not complete. (e.g. missing the requirements form, missing website preview)" }); } else { throw error; } } const labels = await github.rest.issues.listLabelsOnIssue({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number }); if (!labels.data.some((item) => item.name === label)) { await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, labels: [label] }); } const marker = ""; const comments = await github.paginate( github.rest.issues.listComments, { owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number } ); const alreadyCommented = comments.some( (comment) => comment.user?.login === "is-a-dev-bot" && comment.body?.includes(marker) ); if (!alreadyCommented) { const body = [ marker, "## ❌ Incomplete PR template", "", "This pull request is missing required information from the PR template.", "", "Please make sure that:", "", "- Every required checkbox is checked.", "- **Website Preview** is filled out.", "- **Website Purpose** is filled out.", "", "Once the template has been completed, this check will run again automatically." ].join("\n"); await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body }); } - name: Remove incomplete label and comment if: steps.validate.outcome == 'success' uses: actions/github-script@v8 with: github-token: ${{ secrets.BOT }} script: | const label = "reason: incomplete pr"; const marker = ""; try { await github.rest.issues.removeLabel({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, name: label }); } catch (error) { if (error.status !== 404) { throw error; } } const comments = await github.paginate( github.rest.issues.listComments, { owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number } ); for (const comment of comments) { if ( comment.user?.login === "is-a-dev-bot" && comment.body?.includes(marker) ) { await github.rest.issues.deleteComment({ owner: context.repo.owner, repo: context.repo.repo, comment_id: comment.id }); } } - name: Fail if PR template is incomplete if: steps.validate.outcome == 'failure' run: | echo "::error::PR template is incomplete." exit 1