reviewbot

Source code for the is-a.dev r...
Log | Files | Refs | README | LICENSE

commit eccf4888c489211d4fb9a81086ce673add9e8908
parent 43234f10ac1f75507ee92ed3aa5d64e3b92a80da
Author: iostpa <iostpa@iostpa.com>
Date:   Sun,  3 May 2026 10:58:46 +0300

Merge pull request #42 from iostpa/label-system

v1.2.0
Diffstat:
M.github/dependabot.yml | 2+-
Mbun.lock | 12++++++------
Mindex.js | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Amessage/label/abuse-risk.md | 3+++
Amessage/label/commercial-usage.md | 3+++
Amessage/label/impersonation.md | 3+++
Amessage/label/inaccessible-website.md | 3+++
Amessage/label/incomplete-pr.md | 3+++
Amessage/label/incomplete-website.md | 5+++++
Amessage/label/invalid-file.md | 3+++
Amessage/label/invalid-records.md | 3+++
Amessage/label/invalid-social.md | 3+++
Amessage/label/lowpriority.md | 5+++++
Amessage/label/merge-conflict.md | 3+++
Amessage/label/not-dev-related.md | 7+++++++
Amessage/label/nsfw.md | 3+++
Amessage/label/other.md | 3+++
Amessage/label/unauthorized.md | 5+++++
Mpackage.json | 4++--
19 files changed, 174 insertions(+), 10 deletions(-)

diff --git a/.github/dependabot.yml b/.github/dependabot.yml @@ -14,7 +14,7 @@ updates: - package-ecosystem: "github-actions" target-branch: "main" - directory: "/.github/workflows" + directory: "/.forgejo/workflows" schedule: interval: "daily" groups: diff --git a/bun.lock b/bun.lock @@ -6,7 +6,7 @@ "name": "reviewbot", "dependencies": { "@fastify/middie": "^9.3.2", - "@sentry/bun": "^10.50.0", + "@sentry/bun": "^10.51.0", "dotenv": "^17.4.2", "fastify": "^5.8.5", "octokit": "^5.0.5", @@ -172,15 +172,15 @@ "@prisma/instrumentation": ["@prisma/instrumentation@7.6.0", "", { "dependencies": { "@opentelemetry/instrumentation": "^0.207.0" }, "peerDependencies": { "@opentelemetry/api": "^1.8" } }, "sha512-ZPW2gRiwpPzEfgeZgaekhqXrbW+Y2RJKHVqUmlhZhKzRNCcvR6DykzylDrynpArKKRQtLxoZy36fK7U0p3pdgQ=="], - "@sentry/bun": ["@sentry/bun@10.50.0", "", { "dependencies": { "@sentry/core": "10.50.0", "@sentry/node": "10.50.0" } }, "sha512-TAGojqOd5ItSBSPMFdJtUDfSGgYaZ7odZI64WmTwG4zYfRFYs3BxwxalU2ljs7kxIVqFoJZoxlEeXbR/SBhgxA=="], + "@sentry/bun": ["@sentry/bun@10.51.0", "", { "dependencies": { "@sentry/core": "10.51.0", "@sentry/node": "10.51.0" } }, "sha512-LOOrMSKHTQ8kx+o75jelIHXUpFlIwAR5UXBNluV20NxyIsKEav3QsxP0J1Oe02hNVuo3yIlK55M3G9Zc4qEuAw=="], - "@sentry/core": ["@sentry/core@10.50.0", "", {}, "sha512-J4A+vzUO3adl0TkFCjaN1+4miamrjHiEIYuLHiuu1lmAjq5WIVw32ObvAh4yMwNtxyaEMosTrrh5M6f12XSJFg=="], + "@sentry/core": ["@sentry/core@10.51.0", "", {}, "sha512-Y45V/YXvVLEXmOdkbD1oG1gkRWFi9guCEGg3PlIlIpRjAbZUrvLGgjRJIc1E7XpSzmOnWbs5BbUxMv4PDaPj2w=="], - "@sentry/node": ["@sentry/node@10.50.0", "", { "dependencies": { "@fastify/otel": "0.18.0", "@opentelemetry/api": "^1.9.1", "@opentelemetry/core": "^2.6.1", "@opentelemetry/instrumentation": "^0.214.0", "@opentelemetry/instrumentation-amqplib": "0.61.0", "@opentelemetry/instrumentation-connect": "0.57.0", "@opentelemetry/instrumentation-dataloader": "0.31.0", "@opentelemetry/instrumentation-fs": "0.33.0", "@opentelemetry/instrumentation-generic-pool": "0.57.0", "@opentelemetry/instrumentation-graphql": "0.62.0", "@opentelemetry/instrumentation-hapi": "0.60.0", "@opentelemetry/instrumentation-http": "0.214.0", "@opentelemetry/instrumentation-ioredis": "0.62.0", "@opentelemetry/instrumentation-kafkajs": "0.23.0", "@opentelemetry/instrumentation-knex": "0.58.0", "@opentelemetry/instrumentation-koa": "0.62.0", "@opentelemetry/instrumentation-lru-memoizer": "0.58.0", "@opentelemetry/instrumentation-mongodb": "0.67.0", "@opentelemetry/instrumentation-mongoose": "0.60.0", "@opentelemetry/instrumentation-mysql": "0.60.0", "@opentelemetry/instrumentation-mysql2": "0.60.0", "@opentelemetry/instrumentation-pg": "0.66.0", "@opentelemetry/instrumentation-redis": "0.62.0", "@opentelemetry/instrumentation-tedious": "0.33.0", "@opentelemetry/sdk-trace-base": "^2.6.1", "@opentelemetry/semantic-conventions": "^1.40.0", "@prisma/instrumentation": "7.6.0", "@sentry/core": "10.50.0", "@sentry/node-core": "10.50.0", "@sentry/opentelemetry": "10.50.0", "import-in-the-middle": "^3.0.0" } }, "sha512-TvwzFQu8MGKzMQ2/tqxcNzFA8UG2kKTB+GDmA4uOzx3+GT849YZRRSJzEXCmYhk1teVd2fbmgqyYY2nyLF5a+Q=="], + "@sentry/node": ["@sentry/node@10.51.0", "", { "dependencies": { "@fastify/otel": "0.18.0", "@opentelemetry/api": "^1.9.1", "@opentelemetry/core": "^2.6.1", "@opentelemetry/instrumentation": "^0.214.0", "@opentelemetry/instrumentation-amqplib": "0.61.0", "@opentelemetry/instrumentation-connect": "0.57.0", "@opentelemetry/instrumentation-dataloader": "0.31.0", "@opentelemetry/instrumentation-fs": "0.33.0", "@opentelemetry/instrumentation-generic-pool": "0.57.0", "@opentelemetry/instrumentation-graphql": "0.62.0", "@opentelemetry/instrumentation-hapi": "0.60.0", "@opentelemetry/instrumentation-http": "0.214.0", "@opentelemetry/instrumentation-ioredis": "0.62.0", "@opentelemetry/instrumentation-kafkajs": "0.23.0", "@opentelemetry/instrumentation-knex": "0.58.0", "@opentelemetry/instrumentation-koa": "0.62.0", "@opentelemetry/instrumentation-lru-memoizer": "0.58.0", "@opentelemetry/instrumentation-mongodb": "0.67.0", "@opentelemetry/instrumentation-mongoose": "0.60.0", "@opentelemetry/instrumentation-mysql": "0.60.0", "@opentelemetry/instrumentation-mysql2": "0.60.0", "@opentelemetry/instrumentation-pg": "0.66.0", "@opentelemetry/instrumentation-redis": "0.62.0", "@opentelemetry/instrumentation-tedious": "0.33.0", "@opentelemetry/sdk-trace-base": "^2.6.1", "@opentelemetry/semantic-conventions": "^1.40.0", "@prisma/instrumentation": "7.6.0", "@sentry/core": "10.51.0", "@sentry/node-core": "10.51.0", "@sentry/opentelemetry": "10.51.0", "import-in-the-middle": "^3.0.0" } }, "sha512-2yZLRZwS1dKG8/4eOTpGSo/gO/EgmT9aPj6lAzUkRa7bZCTTdW4BraaHU0leX5T94909Qfhbr3W5AVTfDOCKiQ=="], - "@sentry/node-core": ["@sentry/node-core@10.50.0", "", { "dependencies": { "@sentry/core": "10.50.0", "@sentry/opentelemetry": "10.50.0", "import-in-the-middle": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.39.0" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/core", "@opentelemetry/exporter-trace-otlp-http", "@opentelemetry/instrumentation", "@opentelemetry/sdk-trace-base", "@opentelemetry/semantic-conventions"] }, "sha512-Eb1BYf4Lc7ZYmdX3acKP6SgyGikrBA370gbGHaWI5jRu7G7vig8sIu1ghPmY5AlvqBPOetado7GniXr6fAXbTw=="], + "@sentry/node-core": ["@sentry/node-core@10.51.0", "", { "dependencies": { "@sentry/core": "10.51.0", "@sentry/opentelemetry": "10.51.0", "import-in-the-middle": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/exporter-trace-otlp-http": ">=0.57.0 <1", "@opentelemetry/instrumentation": ">=0.57.1 <1", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.39.0" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/core", "@opentelemetry/exporter-trace-otlp-http", "@opentelemetry/instrumentation", "@opentelemetry/sdk-trace-base", "@opentelemetry/semantic-conventions"] }, "sha512-VP9DMEzBEuauABrfDHYz/pRYa74M09uRJLz0ls3yel3sKhYHMyCB29ZxbKcciUhD4d33dwgi8DbaPZV2H/wnfQ=="], - "@sentry/opentelemetry": ["@sentry/opentelemetry@10.50.0", "", { "dependencies": { "@sentry/core": "10.50.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.39.0" } }, "sha512-axn3pgDPveGdaMUC0abMCmFN7ux2pA5ebPufCef4lMIsyg7BBQvaEJ+vE19wjstMaBCAJGsdZlL3eeP2rtgRMw=="], + "@sentry/opentelemetry": ["@sentry/opentelemetry@10.51.0", "", { "dependencies": { "@sentry/core": "10.51.0" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/core": "^1.30.1 || ^2.1.0", "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.1.0", "@opentelemetry/semantic-conventions": "^1.39.0" } }, "sha512-Qc7AlCE4uhB+SvHLqah4RgR1WdY7wmmr/hx9g/prDP9R1ocshmUEMrZK9qjuwaklW7/fmkFCXI8ETxo5L1bHIA=="], "@types/aws-lambda": ["@types/aws-lambda@8.10.147", "", {}, ""], diff --git a/index.js b/index.js @@ -18,7 +18,10 @@ const secret = process.env.WEBHOOK_SECRET; const newPRs = fs.readFileSync('./message/opened.md', 'utf8'); const mergedPRs = fs.readFileSync('./message/merged.md', 'utf8'); const draftPRs = fs.readFileSync('./message/draft.md', 'utf8'); +const lowPriorityMessage = fs.readFileSync('./message/label/lowpriority.md', 'utf8'); const ignoreLabels = ["maintainer"]; +const statusLabels = ["status: low priority", "status: needs preview", "status: denied", "status: invalid"]; +const reasonLabels = ["reason: abuse risk", "reason: commercial usage", "reason: impersonation", "reason: inaccessible website", "reason: incomplete pr", "reason: incomplete website", "reason: invalid file", "reason: invalid records", "reason: invalid social", "reason: merge conflict", "reason: not dev related", "reason: nsfw", "reason: other", "reason: unauthorized"]; Sentry.init({ dsn: sentryDsn, @@ -55,7 +58,7 @@ app.webhooks.on('pull_request.opened', async ({ octokit, payload }) => { }); const allLabels = labels.data.map((label) => label.name); if (ignoreLabels.some((label) => allLabels.includes(label))) { - console.log(`#${payload.pull_request.number} from https://github.com/${payload.repository.full_name} is by a maintainer, skipping pull request.`) + console.log(`#${payload.pull_request.number} from https://github.com/${payload.repository.full_name} is by a maintainer, skipping pull request.`); return; } if (payload.pull_request.draft === true) { @@ -87,6 +90,112 @@ app.webhooks.on('pull_request.opened', async ({ octokit, payload }) => { } }); +// Label system +app.webhooks.on('pull_request.labeled', async ({ octokit, payload }) => { + let preview, denied, invalid, lowpriority; + if (payload.label.name === statusLabels[1]){ + preview = true; + } else if (payload.label.name === statusLabels[2]) { + denied = true; + } else if (payload.label.name === statusLabels[3]) { + invalid = true; + } else if (payload.label.name === statusLabels[0]) { + lowpriority = true; + } + + if (denied === true || invalid === true) { + try { + const listOfLabels = []; + // timeout so that it creates a little time window for the maintainer to add the rest of the labels + await new Promise(resolve => setTimeout(resolve, 5000)); + const data = await octokit.request('GET /repos/{owner}/{repo}/pulls/{pull_number}', { + owner: payload.repository.owner.login, + repo: payload.repository.name, + pull_number: payload.pull_request.number + }); + const labelData = data.data.labels; + for (let i in labelData) { + if (labelData[i].name) { + listOfLabels.push(labelData[i].name); + } + } + + // start adding the messages + const allMessages = []; + for (let i in listOfLabels) { + if (reasonLabels.includes(listOfLabels[i])) { + let initialReason = listOfLabels[i].toString().replace(/reason:\s/i, ''); + let finalReason = initialReason.replace(/\s+/g, '-'); + let message = fs.readFileSync(`./message/label/${finalReason}.md`, 'utf8'); + allMessages.push(message); + } + } + + if (preview === true && !listOfLabels.includes("reason: inaccessible website")) { + let message = fs.readFileSync(`./message/label/inaccessible-website.md`, 'utf8'); + allMessages.push(message); + }; + + const labelMessages = allMessages.join('\n\n'); + const body = ` +# Invalid Pull Request + +This pull request is invalid due to the following reason(s): + +--- +${labelMessages} + +--- + +If you need any help, please create an issue or ask our team in the [Discord server](https://discord.gg/is-a-dev-830872854677422150) + +`; + await octokit.rest.issues.createComment({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + issue_number: payload.pull_request.number, + body: body + }); + console.log(`Sent reason messages at #${payload.pull_request.number} from ${payload.repository.name}`); + if (denied === true) { + await octokit.request('PATCH /repos/{owner}/{repo}/pulls/{pull_number}', { + owner: payload.repository.owner.login, + repo: payload.repository.name, + pull_number: payload.pull_request.number, + state: 'closed', + }); + console.log(`Closed pull request at #${payload.pull_request.number} from ${payload.repository.name}`); + }; + } catch (error) { + Sentry.captureException(error); + fastify.log.error(error); + if (error.response) { + console.error(`Error! Status: ${error.response.status}. Message: ${error.response.data.message}`); + } else { + console.error(error); + } + }; + } else if (lowpriority === true) { + try { + await octokit.rest.issues.createComment({ + owner: payload.repository.owner.login, + repo: payload.repository.name, + issue_number: payload.pull_request.number, + body: lowPriorityMessage + }); + console.log(`Sent low priority message to ${payload.pull_request.number} from ${payload.repository.name}`); + } catch (error) { + Sentry.captureException(error); + fastify.log.error(error); + if (error.response) { + console.error(`Error! Status: ${error.response.status}. Message: ${error.response.data.message}`); + } else { + console.error(error); + } + }; + } +}); + // https://github.com/octokit/webhooks.js/?tab=readme-ov-file#webhook-events app.webhooks.on('pull_request.closed', async ({ octokit, payload }) => { console.log(`Received a closed pull request event for #${payload.pull_request.number} on https://github.com/${payload.repository.full_name}`); diff --git a/message/label/abuse-risk.md b/message/label/abuse-risk.md @@ -0,0 +1,2 @@ +### Abuse Risk +We believe this pull request risks the abuse of our service. One possible reason we might have reached this conclusion is that there is a risk of malware or malicious content on your website, or other security issues. Another possible reason is that you are hosting copyright infringing material; please ensure that all content on your website respects copyright laws. Piracy and infringing on third-party rights is prohibited per our [Terms of Service](https://is-a.dev/terms).+ \ No newline at end of file diff --git a/message/label/commercial-usage.md b/message/label/commercial-usage.md @@ -0,0 +1,2 @@ +### Commercial Usage +It is explicitly stated in our [Terms of Service](https://is-a.dev/terms) that we **prohibit** using our subdomains for commercial, for-profit or political purposes. Your website violates our Terms of Service.+ \ No newline at end of file diff --git a/message/label/impersonation.md b/message/label/impersonation.md @@ -0,0 +1,2 @@ +### Impersonation +Impersonation is explicitly prohibited in our [Terms of Service](https://is-a.dev/terms). Your website is violating this rule by impersonating or misrepresenting a person or entity.+ \ No newline at end of file diff --git a/message/label/inaccessible-website.md b/message/label/inaccessible-website.md @@ -0,0 +1,2 @@ +### Inaccessible Website +Your website is inaccessible. This means that at the time of review, the responsible maintainer was unable to access your website and was met with an error. If it is not possible for it to be accessible immediately via a link, it is *mandatory* to provide a **preview** of your website in image or video form.+ \ No newline at end of file diff --git a/message/label/incomplete-pr.md b/message/label/incomplete-pr.md @@ -0,0 +1,2 @@ +### Incomplete PR +Your pull request is incomplete. This means that you have not filled out the PR template, which includes completing the requirements form, agreeing to our [Terms of Service](https://is-a.dev/terms), and providing a preview of your website if applicable, all of which are **mandatory**.+ \ No newline at end of file diff --git a/message/label/incomplete-website.md b/message/label/incomplete-website.md @@ -0,0 +1,4 @@ +### Incomplete Website +This website is incomplete and has either little to no content or has placeholder text and links; please either add more content or replace the placeholder text and links. Please note that said additional content must be related to software development and must comply with our [Terms of Service](https://is-a.dev/terms). + +Additionally, note that we do not have very high standards for a "complete" website. Using a URL record to redirect to your GitHub account page, for example, is totally acceptable as complete and related to software development.+ \ No newline at end of file diff --git a/message/label/invalid-file.md b/message/label/invalid-file.md @@ -0,0 +1,2 @@ +### Invalid File +Your file and its format is invalid and fails checks. Check that your file is in the correct directory, has a valid filename, and is valid JSON. For more information, read [our documentation on file structure](https://docs.is-a.dev/domain-structure).+ \ No newline at end of file diff --git a/message/label/invalid-records.md b/message/label/invalid-records.md @@ -0,0 +1,2 @@ +### Invalid Records +One or more of your records are *invalid*. Please see [our documentation on records](https://docs.is-a.dev/domain-structure/#-records-required).+ \ No newline at end of file diff --git a/message/label/invalid-social.md b/message/label/invalid-social.md @@ -0,0 +1,2 @@ +### Invalid Social +One or more of the social handles you've provided in your file(s) are invalid. Common examples include the mistake of using a GitHub noreply email or providing an account that doesn't exist, such as a nonexistent Twitter account.+ \ No newline at end of file diff --git a/message/label/lowpriority.md b/message/label/lowpriority.md @@ -0,0 +1,4 @@ +## Low Priority +This pull request has been marked as "low priority" by a maintainer. This means that maintainers will prioritise reviewing and merging other pull requests over this one. As such, you will have to wait a longer period of time than others in waiting for a PR review. + +**Why has my pull request been marked as low priority**? The most likely reason is that you were trying to get maintainers to review and merge your PR by pinging/mentioning them (perhaps even repeatedly) on Discord or another platform. We do not appreciate this type of behavior; we (the maintainers) are volunteers, and we try our best to keep up with and review PRs *at our own pace*. Please be considerate and wait patiently for a review without bugging maintainers the next time you make a pull request.+ \ No newline at end of file diff --git a/message/label/merge-conflict.md b/message/label/merge-conflict.md @@ -0,0 +1,2 @@ +### Merge Conflict +Your pull request has a merge conflict. Please either resolve them locally or redo the pull request.+ \ No newline at end of file diff --git a/message/label/not-dev-related.md b/message/label/not-dev-related.md @@ -0,0 +1,6 @@ +### Not Related to Software Development +All root subdomains *must be related to software development*. This page does not appear to comply with this. Note that you may use a **nested** subdomain for practically anything, including something unrelated to software development (as long as it complies with our [Terms of Service](https://is-a.dev/terms)). + +A nested subdomain is a subdomain of a subdomain; e.g. `foo.bar.is-a.dev` instead of a root subdomain (`bar.is-a.dev`). + +You may not register a nested subdomain without owning and registering the root subdomain it is nested under.+ \ No newline at end of file diff --git a/message/label/nsfw.md b/message/label/nsfw.md @@ -0,0 +1,2 @@ +### NSFW +Your webpage contains NSFW ("Not Safe For Work") content. This usually refers to pornography, gore, or other disturbing content not suitable for children. This is explicitly prohibited in our [Terms of Service](https://is-a.dev/terms).+ \ No newline at end of file diff --git a/message/label/other.md b/message/label/other.md @@ -0,0 +1,2 @@ +### Other +The maintainer has a different reason as to why the pull request should be closed. Please read the maintainer's comment if you haven't done that already.+ \ No newline at end of file diff --git a/message/label/unauthorized.md b/message/label/unauthorized.md @@ -0,0 +1,4 @@ +### Unauthorised +You are not authorised to modify the subdomain(s) in this pull request! You are either attempting to modify a subdomain which another user owns, or attempting to register a *nested subdomain* without having registered the root subdomain first. + +If it is the latter scenario, please first register the root subdomain, `example.is-a.dev`, where the nested subdomain you are attempting to register here is `foo.example.is-a.dev`.+ \ No newline at end of file diff --git a/package.json b/package.json @@ -1,7 +1,7 @@ { "name": "reviewbot", "private": true, - "version": "1.1.0", + "version": "1.2.0", "type": "module", "description": "An app to assist in the review process of is-a-dev", "author": "iostpa", @@ -17,7 +17,7 @@ }, "dependencies": { "@fastify/middie": "^9.3.2", - "@sentry/bun": "^10.50.0", + "@sentry/bun": "^10.51.0", "dotenv": "^17.4.2", "fastify": "^5.8.5", "octokit": "^5.0.5"
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror