Skip to content

Commit 3a9c46d

Browse files
authored
ci: add issue triage and stale-issue automation (#4829)
* ci: add issue triage and stale-issue automation Adds two GitHub Actions workflows: - issue-triage.yml: on new issues, runs Claude Code Action to check completeness against issue templates and surface similar existing issues (open or closed). Labels incomplete issues with 'needs-info'. - stale-issues.yml: daily cron that closes issues labelled 'needs-info' after 48 hours of inactivity. Refs #4804 * ci: use existing 'issue needs work' label and match repo conventions - Switch triage/stale workflows from creating a new 'needs-info' label to using the existing 'issue needs work' label - Drop the label-create step and the corresponding allowed-tool entry - Rename stale workflow to match the new label - Use ${{ github.token }} for GH_TOKEN to match claude.yml - Add local-time comment on the cron schedule, matching the style used in dependabot-rotation.yml * ci: address code review feedback on triage and stale workflows - Add timeout-minutes: 10 to triage job to cap runaway LLM usage - Add exempt-all-assignees: true so maintainer-claimed issues are not auto-closed - Set stale-issue-message: '' explicitly to document intent - Drop redundant stale-issue-label (same as only-labels) * ci: drop unused gh api allowance from triage workflow Addresses review feedback: gh api:* was broader than needed and not used by the prompt. The remaining gh issue/search subcommands cover all documented operations. * ci: address remaining review feedback on triage and stale workflows - restore stale-issue-label to prevent default "Stale" label - correct "48 hours" wording to "2 days" (cron window is up to 72h) - include generic-issue template placeholders in compliance check - skip triage for bot-opened issues - tighten gh search allowlist to gh search issues * ci: extend needs-info window from 2 to 3 days
1 parent 3364526 commit 3a9c46d

2 files changed

Lines changed: 129 additions & 0 deletions

File tree

.github/workflows/issue-triage.yml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
name: Issue triage
2+
3+
on:
4+
issues:
5+
types: [opened]
6+
workflow_dispatch:
7+
inputs:
8+
issue_number:
9+
description: 'Issue number to triage (for manual testing)'
10+
required: true
11+
type: string
12+
13+
jobs:
14+
triage:
15+
if: github.event_name == 'workflow_dispatch' || github.event.sender.type != 'Bot'
16+
runs-on: ubuntu-latest
17+
timeout-minutes: 10
18+
permissions:
19+
contents: read
20+
issues: write
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v6
24+
with:
25+
fetch-depth: 1
26+
27+
- name: Triage with Claude
28+
uses: anthropics/claude-code-action@v1
29+
env:
30+
GH_TOKEN: ${{ github.token }}
31+
with:
32+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
33+
prompt: |
34+
You are triaging a newly opened issue in the Equinor Design System (EDS) repository.
35+
36+
Repository: ${{ github.repository }}
37+
Issue number: ${{ github.event.issue.number || inputs.issue_number }}
38+
39+
Start by reading the issue:
40+
gh issue view ${{ github.event.issue.number || inputs.issue_number }}
41+
42+
Do TWO things, in order.
43+
44+
=== 1. Compliance check ===
45+
The repo uses issue templates (bug, feature request, generic). Each template has placeholder prompts like:
46+
"A clear and concise description of what the bug is."
47+
"Steps to reproduce the bug: 1. 2. 3. 4."
48+
"Describe the solution you'd like"
49+
"In order to <achieve some value>, as a <type of user>, I want <some functionality>." (default generic title)
50+
"A clear and concise description of the main goal" (generic: General objective)
51+
"(A list of) actionable goals that leads to fulfilling the general objective" (generic: Specific objectives)
52+
"The definition of done" (generic: Outcome)
53+
Treat the issue as INCOMPLETE if any of the following are true:
54+
- Placeholder text is left unchanged
55+
- Required sections are empty
56+
- The content is too vague or trivial to act on (e.g. only a title with no body, or body is "it doesn't work")
57+
58+
If INCOMPLETE:
59+
a. Add the "issue needs work" label (note: the label name contains spaces, quote it):
60+
gh issue edit ${{ github.event.issue.number || inputs.issue_number }} --add-label "issue needs work"
61+
b. Post a single comment (gh issue comment) that:
62+
- Politely thanks the author for opening the issue
63+
- Lists specifically what information is missing
64+
- Notes that the issue will be closed automatically after 3 days if not updated
65+
- Invites the author to edit the issue or add a comment with the missing details
66+
67+
If COMPLETE: skip this part entirely. Do nothing.
68+
69+
=== 2. Similarity search ===
70+
Search for related issues in BOTH open and closed state — a closed issue may contain the resolution.
71+
72+
Derive 2-4 keyword searches from the issue title and body, then run them:
73+
gh search issues --repo ${{ github.repository }} --state all --limit 20 <keywords>
74+
You may also use:
75+
gh issue list --repo ${{ github.repository }} --state all --search "<keywords>" --limit 20
76+
77+
Exclude the current issue (#${{ github.event.issue.number || inputs.issue_number }}) from results.
78+
79+
Apply a HIGH threshold for "related": the issue must clearly overlap in symptom, component, or feature — not just share a common word. Prefer quality over quantity. If unsure, do not comment.
80+
81+
If you find 1-5 strong matches, post a SINGLE comment that:
82+
- Starts with a brief sentence explaining these may be related
83+
- Lists each match as: "- #NUMBER — TITLE (open/closed): one-sentence reason it's relevant"
84+
- For closed matches with a resolution, call it out explicitly (e.g. "closed as fixed in #XYZ")
85+
- Ends with this disclaimer (exact text):
86+
_This comment was generated by an LLM and may be inaccurate. Please verify that the linked issues are actually relevant._
87+
88+
If there are no strong matches: do not post a comment.
89+
90+
=== Constraints ===
91+
- Do not modify any files in the repository.
92+
- Do not open pull requests.
93+
- Post at most one compliance comment and at most one similarity comment.
94+
- Keep comments concise and friendly.
95+
96+
claude_args: >-
97+
--allowed-tools
98+
"Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh issue edit:*),Bash(gh issue comment:*),Bash(gh search issues:*)"

.github/workflows/stale-issues.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Close stale issues
2+
3+
on:
4+
schedule:
5+
# Every day at 08:00 Oslo (CEST) / 07:00 Oslo (CET) — 06:00 UTC
6+
- cron: '0 6 * * *'
7+
workflow_dispatch:
8+
9+
jobs:
10+
stale:
11+
runs-on: ubuntu-latest
12+
permissions:
13+
issues: write
14+
steps:
15+
- uses: actions/stale@v9
16+
with:
17+
only-labels: 'issue needs work'
18+
days-before-issue-stale: 3
19+
days-before-issue-close: 0
20+
remove-issue-stale-when-updated: true
21+
exempt-all-assignees: true
22+
# Same as only-labels — keeps the existing label in place rather than adding the default "Stale"
23+
stale-issue-label: 'issue needs work'
24+
stale-issue-message: ''
25+
close-issue-message: |
26+
Closing this issue because the requested information was not provided within 3 days.
27+
28+
If you'd like to continue, please reopen the issue and add the missing details (or comment here and a maintainer can reopen it for you).
29+
# PRs are not handled by this workflow
30+
days-before-pr-stale: -1
31+
days-before-pr-close: -1

0 commit comments

Comments
 (0)