diff --git a/.github/scripts/tianyan-analyze.js b/.github/scripts/tianyan-analyze.js index 4fed2b17..bdaf551c 100644 --- a/.github/scripts/tianyan-analyze.js +++ b/.github/scripts/tianyan-analyze.js @@ -334,9 +334,11 @@ async function main() { console.log(`📊 分析结果: 共 ${result.total} 个, 可自动修复 ${result.auto_fixable} 个, 需人工 ${result.manual_only} 个`); console.log(`📁 结果保存: ${outputPath}`); - // Output for GitHub Actions - console.log(`::set-output name=auto_fixable_count::${result.auto_fixable}`); - console.log(`::set-output name=total_errors::${result.total}`); + // Output for GitHub Actions (using GITHUB_OUTPUT env file) + if (process.env.GITHUB_OUTPUT) { + fs.appendFileSync(process.env.GITHUB_OUTPUT, `auto_fixable_count=${result.auto_fixable}\n`); + fs.appendFileSync(process.env.GITHUB_OUTPUT, `total_errors=${result.total}\n`); + } } main().catch(e => { diff --git a/.github/scripts/tianyan-repair.js b/.github/scripts/tianyan-repair.js index 26e7c89a..0471db59 100644 --- a/.github/scripts/tianyan-repair.js +++ b/.github/scripts/tianyan-repair.js @@ -265,12 +265,14 @@ async function repairError(analysis, config) { return result; } + const todayDate = new Date().toISOString().slice(0, 10); + const rootCauseShort = (analysis.root_cause || analysis.error_type || '').slice(0, 80); const systemPrompt = `你是铸渊核心大脑。根据以下分析结果生成修复代码。 规则: 1. 只修改必要的行,最小化变更 2. 保留所有注释和格式 3. 输出完整的修复后文件内容 -4. 在修复位置添加注释:# [AUTO-FIX] ${new Date().toISOString().slice(0, 10)} by 铸渊 - ${analysis.root_cause} +4. 在修复位置添加注释:# [AUTO-FIX] ${todayDate} by 铸渊 - ${rootCauseShort} 5. 严禁修改任何与报错无关的代码 6. 严禁删除任何安全检查或天眼扫描步骤 7. 输出格式:将完整修复后文件内容放在代码块中`; diff --git a/.github/scripts/tianyan-review.js b/.github/scripts/tianyan-review.js index ad445638..58473ef9 100644 --- a/.github/scripts/tianyan-review.js +++ b/.github/scripts/tianyan-review.js @@ -103,10 +103,16 @@ function checkH2_FileSyntax(modifiedFiles) { if (content.includes('\t')) { throw new Error('YAML contains tab characters'); } - // Check for basic YAML structure (should start with valid YAML content) + // Basic YAML structural check: must have at least one key-value or comment const trimmed = content.trim(); - if (trimmed.length > 0 && !trimmed.startsWith('#') && !trimmed.startsWith('name:') && !trimmed.startsWith('on:') && !trimmed.startsWith('---') && !trimmed.match(/^[a-zA-Z_]/)) { - throw new Error('YAML does not start with valid content'); + if (trimmed.length > 0) { + const hasValidStructure = trimmed.split('\n').some(line => { + const l = line.trim(); + return l.startsWith('#') || l.startsWith('---') || l.includes(':') || l.startsWith('-'); + }); + if (!hasValidStructure) { + throw new Error('YAML does not contain valid structure'); + } } } result.details.push(`${filePath}: ✅ syntax OK`); @@ -199,7 +205,7 @@ function checkH6_ChangeScope(modifiedFiles, config) { const maxTotal = config.safety.max_total_changed_lines || 200; for (const filePath of modifiedFiles) { - const diff = gitExec(`git diff --numstat HEAD~1 -- "${filePath}"`); + const diff = gitExec(`git diff --numstat main -- "${filePath}"`) || gitExec(`git diff --numstat HEAD -- "${filePath}"`); if (!diff) continue; const parts = diff.split('\t'); @@ -234,8 +240,8 @@ function checkH7_SecretsIntegrity(modifiedFiles) { for (const filePath of modifiedFiles) { if (!filePath.endsWith('.yml') && !filePath.endsWith('.yaml')) continue; - // Get original content from git - const originalContent = gitExec(`git show HEAD~1:"${filePath}" 2>/dev/null`); + // Get original content from git (use main branch as reference) + const originalContent = gitExec(`git show main:"${filePath}" 2>/dev/null`) || gitExec(`git show HEAD:"${filePath}" 2>/dev/null`); const absPath = path.join(ROOT, filePath); if (!fs.existsSync(absPath)) continue; const newContent = fs.readFileSync(absPath, 'utf8'); diff --git a/.github/workflows/merge-watchdog.yml b/.github/workflows/merge-watchdog.yml index 15e6190e..86c39f08 100644 --- a/.github/workflows/merge-watchdog.yml +++ b/.github/workflows/merge-watchdog.yml @@ -74,14 +74,24 @@ jobs: echo "PR #$PR_NUM: $PR_TITLE" - # 从 PR 标题中提取目标 Workflow - # 格式约定: 🌙 [AUTO-FIX] YYYY-MM-DD 天眼夜间自动修复 (N个修复) - WORKFLOW=$(echo "$PR_TITLE" | grep -oP '\[AUTO-FIX\]\s+\K[^(]+' | sed 's/天眼夜间自动修复//' | xargs || echo "unknown") + # 从 PR body/commits 中提取修复的目标 Workflow + # 先尝试从 PR body 获取修复清单,再用 PR 标题作为回退 + if [ "${{ github.event_name }}" != "workflow_dispatch" ]; then + PR_BODY="${{ github.event.pull_request.body }}" + # Try to extract workflow names from commit messages or PR body + WORKFLOW=$(echo "$PR_BODY" | grep -oP '\b[\w-]+\.yml\b' | sort -u | head -5 | tr '\n' ',' | sed 's/,$//' || echo "") + fi + + if [ -z "$WORKFLOW" ]; then + # Fallback: use branch name to extract date info, mark as "nightly-repair" + BRANCH_NAME="${{ github.event.pull_request.head.ref }}" + WORKFLOW="nightly-repair-$(echo "$BRANCH_NAME" | grep -oP '\d{8}' || echo 'unknown')" + fi echo "target_workflows=$WORKFLOW" >> $GITHUB_OUTPUT echo "should_watch=true" >> $GITHUB_OUTPUT echo "pr_number=$PR_NUM" >> $GITHUB_OUTPUT - echo "👁️ 开始看守: PR #$PR_NUM" + echo "👁️ 开始看守: PR #$PR_NUM (targets: $WORKFLOW)" # ======================================== # 注册看守 + 观察目标 Workflow 运行结果 diff --git a/.github/workflows/tianyan-nightly-scan.yml b/.github/workflows/tianyan-nightly-scan.yml index d8105cd8..9bb9c63b 100644 --- a/.github/workflows/tianyan-nightly-scan.yml +++ b/.github/workflows/tianyan-nightly-scan.yml @@ -146,8 +146,8 @@ jobs: exit 0 fi - # Create repair branch - BRANCH="${REPAIR_BRANCH_PREFIX}-$(date +%Y%m%d)-001" + # Create repair branch (use timestamp to avoid conflicts) + BRANCH="${REPAIR_BRANCH_PREFIX}-$(date +%Y%m%d)-$(date +%H%M%S)" git config user.name "zhuyuan-bot" git config user.email "zhuyuan@guanghulab.com" git checkout -b "$BRANCH"