chore: update issue verifier (#43339)
Co-authored-by: Steven <steven@ceriously.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
parent
f15b5d0af7
commit
f0625662f4
8 changed files with 207 additions and 254 deletions
42
.github/actions/issue-validator/canary.md
vendored
Normal file
42
.github/actions/issue-validator/canary.md
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
Please verify that your issue can be recreated with `next@canary`.
|
||||
|
||||
### **Why was this issue marked with the `please verify canary` label?**
|
||||
|
||||
We noticed the provided reproduction was using an older version of Next.js, instead of `canary`.
|
||||
|
||||
The canary version of Next.js ships daily and includes all features and fixes that have not been released to the stable version yet. You can think of canary as a _public beta_. Some issues may already be fixed in the canary version, so please verify that your issue reproduces by running `npm install next@canary` and test it in your project, using your reproduction steps.
|
||||
|
||||
If the issue does not reproduce with the `canary` version, then it has already been fixed and this issue can be closed.
|
||||
|
||||
### **How can I quickly verify if my issue has been fixed in `canary`?**
|
||||
|
||||
The safest way is to install `next@canary` in your project and test it, but you can also search through [closed Next.js issues](https://github.com/vercel/next.js/issues?q=is%3Aissue+is%3Aclosed) for duplicates or check the [Next.js releases](https://github.com/vercel/next.js/releases).
|
||||
|
||||
### **My issue has been open for a long time, why do I need to verify `canary` now?**
|
||||
|
||||
Next.js does not backport bug fixes to older versions of Next.js. Instead, we are trying to introduce only a minimal amount of breaking changes between major releases.
|
||||
|
||||
### **What happens if I don't verify against the canary version of Next.js?**
|
||||
|
||||
An issue with the `please verify canary` that receives no meaningful activity (e.g. new comments that acknowledge verification against `canary`) will be automatically closed and locked after 30 days.
|
||||
|
||||
If your issue has not been resolved in that time and it has been closed/locked, please open a new issue, with the required reproduction, using `next@canary`.
|
||||
|
||||
### **I did not open this issue, but it is relevant to me, what can I do to help?**
|
||||
|
||||
Anyone experiencing the same issue is welcome to provide a minimal reproduction following the above steps. Furthermore, you can upvote the issue using the :+1: reaction on the topmost comment (please **do not** comment "I have the same issue" without repro steps). Then, we can sort issues by votes to prioritize.
|
||||
|
||||
### **I think my reproduction is good enough, why aren't you looking into it quicker?**
|
||||
|
||||
We look into every Next.js issue and constantly monitor open issues for new comments.
|
||||
|
||||
However, sometimes we might miss one or two due to the popularity/high traffic of the repository. We apologize, and kindly ask you to refrain from tagging core maintainers, as that will usually not result in increased priority.
|
||||
|
||||
Upvoting issues to show your interest will help us prioritize and address them as quickly as possible. That said, every issue is important to us, and if an issue gets closed by accident, we encourage you to open a new one linking to the old issue and we will look into it.
|
||||
|
||||
### **Useful Resources**
|
||||
|
||||
- [How to Contribute to Open Source (Next.js)](https://www.youtube.com/watch?v=cuoNzXFLitc)
|
||||
- [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve)
|
||||
- [Reporting a Next.js bug](https://github.com/vercel/next.js/blob/canary/.github/ISSUE_TEMPLATE/1.bug_report.yml)
|
||||
- [Next.js Triaging issues](https://github.com/vercel/next.js/blob/canary/contributing/repository/triaging.md)
|
84
.github/actions/issue-validator/e741f80fb604c28085a7.mjs
vendored
Normal file
84
.github/actions/issue-validator/e741f80fb604c28085a7.mjs
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
// @ts-check
|
||||
import * as github from '@actions/github'
|
||||
import * as core from '@actions/core'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const verifyCanaryLabel = 'please verify canary'
|
||||
const addReproductionLabel = 'please add a complete reproduction'
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* id :number
|
||||
* node_id :string
|
||||
* url :string
|
||||
* name :string
|
||||
* description :string
|
||||
* color :string
|
||||
* default :boolean
|
||||
* }} Label
|
||||
*/
|
||||
|
||||
async function run() {
|
||||
try {
|
||||
const { payload, repo } = github.context
|
||||
const { issue, pull_request } = payload
|
||||
|
||||
if (pull_request || !issue?.body || !process.env.GITHUB_TOKEN) return
|
||||
|
||||
/** @type {Label} */
|
||||
const newLabel = payload.label
|
||||
const { body, number: issueNumber } = issue
|
||||
const client = github.getOctokit(process.env.GITHUB_TOKEN).rest
|
||||
const issueCommon = { ...repo, issue_number: issueNumber }
|
||||
|
||||
/** @param {string|null|undefined} link */
|
||||
async function hasRepro(link) {
|
||||
if (!link) return false
|
||||
try {
|
||||
const url = new URL(link)
|
||||
if (['example.com'].includes(url.hostname)) {
|
||||
return false
|
||||
}
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
const response = await fetch(link)
|
||||
return response.ok
|
||||
}
|
||||
|
||||
const hasValidRepro = await hasRepro(
|
||||
body.match(/will be addressed faster\n\n(.*)\n\n### To Reproduce/i)?.[1]
|
||||
)
|
||||
|
||||
if (!hasValidRepro || newLabel.name === addReproductionLabel) {
|
||||
await client.issues.createComment({
|
||||
...issueCommon,
|
||||
body: readFileSync(join(__dirname, 'repro.md'), 'utf8'),
|
||||
})
|
||||
return core.info(
|
||||
'Commented on issue, because it did not have a sufficient reproduction.'
|
||||
)
|
||||
}
|
||||
|
||||
const isVerifyCanaryChecked = body.match(
|
||||
/- \[x\] I verified that the issue exists in the latest Next.js canary release/i
|
||||
)
|
||||
|
||||
if (!isVerifyCanaryChecked || newLabel.name === verifyCanaryLabel) {
|
||||
await client.issues.createComment({
|
||||
...issueCommon,
|
||||
body: readFileSync(join(__dirname, 'canary.md'), 'utf8'),
|
||||
})
|
||||
return core.info(
|
||||
'Commented on issue, because it was not verified against canary.'
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
4
.github/actions/issue-validator/index.mjs
vendored
4
.github/actions/issue-validator/index.mjs
vendored
File diff suppressed because one or more lines are too long
57
.github/actions/issue-validator/licenses.txt
vendored
57
.github/actions/issue-validator/licenses.txt
vendored
|
@ -478,25 +478,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|||
THE SOFTWARE.
|
||||
|
||||
|
||||
lru-cache
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
nextjs-project
|
||||
The MIT License (MIT)
|
||||
|
||||
|
@ -566,25 +547,6 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
|||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
semver
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
tr46
|
||||
MIT
|
||||
|
||||
|
@ -682,22 +644,3 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
yallist
|
||||
ISC
|
||||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
|
67
.github/actions/issue-validator/package-lock.json
generated
vendored
67
.github/actions/issue-validator/package-lock.json
generated
vendored
|
@ -6,11 +6,9 @@
|
|||
"": {
|
||||
"dependencies": {
|
||||
"@actions/core": "1.9.0",
|
||||
"@actions/github": "5.0.3",
|
||||
"semver": "7.3.7"
|
||||
"@actions/github": "5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/semver": "7.3.10",
|
||||
"@vercel/ncc": "0.34.0"
|
||||
}
|
||||
},
|
||||
|
@ -142,12 +140,6 @@
|
|||
"@octokit/openapi-types": "^12.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.10.tgz",
|
||||
"integrity": "sha512-zsv3fsC7S84NN6nPK06u79oWgrPVd0NvOyqgghV1haPaFcVxIrP4DLomRwGAXk0ui4HZA7mOcSFL98sMVW9viw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@vercel/ncc": {
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
|
||||
|
@ -175,17 +167,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
|
@ -213,20 +194,6 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
|
@ -263,11 +230,6 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -393,12 +355,6 @@
|
|||
"@octokit/openapi-types": "^12.10.0"
|
||||
}
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "7.3.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.10.tgz",
|
||||
"integrity": "sha512-zsv3fsC7S84NN6nPK06u79oWgrPVd0NvOyqgghV1haPaFcVxIrP4DLomRwGAXk0ui4HZA7mOcSFL98sMVW9viw==",
|
||||
"dev": true
|
||||
},
|
||||
"@vercel/ncc": {
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
|
||||
|
@ -420,14 +376,6 @@
|
|||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
|
@ -444,14 +392,6 @@
|
|||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
|
@ -485,11 +425,6 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
6
.github/actions/issue-validator/package.json
vendored
6
.github/actions/issue-validator/package.json
vendored
|
@ -5,12 +5,10 @@
|
|||
"build": "ncc -m -o . build src/index.mjs --license licenses.txt"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/semver": "7.3.10",
|
||||
"@vercel/ncc": "0.34.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "1.9.0",
|
||||
"@actions/github": "5.0.3",
|
||||
"semver": "7.3.7"
|
||||
"@actions/core": "1.10.0",
|
||||
"@actions/github": "5.1.1"
|
||||
}
|
||||
}
|
||||
|
|
38
.github/actions/issue-validator/repro.md
vendored
Normal file
38
.github/actions/issue-validator/repro.md
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
We cannot recreate the issue with the provided information. **Please add a reproduction in order for us to be able to investigate.**
|
||||
|
||||
### **Why was this issue marked with the `please add a complete reproduction` label?**
|
||||
|
||||
To be able to investigate, we need access to a reproduction to identify what triggered the issue. We prefer a link to a public GitHub repository ([template](https://github.com/vercel/next.js/tree/canary/examples/reproduction-template)), but you can also use a tool like [CodeSandbox](https://codesandbox.io/s/github/vercel/next.js/tree/canary/examples/reproduction-template) or [StackBlitz](https://stackblitz.com/fork/github/vercel/next.js/tree/canary/examples/reproduction-template).
|
||||
|
||||
To make sure the issue is resolved as quickly as possible, please make sure that the reproduction is as **minimal** as possible. This means that you should **remove unnecessary code, files, and dependencies** that do not contribute to the issue.
|
||||
|
||||
Please test your reproduction against the latest version of Next.js (`next@canary`) to make sure your issue has not already been fixed.
|
||||
|
||||
### **I added a link, why was it still marked?**
|
||||
|
||||
Ensure the link is pointing to a codebase that is accessible (e.g. not a private repository). "[example.com](http://example.com/)", "n/a", "will add later", etc. are not acceptable links -- we need to see a public codebase. See the above section for accepted links.
|
||||
|
||||
### **What happens if I don't provide a sufficient minimal reproduction?**
|
||||
|
||||
Issues with the `please add a complete reproduction` label that receives no meaningful activity (e.g. new comments with a reproduction link) are automatically closed and locked after 30 days.
|
||||
|
||||
If your issue has _not_ been resolved in that time and it has been closed/locked, please open a new issue with the required reproduction.
|
||||
|
||||
### **I did not open this issue, but it is relevant to me, what can I do to help?**
|
||||
|
||||
Anyone experiencing the same issue is welcome to provide a minimal reproduction following the above steps. Furthermore, you can upvote the issue using the :+1: reaction on the topmost comment (please **do not** comment "I have the same issue" without repro steps). Then, we can sort issues by votes to prioritize.
|
||||
|
||||
### **I think my reproduction is good enough, why aren't you looking into it quicker?**
|
||||
|
||||
We look into every Next.js issue and constantly monitor open issues for new comments.
|
||||
|
||||
However, sometimes we might miss one or two due to the popularity/high traffic of the repository. We apologize, and kindly ask you to refrain from tagging core maintainers, as that will usually not result in increased priority.
|
||||
|
||||
Upvoting issues to show your interest will help us prioritize and address them as quickly as possible. That said, every issue is important to us, and if an issue gets closed by accident, we encourage you to open a new one linking to the old issue and we will look into it.
|
||||
|
||||
### **Useful Resources**
|
||||
|
||||
- [How to Contribute to Open Source (Next.js)](https://www.youtube.com/watch?v=cuoNzXFLitc)
|
||||
- [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve)
|
||||
- [Reporting a Next.js bug](https://github.com/vercel/next.js/blob/canary/.github/ISSUE_TEMPLATE/1.bug_report.yml)
|
||||
- [Next.js Triaging issues](https://github.com/vercel/next.js/blob/canary/contributing/repository/triaging.md)
|
163
.github/actions/issue-validator/src/index.mjs
vendored
163
.github/actions/issue-validator/src/index.mjs
vendored
|
@ -1,13 +1,13 @@
|
|||
// @ts-check
|
||||
import * as github from '@actions/github'
|
||||
import * as core from '@actions/core'
|
||||
import { gte as semverGte } from 'semver'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const verifyCanaryLabel = 'please verify canary'
|
||||
const bugReportLabel = 'template: bug'
|
||||
const addReproductionLabel = 'please add a complete reproduction'
|
||||
const debug = !!process.env.DEBUG
|
||||
const json = (o) => JSON.stringify(o, null, 2)
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
|
@ -26,146 +26,59 @@ async function run() {
|
|||
const { payload, repo } = github.context
|
||||
const { issue, pull_request } = payload
|
||||
|
||||
if (pull_request || !issue?.body) return
|
||||
if (pull_request || !issue?.body || !process.env.GITHUB_TOKEN) return
|
||||
|
||||
/** @type {Label} */
|
||||
const newLabel = payload.label
|
||||
const { body, number: issueNumber } = issue
|
||||
/** @type {Label[]} */
|
||||
const labels = issue.labels
|
||||
|
||||
if (debug) {
|
||||
core.info(
|
||||
`Validating issue ${issueNumber}:
|
||||
Labels:
|
||||
New: ${json(newLabel)}
|
||||
All: ${json(labels)}
|
||||
Body: ${body}`
|
||||
)
|
||||
}
|
||||
|
||||
const isBugReport = newLabel.name === bugReportLabel
|
||||
|
||||
const isManuallyLabeled = labels.some(
|
||||
(label) => label.name === verifyCanaryLabel
|
||||
)
|
||||
|
||||
if (!isBugReport && !isManuallyLabeled) {
|
||||
return core.info(
|
||||
'Issue is ignored, because it is not a bug report or is not manually labeled'
|
||||
)
|
||||
}
|
||||
|
||||
if (!process.env.GITHUB_TOKEN) {
|
||||
throw new Error('GITHUB_TOKEN is not set')
|
||||
}
|
||||
|
||||
const client = github.getOctokit(process.env.GITHUB_TOKEN).rest
|
||||
const issueCommon = { ...repo, issue_number: issueNumber }
|
||||
|
||||
/**
|
||||
* @param {string} label
|
||||
* @param {string} comment
|
||||
*/
|
||||
function notifyOnIssue(label, comment) {
|
||||
const issueCommon = { ...repo, issue_number: issueNumber }
|
||||
|
||||
if (debug) {
|
||||
core.info('Skipping comment/label because we are in DEBUG mode')
|
||||
core.info(json({ label, comment }))
|
||||
return
|
||||
/** @param {string|null|undefined} link */
|
||||
async function hasRepro(link) {
|
||||
if (!link) return false
|
||||
try {
|
||||
const url = new URL(link)
|
||||
if (['example.com'].includes(url.hostname)) {
|
||||
return false
|
||||
}
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
client.issues.addLabels({ ...issueCommon, labels: [label] }),
|
||||
client.issues.createComment({ ...issueCommon, body: comment }),
|
||||
])
|
||||
const response = await fetch(link)
|
||||
return response.ok
|
||||
}
|
||||
|
||||
const isVerifyCanaryChecked = body.includes(
|
||||
'- [X] I verified that the issue exists in Next.js canary release'
|
||||
const hasValidRepro = await hasRepro(
|
||||
body.match(/will be addressed faster\n\n(.*)\n\n### To Reproduce/i)?.[1]
|
||||
)
|
||||
|
||||
if (!isVerifyCanaryChecked || isManuallyLabeled) {
|
||||
await notifyOnIssue(
|
||||
verifyCanaryLabel,
|
||||
'Please verify your issue reproduces with `next@canary`. The canary version of Next.js ships daily and includes all features and fixes that have not been released to the stable version yet. Think of canary as a public beta. Some issues may already be fixed in the canary version, so please verify that your issue reproduces by running `npm install next@canary`. If the issue does not reproduce with the canary version, then it has already been fixed and this issue can be closed.'
|
||||
)
|
||||
if (!hasValidRepro || newLabel.name === addReproductionLabel) {
|
||||
await client.issues.createComment({
|
||||
...issueCommon,
|
||||
body: readFileSync(join(__dirname, 'repro.md'), 'utf8'),
|
||||
})
|
||||
return core.info(
|
||||
`Commented on issue, because it was ${
|
||||
isManuallyLabeled ? 'manually labeled' : 'not verified against canary'
|
||||
}`
|
||||
'Commented on issue, because it did not have a sufficient reproduction.'
|
||||
)
|
||||
}
|
||||
|
||||
const reproductionUrl = body
|
||||
.match(/### Link to reproduction\n\n(?<url>.*)\n/)
|
||||
?.groups?.url.trim()
|
||||
|
||||
if (!reproductionUrl || !(await fetch(reproductionUrl)).ok) {
|
||||
await notifyOnIssue(
|
||||
addReproductionLabel,
|
||||
'The link to the reproduction appears to be incorrect/unreachable. Please add a link to the reproduction of the issue. This is a required field. If your project is private, you can invite @balazsorban44 to the repository so the Next.js team can investigate further.'
|
||||
)
|
||||
return core.info(
|
||||
`Commented on issue, because the reproduction url (${reproductionUrl}) was not reachable`
|
||||
)
|
||||
}
|
||||
|
||||
const containsNextInfoOutput = [
|
||||
'Operating System:',
|
||||
'Binaries:',
|
||||
'Relevant packages:',
|
||||
].every((i) => body.includes(i))
|
||||
|
||||
if (!containsNextInfoOutput) {
|
||||
return core.info(
|
||||
'Could not detect `next info` output, skipping as version detection might be unreliable'
|
||||
)
|
||||
}
|
||||
|
||||
const reported = body.match(
|
||||
/Relevant packages:\n next: (?<version>\d+\.\d+\.\d+)/
|
||||
)?.groups?.version
|
||||
|
||||
core.info(`Reported Next.js version: ${reported}`)
|
||||
|
||||
// REVIEW: Should we add a label here?
|
||||
if (!reported) return
|
||||
|
||||
const last = await getLastVersion()
|
||||
core.info(`Last Next.js version, based on npm releases: ${last}`)
|
||||
|
||||
if (!last.includes('canary') || reported === last) return
|
||||
|
||||
await notifyOnIssue(
|
||||
verifyCanaryLabel,
|
||||
`The reported Next.js version did not match the latest \`next@canary\` version (${last}). The canary version of Next.js ships daily and includes all features and fixes that have not been released to the stable version yet. Think of canary as a public beta. Some issues may already be fixed in the canary version, so please verify that your issue reproduces by running \`npm install next@canary\`. If the issue does not reproduce with the canary version, then it has already been fixed and this issue can be closed.`
|
||||
)
|
||||
return core.info(
|
||||
`Commented on issue, because it was not verified against canary`
|
||||
const isVerifyCanaryChecked = body.match(
|
||||
/- \[x\] I verified that the issue exists in the latest Next.js canary release/i
|
||||
)
|
||||
|
||||
if (!isVerifyCanaryChecked || newLabel.name === verifyCanaryLabel) {
|
||||
await client.issues.createComment({
|
||||
...issueCommon,
|
||||
body: readFileSync(join(__dirname, 'canary.md'), 'utf8'),
|
||||
})
|
||||
return core.info(
|
||||
'Commented on issue, because it was not verified against canary.'
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
core.setFailed(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
run()
|
||||
|
||||
async function getLastVersion() {
|
||||
try {
|
||||
const res = await fetch('https://registry.npmjs.org/next', {
|
||||
headers: {
|
||||
accept:
|
||||
'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*',
|
||||
},
|
||||
})
|
||||
const value = (await res.body?.getReader().read())?.value
|
||||
const string = new TextDecoder().decode(value?.slice(0, 100))
|
||||
const re = /"latest":"(?<latest>.*)","canary":"(?<canary>.*)","/
|
||||
const { latest, canary } = string.match(re)?.groups ?? {}
|
||||
return semverGte(latest, canary) ? canary : latest
|
||||
} catch (error) {
|
||||
core.error(error)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue