blank_issues_enabled: false only hides the chooser link — the CLI / API / direct URLs still create template-less issues (e.g. #174 by a CONTRIBUTOR). This workflow enforces the policy: an issue opened by someone without write access that carries no template label (bug / enhancement) is commented on and closed as not-planned. Proper bug reports / feature requests and write-access users are unaffected. Takes effect only once on the default branch (main).
66 lines
2.7 KiB
YAML
66 lines
2.7 KiB
YAML
name: Issue template guard
|
|
|
|
# Blank / free-form issues bypass `blank_issues_enabled: false` (it only hides
|
|
# the chooser link — the CLI, API and direct URLs still create template-less
|
|
# issues). This guard enforces the policy after the fact: an issue opened by
|
|
# someone WITHOUT write access that did not go through a template (no template
|
|
# label) is commented on and closed. Properly-filed bug reports / feature
|
|
# requests (which carry `bug` / `enhancement`) and anyone with write access are
|
|
# left alone.
|
|
#
|
|
# Note: workflows for `issues` events run from the file on the DEFAULT branch,
|
|
# so this only takes effect once it lands on `main`.
|
|
|
|
on:
|
|
issues:
|
|
types: [opened]
|
|
|
|
permissions:
|
|
issues: write
|
|
|
|
jobs:
|
|
guard:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const issue = context.payload.issue;
|
|
|
|
// Write-access roles are exempt.
|
|
const privileged = ['OWNER', 'MEMBER', 'COLLABORATOR'];
|
|
if (privileged.includes(issue.author_association)) {
|
|
core.info(`author_association=${issue.author_association} — allowed`);
|
|
return;
|
|
}
|
|
|
|
// A template was used iff it stamped its label.
|
|
const TEMPLATE_LABELS = ['bug', 'enhancement'];
|
|
const labels = (issue.labels || []).map((l) => (typeof l === 'string' ? l : l.name));
|
|
if (labels.some((l) => TEMPLATE_LABELS.includes(l))) {
|
|
core.info('template label present — allowed');
|
|
return;
|
|
}
|
|
|
|
// Non-privileged + no template → guide and close.
|
|
const { owner, repo } = context.repo;
|
|
const chooser = `https://github.com/${owner}/${repo}/issues/new/choose`;
|
|
const body = [
|
|
'感谢你的反馈。',
|
|
'',
|
|
'本仓库的 issue 需要通过模板提交:请使用 **Bug 反馈** 或 **功能请求** 模板重新创建,',
|
|
'以便我们准确、高效地处理。直接创建的空白 / 自定义 issue 会被自动关闭。',
|
|
'',
|
|
`- 重新创建:${chooser}`,
|
|
'- 日常使用、快速交流类问题,可先到 README 中的 QQ 群',
|
|
'',
|
|
'本 issue 将自动关闭,感谢理解。',
|
|
].join('\n');
|
|
|
|
await github.rest.issues.createComment({ owner, repo, issue_number: issue.number, body });
|
|
await github.rest.issues.update({
|
|
owner, repo, issue_number: issue.number,
|
|
state: 'closed', state_reason: 'not_planned',
|
|
});
|
|
core.info(`closed #${issue.number} (author_association=${issue.author_association}, no template label)`);
|