Refactor hackathon UI and enhance submission features #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Close Linked Issues | |
| # Auto-close issues referenced with Closes/Fixes/Resolves #N when a PR merges. | |
| # | |
| # GitHub's built-in auto-close only fires for PRs merged into the default branch | |
| # (main). This repo's feature PRs merge into integration branches such as | |
| # feat/t-replace, so linked issues are otherwise left open. This workflow closes | |
| # them on any base branch. | |
| # | |
| # pull_request_target runs in the base-repo context, so it has an issues:write | |
| # token even for PRs opened from forks (the normal pull_request event would get | |
| # a read-only token). It never checks out or runs PR head code, so it is safe. | |
| on: | |
| pull_request_target: | |
| types: [closed] | |
| permissions: | |
| issues: write | |
| contents: read | |
| jobs: | |
| close-linked-issues: | |
| name: Close linked issues | |
| runs-on: ubuntu-latest | |
| if: github.event.pull_request.merged == true | |
| steps: | |
| - name: Close issues referenced in the PR body | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const pr = context.payload.pull_request; | |
| const body = pr.body || ''; | |
| // Match "<keyword> #123" / "<keyword>: #123", keyword case-insensitive. | |
| const keyword = '(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)'; | |
| const re = new RegExp(`${keyword}\\s*:?\\s+#(\\d+)`, 'gi'); | |
| const numbers = new Set(); | |
| for (const m of body.matchAll(re)) { | |
| numbers.add(Number(m[1])); | |
| } | |
| if (numbers.size === 0) { | |
| core.info('No "Closes/Fixes/Resolves #N" references found in the PR body.'); | |
| return; | |
| } | |
| for (const issue_number of numbers) { | |
| try { | |
| const { data: issue } = await github.rest.issues.get({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number, | |
| }); | |
| // Skip PRs (the API treats PRs as issues) and already-closed issues. | |
| if (issue.pull_request) { | |
| core.info(`#${issue_number} is a pull request, skipping.`); | |
| continue; | |
| } | |
| if (issue.state === 'closed') { | |
| core.info(`#${issue_number} is already closed, skipping.`); | |
| continue; | |
| } | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number, | |
| body: `Closed by #${pr.number} (merged into \`${pr.base.ref}\`).`, | |
| }); | |
| await github.rest.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number, | |
| state: 'closed', | |
| state_reason: 'completed', | |
| }); | |
| core.info(`Closed #${issue_number}.`); | |
| } catch (err) { | |
| core.warning(`Could not close #${issue_number}: ${err.message}`); | |
| } | |
| } |