GameServerManager/.github/workflows/pr-auto-check.yml
2025-08-15 14:45:38 +08:00

209 lines
8.7 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

name: PR 自动审查与分流
on:
pull_request_target:
types: [opened, reopened, synchronize, ready_for_review]
permissions:
contents: write
pull-requests: write
concurrency:
group: pr-${{ github.event.pull_request.number }}
cancel-in-progress: false
jobs:
pr-flow:
name: PR 自动化流程
runs-on: ubuntu-latest
steps:
- name: 初始评论 - 正在进行自动化审查
uses: actions/github-script@v7
with:
script: |
const { owner, repo, number } = context.issue;
// 获取 PR 变更的文件列表
const files = await github.paginate(github.rest.pulls.listFiles, {
owner, repo, pull_number: number, per_page: 100
});
const fileList = files.map(f => `- \`${f.filename}\` (${f.status})`).join('\n');
const fileCount = files.length;
await github.rest.issues.createComment({
owner, repo, issue_number: number,
body: `⚠ 本 PR 已进入自动化审查流程,正在进行代码审查,请稍后\n\n**本次变更文件 (${fileCount} 个):**\n${fileList}\n\n正在进行变更类型识别与 TypeScript 语法检查...`
});
- name: 检出 PR 提交代码
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: 识别是否仅修改文档
id: flags
uses: actions/github-script@v7
with:
script: |
const { owner, repo, number } = context.issue;
const files = await github.paginate(github.rest.pulls.listFiles, { owner, repo, pull_number: number, per_page: 100 });
const isDoc = (f) => {
const n = f.filename.toLowerCase();
return n.endsWith('.md') || n.endsWith('.mdx') || n.endsWith('.txt') || n.startsWith('docs/');
};
const docsOnly = files.length > 0 && files.every(isDoc);
core.setOutput('docs_only', String(docsOnly));
- name: 仅文档变更 - 回复
if: ${{ steps.flags.outputs.docs_only == 'true' }}
uses: actions/github-script@v7
with:
script: |
const { owner, repo, number } = context.issue;
await github.rest.issues.createComment({
owner, repo, issue_number: number,
body: '📝 本次提交仅为纯文档/文本变更。请等待作者最终审核。'
});
- name: 设置 Node 版本
if: ${{ steps.flags.outputs.docs_only != 'true' }}
uses: actions/setup-node@v4
with:
node-version: '20'
- name: 安装依赖server
if: ${{ steps.flags.outputs.docs_only != 'true' }}
run: |
cd server
npm ci --ignore-scripts
- name: TypeScript 语法检查server
if: ${{ steps.flags.outputs.docs_only != 'true' }}
id: tsc_server
shell: bash
run: |
set +e
cd server
npx tsc --noEmit 2>&1 | tee ../tsc_server_output.txt
rc=$?
cd ..
if [ $rc -ne 0 ]; then echo "failed=true" >> $GITHUB_OUTPUT; else echo "failed=false" >> $GITHUB_OUTPUT; fi
exit 0
- name: 安装依赖client
if: ${{ steps.flags.outputs.docs_only != 'true' }}
run: |
cd client
npm ci --ignore-scripts
- name: TypeScript 语法检查client
if: ${{ steps.flags.outputs.docs_only != 'true' }}
id: tsc_client
shell: bash
run: |
set +e
cd client
npx tsc --noEmit 2>&1 | tee ../tsc_client_output.txt
rc=$?
cd ..
if [ $rc -ne 0 ]; then echo "failed=true" >> $GITHUB_OUTPUT; else echo "failed=false" >> $GITHUB_OUTPUT; fi
exit 0
- name: 类型检查失败时回复 PR
if: ${{ (steps.tsc_server.outputs.failed == 'true' || steps.tsc_client.outputs.failed == 'true') && steps.flags.outputs.docs_only != 'true' }}
uses: actions/github-script@v7
with:
script: |
const { owner, repo, number } = context.issue;
const fs = require('fs');
let errorDetails = '';
// 读取 server 端错误信息
if ('${{ steps.tsc_server.outputs.failed }}' === 'true') {
try {
const serverErrors = fs.readFileSync('tsc_server_output.txt', 'utf8');
if (serverErrors.trim()) {
errorDetails += '**Server 端类型错误:**\n```\n' + serverErrors.trim() + '\n```\n\n';
}
} catch (e) {
errorDetails += '**Server 端类型检查失败**(无法读取详细错误信息)\n\n';
}
}
// 读取 client 端错误信息
if ('${{ steps.tsc_client.outputs.failed }}' === 'true') {
try {
const clientErrors = fs.readFileSync('tsc_client_output.txt', 'utf8');
if (clientErrors.trim()) {
errorDetails += '**Client 端类型错误:**\n```\n' + clientErrors.trim() + '\n```\n\n';
}
} catch (e) {
errorDetails += '**Client 端类型检查失败**(无法读取详细错误信息)\n\n';
}
}
await github.rest.issues.createComment({
owner, repo, issue_number: number,
body: `❌ 自动化类型检查未通过。命令:\`npx tsc --noEmit\`\n\n${errorDetails}请根据上述错误信息修复类型错误后再次提交,系统会重新审查~`
});
- name: 确保 base 仓库存在 feature 分支
if: ${{ success() && steps.flags.outputs.docs_only != 'true' && steps.tsc_server.outputs.failed != 'true' && steps.tsc_client.outputs.failed != 'true' }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.ACTIONS_PAT }}
script: |
const { owner, repo } = context.issue;
async function ensureFeature() {
try {
await github.rest.git.getRef({ owner, repo, ref: 'heads/feature' });
} catch (err) {
if (err.status === 404) {
const baseRef = await github.rest.git.getRef({ owner, repo, ref: 'heads/main' });
await github.rest.git.createRef({ owner, repo, ref: 'refs/heads/feature', sha: baseRef.data.object.sha });
} else {
throw err;
}
}
}
await ensureFeature();
- name: 如目标为 main则将 PR 目标分支切换为 feature
if: ${{ success() && steps.flags.outputs.docs_only != 'true' && steps.tsc_server.outputs.failed != 'true' && steps.tsc_client.outputs.failed != 'true' && github.event.pull_request.base.ref == 'main' }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.ACTIONS_PAT }}
script: |
const { owner, repo, number } = context.issue;
await github.rest.pulls.update({ owner, repo, pull_number: number, base: 'feature' });
- name: 合并 PR目标为 feature 时直接合并)
if: ${{ success() && steps.flags.outputs.docs_only != 'true' && steps.tsc_server.outputs.failed != 'true' && steps.tsc_client.outputs.failed != 'true' }}
uses: actions/github-script@v7
with:
github-token: ${{ secrets.ACTIONS_PAT }}
script: |
const { owner, repo, number } = context.issue;
try {
const pr = await github.rest.pulls.get({ owner, repo, pull_number: number });
if (pr.data.state !== 'open') {
return await github.rest.issues.createComment({ owner, repo, issue_number: number, body: '⚠️ PR 当前非 open 状态,自动合并已跳过。' });
}
await github.rest.pulls.merge({ owner, repo, pull_number: number, merge_method: 'merge' });
await github.rest.issues.createComment({
owner, repo, issue_number: number,
body: '✅ 您的 PR 已通过自动化检查,现已合并至 feature测试分支。\n维护者将进行最终检查若无问题会合并到 main 分支并在下个版本发布时包含。感谢贡献!❤'
});
} catch (e) {
const msg = (e && e.message) ? e.message : String(e);
await github.rest.issues.createComment({ owner, repo, issue_number: number, body: `⚠️ 自动合并失败,请维护者查看:\n\n\`\`\`\n${msg}\n\`\`\`` });
core.setFailed('Auto merge failed');
}