11name : Docker Build and Push
22
3+ # 🔒 工作流级权限控制
4+ permissions :
5+ contents : read
6+ packages : write
7+ pull-requests : write
8+
39on :
4- # PR 提交或更新时触发
10+ # PR 提交或更新时触发(用于构建检查)
511 pull_request :
612 branches : [main, master, develop]
713 types : [opened, synchronize, reopened]
814
15+ # 专门用于 PR 评论的触发器(支持 fork 仓库)
16+ pull_request_target :
17+ types : [opened, synchronize, reopened]
18+ branches : [main, master, develop]
19+
920 # 合并到主分支时触发
1021 push :
1122 branches : [main, master]
12- # 支持手动触发
23+
24+ # 支持手动触发
1325 workflow_dispatch :
1426
1527env :
1628 # 使用 vars 而不是 secrets 来存储用户名(推荐做法)
1729 DOCKER_IMAGE : ${{ vars.DOCKERHUB_USERNAME && vars.DOCKERHUB_USERNAME != '' && vars.DOCKERHUB_USERNAME || 'defaultuser' }}/ruiqi-waf
1830
19- # 精简权限
20- permissions :
21- contents : read
22- packages : write
23- pull-requests : write
24-
2531jobs :
26- docker :
32+ # 主要的构建检查 job(使用 pull_request,安全执行外部代码)
33+ docker-build :
34+ name : Docker Build Check
2735 runs-on : ubuntu-latest
36+ # 只在 pull_request 和 push 事件时运行,不在 pull_request_target 时运行
37+ if : github.event_name != 'pull_request_target'
38+
39+ outputs :
40+ build-status : ${{ steps.set-status.outputs.build_status }}
41+ build-result : ${{ steps.set-status.outputs.build_result }}
42+ image-tags : ${{ steps.meta.outputs.tags }}
43+ build-time : ${{ steps.set-status.outputs.build_time }}
44+ commit-sha : ${{ steps.set-status.outputs.commit_sha }}
45+
2846 steps :
2947 - name : Checkout
3048 uses : actions/checkout@v4
89107 # PR阶段优化:禁用不必要的功能
90108 provenance : false
91109 sbom : false
110+ continue-on-error : true
92111
93112 # 推送阶段:完整多平台构建
94113 - name : Build and push (Multi-platform)
@@ -109,76 +128,230 @@ jobs:
109128 provenance : true
110129 sbom : true
111130
112- # 优化的PR评论
113- - name : Comment PR
114- if : github.event_name == 'pull_request'
131+ # 📤 设置输出状态
132+ - name : Set job outputs
133+ id : set-status
134+ if : always()
135+ run : |
136+ if [ "${{ job.status }}" = "success" ]; then
137+ echo "build_status=success" >> $GITHUB_OUTPUT
138+ echo "build_result=passed" >> $GITHUB_OUTPUT
139+ else
140+ echo "build_status=failure" >> $GITHUB_OUTPUT
141+ echo "build_result=failed" >> $GITHUB_OUTPUT
142+ fi
143+ echo "build_time=$(date '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_OUTPUT
144+ echo "commit_sha=${{ github.sha }}" >> $GITHUB_OUTPUT
145+
146+ # 生成详细构建报告
147+ - name : Generate Docker build summary
148+ if : always()
149+ run : |
150+ echo "## 🚀 Docker Build Report" >> $GITHUB_STEP_SUMMARY
151+ echo "" >> $GITHUB_STEP_SUMMARY
152+
153+ # 构建状态
154+ echo "### 📋 Build Status" >> $GITHUB_STEP_SUMMARY
155+ echo "| Item | Status | Details |" >> $GITHUB_STEP_SUMMARY
156+ echo "|------|--------|---------|" >> $GITHUB_STEP_SUMMARY
157+
158+ if [ "${{ job.status }}" = "success" ]; then
159+ if [ "${{ github.event_name }}" = "pull_request" ]; then
160+ echo "| Docker Build | ✅ Passed | AMD64 architecture verification successful |" >> $GITHUB_STEP_SUMMARY
161+ echo "| Platform | 📱 Single | linux/amd64 (PR optimization) |" >> $GITHUB_STEP_SUMMARY
162+ echo "| Cache | 🚀 Optimized | GitHub Actions cache enabled |" >> $GITHUB_STEP_SUMMARY
163+ else
164+ echo "| Docker Build | ✅ Passed | Multi-platform build successful |" >> $GITHUB_STEP_SUMMARY
165+ echo "| Platform | 🌐 Multi | linux/amd64, linux/arm64 |" >> $GITHUB_STEP_SUMMARY
166+ echo "| Registry Push | ✅ Completed | Docker Hub + GitHub Container Registry |" >> $GITHUB_STEP_SUMMARY
167+ fi
168+ else
169+ echo "| Docker Build | ❌ Failed | Please check build logs |" >> $GITHUB_STEP_SUMMARY
170+ fi
171+
172+ echo "" >> $GITHUB_STEP_SUMMARY
173+ echo "### 📊 Build Information" >> $GITHUB_STEP_SUMMARY
174+ echo "- **Event Type**: ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
175+ echo "- **Commit SHA**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
176+ echo "- **Branch**: \`${{ github.ref_name }}\`" >> $GITHUB_STEP_SUMMARY
177+ echo "- **Triggered by**: @${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
178+ echo "- **Build Time**: $(date '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
179+
180+ # 🔒 安全的 PR 评论 job(使用 pull_request_target,但不 checkout 外部代码)
181+ pr-comment :
182+ name : PR Comment Handler
183+ runs-on : ubuntu-latest
184+ # 只在 pull_request_target 事件时运行
185+ if : github.event_name == 'pull_request_target'
186+
187+ steps :
188+ # 🔒 重要:不 checkout 任何代码,特别是 PR 代码!
189+ # 🔒 只使用 GitHub API 获取工作流运行结果
190+
191+ - name : Wait for main build to complete
115192 uses : actions/github-script@v7
193+ id : wait-for-build
116194 with :
117195 script : |
118- const success = '${{ job.status }}' === 'success';
119- const emoji = success ? '✅' : '❌';
120- const statusEn = success ? 'Success' : 'Failed';
121- const statusCn = success ? '成功' : '失败';
122- const buildTime = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
196+ const { owner, repo } = context.repo;
197+ const headSha = context.payload.pull_request.head.sha;
198+
199+ console.log(`等待 commit ${headSha} 的构建完成...`);
200+
201+ // 等待最多 15 分钟(Docker 构建可能较长)
202+ const maxWaitTime = 15 * 60 * 1000; // 15 minutes
203+ const startTime = Date.now();
204+
205+ while (Date.now() - startTime < maxWaitTime) {
206+ try {
207+ // 获取 commit 的所有 check runs
208+ const { data: checkRuns } = await github.rest.checks.listForRef({
209+ owner,
210+ repo,
211+ ref: headSha,
212+ });
213+
214+ // 查找我们的Docker构建工作流
215+ const dockerCheck = checkRuns.check_runs.find(run =>
216+ run.name === 'Docker Build Check'
217+ );
218+
219+ if (dockerCheck) {
220+ console.log(`发现构建: ${dockerCheck.name}, 状态: ${dockerCheck.status}`);
221+
222+ if (dockerCheck.status === 'completed') {
223+ console.log(`构建完成,结论: ${dockerCheck.conclusion}`);
224+ return {
225+ completed: true,
226+ conclusion: dockerCheck.conclusion,
227+ details_url: dockerCheck.details_url
228+ };
229+ }
230+ }
231+
232+ // 等待 30 秒后重试
233+ await new Promise(resolve => setTimeout(resolve, 30000));
234+ } catch (error) {
235+ console.log(`获取构建状态时出错: ${error.message}`);
236+ await new Promise(resolve => setTimeout(resolve, 30000));
237+ }
238+ }
123239
124- // 构建中文报告
125- let chineseReport = `### 中文报告
240+ // 超时情况
241+ console.log('等待超时,使用默认值');
242+ return {
243+ completed: false,
244+ conclusion: 'timed_out',
245+ details_url: null
246+ };
126247
127- **🏗️ 构建详情:**
128- - 验证平台: \`linux/amd64\`
129- - 构建状态: ${statusCn}
130- - 提交: \`${{ github.event.pull_request.head.sha }}\`
131- - 构建时间: ${buildTime}
248+ - name : Comment on PR
249+ uses : actions/github-script@v7
250+ with :
251+ script : |
252+ const buildResult = ${{ steps.wait-for-build.outputs.result }};
253+ const prNumber = context.payload.pull_request.number;
254+ const buildTime = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
132255
133- ` ;
256+ let emoji, statusEn, statusCn, conclusion ;
134257
135- if (success) {
136- chineseReport += `**✅ 结果:** 基础架构验证通过,合并后将自动构建完整多平台镜像
258+ if (!buildResult.completed) {
259+ emoji = '⏰';
260+ statusEn = 'In Progress';
261+ statusCn = '进行中';
262+ conclusion = 'pending';
263+ } else {
264+ switch(buildResult.conclusion) {
265+ case 'success':
266+ emoji = '✅';
267+ statusEn = 'Success';
268+ statusCn = '成功';
269+ conclusion = 'success';
270+ break;
271+ case 'failure':
272+ emoji = '❌';
273+ statusEn = 'Failed';
274+ statusCn = '失败';
275+ conclusion = 'failure';
276+ break;
277+ default:
278+ emoji = '⚠️';
279+ statusEn = 'Unknown';
280+ statusCn = '未知';
281+ conclusion = 'neutral';
282+ }
283+ }
137284
138- **💡 优化说明:** PR阶段仅构建AMD64以提高速度,完整的多平台构建将在合并后进行`;
285+ // 构建中文报告
286+ let chineseReport = `### 中文报告\n\n`;
287+
288+ if (!buildResult.completed) {
289+ chineseReport += `**⏰ 状态:** Docker 构建正在进行中,请稍候查看结果。`;
290+ } else if (buildResult.conclusion === 'success') {
291+ chineseReport += `**🎉 结果:** Docker 构建验证通过!镜像构建成功。\n\n`;
292+ chineseReport += `**🏗️ 构建详情:**\n`;
293+ chineseReport += `- ✅ 验证平台: \`linux/amd64\`\n`;
294+ chineseReport += `- ✅ 构建状态: ${statusCn}\n`;
295+ chineseReport += `- ✅ 缓存优化: GitHub Actions 缓存已启用\n`;
296+ chineseReport += `- ✅ 提交: \`${context.payload.pull_request.head.sha}\`\n`;
297+ chineseReport += `- ✅ 构建时间: ${buildTime}\n\n`;
298+ chineseReport += `**💡 优化说明:** PR 阶段仅构建 AMD64 以提高速度,完整的多平台构建将在合并后进行。`;
299+ } else if (buildResult.conclusion === 'failure') {
300+ chineseReport += `**⚠️ 需要关注:** Docker 构建失败,请查看详细日志。\n\n`;
301+ chineseReport += `**🔧 常见解决方案:**\n`;
302+ chineseReport += `- 检查 Dockerfile 语法\n`;
303+ chineseReport += `- 确认依赖包版本\n`;
304+ chineseReport += `- 验证构建上下文路径\n\n`;
305+ chineseReport += `点击下方链接查看详细构建日志。`;
139306 } else {
140- chineseReport += `**❌ 需要关注 :** 请检查构建日志并修复问题 `;
307+ chineseReport += `**ℹ️ 状态 :** 构建状态异常,请检查工作流配置。 `;
141308 }
142309
143310 // 构建英文报告
144- let englishReport = `### English Report
145-
146- **🏗️ Build Details:**
147- - Verification Platform: \`linux/amd64\`
148- - Build Status: ${statusEn}
149- - Commit: \`${{ github.event.pull_request.head.sha }}\`
150- - Build Time: ${buildTime}
151-
152- `;
153-
154- if (success) {
155- englishReport += `**✅ Result:** Architecture verification passed, full multi-platform build will be triggered after merge
156-
157- **💡 Optimization Note:** PR stage only builds AMD64 to improve speed, complete multi-platform build will be performed after merge`;
311+ let englishReport = `### English Report\n\n`;
312+
313+ if (!buildResult.completed) {
314+ englishReport += `**⏰ Status:** Docker build is in progress, please wait for results.`;
315+ } else if (buildResult.conclusion === 'success') {
316+ englishReport += `**🎉 Result:** Docker build verification passed! Image build successful.\n\n`;
317+ englishReport += `**🏗️ Build Details:**\n`;
318+ englishReport += `- ✅ Verification Platform: \`linux/amd64\`\n`;
319+ englishReport += `- ✅ Build Status: ${statusEn}\n`;
320+ englishReport += `- ✅ Cache Optimization: GitHub Actions cache enabled\n`;
321+ englishReport += `- ✅ Commit: \`${context.payload.pull_request.head.sha}\`\n`;
322+ englishReport += `- ✅ Build Time: ${buildTime}\n\n`;
323+ englishReport += `**💡 Optimization Note:** PR stage only builds AMD64 to improve speed, complete multi-platform build will be performed after merge.`;
324+ } else if (buildResult.conclusion === 'failure') {
325+ englishReport += `**⚠️ Attention Required:** Docker build failed, please check detailed logs.\n\n`;
326+ englishReport += `**🔧 Common Solutions:**\n`;
327+ englishReport += `- Check Dockerfile syntax\n`;
328+ englishReport += `- Verify dependency versions\n`;
329+ englishReport += `- Validate build context path\n\n`;
330+ englishReport += `Click the link below to view detailed build logs.`;
158331 } else {
159- englishReport += `**❌ Attention Required :** Please check build logs and fix issues `;
332+ englishReport += `**ℹ️ Status :** Build status is abnormal, please check workflow configuration. `;
160333 }
161334
162- // 组合最终内容(中文在前,英文在后)
163- const body = `## 🚀 Docker Quick Build ${statusEn} ${emoji}
164-
165- **PR #${{ github.event.pull_request.number }}** AMD64 platform verification completed (optimized to build single platform only for faster verification)
166-
167- ${chineseReport}
335+ // 组合最终内容
336+ let body = `## 🚀 Docker Quick Build ${statusEn} ${emoji}\n\n`;
337+ body += `**PR #${prNumber}** AMD64 platform verification completed (optimized for faster verification)\n\n`;
338+ body += `${chineseReport}\n\n---\n\n${englishReport}`;
168339
169- ---
170-
171- ${englishReport}`;
340+ // 如果有详细链接,添加到报告中
341+ if (buildResult.details_url) {
342+ body += `\n\n**🔗 查看详细信息 / View Details:** [点击查看完整构建结果 / Click here to see full build results](${buildResult.details_url})`;
343+ }
172344
173345 // 查找并更新现有评论
174346 const { data: comments } = await github.rest.issues.listComments({
175347 owner: context.repo.owner,
176348 repo: context.repo.repo,
177- issue_number: context.issue.number ,
349+ issue_number: prNumber ,
178350 });
179351
180352 const botComment = comments.find(comment =>
181- comment.user.type === 'Bot' && comment.body.includes('Docker Quick Build')
353+ comment.user.type === 'Bot' &&
354+ comment.body.includes('🚀 Docker Quick Build')
182355 );
183356
184357 if (botComment) {
@@ -188,11 +361,13 @@ jobs:
188361 comment_id: botComment.id,
189362 body: body
190363 });
364+ console.log('已更新现有的 PR 评论');
191365 } else {
192366 await github.rest.issues.createComment({
193367 owner: context.repo.owner,
194368 repo: context.repo.repo,
195- issue_number: context.issue.number ,
369+ issue_number: prNumber ,
196370 body: body
197371 });
372+ console.log('已创建新的 PR 评论');
198373 }
0 commit comments