2b570a432a
PR 描述中无 Closes/Fixes/Resolves #N 时,grep 返回 1,set -e 导致脚本 在未执行分支名回退逻辑前即退出。为管道添加 || true,使无匹配时继续 从分支名 ai_fix/N_xxx 解析 Issue 编号。 Made-with: Cursor
128 lines
5.0 KiB
YAML
128 lines
5.0 KiB
YAML
# PR 合并后自动关闭关联的 Issue
|
||
# 当 PR 从 ai_fix/N_xxx 分支合并到 main 时,关闭 #N 对应的 Issue(若 PR 描述中未含 Closes #N 则通过分支名解析)
|
||
# 关闭后发送 Telegram 通知(复用 TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID)
|
||
|
||
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 描述解析(无匹配时 grep 会 exit 1,需 || true 避免 set -e 导致脚本退出)
|
||
ISSUE_NUM=$(echo "$BODY" | grep -oE '(Closes|Fixes|Resolves) #([0-9]+)' | head -1 | grep -oE '[0-9]+' || true)
|
||
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: Get issue details
|
||
if: steps.pr.outputs.skip != 'true'
|
||
id: issue
|
||
env:
|
||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
ISSUE_NUM="${{ steps.pr.outputs.ISSUE_NUMBER }}"
|
||
# 获取 issue 标题与 URL(用于 TG 消息)
|
||
JSON=$(gh issue view "$ISSUE_NUM" --json title,url 2>/dev/null || echo '{"title":"","url":""}')
|
||
TITLE=$(echo "$JSON" | jq -r '.title')
|
||
ISSUE_URL=$(echo "$JSON" | jq -r '.url')
|
||
echo "title<<EOF" >> $GITHUB_OUTPUT
|
||
echo "$TITLE" >> $GITHUB_OUTPUT
|
||
echo "EOF" >> $GITHUB_OUTPUT
|
||
echo "url=$ISSUE_URL" >> $GITHUB_OUTPUT
|
||
|
||
- 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.`);
|
||
}
|
||
|
||
- name: Send Telegram notification
|
||
if: steps.pr.outputs.skip != 'true'
|
||
env:
|
||
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
|
||
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
|
||
run: |
|
||
# 与 docker-build 一致:未配置则跳过
|
||
if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then
|
||
echo "⚠️ Telegram Bot Token 或 Chat ID 未配置,跳过通知"
|
||
exit 0
|
||
fi
|
||
|
||
ISSUE_NUM="${{ steps.pr.outputs.ISSUE_NUMBER }}"
|
||
ISSUE_TITLE="${{ steps.issue.outputs.title }}"
|
||
ISSUE_URL="${{ steps.issue.outputs.url }}"
|
||
PR_URL="${{ github.event.pull_request.html_url }}"
|
||
|
||
# 与 docker-build 相同的 HTML 消息格式
|
||
MESSAGE="✅ <b>AI 修复的 Issue 已关闭</b>"$'\n'$'\n'"🔢 <b>Issue:</b> #${ISSUE_NUM} ${ISSUE_TITLE}"$'\n'"📎 <a href=\"${ISSUE_URL}\">查看 Issue</a>"$'\n'"🔗 <a href=\"${PR_URL}\">查看 PR</a>"
|
||
|
||
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$(jq -n \
|
||
--arg chat_id "$TELEGRAM_CHAT_ID" \
|
||
--arg text "$MESSAGE" \
|
||
'{chat_id: $chat_id, text: $text, parse_mode: "HTML", disable_web_page_preview: false}')" > /tmp/telegram_response.json
|
||
|
||
if [ $? -eq 0 ]; then
|
||
RESPONSE=$(cat /tmp/telegram_response.json)
|
||
if echo "$RESPONSE" | grep -q '"ok":true'; then
|
||
echo "✅ Telegram 通知发送成功"
|
||
else
|
||
echo "❌ Telegram 通知发送失败: $RESPONSE"
|
||
exit 0
|
||
fi
|
||
else
|
||
echo "❌ 发送 Telegram 消息时发生错误"
|
||
exit 0
|
||
fi
|