Spaces:
Paused
Paused
| import remarkParse from 'remark-parse'; | |
| import { unified } from 'unified'; | |
| // @TODO maybe we could use label or some other better ways to distinguish bug/feature issues | |
| const matchTitle = ['路由地址', 'Routes']; | |
| const maintainerURL = 'https://raw.githubusercontent.com/DIYgod/RSSHub/gh-pages/build/maintainers.json'; | |
| const successTag = 'bug ping: pinged'; | |
| const parseFailTag = 'bug ping: parsing failed'; | |
| const failTag = 'bug ping: not found'; | |
| const deprecatedRoute = 'route: deprecated'; | |
| const route = 'route'; | |
| // DnD (do-not-disturb) usernames, add yours here to avoid being notified | |
| // eslint-disable-next-line unicorn/no-useless-collection-argument | |
| const dndUsernames = new Set([]); | |
| async function parseBodyRoutes(body, core) { | |
| const ast = await unified().use(remarkParse).parse(body); | |
| // Is this a bug report? | |
| const title = ast.children[0].children[0].value.trim(); | |
| core.debug(`title: ${title}`); | |
| if (!matchTitle.some((ele) => ele.localeCompare(title) === 0)) { | |
| return null; | |
| } | |
| let routes = ast.children[1].value.trim(); | |
| core.debug(`routes: ${JSON.stringify(routes)}`); | |
| if (routes.localeCompare('NOROUTE') === 0) { | |
| return null; | |
| } | |
| if (routes) { | |
| routes = routes.split(/\r?\n/).filter(Boolean); | |
| const dedup = [...new Set(routes)]; | |
| if (dedup.length !== routes.length) { | |
| core.warning('Duplication detected.'); | |
| } | |
| core.debug(dedup); | |
| return dedup; | |
| } | |
| throw new Error('unable to parse the issue body: route does not exist'); | |
| } | |
| async function getMaintainersByRoutes(routes, core) { | |
| const response = await fetch(maintainerURL); | |
| const maintainers = await response.json(); | |
| return routes.map((e) => { | |
| const m = maintainers[e]; | |
| if (m === undefined) { | |
| core.warning(`Route ${e} not found`); | |
| } | |
| return m; | |
| }); | |
| } | |
| export default async function callMaintainer({ github, context, core }) { | |
| const body = context.payload.issue.body; | |
| const issueFacts = { | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| }; | |
| const addLabels = (labels) => | |
| github.rest.issues | |
| .addLabels({ | |
| ...issueFacts, | |
| labels, | |
| }) | |
| .catch((error) => { | |
| core.warning(error); | |
| }); | |
| const updateIssueState = (state) => | |
| github.rest.issues | |
| .update({ | |
| ...issueFacts, | |
| state, | |
| }) | |
| .catch((error) => { | |
| core.warning(error); | |
| }); | |
| if (context.payload.issue.state === 'closed') { | |
| await updateIssueState('open'); | |
| } | |
| const routes = await parseBodyRoutes(body, core).catch((error) => { | |
| core.warning(error); | |
| }); | |
| if (routes === null) { | |
| return; // Not a bug report, or NOROUTE | |
| } | |
| if (routes === undefined) { | |
| await addLabels([parseFailTag]); | |
| return; | |
| } | |
| const maintainers = await getMaintainersByRoutes(routes, core); | |
| let successCount = 0; | |
| let emptyCount = 0; | |
| let failedCount = 0; | |
| let comments = '##### Searching for maintainers: \n\n'; | |
| for (const [i, route] of routes.entries()) { | |
| const main = maintainers[i]; | |
| if (main === undefined) { | |
| comments += `- \`${route}\`: **Route not found**\n`; | |
| failedCount += 1; | |
| continue; | |
| } | |
| if (main.length === 0) { | |
| comments += `- \`${route}\`: No maintainer listed, possibly a v1 or misconfigured route\n`; | |
| emptyCount += 1; | |
| continue; | |
| } | |
| if (main.length > 0) { | |
| const pingStr = main | |
| .map((e) => { | |
| if (dndUsernames.has(e)) { | |
| return `\`@${e}\``; // Wrap in an inline code block to make sure no mention will be sent | |
| } | |
| return `@${e}`; | |
| }) | |
| .join(' '); | |
| comments += `- \`${route}\`: ${pingStr}\n`; | |
| successCount += 1; | |
| } | |
| } | |
| const labels = ['']; | |
| if (failedCount > 0) { | |
| labels.push(failTag); | |
| } else { | |
| labels.push(successTag); | |
| } | |
| if (emptyCount > 0) { | |
| labels.push(deprecatedRoute); | |
| } | |
| if (successCount > 0) { | |
| labels.push(route); | |
| } | |
| // Write labels (status, affected route count) | |
| await addLabels(labels); | |
| // Reply to the issue and notify the maintainers (if any) | |
| await github.rest.issues | |
| .createComment({ | |
| ...issueFacts, | |
| body: `${comments} | |
| > To maintainers: if you are not willing to be disturbed, list your username in \`scripts/workflow/test-issue/call-maintainer.js\`. In this way, your username will be wrapped in an inline code block when tagged so you will not be notified. | |
| If all routes can not be found, the issue will be closed automatically. Please use \`NOROUTE\` for a route-irrelevant issue or leave a comment if it is a mistake. | |
| 如果所有路由都无法匹配,issue 将会被自动关闭。如果 issue 和路由无关,请使用 \`NOROUTE\` 关键词,或者留下评论。我们会重新审核。 | |
| `, | |
| }) | |
| .catch((error) => { | |
| core.warning(error); | |
| }); | |
| if (failedCount && emptyCount === 0 && successCount === 0) { | |
| await updateIssueState('closed'); | |
| } | |
| } | |