From 5dd3261868c85b21fc489e56d6de4bfbe5253516 Mon Sep 17 00:00:00 2001 From: Arthur Dos Santos Sousa <102875535+KiritoGamesPlays@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:42:28 -0300 Subject: [PATCH 01/33] Update CNAME record in kiritodb.adssousag.json --- domains/kiritodb.adssousag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domains/kiritodb.adssousag.json b/domains/kiritodb.adssousag.json index 42a2f78e7a..964e2a8b88 100644 --- a/domains/kiritodb.adssousag.json +++ b/domains/kiritodb.adssousag.json @@ -4,7 +4,7 @@ "email": "arthursantossousa05@gmail.com" }, "records": { - "CNAME": "kiritodb-host.triniumhost.com" + "CNAME": "p-host.triniumhost.indevs.in" }, "proxied": true } From 0f05ff41874cc73a7b21729ae6d72b344323dc90 Mon Sep 17 00:00:00 2001 From: Arthur Dos Santos Sousa <102875535+KiritoGamesPlays@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:42:33 -0300 Subject: [PATCH 02/33] Update CNAME record in kiritoapi.adssousag.json --- domains/kiritoapi.adssousag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domains/kiritoapi.adssousag.json b/domains/kiritoapi.adssousag.json index de8e5bd978..964e2a8b88 100644 --- a/domains/kiritoapi.adssousag.json +++ b/domains/kiritoapi.adssousag.json @@ -4,7 +4,7 @@ "email": "arthursantossousa05@gmail.com" }, "records": { - "CNAME": "kiritoapi-host.triniumhost.com" + "CNAME": "p-host.triniumhost.indevs.in" }, "proxied": true } From 144bc6c3a703910823c76e145051cdbf63bbc4e1 Mon Sep 17 00:00:00 2001 From: Arthur Dos Santos Sousa <102875535+KiritoGamesPlays@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:42:37 -0300 Subject: [PATCH 03/33] Update CNAME record in db-projetos.adssousag.json --- domains/db-projetos.adssousag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domains/db-projetos.adssousag.json b/domains/db-projetos.adssousag.json index 922dcdfd2e..964e2a8b88 100644 --- a/domains/db-projetos.adssousag.json +++ b/domains/db-projetos.adssousag.json @@ -4,7 +4,7 @@ "email": "arthursantossousa05@gmail.com" }, "records": { - "CNAME": "p3-host.triniumhost.com" + "CNAME": "p-host.triniumhost.indevs.in" }, "proxied": true } From 6dcb503a0e4b8d3b926c8cd3f6eea62cb8a61f19 Mon Sep 17 00:00:00 2001 From: Arthur Dos Santos Sousa <102875535+KiritoGamesPlays@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:42:41 -0300 Subject: [PATCH 04/33] Update CNAME record in mesh-kiritoapi.adssousag.json --- domains/mesh-kiritoapi.adssousag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domains/mesh-kiritoapi.adssousag.json b/domains/mesh-kiritoapi.adssousag.json index 922dcdfd2e..964e2a8b88 100644 --- a/domains/mesh-kiritoapi.adssousag.json +++ b/domains/mesh-kiritoapi.adssousag.json @@ -4,7 +4,7 @@ "email": "arthursantossousa05@gmail.com" }, "records": { - "CNAME": "p3-host.triniumhost.com" + "CNAME": "p-host.triniumhost.indevs.in" }, "proxied": true } From fb0fdf529707e0dd4734b4c05442ab5012869dc4 Mon Sep 17 00:00:00 2001 From: Arthur Dos Santos Sousa <102875535+KiritoGamesPlays@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:42:44 -0300 Subject: [PATCH 05/33] Update CNAME record in myst-kiritoapi.adssousag.json --- domains/myst-kiritoapi.adssousag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domains/myst-kiritoapi.adssousag.json b/domains/myst-kiritoapi.adssousag.json index 922dcdfd2e..964e2a8b88 100644 --- a/domains/myst-kiritoapi.adssousag.json +++ b/domains/myst-kiritoapi.adssousag.json @@ -4,7 +4,7 @@ "email": "arthursantossousa05@gmail.com" }, "records": { - "CNAME": "p3-host.triniumhost.com" + "CNAME": "p-host.triniumhost.indevs.in" }, "proxied": true } From 208061827a0a94364f553ff376b616097d07e79e Mon Sep 17 00:00:00 2001 From: Arthur Dos Santos Sousa <102875535+KiritoGamesPlays@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:42:51 -0300 Subject: [PATCH 06/33] Update CNAME record in status-kiritodb.adssousag.json --- domains/status-kiritodb.adssousag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domains/status-kiritodb.adssousag.json b/domains/status-kiritodb.adssousag.json index 922dcdfd2e..964e2a8b88 100644 --- a/domains/status-kiritodb.adssousag.json +++ b/domains/status-kiritodb.adssousag.json @@ -4,7 +4,7 @@ "email": "arthursantossousa05@gmail.com" }, "records": { - "CNAME": "p3-host.triniumhost.com" + "CNAME": "p-host.triniumhost.indevs.in" }, "proxied": true } From 61ba50f5f34d9c2a484fb3d2820f83c4ba187950 Mon Sep 17 00:00:00 2001 From: Arthur Dos Santos Sousa <102875535+KiritoGamesPlays@users.noreply.github.com> Date: Tue, 18 Aug 2026 20:42:56 -0300 Subject: [PATCH 07/33] Update CNAME record in status-kiritoapi.adssousag.json --- domains/status-kiritoapi.adssousag.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domains/status-kiritoapi.adssousag.json b/domains/status-kiritoapi.adssousag.json index 922dcdfd2e..964e2a8b88 100644 --- a/domains/status-kiritoapi.adssousag.json +++ b/domains/status-kiritoapi.adssousag.json @@ -4,7 +4,7 @@ "email": "arthursantossousa05@gmail.com" }, "records": { - "CNAME": "p3-host.triniumhost.com" + "CNAME": "p-host.triniumhost.indevs.in" }, "proxied": true } From bc17404f7ca085aed78f7c4cc8f05cd6e15ca8c8 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 11:48:15 +0800 Subject: [PATCH 08/33] Create check-pr-template.js --- util/check-pr-template.js | 76 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 util/check-pr-template.js diff --git a/util/check-pr-template.js b/util/check-pr-template.js new file mode 100644 index 0000000000..c05db0f978 --- /dev/null +++ b/util/check-pr-template.js @@ -0,0 +1,76 @@ +const body = process.env.PR_BODY || ""; + +const REQUIRED_CHECKBOXES = [ + "I agree to the [Terms of Service]", + "My file is following the [domain structure]", + "My website is reachable and completed.", + "My website is software development related.", + "My website is not for commercial use.", + "I have provided sufficient contact information in the `owner` key.", + "I have provided a link to my website below.", +]; + +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + +function isRequiredCheckboxChecked(text) { + const regex = new RegExp( + `-\\s*\\[[xX]\\]\\s*(?:\\s*)?${escapeRegExp(text)}`, + "i", + ); + + return regex.test(body); +} + +function getSection(startMarker, endMarker) { + const regex = new RegExp( + `${escapeRegExp(startMarker)}([\\s\\S]*?)${escapeRegExp(endMarker)}`, + "i", + ); + + const match = body.match(regex); + + return match ? match[1].trim() : ""; +} + +const errors = []; + +const uncheckedRequirements = REQUIRED_CHECKBOXES.filter( + (requirement) => !isRequiredCheckboxChecked(requirement), +); + +if (uncheckedRequirements.length > 0) { + errors.push( + "The following required checkboxes have not been checked:", + ...uncheckedRequirements.map((requirement) => `- ${requirement}`), + ); +} + +const websitePreview = getSection( + "", + "", +); + +if (!websitePreview) { + errors.push("The **Website Preview** section has not been filled out."); +} + +const websitePurpose = getSection( + "", + "", +); + +if (!websitePurpose) { + errors.push("The **Website Purpose** section has not been filled out."); +} + +if (errors.length > 0) { + console.error("PR template validation failed."); + console.error(""); + console.error(errors.join("\n")); + + process.exit(1); +} + +console.log("PR template validation passed."); From dc8f6e9099330c94d9450acf8346160f21d9c1bc Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 11:53:40 +0800 Subject: [PATCH 09/33] Create pr-template.yml --- .github/workflows/pr-template.yml | 142 ++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 .github/workflows/pr-template.yml diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml new file mode 100644 index 0000000000..cf4f83152a --- /dev/null +++ b/.github/workflows/pr-template.yml @@ -0,0 +1,142 @@ +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 scripts/validate-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.name, + name: label + }); + } catch (error) { + if (error.status === 404) { + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.name, + name: label, + color: "D93F0B", + description: "Your PR template is not complete. (e.g. missing the requirements form, missing website preview)" + }); + } else { + throw error; + } + } + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.name, + issue_number: context.issue.number, + labels: [label] + }); + + const body = [ + "## ❌ 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.name, + issue_number: context.issue.number, + body + }); + + - name: Remove incomplete label + if: steps.validate.outcome == 'success' + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.BOT }} + script: | + const label = "reason: incomplete pr"; + + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.name, + issue_number: context.issue.number, + name: label + }); + } catch (error) { + if (error.status !== 404) { + throw error; + } + + tests: + name: Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - run: npm ci + + - name: Fetch PR information + if: github.event_name == 'pull_request' + run: | + echo "PR_AUTHOR=${{ github.event.pull_request.user.login }}" >> $GITHUB_ENV + echo "PR_AUTHOR_ID=${{ github.event.pull_request.user.id }}" >> $GITHUB_ENV + + LABELS=$(gh api --jq '[.labels[].name]' /repos/{owner}/{repo}/pulls/${{ github.event.number }}) + echo "PR_LABELS=$LABELS" >> $GITHUB_ENV + + FILES=$(gh api --jq '[.[] | select(.status != "removed") | .filename]' /repos/{owner}/{repo}/pulls/${{ github.event.number }}/files) + echo "CHANGED_FILES=$FILES" >> $GITHUB_ENV + + REMOVED_FILE_DATA=$(gh api --jq '[.[] | select(.status == "removed") | {name: .filename, data: .patch}]' /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files) + echo "DELETED_FILES=$REMOVED_FILE_DATA" >> $GITHUB_ENV + env: + GH_TOKEN: ${{ github.token }} + + - uses: gacts/install-dnscontrol@890ba3249712c51203ccb7aba63307c0091e921b # v1.3.4 + if: github.event_name == 'pull_request' && contains(fromJson(env.CHANGED_FILES), 'dnsconfig.js') + with: + version: 4.14.0 + + - name: Run DNSControl checks + run: dnscontrol check + if: github.event_name == 'pull_request' && contains(fromJson(env.CHANGED_FILES), 'dnsconfig.js') + + - name: Run tests + run: npx ava tests/*.test.js --timeout=1m From 120bf3a8eeb3cff954ee6ebda1a693d7c9af4328 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 11:54:35 +0800 Subject: [PATCH 10/33] Update check-pr-template.js --- util/check-pr-template.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/util/check-pr-template.js b/util/check-pr-template.js index c05db0f978..1b20233213 100644 --- a/util/check-pr-template.js +++ b/util/check-pr-template.js @@ -47,21 +47,21 @@ if (uncheckedRequirements.length > 0) { ); } -const websitePreview = getSection( - "", - "", -); - -if (!websitePreview) { +if ( + !getSection( + "", + "", + ) +) { errors.push("The **Website Preview** section has not been filled out."); } -const websitePurpose = getSection( - "", - "", -); - -if (!websitePurpose) { +if ( + !getSection( + "", + "", + ) +) { errors.push("The **Website Purpose** section has not been filled out."); } @@ -69,7 +69,6 @@ if (errors.length > 0) { console.error("PR template validation failed."); console.error(""); console.error(errors.join("\n")); - process.exit(1); } From 4b926a8f12871a84eb692630039aabcc8f23996d Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 11:55:31 +0800 Subject: [PATCH 11/33] Update pr-template.yml --- .github/workflows/pr-template.yml | 123 ++++++++++++++---------------- 1 file changed, 58 insertions(+), 65 deletions(-) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index cf4f83152a..6bf51a6c08 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -16,6 +16,7 @@ jobs: validate: name: Validate runs-on: ubuntu-latest + steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: @@ -39,50 +40,78 @@ jobs: try { await github.rest.issues.getLabel({ owner: context.repo.owner, - repo: context.repo.name, + repo: context.repo.repo, name: label }); } catch (error) { if (error.status === 404) { await github.rest.issues.createLabel({ owner: context.repo.owner, - repo: context.repo.name, + repo: context.repo.repo, name: label, - color: "D93F0B", - description: "Your PR template is not complete. (e.g. missing the requirements form, missing website preview)" + color: "d73a4a", + description: "The PR template has not been completely filled out." }); } else { throw error; } } - await github.rest.issues.addLabels({ + const labels = await github.rest.issues.listLabelsOnIssue({ owner: context.repo.owner, - repo: context.repo.name, - issue_number: context.issue.number, - labels: [label] + repo: context.repo.repo, + issue_number: context.issue.number }); - const body = [ - "## ❌ 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"); + 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] + }); + } - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.name, - issue_number: context.issue.number, - body - }); + 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 if: steps.validate.outcome == 'success' @@ -95,7 +124,7 @@ jobs: try { await github.rest.issues.removeLabel({ owner: context.repo.owner, - repo: context.repo.name, + repo: context.repo.repo, issue_number: context.issue.number, name: label }); @@ -103,40 +132,4 @@ jobs: if (error.status !== 404) { throw error; } - - tests: - name: Tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - - run: npm ci - - - name: Fetch PR information - if: github.event_name == 'pull_request' - run: | - echo "PR_AUTHOR=${{ github.event.pull_request.user.login }}" >> $GITHUB_ENV - echo "PR_AUTHOR_ID=${{ github.event.pull_request.user.id }}" >> $GITHUB_ENV - - LABELS=$(gh api --jq '[.labels[].name]' /repos/{owner}/{repo}/pulls/${{ github.event.number }}) - echo "PR_LABELS=$LABELS" >> $GITHUB_ENV - - FILES=$(gh api --jq '[.[] | select(.status != "removed") | .filename]' /repos/{owner}/{repo}/pulls/${{ github.event.number }}/files) - echo "CHANGED_FILES=$FILES" >> $GITHUB_ENV - - REMOVED_FILE_DATA=$(gh api --jq '[.[] | select(.status == "removed") | {name: .filename, data: .patch}]' /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files) - echo "DELETED_FILES=$REMOVED_FILE_DATA" >> $GITHUB_ENV - env: - GH_TOKEN: ${{ github.token }} - - - uses: gacts/install-dnscontrol@890ba3249712c51203ccb7aba63307c0091e921b # v1.3.4 - if: github.event_name == 'pull_request' && contains(fromJson(env.CHANGED_FILES), 'dnsconfig.js') - with: - version: 4.14.0 - - - name: Run DNSControl checks - run: dnscontrol check - if: github.event_name == 'pull_request' && contains(fromJson(env.CHANGED_FILES), 'dnsconfig.js') - - - name: Run tests - run: npx ava tests/*.test.js --timeout=1m + } From 954e741333c11e11359850cf4aa9c0e4e8e63314 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 11:56:27 +0800 Subject: [PATCH 12/33] Update pr-template.yml --- .github/workflows/pr-template.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index 6bf51a6c08..d67c475249 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -49,8 +49,8 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, name: label, - color: "d73a4a", - description: "The PR template has not been completely filled out." + color: "D93F0B", + description: "Your PR template is not complete. (e.g. missing the requirements form, missing website preview)" }); } else { throw error; From b70dd712126d9691a929d4194ebff3568d4366ff Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 11:59:29 +0800 Subject: [PATCH 13/33] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ab3ce23107..42ef157516 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,19 +7,23 @@ FAILURE TO COMPLETE ALL REQUIREMENTS WILL RESULT IN A DENIAL OF YOUR PR! -- [ ] I **agree** to the [Terms of Service](https://is-a.dev/terms). -- [ ] My file is following the [domain structure](https://docs.is-a.dev/domain-structure/). -- [ ] My website is **reachable** and **completed**. -- [ ] My website is **software development** related. -- [ ] My website is **not for commercial use**. -- [ ] I have provided sufficient contact information in the `owner` key. -- [ ] I have provided a link to my website below. +- [ ] I **agree** to the [Terms of Service](https://is-a.dev/terms). +- [ ] My file is following the [domain structure](https://docs.is-a.dev/domain-structure/). +- [ ] My website is **reachable** and **completed**. +- [ ] My website is **software development** related. +- [ ] My website is **not for commercial use**. +- [ ] I have provided sufficient contact information in the `owner` key. +- [ ] I have provided a link to my website below. # Website Preview - + - - + + + # Website Purpose + + + From aefe6a87835d461926c1da8d540c823e6827fa42 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:04:02 +0800 Subject: [PATCH 14/33] Update pr-template.yml --- .github/workflows/pr-template.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index d67c475249..8f891d97a6 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -16,7 +16,6 @@ jobs: validate: name: Validate runs-on: ubuntu-latest - steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: @@ -27,7 +26,7 @@ jobs: continue-on-error: true env: PR_BODY: ${{ github.event.pull_request.body }} - run: node scripts/validate-pr-template.js + run: node util/check-pr-template.js - name: Handle incomplete PR if: steps.validate.outcome == 'failure' @@ -133,3 +132,9 @@ jobs: throw error; } } + + - name: Fail if PR template is incomplete + if: steps.validate.outcome == 'failure' + run: | + echo "::error::PR template is incomplete." + exit 1 From 37528a4a3626863ab3e3171b38d70a07860ebc69 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:07:00 +0800 Subject: [PATCH 15/33] Update pr-template.yml --- .github/workflows/pr-template.yml | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index 8f891d97a6..349ac60863 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -112,13 +112,14 @@ jobs: }); } - - name: Remove incomplete label + - 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({ @@ -133,6 +134,28 @@ jobs: } } + 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: | From 759626cf0ea55a1ebe49e61dda0daa070278f170 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:07:29 +0800 Subject: [PATCH 16/33] Refactor PR template validation and requirements --- util/check-pr-template.js | 68 ++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/util/check-pr-template.js b/util/check-pr-template.js index 1b20233213..fbc4b58425 100644 --- a/util/check-pr-template.js +++ b/util/check-pr-template.js @@ -1,22 +1,18 @@ const body = process.env.PR_BODY || ""; const REQUIRED_CHECKBOXES = [ - "I agree to the [Terms of Service]", - "My file is following the [domain structure]", - "My website is reachable and completed.", - "My website is software development related.", - "My website is not for commercial use.", - "I have provided sufficient contact information in the `owner` key.", - "I have provided a link to my website below.", + "TOS", + "DOMAIN_STRUCTURE", + "WEBSITE_REACHABLE", + "SOFTWARE_RELATED", + "NON_COMMERCIAL", + "CONTACT_INFO", + "WEBSITE_LINK", ]; -function escapeRegExp(value) { - return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); -} - -function isRequiredCheckboxChecked(text) { +function isCheckboxChecked(marker) { const regex = new RegExp( - `-\\s*\\[[xX]\\]\\s*(?:\\s*)?${escapeRegExp(text)}`, + `-\\s*\\[[xX]\\]\\s*`, "i", ); @@ -34,41 +30,47 @@ function getSection(startMarker, endMarker) { return match ? match[1].trim() : ""; } +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + const errors = []; -const uncheckedRequirements = REQUIRED_CHECKBOXES.filter( - (requirement) => !isRequiredCheckboxChecked(requirement), +for (const checkbox of REQUIRED_CHECKBOXES) { + if (!isCheckboxChecked(checkbox)) { + errors.push( + `The \`${checkbox}\` requirement has not been checked.`, + ); + } +} + +const websitePreview = getSection( + "", + "", ); -if (uncheckedRequirements.length > 0) { +if (!websitePreview) { errors.push( - "The following required checkboxes have not been checked:", - ...uncheckedRequirements.map((requirement) => `- ${requirement}`), + "The **Website Preview** section has not been filled out.", ); } -if ( - !getSection( - "", - "", - ) -) { - errors.push("The **Website Preview** section has not been filled out."); -} +const websitePurpose = getSection( + "", + "", +); -if ( - !getSection( - "", - "", - ) -) { - errors.push("The **Website Purpose** section has not been filled out."); +if (!websitePurpose) { + errors.push( + "The **Website Purpose** section has not been filled out.", + ); } if (errors.length > 0) { console.error("PR template validation failed."); console.error(""); console.error(errors.join("\n")); + process.exit(1); } From 4bbc190839a9b7246de997fa5639f858f024e6c2 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:12:44 +0800 Subject: [PATCH 17/33] Update check-pr-template.js --- util/check-pr-template.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/util/check-pr-template.js b/util/check-pr-template.js index fbc4b58425..41c6e82c55 100644 --- a/util/check-pr-template.js +++ b/util/check-pr-template.js @@ -1,4 +1,15 @@ +const trustedUsers = require("./trusted.json"); + const body = process.env.PR_BODY || ""; +const authorUsername = process.env.PR_AUTHOR || ""; +const authorId = Number(process.env.PR_AUTHOR_ID); + +const isTrustedUser = trustedUsers.some((u) => u.id === authorId); + +if (isTrustedUser) { + console.log(`PR author "${authorUsername}" is a trusted user. Skipping template validation.`); + process.exit(0); +} const REQUIRED_CHECKBOXES = [ "TOS", From 385f56b04f51f2d477ac282c2b5e6688961074d2 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:13:15 +0800 Subject: [PATCH 18/33] Add PR author information to workflow --- .github/workflows/pr-template.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index 349ac60863..301faa5f9c 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -26,6 +26,8 @@ jobs: continue-on-error: true env: PR_BODY: ${{ github.event.pull_request.body }} + PR_AUTHOR: ${{ github.event.pull_request.user.login }} + PR_AUTHOR_ID: ${{ github.event.pull_request.user.id }} run: node util/check-pr-template.js - name: Handle incomplete PR From 80248268155073f89ba00cce63179440c18e0238 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:15:37 +0800 Subject: [PATCH 19/33] Rename check-pr-template.js to check-pr-template.cjs --- util/{check-pr-template.js => check-pr-template.cjs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename util/{check-pr-template.js => check-pr-template.cjs} (100%) diff --git a/util/check-pr-template.js b/util/check-pr-template.cjs similarity index 100% rename from util/check-pr-template.js rename to util/check-pr-template.cjs From 91e9381a9d2a43edd08edfb621bd8876c52f29b7 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:15:49 +0800 Subject: [PATCH 20/33] Update pr-template.yml --- .github/workflows/pr-template.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index 301faa5f9c..b6d2eedb34 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -28,7 +28,7 @@ jobs: PR_BODY: ${{ github.event.pull_request.body }} PR_AUTHOR: ${{ github.event.pull_request.user.login }} PR_AUTHOR_ID: ${{ github.event.pull_request.user.id }} - run: node util/check-pr-template.js + run: node util/check-pr-template.cjs - name: Handle incomplete PR if: steps.validate.outcome == 'failure' From c6f96046090fc31584d90efe9f0d165b9fbf3283 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:17:46 +0800 Subject: [PATCH 21/33] Implement bypass for PR template validation Added logic to bypass PR template validation for trusted users and specific labels. --- util/check-pr-template.cjs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/util/check-pr-template.cjs b/util/check-pr-template.cjs index 41c6e82c55..0c691a5060 100644 --- a/util/check-pr-template.cjs +++ b/util/check-pr-template.cjs @@ -3,14 +3,23 @@ const trustedUsers = require("./trusted.json"); const body = process.env.PR_BODY || ""; const authorUsername = process.env.PR_AUTHOR || ""; const authorId = Number(process.env.PR_AUTHOR_ID); +const labels = JSON.parse(process.env.PR_LABELS || "[]"); + +const BYPASS_LABEL = "ci: bypass-template-check"; const isTrustedUser = trustedUsers.some((u) => u.id === authorId); +const hasBypassLabel = labels.includes(BYPASS_LABEL); if (isTrustedUser) { console.log(`PR author "${authorUsername}" is a trusted user. Skipping template validation.`); process.exit(0); } +if (hasBypassLabel) { + console.log(`PR has the "${BYPASS_LABEL}" label. Skipping template validation.`); + process.exit(0); +} + const REQUIRED_CHECKBOXES = [ "TOS", "DOMAIN_STRUCTURE", From fce6208c003f39101f6967c1cd75599398f8758b Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:18:47 +0800 Subject: [PATCH 22/33] Add support for labeled pull requests Added handling for labeled pull requests in the workflow. --- .github/workflows/pr-template.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index b6d2eedb34..f314e3f18c 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -6,6 +6,7 @@ on: - opened - edited - synchronize + - labeled permissions: contents: read @@ -28,6 +29,7 @@ jobs: PR_BODY: ${{ github.event.pull_request.body }} PR_AUTHOR: ${{ github.event.pull_request.user.login }} PR_AUTHOR_ID: ${{ github.event.pull_request.user.id }} + PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }} run: node util/check-pr-template.cjs - name: Handle incomplete PR From 3fdd6c20b834bdaadc2a7532f11a18f825824452 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:28:35 +0800 Subject: [PATCH 23/33] Clarify PR template completion requirements Updated the PR template to clarify completion requirements. --- .github/workflows/pr-template.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index f314e3f18c..4df051d61a 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -99,13 +99,16 @@ jobs: "", "This pull request is missing required information from the PR template.", "", + "***Your PR will not be approved without the template being properly filled out!***", + "", "Please make sure that:", "", - "- Every required checkbox is checked.", - "- **Website Preview** is filled out.", - "- **Website Purpose** is filled out.", + "- The PR template has not been modified. *(modifying the PR template will make this check fail)*", + "- All requirement checkboxes are checked. *(they must be changed exactly to `[x]`, NOT something like `[ x ]`)*", + "- **Website Preview** is filled out. *(make sure it is filled between the start/end comment markers)*", + "- **Website Purpose** is filled out. *(make sure it is filled between the start/end comment markers)*", "", - "Once the template has been completed, this check will run again automatically." + "Once the template has been properly completed, this check will run again automatically." ].join("\n"); await github.rest.issues.createComment({ From 1fcfd17a9b903e8908fd9b95e57e88c6c777223c Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:36:32 +0800 Subject: [PATCH 24/33] Update pr-template.yml --- .github/workflows/pr-template.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index 4df051d61a..5de748281d 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -103,11 +103,15 @@ jobs: "", "Please make sure that:", "", - "- The PR template has not been modified. *(modifying the PR template will make this check fail)*", - "- All requirement checkboxes are checked. *(they must be changed exactly to `[x]`, NOT something like `[ x ]`)*", - "- **Website Preview** is filled out. *(make sure it is filled between the start/end comment markers)*", - "- **Website Purpose** is filled out. *(make sure it is filled between the start/end comment markers)*", - "", + "- The PR template has not been modified.", + " - *Modifying the PR template will make this check fail.*", + "- All requirement checkboxes are checked.", + " - *All checkboxes must be changed exactly to `[x]`, NOT something like `[ x ]`.*", + "- **Website Preview** is filled out.", + " - *Make sure it is filled between the start/end comment markers.*", + "- **Website Purpose** is filled out.", + " - *Make sure it is filled between the start/end comment markers.*", + "---", "Once the template has been properly completed, this check will run again automatically." ].join("\n"); From 06c9374f8254bacf360d2585da58d8c8fdefd807 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:39:00 +0800 Subject: [PATCH 25/33] Refactor PR information fetching in CI workflow --- .github/workflows/ci.yml | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 826f192592..84467788f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,20 +29,15 @@ jobs: - name: Fetch PR information if: github.event_name == 'pull_request' - run: | - echo "PR_AUTHOR=${{ github.event.pull_request.user.login }}" >> $GITHUB_ENV - echo "PR_AUTHOR_ID=${{ github.event.pull_request.user.id }}" >> $GITHUB_ENV - - LABELS=$(gh api --jq '[.labels[].name]' /repos/{owner}/{repo}/pulls/${{ github.event.number }}) - echo "PR_LABELS=$LABELS" >> $GITHUB_ENV - - FILES=$(gh api --jq '[.[] | select(.status != "removed") | .filename]' /repos/{owner}/{repo}/pulls/${{ github.event.number }}/files) - echo "CHANGED_FILES=$FILES" >> $GITHUB_ENV - - REMOVED_FILE_DATA=$(gh api --jq '[.[] | select(.status == "removed") | {name: .filename, data: .patch}]' /repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files) - echo "DELETED_FILES=$REMOVED_FILE_DATA" >> $GITHUB_ENV env: GH_TOKEN: ${{ github.token }} + PR: ${{ github.event.pull_request.number }} + run: | + echo "PR_AUTHOR=${{ github.event.pull_request.user.login }}" >> "$GITHUB_ENV" + echo "PR_AUTHOR_ID=${{ github.event.pull_request.user.id }}" >> "$GITHUB_ENV" + echo "PR_LABELS=$(gh api --jq '[.labels[].name]' "repos/${{ github.repository }}/pulls/$PR")" >> "$GITHUB_ENV" + echo "CHANGED_FILES=$(gh api --jq '[.[] | select(.status != "removed") | .filename]' "repos/${{ github.repository }}/pulls/$PR/files")" >> "$GITHUB_ENV" + echo "DELETED_FILES=$(gh api --jq '[.[] | select(.status == "removed") | {name: .filename, data: .patch}]' "repos/${{ github.repository }}/pulls/$PR/files")" >> "$GITHUB_ENV" - uses: gacts/install-dnscontrol@890ba3249712c51203ccb7aba63307c0091e921b # v1.3.4 if: github.event_name == 'pull_request' && contains(fromJson(env.CHANGED_FILES), 'dnsconfig.js') @@ -50,8 +45,8 @@ jobs: version: 4.14.0 - name: Run DNSControl checks - run: dnscontrol check if: github.event_name == 'pull_request' && contains(fromJson(env.CHANGED_FILES), 'dnsconfig.js') + run: dnscontrol check - name: Run tests run: npx ava tests/*.test.js --timeout=1m From ecc345a374ccf792c3e21b80220aa3261570631e Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:42:35 +0800 Subject: [PATCH 26/33] Update PR_LABELS command in CI workflow --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84467788f4..84b74fed9e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: run: | echo "PR_AUTHOR=${{ github.event.pull_request.user.login }}" >> "$GITHUB_ENV" echo "PR_AUTHOR_ID=${{ github.event.pull_request.user.id }}" >> "$GITHUB_ENV" - echo "PR_LABELS=$(gh api --jq '[.labels[].name]' "repos/${{ github.repository }}/pulls/$PR")" >> "$GITHUB_ENV" + echo "PR_LABELS=$(gh pr view ${{ github.event.pull_request.number }} --json labels --jq '[.labels[].name]')" >> "$GITHUB_ENV" echo "CHANGED_FILES=$(gh api --jq '[.[] | select(.status != "removed") | .filename]' "repos/${{ github.repository }}/pulls/$PR/files")" >> "$GITHUB_ENV" echo "DELETED_FILES=$(gh api --jq '[.[] | select(.status == "removed") | {name: .filename, data: .patch}]' "repos/${{ github.repository }}/pulls/$PR/files")" >> "$GITHUB_ENV" From 43ad213be8155bc6d45a83a372bd42e110c2b1fd Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 12:55:25 +0800 Subject: [PATCH 27/33] Update bypass label handling in PR template check --- util/check-pr-template.cjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/check-pr-template.cjs b/util/check-pr-template.cjs index 0c691a5060..51a8b8ec23 100644 --- a/util/check-pr-template.cjs +++ b/util/check-pr-template.cjs @@ -5,10 +5,10 @@ const authorUsername = process.env.PR_AUTHOR || ""; const authorId = Number(process.env.PR_AUTHOR_ID); const labels = JSON.parse(process.env.PR_LABELS || "[]"); -const BYPASS_LABEL = "ci: bypass-template-check"; +const BYPASS_LABELS = ["ci: bypass-template-check", "maintainer"]; const isTrustedUser = trustedUsers.some((u) => u.id === authorId); -const hasBypassLabel = labels.includes(BYPASS_LABEL); +const hasBypassLabel = labels.some((l) => BYPASS_LABELS.includes(l)); if (isTrustedUser) { console.log(`PR author "${authorUsername}" is a trusted user. Skipping template validation.`); @@ -16,7 +16,7 @@ if (isTrustedUser) { } if (hasBypassLabel) { - console.log(`PR has the "${BYPASS_LABEL}" label. Skipping template validation.`); + console.log(`PR has a label which bypasses this check. Skipping template validation.`); process.exit(0); } From 3bcd5904266cab2764b6fb5d3a8a6abcb5ed74af Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:09:01 +0800 Subject: [PATCH 28/33] Update pr-template.yml --- .github/workflows/pr-template.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml index 5de748281d..5a46992a46 100644 --- a/.github/workflows/pr-template.yml +++ b/.github/workflows/pr-template.yml @@ -4,6 +4,7 @@ on: pull_request_target: types: - opened + - reopened - edited - synchronize - labeled From cd783fc6165693b1de8a9e903d3da3809e0b3a5e Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:10:23 +0800 Subject: [PATCH 29/33] Enhance PR workflow with template validation Updated PR workflow to include additional event types and added a template validation step. --- .github/workflows/pr.yml | 246 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 .github/workflows/pr.yml diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 0000000000..d596986cc4 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,246 @@ +name: PR + +on: + pull_request_target: + types: + - opened + - reopened + - edited + - synchronize + - labeled + +permissions: + contents: read + pull-requests: write + issues: write + +jobs: + label: + name: Label + runs-on: ubuntu-latest + + steps: + - name: Check changed paths + id: changes + uses: dorny/paths-filter@v3 + with: + filters: | + ci: + - ".github/workflows/*" + - "tests/*" + - "util/*" + - "package.json" + - "package-lock.json" + - "dnsconfig.js" + domain: + - "domains/*" + + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + ref: ${{ github.event.repository.default_branch }} + + - name: Check trusted user + id: check + env: + PR_AUTHOR_ID: ${{ github.event.pull_request.user.id }} + run: | + node - <<'NODE' + const trustedUsers = require("./util/trusted.json"); + + const authorId = Number(process.env.PR_AUTHOR_ID); + + if (!trustedUsers.some((u) => u.id === authorId)) { + console.log("PR author is not a trusted user."); + process.exit(1); + } + + console.log("PR author is a trusted user."); + NODE + + - name: Add labels + uses: actions/github-script@v8 + env: + CI_CHANGED: ${{ steps.changes.outputs.ci }} + DOMAIN_CHANGED: ${{ steps.changes.outputs.domain }} + MAINTAINER: ${{ steps.check.outcome == 'success' }} + with: + github-token: ${{ secrets.BOT }} + script: | + const labels = []; + + if (process.env.CI_CHANGED === "true") + labels.push("ci"); + + if (process.env.DOMAIN_CHANGED === "true") + labels.push("domain"); + + if (process.env.MAINTAINER === "true") + labels.push("maintainer"); + + if (labels.length) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels + }); + } + + template: + name: Template + 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 }} + PR_AUTHOR: ${{ github.event.pull_request.user.login }} + PR_AUTHOR_ID: ${{ github.event.pull_request.user.id }} + PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }} + run: node util/check-pr-template.cjs + + - 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.", + "", + "***Your PR will not be approved without the template being properly filled out!***", + "", + "Please make sure that:", + "", + "- The PR template has not been modified.", + " - *Modifying the PR template will make this check fail.*", + "- All requirement checkboxes are checked.", + " - *All checkboxes must be changed exactly to `[x]`, NOT something like `[ x ]`.*", + "- **Website Preview** is filled out.", + " - *Make sure it is filled between the start/end comment markers.*", + "- **Website Purpose** is filled out.", + " - *Make sure it is filled between the start/end comment markers.*", + "---", + "Once the template has been properly 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 From aa1a997741e88525e2cad2493106d69175ad24b8 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:20:22 +0800 Subject: [PATCH 30/33] Update pr.yml --- .github/workflows/pr.yml | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d596986cc4..06539107bb 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -34,13 +34,25 @@ jobs: - "dnsconfig.js" domain: - "domains/*" + documentation: + - ".github/PULL_REQUEST_TEMPLATE.md" + - ".github/copilot-instructions.md" + - "README.md" + r-william: + - ".github/CODEOWNERS" + - "CODE_OF_CONDUCT.md" + - "CONTRIBUTING.md" + - "SECURITY.md" + - "TERMS_OF_SERVICE.md" + - "LICENSE" - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: ref: ${{ github.event.repository.default_branch }} - name: Check trusted user - id: check + id: check-trusted + continue-on-error: true env: PR_AUTHOR_ID: ${{ github.event.pull_request.user.id }} run: | @@ -61,28 +73,32 @@ jobs: uses: actions/github-script@v8 env: CI_CHANGED: ${{ steps.changes.outputs.ci }} + DOCUMENTATION: ${{ steps.changes.outputs.documentation }} DOMAIN_CHANGED: ${{ steps.changes.outputs.domain }} - MAINTAINER: ${{ steps.check.outcome == 'success' }} + MAINTAINER: ${{ steps.check-trusted.outcome == 'success' }} + R_WILLIAM: ${{ steps.changes.outputs.r-william }} with: github-token: ${{ secrets.BOT }} script: | const labels = []; - if (process.env.CI_CHANGED === "true") + if (process.env.CI_CHANGED === "true") { labels.push("ci"); + labels.push("r: william"); + } + if (process.env.DOCUMENTATION === "true") labels.push("documentation"); + if (process.env.DOMAIN_CHANGED === "true") labels.push("domain"); + if (process.env.MAINTAINER === "true") labels.push("maintainer"); + if (process.env.R_WILLIAM === "true") labels.push("r: william"); - if (process.env.DOMAIN_CHANGED === "true") - labels.push("domain"); + const uniqueLabels = [...new Set(labels)]; - if (process.env.MAINTAINER === "true") - labels.push("maintainer"); - - if (labels.length) { + if (uniqueLabels.length) { await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - labels + labels: uniqueLabels }); } From 706fb0c18db11cb062e92ead9741ce1f5b88c720 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:20:49 +0800 Subject: [PATCH 31/33] Delete .github/workflows/pr-template.yml --- .github/workflows/pr-template.yml | 175 ------------------------------ 1 file changed, 175 deletions(-) delete mode 100644 .github/workflows/pr-template.yml diff --git a/.github/workflows/pr-template.yml b/.github/workflows/pr-template.yml deleted file mode 100644 index 5a46992a46..0000000000 --- a/.github/workflows/pr-template.yml +++ /dev/null @@ -1,175 +0,0 @@ -name: PR Template - -on: - pull_request_target: - types: - - opened - - reopened - - edited - - synchronize - - labeled - -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 }} - PR_AUTHOR: ${{ github.event.pull_request.user.login }} - PR_AUTHOR_ID: ${{ github.event.pull_request.user.id }} - PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }} - run: node util/check-pr-template.cjs - - - 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.", - "", - "***Your PR will not be approved without the template being properly filled out!***", - "", - "Please make sure that:", - "", - "- The PR template has not been modified.", - " - *Modifying the PR template will make this check fail.*", - "- All requirement checkboxes are checked.", - " - *All checkboxes must be changed exactly to `[x]`, NOT something like `[ x ]`.*", - "- **Website Preview** is filled out.", - " - *Make sure it is filled between the start/end comment markers.*", - "- **Website Purpose** is filled out.", - " - *Make sure it is filled between the start/end comment markers.*", - "---", - "Once the template has been properly 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 From aa560a59e9b563e7881b1e8dc9104d0528331a35 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:27:22 +0800 Subject: [PATCH 32/33] Add GitHub Action to update PR branches on push --- .github/workflows/update-pr-branches.yml | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/update-pr-branches.yml diff --git a/.github/workflows/update-pr-branches.yml b/.github/workflows/update-pr-branches.yml new file mode 100644 index 0000000000..9695d701b0 --- /dev/null +++ b/.github/workflows/update-pr-branches.yml @@ -0,0 +1,41 @@ +name: Update PR Branches + +on: + push: + branches: + - main + +permissions: + contents: write + pull-requests: write + +jobs: + update: + name: Update + runs-on: ubuntu-latest + + steps: + - name: Update branches + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.BOT }} + script: | + const { data: prs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: "open" + }); + + for (const pr of prs) { + try { + await github.rest.pulls.updateBranch({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: pr.number + }); + + console.log(`Updated #${pr.number} (${pr.head.ref})`); + } catch (error) { + console.log(`Could not update #${pr.number}: ${error.message}`); + } + } From d7c47eba87af0a1035ed3385775601d5d2239789 Mon Sep 17 00:00:00 2001 From: William Harrison <87287585+wdhdev@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:30:21 +0800 Subject: [PATCH 33/33] Update update-pr-branches.yml --- .github/workflows/update-pr-branches.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/update-pr-branches.yml b/.github/workflows/update-pr-branches.yml index 9695d701b0..f5696ddc07 100644 --- a/.github/workflows/update-pr-branches.yml +++ b/.github/workflows/update-pr-branches.yml @@ -1,13 +1,7 @@ name: Update PR Branches on: - push: - branches: - - main - -permissions: - contents: write - pull-requests: write + workflow_dispatch: jobs: update: