diff --git a/.github/workflows/close-issue-on-pr-merge.yml b/.github/workflows/close-issue-on-pr-merge.yml new file mode 100644 index 0000000..b7e4894 --- /dev/null +++ b/.github/workflows/close-issue-on-pr-merge.yml @@ -0,0 +1,70 @@ +# PR 合并后自动关闭关联的 Issue +# 当 PR 从 ai_fix/N_xxx 分支合并到 main 时,关闭 #N 对应的 Issue(若 PR 描述中未含 Closes #N 则通过分支名解析) + +name: Close issue on PR merge + +on: + pull_request: + types: [closed] + branches: [main] + +jobs: + close-issue: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: read + + steps: + - name: Get PR info + id: pr + run: | + # 从 PR body 查找 Closes #N / Fixes #N(若已有则 GitHub 已自动关 issue,本 step 仅做解析) + BODY="${{ github.event.pull_request.body }}" + HEAD_REF="${{ github.event.pull_request.head.ref }}" + + # 优先从 PR 描述解析 + ISSUE_NUM=$(echo "$BODY" | grep -oE '(Closes|Fixes|Resolves) #([0-9]+)' | head -1 | grep -oE '[0-9]+') + if [ -z "$ISSUE_NUM" ]; then + # 从分支名解析 ai_fix/N_xxx + ISSUE_NUM=$(echo "$HEAD_REF" | sed -n 's|^ai_fix/\([0-9]*\)_.*|\1|p') + fi + + if [ -z "$ISSUE_NUM" ]; then + echo "ISSUE_NUMBER=" >> $GITHUB_OUTPUT + echo "skip=true" >> $GITHUB_OUTPUT + echo "未从 PR 描述或分支名解析到 Issue 编号,跳过关闭" + exit 0 + fi + + echo "ISSUE_NUMBER=$ISSUE_NUM" >> $GITHUB_OUTPUT + echo "skip=false" >> $GITHUB_OUTPUT + echo "解析到 Issue #$ISSUE_NUM" + + - name: Close issue + if: steps.pr.outputs.skip != 'true' + uses: actions/github-script@v7 + with: + script: | + const issueNumber = parseInt('${{ steps.pr.outputs.ISSUE_NUMBER }}', 10); + if (!issueNumber || isNaN(issueNumber)) { + console.log('No valid issue number, skip'); + return; + } + const { data: issue } = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber + }); + if (issue.state === 'open') { + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issueNumber, + state: 'closed' + }); + console.log(`Issue #${issueNumber} closed.`); + } else { + console.log(`Issue #${issueNumber} already closed.`); + }