Skip to content

Commit 02ccb7f

Browse files
committed
refactor: 빌드, 테스트 리포트를 하나로 병합
1 parent aefa6d8 commit 02ccb7f

1 file changed

Lines changed: 88 additions & 70 deletions

File tree

.github/workflows/ci.yml

Lines changed: 88 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -196,62 +196,13 @@ jobs:
196196
197197
exit $XC_STATUS
198198
199-
- name: Comment build failure on PR
200-
if: failure() && github.event.pull_request.head.repo.fork == false
201-
uses: actions/github-script@v8
199+
- name: Upload build log
200+
if: always()
201+
uses: actions/upload-artifact@v6
202202
with:
203-
script: |
204-
const fs = require('fs');
205-
const path = 'build.log';
206-
let body = '❌ iOS CI build failed.\n\n';
207-
if (fs.existsSync(path)) {
208-
const log = fs.readFileSync(path, 'utf8');
209-
const lines = log.split(/\r?\n/);
210-
const errorLines = lines.filter((line) => /^(.*?):(\d+):(\d+):\s+error:/i.test(line));
211-
if (errorLines.length > 0) {
212-
body += "Compiler error lines:\n\n```\n" + errorLines.join('\n') + '\n```\n';
213-
214-
const repoRoot = process.env.GITHUB_WORKSPACE || process.cwd();
215-
const pathMod = require('path');
216-
const snippets = [];
217-
for (const line of errorLines) {
218-
const match = line.match(/^(.*?):(\d+):(\d+):\s+error:/);
219-
if (!match) continue;
220-
const filePath = match[1];
221-
const lineNum = parseInt(match[2], 10);
222-
const absPath = filePath.startsWith('/') ? filePath : pathMod.join(repoRoot, filePath);
223-
if (!fs.existsSync(absPath)) continue;
224-
const fileLines = fs.readFileSync(absPath, 'utf8').split(/\r?\n/);
225-
const start = Math.max(0, lineNum - 3);
226-
const end = Math.min(fileLines.length, lineNum + 2);
227-
const snippet = fileLines
228-
.slice(start, end)
229-
.map((l, idx) => {
230-
const ln = start + idx + 1;
231-
return `${ln.toString().padStart(4, ' ')}| ${l}`;
232-
})
233-
.join('\n');
234-
snippets.push(`File: ${filePath}:${lineNum}\n${snippet}`);
235-
}
236-
if (snippets.length > 0) {
237-
body += "\nCode excerpts:\n\n```\n" + snippets.join('\n\n') + "\n```\n";
238-
}
239-
} else {
240-
body += "No compiler-style error diagnostics were found in build.log.";
241-
}
242-
} else {
243-
body += 'build.log not found.';
244-
}
245-
if (!context.payload.pull_request) {
246-
core.info('No PR context; skipping comment.');
247-
return;
248-
}
249-
await github.rest.issues.createComment({
250-
owner: context.repo.owner,
251-
repo: context.repo.repo,
252-
issue_number: context.payload.pull_request.number,
253-
body
254-
});
203+
name: ios-build
204+
path: build.log
205+
if-no-files-found: ignore
255206

256207
test:
257208
name: Test (${{ matrix.name }})
@@ -476,26 +427,31 @@ jobs:
476427
path: test-results/${{ matrix.name }}
477428
if-no-files-found: ignore
478429

479-
test-report:
480-
name: Test Report
430+
report:
431+
name: Report
481432
runs-on: ubuntu-latest
482-
needs: test
483-
if: always() && needs.test.result == 'failure' && github.event.pull_request.head.repo.fork == false
433+
needs: [build, test]
434+
if: always() && (needs.build.result == 'failure' || needs.test.result == 'failure') && github.event.pull_request.head.repo.fork == false
484435
steps:
485-
- name: Download test logs
436+
- uses: actions/checkout@v5
437+
438+
- name: Download CI logs
486439
uses: actions/download-artifact@v7
440+
continue-on-error: true
487441
with:
488442
path: test-artifacts
489443

490-
- name: Comment test failure on PR
444+
- name: Comment CI failure on PR
491445
uses: actions/github-script@v8
446+
env:
447+
BUILD_RESULT: ${{ needs.build.result }}
448+
TEST_RESULT: ${{ needs.test.result }}
492449
with:
493450
script: |
494451
const fs = require('fs');
495452
const path = require('path');
496453
497454
const root = 'test-artifacts';
498-
const summaries = [];
499455
500456
function walk(directory) {
501457
if (!fs.existsSync(directory)) return [];
@@ -560,6 +516,64 @@ jobs:
560516
return selectedLines.slice(0, 30).join('\n');
561517
}
562518
519+
function extractBuildSection() {
520+
if (process.env.BUILD_RESULT !== 'failure') return '';
521+
522+
const logPath = path.join(root, 'ios-build', 'build.log');
523+
let section = '## Build failed\n\n';
524+
525+
if (!fs.existsSync(logPath)) {
526+
return section + 'No build log artifact was found. The build likely failed before xcodebuild started.\n\n';
527+
}
528+
529+
const log = fs.readFileSync(logPath, 'utf8');
530+
const lines = log.split(/\r?\n/);
531+
const errorLines = lines
532+
.filter((line) => /^(.*?):(\d+):(\d+):\s+error:/i.test(line))
533+
.map(cleanLine)
534+
.filter(Boolean);
535+
536+
if (errorLines.length <= 0) {
537+
return section + 'No compiler-style error diagnostics were found in build.log.\n\n';
538+
}
539+
540+
section += 'Compiler error lines:\n\n```text\n' + errorLines.join('\n') + '\n```\n\n';
541+
542+
const repoRoot = process.env.GITHUB_WORKSPACE || process.cwd();
543+
const snippets = [];
544+
545+
for (const line of errorLines) {
546+
const match = line.match(/^(.*?):(\d+):(\d+):\s+error:/);
547+
if (!match) continue;
548+
549+
const filePath = match[1];
550+
const lineNum = parseInt(match[2], 10);
551+
const absPath = filePath.startsWith('/') ? filePath : path.join(repoRoot, filePath);
552+
if (!fs.existsSync(absPath)) continue;
553+
554+
const fileLines = fs.readFileSync(absPath, 'utf8').split(/\r?\n/);
555+
const start = Math.max(0, lineNum - 3);
556+
const end = Math.min(fileLines.length, lineNum + 2);
557+
const snippet = fileLines
558+
.slice(start, end)
559+
.map((sourceLine, index) => {
560+
const currentLine = start + index + 1;
561+
return `${currentLine.toString().padStart(4, ' ')}| ${sourceLine}`;
562+
})
563+
.join('\n');
564+
snippets.push(`File: ${filePath}:${lineNum}\n${snippet}`);
565+
}
566+
567+
if (snippets.length <= 0) return section;
568+
569+
return section + 'Code excerpts:\n\n```text\n' + snippets.join('\n\n') + '\n```\n\n';
570+
}
571+
572+
function extractTestSection() {
573+
if (process.env.TEST_RESULT !== 'failure') return '';
574+
575+
const summaries = [];
576+
563577
for (const summaryPath of walk(root).filter((filePath) => path.basename(filePath) === 'summary.txt')) {
564578
const artifactName = summaryPath.split(path.sep)[1] || 'unknown';
565579
const artifactDirectory = path.dirname(summaryPath);
@@ -591,21 +605,25 @@ jobs:
591605
}
592606
}
593607
594-
let body = '❌ iOS CI tests failed.\n\n';
608+
let section = '## Tests failed\n\n';
609+
610+
if (summaries.length <= 0) {
611+
return section + 'No failed scheme summary was found. Check the uploaded test log artifacts.\n\n';
612+
}
595613
596-
if (summaries.length <= 0) {
597-
body += 'No failed scheme summary was found. Check the uploaded test log artifacts.';
598-
} else {
599-
body += 'Failed schemes:\n\n';
614+
section += 'Failed schemes:\n\n';
600615
for (const summary of summaries) {
601-
body += `- ${summary.scheme} (${summary.artifactName})\n`;
616+
section += `- ${summary.scheme} (${summary.artifactName})\n`;
602617
if (summary.snippet) {
603-
body += '\n```text\n' + summary.snippet + '\n```\n\n';
618+
section += '\n```text\n' + summary.snippet + '\n```\n\n';
604619
}
605620
}
606-
body += '\nCheck the uploaded test log artifacts for full diagnostics.';
621+
622+
return section + 'Check the uploaded test log artifacts for full diagnostics.\n\n';
607623
}
608624
625+
const body = '❌ iOS CI failed.\n\n' + extractBuildSection() + extractTestSection();
626+
609627
if (!context.payload.pull_request) {
610628
core.info('No PR context; skipping comment.');
611629
return;

0 commit comments

Comments
 (0)