diff --git a/.github/workflows/duplicate-issues.yml b/.github/workflows/duplicate-issues.yml index bc393269f9..09d669b6ff 100644 --- a/.github/workflows/duplicate-issues.yml +++ b/.github/workflows/duplicate-issues.yml @@ -2,10 +2,11 @@ name: duplicate-issues on: issues: - types: [opened] + types: [opened, edited] jobs: check-duplicates: + if: github.event.action == 'opened' runs-on: blacksmith-4vcpu-ubuntu-2404 permissions: contents: read @@ -80,3 +81,124 @@ jobs: issue_number: context.payload.issue.number, labels: ["needs:compliance"], }) + + recheck-compliance: + if: github.event.action == 'edited' && contains(github.event.issue.labels.*.name, 'needs:compliance') + runs-on: blacksmith-4vcpu-ubuntu-2404 + permissions: + contents: read + issues: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup-bun + + - name: Install dependencies + run: bun install + + - name: Install opencode + run: curl -fsSL https://opencode.ai/install | bash + + - name: Build recheck prompt + uses: actions/github-script@v8 + with: + script: | + const fs = require("fs") + const issue = context.payload.issue + const body = issue.body ?? "" + const text = [ + "Recheck this edited issue for compliance:", + "", + "MODE: recheck-compliance", + `CURRENT_ISSUE_NUMBER: ${issue.number}`, + "", + `Title: ${issue.title}`, + "", + "Description:", + body, + ].join("\n") + + fs.writeFileSync("issue_info.txt", text) + + - name: Recheck compliance + env: + OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + bun script/duplicate-issue.ts -f issue_info.txt "Recheck compliance for this edited issue and return either No action required or a compliance comment body" > issue_comment.txt + + - name: Update compliance state + env: + COMMENT: ${{ github.workspace }}/issue_comment.txt + uses: actions/github-script@v8 + with: + script: | + const fs = require("fs") + const marker = "" + const comment = fs.readFileSync(process.env.COMMENT, "utf8").trim() + const issue_number = context.payload.issue.number + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + per_page: 100, + }) + + const compliance = comments.filter((x) => (x.body ?? "").includes(marker)) + + if (comment === "No action required") { + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + name: "needs:compliance", + }) + } catch {} + + for (const entry of compliance) { + await github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: entry.id, + }) + } + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + body: "Thanks for updating your issue. It now meets our contributing guidelines. :+1:", + }) + return + } + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + labels: ["needs:compliance"], + }) + + const body = `_The following comment was made by an LLM, it may be inaccurate:_\n\n${comment}` + const existing = compliance.at(-1) + if (!existing) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + body, + }) + return + } + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }) diff --git a/.opencode/agent/duplicate-issue.md b/.opencode/agent/duplicate-issue.md index efad62b455..e840d20624 100644 --- a/.opencode/agent/duplicate-issue.md +++ b/.opencode/agent/duplicate-issue.md @@ -19,6 +19,11 @@ Use the github-issue-search tool to find potentially related issues. IMPORTANT: The input will contain a line `CURRENT_ISSUE_NUMBER: NNNN`. Never mark that issue as a duplicate of itself. +The input may also contain `MODE: recheck-compliance`. + +- When MODE is `recheck-compliance`, ONLY run compliance checks. Do not run duplicate checks. Do not include duplicate or keybind sections. +- When MODE is missing, do the full opened-issue behavior (compliance + duplicates + keybind note). + ## Compliance checks This project has three issue templates: @@ -49,12 +54,19 @@ If the issue mentions keybinds, keyboard shortcuts, or key bindings, include a n ## Output rules -If the issue is compliant AND no duplicates are found AND no keybind note is needed, output exactly: +If MODE is `recheck-compliance` and the issue is compliant, output exactly: + +No action required + +If MODE is missing and the issue is compliant AND no duplicates are found AND no keybind note is needed, output exactly: No action required Otherwise output exactly one markdown comment body with this structure: +- In `recheck-compliance` mode: include only the non-compliant section and ending note. +- In default mode: include sections as needed (non-compliant, duplicates, keybind). + - If non-compliant, start with: