diff --git a/.github/workflows/bingshuo-deploy-agent.yml b/.github/workflows/bingshuo-deploy-agent.yml index 1b212866..f1888e84 100644 --- a/.github/workflows/bingshuo-deploy-agent.yml +++ b/.github/workflows/bingshuo-deploy-agent.yml @@ -4,6 +4,7 @@ name: "🧊 冰朔人格体 · 自动部署诊断" # 1. 手动触发(workflow_dispatch) # 2. Issue 评论包含触发关键词 # 3. 新 Issue 带有 bingshuo-deploy 标签 +# 4. 合作者推送模块后,模块文档工作流完成时自动触发 on: workflow_dispatch: inputs: @@ -27,6 +28,11 @@ on: issues: types: [opened] + # 合作者推送模块后,模块文档工作流完成时自动触发冰朔人格体部署诊断 + workflow_run: + workflows: ["铸渊 · HoloLake Era 模块文档自动生成"] + types: [completed] + permissions: contents: write issues: write @@ -42,6 +48,7 @@ jobs: # 3. 新 Issue 带有 bingshuo-deploy 标签 if: | github.event_name == 'workflow_dispatch' || + github.event_name == 'workflow_run' || (github.event_name == 'issue_comment' && ( contains(github.event.comment.body, '启动冰朔人格体') || contains(github.event.comment.body, '冰朔人格体') || diff --git a/.github/workflows/generate-module-doc.yml b/.github/workflows/generate-module-doc.yml index 9c837b39..911e760f 100644 --- a/.github/workflows/generate-module-doc.yml +++ b/.github/workflows/generate-module-doc.yml @@ -57,14 +57,13 @@ jobs: } fi - notify-collaborator: - name: 📧 通知合作者模块已收到 + check-and-notify: + name: 🔍 模块自检 + 📧 通知推送者 runs-on: ubuntu-latest # 仅 push 事件触发(workflow_dispatch 为手动,不发通知) if: github.event_name == 'push' permissions: - contents: read - issues: write + contents: write steps: - name: Checkout @@ -88,7 +87,59 @@ jobs: echo "EOF" >> $GITHUB_OUTPUT echo "📄 改动文件:$FILES" - - name: 发送模块收讫通知 + - name: 🔍 模块自检 + id: check + run: | + CHANGED_FILES="${{ steps.changed.outputs.files }}" + MODULES="m01-login m03-personality m05-user-center m06-ticket m07-dialogue-ui m10-cloud m11-module m12-kanban m15-cloud-drive dingtalk-bot backend-integration status-board" + + RESULT="pass" + DETAILS="" + + for mod in $MODULES; do + # 只检查本次有改动的模块 + if echo "$CHANGED_FILES" | grep -q "^${mod}/"; then + echo "🔍 检查模块: $mod" + + if [ -d "$mod" ]; then + if [ ! -f "$mod/README.md" ]; then + DETAILS="${DETAILS}❌ ${mod} 缺少 README.md(必须提供)"$'\n' + RESULT="fail" + fi + if [ ! -f "$mod/package.json" ]; then + DETAILS="${DETAILS}⚠️ ${mod} 缺少 package.json(建议补充)"$'\n' + fi + if [ ! -d "$mod/src" ]; then + DETAILS="${DETAILS}⚠️ ${mod} 缺少 src/ 目录(建议补充)"$'\n' + fi + + # 检查 package.json 格式是否正确 + if [ -f "$mod/package.json" ]; then + if ! node -e "JSON.parse(require('fs').readFileSync('$mod/package.json','utf8'))" 2>/dev/null; then + DETAILS="${DETAILS}❌ ${mod}/package.json 格式错误(JSON 解析失败)"$'\n' + RESULT="fail" + else + DETAILS="${DETAILS}✅ ${mod} 结构检查通过"$'\n' + fi + else + DETAILS="${DETAILS}✅ ${mod} 基本结构检查通过"$'\n' + fi + fi + fi + done + + if [ -z "$DETAILS" ]; then + DETAILS="✅ 所有模块检查通过" + fi + + echo "test_result=$RESULT" >> $GITHUB_OUTPUT + # 使用 heredoc 方式输出多行详情 + echo "test_details<> $GITHUB_OUTPUT + echo "$DETAILS" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "🔍 自检结果: $RESULT" + + - name: 📧 发送模块收讫通知(Commit Comment → 推送者本人) env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPO: ${{ github.repository }} @@ -96,5 +147,7 @@ jobs: CHANGED_FILES: ${{ steps.changed.outputs.files }} COMMIT_SHA: ${{ github.sha }} COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + TEST_RESULT: ${{ steps.check.outputs.test_result }} + TEST_DETAILS: ${{ steps.check.outputs.test_details }} run: node scripts/notify-module-received.js diff --git a/scripts/notify-module-received.js b/scripts/notify-module-received.js index 637e1afc..daa668d4 100644 --- a/scripts/notify-module-received.js +++ b/scripts/notify-module-received.js @@ -1,14 +1,21 @@ // scripts/notify-module-received.js -// 铸渊 · 模块收讫通知系统 -// 当合作者上传模块后,自动创建 GitHub Issue @提及 → GitHub 自动发邮件给对方 +// 铸渊 · 模块收讫通知系统 v2.0 +// 当合作者上传模块后,通过 Commit Comment @推送者 → GitHub 自动发邮件给推送者 +// +// v2.0 改动: +// - 改用 Commit Comment(而非 Issue)通知,邮件只发给推送者本人,不再通知仓库所有者 +// - 通知中包含模块自检结果(通过/未通过 + 详细报告) +// - 直接使用 github.actor 作为 @提及目标,无需 collaborators.json 中填写 github_username // // 环境变量(由 GitHub Actions 注入): // GITHUB_TOKEN — 仓库 token(自动注入) // GITHUB_REPO — 格式: owner/repo(如 qinfendebingshuo/guanghulab) // PUSHER_LOGIN — github.actor,即推送者的 GitHub 用户名 // CHANGED_FILES — 本次 push 中改动的文件列表(换行分隔) -// COMMIT_SHA — 本次 commit SHA(前8位) +// COMMIT_SHA — 本次 commit 完整 SHA // COMMIT_MESSAGE — 本次 commit 消息 +// TEST_RESULT — 自检结果:pass / fail +// TEST_DETAILS — 自检详细报告 const fs = require('fs'); const https = require('https'); @@ -18,8 +25,11 @@ const GITHUB_TOKEN = process.env.GITHUB_TOKEN; const GITHUB_REPO = process.env.GITHUB_REPO || ''; const PUSHER_LOGIN = (process.env.PUSHER_LOGIN || '').trim(); const CHANGED_FILES = (process.env.CHANGED_FILES || '').trim(); -const COMMIT_SHA = (process.env.COMMIT_SHA || '').slice(0, 8); +const COMMIT_SHA = (process.env.COMMIT_SHA || '').trim(); +const COMMIT_SHA_SHORT = COMMIT_SHA.slice(0, 8); const COMMIT_MSG = (process.env.COMMIT_MESSAGE || '').split('\n')[0].slice(0, 80); +const TEST_RESULT = (process.env.TEST_RESULT || 'unknown').trim(); +const TEST_DETAILS = (process.env.TEST_DETAILS || '').trim(); if (!GITHUB_TOKEN || !GITHUB_REPO) { console.error('❌ 缺少 GITHUB_TOKEN 或 GITHUB_REPO'); @@ -31,6 +41,11 @@ if (!PUSHER_LOGIN) { process.exit(0); } +if (!COMMIT_SHA) { + console.log('⚠️ 未获取到 Commit SHA,跳过通知'); + process.exit(0); +} + const [OWNER, REPO] = GITHUB_REPO.split('/'); // ========== 加载合作者配置 ========== @@ -39,8 +54,7 @@ try { const config = JSON.parse(fs.readFileSync('.github/brain/collaborators.json', 'utf8')); collaborators = config.collaborators || []; } catch (e) { - console.error('❌ 无法读取 collaborators.json:', e.message); - process.exit(1); + console.log('⚠️ 无法读取 collaborators.json,将使用 GitHub 用户名:', e.message); } // ========== 按推送者 GitHub 用户名查找合作者 ========== @@ -76,71 +90,81 @@ function detectChangedModules(changedFilesStr) { return Array.from(moduleDirs); } -// ========== 构建通知 Issue 内容 ========== -function buildIssueContent(collab, changedModules, allFiles) { +// ========== 构建通知内容(Commit Comment 格式)========== +function buildNotificationContent(collab, changedModules, allFiles) { const now = new Date().toISOString().replace('T', ' ').slice(0, 16) + ' UTC'; - const mention = collab && collab.github_username ? `@${collab.github_username}` : `@${PUSHER_LOGIN}`; const devLabel = collab ? `${collab.dev_id} · ${collab.emoji} ${collab.name}` : PUSHER_LOGIN; const moduleListStr = changedModules.length > 0 ? changedModules.map(m => `- \`${m}/\``).join('\n') - : '- (系统自动检测,请核对)'; + : '- (未检测到标准模块目录)'; const fileLines = allFiles.split('\n').filter(Boolean); const fileListStr = fileLines.slice(0, 20).map(f => ` - \`${f}\``).join('\n'); const extraNote = fileLines.length > 20 ? `\n - ...(共 ${fileLines.length} 个文件)` : ''; - const title = `📦 铸渊收讫 · [${collab ? collab.dev_id : 'DEV-???'}] ${collab ? collab.name : PUSHER_LOGIN} 模块已收到`; + const isPass = TEST_RESULT === 'pass'; + const isUnknown = TEST_RESULT === 'unknown'; + const statusEmoji = isPass ? '✅' : (isUnknown ? 'ℹ️' : '❌'); + const statusText = isPass ? '自检通过' : (isUnknown ? '自检未执行' : '自检未通过'); - const body = `## 铸渊收讫通知 + let body = `## 📦 光湖自动化系统 · 模块收讫回执\n\n`; + body += `@${PUSHER_LOGIN} 你好!\n\n`; -${mention} 你好!🎉 + if (isPass || isUnknown) { + body += `🎉 **你上传的模块已收到,自检通过!**\n\n`; + } else { + body += `⚠️ **你上传的模块已收到,但自检发现以下问题,请修改后重新上传:**\n\n`; + } -铸渊(自动化系统)已确认收到你上传的模块。 + body += `---\n\n`; + body += `### 📋 收讫详情\n\n`; + body += `| 字段 | 内容 |\n`; + body += `|------|------|\n`; + body += `| **合作者** | ${devLabel} |\n`; + body += `| **GitHub 账号** | @${PUSHER_LOGIN} |\n`; + body += `| **收到时间** | ${now} |\n`; + body += `| **Commit** | \`${COMMIT_SHA_SHORT}\` |\n`; + body += `| **提交说明** | ${COMMIT_MSG || '(无)'} |\n`; + body += `| **自检结果** | ${statusEmoji} ${statusText} |\n\n`; ---- + body += `### 📦 涉及模块\n\n${moduleListStr}\n\n`; + body += `### 📄 上传文件清单\n\n${fileListStr}${extraNote}\n\n`; -### 📋 收讫详情 + // 自检报告 + body += `### ${statusEmoji} 自检报告\n\n`; + if (TEST_DETAILS) { + body += `\`\`\`\n${TEST_DETAILS}\n\`\`\`\n\n`; + } else { + body += isPass ? '所有检查项目通过。\n\n' : '(未获取到详细检查报告)\n\n'; + } -| 字段 | 内容 | -|------|------| -| **合作者** | ${devLabel} | -| **GitHub 账号** | @${PUSHER_LOGIN} | -| **收到时间** | ${now} | -| **Commit** | \`${COMMIT_SHA}\` | -| **提交说明** | ${COMMIT_MSG || '(无)'} | + if (!isPass && !isUnknown) { + body += `### 📌 修改指南\n\n`; + body += `1. 请根据以上自检报告修改相关文件\n`; + body += `2. 修改完成后重新推送到仓库\n`; + body += `3. 铸渊将自动重新检查并发送新的回执\n\n`; + } else { + body += `### 📌 下一步\n\n`; + body += `1. 模块结构检查已通过,无需额外操作\n`; + body += `2. 铸渊将自动更新 [部署模块总文档](https://github.com/${GITHUB_REPO}/blob/main/docs/HoloLake-Era-OS-Modules.md)\n`; + body += `3. 如需修改,请继续推送即可\n\n`; + } -### 📦 涉及模块 + body += `---\n`; + body += `*—— 光湖自动化系统 · 铸渊(ZhùYuān)· ${now}*`; -${moduleListStr} - -### 📄 上传文件清单 - -${fileListStr}${extraNote} - ---- - -### 📌 下一步 - -1. **铸渊将自动更新** [HoloLake Era 操作系统部署模块](https://github.com/${GITHUB_REPO}/blob/main/docs/HoloLake-Era-OS-Modules.md) 总文档 -2. **模块结构检查** 已自动运行,请确认 CI 状态绿灯 -3. 如需补充 \`SYSLOG.md\`、\`package.json\` 或 \`src/\` 目录,请继续推送 - -> 💡 如有问题,请直接在本 Issue 回复,铸渊会收到通知。 - ---- -*—— 铸渊(ZhùYuān)· 光湖自动化系统 · 自动通知 #${now}*`; - - return { title, body }; + return body; } -// ========== 调用 GitHub API 创建 Issue ========== -function createIssue(title, body) { +// ========== 调用 GitHub API 创建 Commit Comment ========== +// Commit Comment 只通知 commit 作者 + @提及的用户,不通知仓库所有者 +function createCommitComment(body) { return new Promise((resolve, reject) => { - const payload = JSON.stringify({ title, body, labels: ['模块收讫'] }); + const payload = JSON.stringify({ body }); const options = { hostname: 'api.github.com', - path: `/repos/${OWNER}/${REPO}/issues`, + path: `/repos/${OWNER}/${REPO}/commits/${COMMIT_SHA}/comments`, method: 'POST', headers: { 'Authorization': `Bearer ${GITHUB_TOKEN}`, @@ -157,8 +181,7 @@ function createIssue(title, body) { res.on('data', chunk => { data += chunk; }); res.on('end', () => { if (res.statusCode === 201) { - const issue = JSON.parse(data); - resolve(issue); + resolve(JSON.parse(data)); } else { reject(new Error(`GitHub API 返回 ${res.statusCode}: ${data}`)); } @@ -171,55 +194,15 @@ function createIssue(title, body) { }); } -// ========== 确保标签存在(不存在则自动创建)========== -function ensureLabel() { - return new Promise((resolve) => { - const labelPayload = JSON.stringify({ - name: '模块收讫', - color: '0075ca', - description: '铸渊自动通知:合作者模块收讫确认', - }); - const options = { - hostname: 'api.github.com', - path: `/repos/${OWNER}/${REPO}/labels`, - method: 'POST', - headers: { - 'Authorization': `Bearer ${GITHUB_TOKEN}`, - 'Accept': 'application/vnd.github+json', - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(labelPayload), - 'User-Agent': 'ZhuyuanBot/1.0', - 'X-GitHub-Api-Version': '2022-11-28', - }, - }; - - const req = https.request(options, res => { - let data = ''; - res.on('data', c => { data += c; }); - res.on('end', () => { - // 201 = created, 422 = already exists,都算OK - resolve(); - }); - }); - req.on('error', () => resolve()); // 标签创建失败不阻断主流程 - req.write(labelPayload); - req.end(); - }); -} - // ========== 主流程 ========== async function main() { console.log(`👤 推送者:${PUSHER_LOGIN}`); console.log(`📁 改动文件:${CHANGED_FILES ? CHANGED_FILES.split('\n').length : 0} 个`); + console.log(`🔍 自检结果:${TEST_RESULT}`); const collab = findCollaborator(PUSHER_LOGIN); if (collab) { console.log(`✅ 识别合作者:${collab.dev_id} · ${collab.name}`); - if (!collab.github_username) { - console.log(`⚠️ ${collab.dev_id}(${collab.name})的 github_username 尚未填写`); - console.log(` 请在 .github/brain/collaborators.json 中补充,以便 @提及 生效`); - console.log(` 通知将仍然创建,但不会有 @提及 邮件通知`); - } } else { console.log(`ℹ️ 未在 collaborators.json 中找到 "${PUSHER_LOGIN}" 的映射,将使用 GitHub 用户名通知`); } @@ -242,16 +225,14 @@ async function main() { process.exit(0); } - // 确保标签存在 - await ensureLabel(); + // 构建并发送通知(通过 Commit Comment,直接通知推送者本人) + const body = buildNotificationContent(collab, changedModules, CHANGED_FILES); + console.log(`📝 创建 Commit Comment 通知(通知目标:@${PUSHER_LOGIN})...`); - // 构建并发送通知 - const { title, body } = buildIssueContent(collab, changedModules, CHANGED_FILES); - console.log(`📝 创建通知 Issue:${title}`); - - const issue = await createIssue(title, body); - console.log(`✅ Issue 已创建:#${issue.number} → ${issue.html_url}`); - console.log(`📧 GitHub 将自动发送邮件通知给 @${collab?.github_username || PUSHER_LOGIN}`); + const comment = await createCommitComment(body); + console.log(`✅ Commit Comment 已创建:${comment.html_url}`); + console.log(`📧 GitHub 将自动发送邮件通知给 @${PUSHER_LOGIN}(推送者本人)`); + console.log(`📧 仓库所有者将不会收到此通知`); } main().catch(err => {