Skip to content

Commit ad464ff

Browse files
authored
Link to first compilation issue line in GitHub Actions (#19)
1 parent 2aca677 commit ad464ff

5 files changed

Lines changed: 95 additions & 78 deletions

File tree

.github/workflows/test.yml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,9 @@ jobs:
3030
- name: configure
3131
run: cmake -S. -Bbuild
3232
- name: build-${{ matrix.os.name }}
33-
run: cmake --build build >> compilation.log 2>&1
34-
- uses: actions/upload-artifact@v6
35-
with:
36-
name: compilation_${{ github.run_id }}_${{ job.check_run_id }}_log
37-
path: compilation*.log
38-
- run: ./build/hello_world
33+
run: |
34+
echo "CPPWARNINGNOTIFIER_LOG_MARKER"
35+
cmake --build build
3936
4037
run-notifier:
4138
needs:
@@ -45,12 +42,11 @@ jobs:
4542
name: CppWarningNotifier
4643
steps:
4744
- uses: actions/checkout@v6
48-
- uses: actions/download-artifact@v7
4945
- uses: ./
5046
with:
51-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5247
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
53-
ARTIFACT_REGEX: compilation_(?<runId>\d+)_(?<jobId>\d+)_log
48+
RUN_ID: ${{ github.run_id }}
49+
JOB_ID: ${{ job.check_run_id }}
5450
STEP_REGEX: build-.*
5551
JOB_REGEX: compile \((?<osName>.+?), (?<osVersion>.+?), (?<config>.+?), (?<cppVersion>.+?), (?<vendorName>.+?), (?<vendorVersion>.+?)\)
5652
ROW_HEADERS: '["osName","osVersion","vendorName","vendorVersion","config"]'

action.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ author: yaito3014
33
description: Notifies about C++ warnings in GitHub Actions
44

55
inputs:
6-
GITHUB_TOKEN:
6+
RUN_ID:
7+
requird: true
8+
JOB_ID:
79
required: true
810
PRIVATE_KEY:
911
required: true
1012
JOB_REGEX:
1113
required: true
1214
STEP_REGEX:
1315
required: true
14-
ARTIFACT_REGEX:
15-
required: true
1616
ROW_HEADERS:
1717
required: true
1818
COLUMN_HEADER:

dist/index.js

Lines changed: 42 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { readdirSync, readFileSync } from "fs";
21
import { App } from "octokit";
32

43
if (!process.env.GITHUB_REF?.startsWith("refs/pull/")) {
@@ -15,10 +14,12 @@ function requireEnv(name: string): string {
1514
const githubRepository = requireEnv("GITHUB_REPOSITORY");
1615
const githubRef = requireEnv("GITHUB_REF");
1716

17+
const current_run_id = parseInt(requireEnv("INPUT_RUN_ID"));
18+
const current_job_id = parseInt(requireEnv("INPUT_JOB_ID"));
19+
1820
const [owner, repo] = githubRepository.split("/");
1921
const pull_request_number = parseInt(githubRef.split("/")[2]);
2022

21-
const artifact_regex = requireEnv("INPUT_ARTIFACT_REGEX");
2223
const job_regex = requireEnv("INPUT_JOB_REGEX");
2324
const step_regex = requireEnv("INPUT_STEP_REGEX");
2425

@@ -31,16 +32,6 @@ const octokit = await app.getInstallationOctokit(installation.id);
3132

3233
let body: string | null = null;
3334

34-
const readdirRecursively = (dir: string): string[] => {
35-
const files: string[] = [];
36-
for (const dirent of readdirSync(dir, { withFileTypes: true })) {
37-
const path = `${dir}/${dirent.name}`;
38-
if (dirent.isDirectory()) files.push(...readdirRecursively(path));
39-
else if (dirent.isFile()) files.push(path);
40-
}
41-
return files;
42-
};
43-
4435
interface Row {
4536
url: string;
4637
status: string;
@@ -49,38 +40,58 @@ interface Row {
4940

5041
const rows: Row[] = [];
5142

52-
for (const file of readdirRecursively(".")) {
53-
console.log("looking", file, "deciding whether skip or not...");
43+
const { data: jobList } = await octokit.rest.actions.listJobsForWorkflowRun({
44+
owner,
45+
repo,
46+
run_id: current_run_id,
47+
});
5448

55-
const artifactMatch = file.match(artifact_regex);
49+
for (const job of jobList.jobs) {
50+
const job_id = job.id;
5651

57-
if (artifactMatch === null) {
58-
continue;
59-
}
52+
if (job_id === current_job_id) continue;
53+
54+
const { url: redirectUrl } = await octokit.rest.actions.downloadJobLogsForWorkflowRun({
55+
owner,
56+
repo,
57+
job_id,
58+
});
6059

61-
if (!artifactMatch.groups?.runId || !artifactMatch.groups?.jobId) {
62-
console.log("artifact regex matched but missing runId/jobId named groups, skipping", file);
60+
const response = await fetch(redirectUrl);
61+
if (!response.ok) {
62+
console.log(`failed to retrieve job log for ${job_id}`);
6363
continue;
6464
}
65-
const { runId, jobId } = artifactMatch.groups;
65+
const jobLog = await response.text();
66+
67+
const warningRegex = /warning( .\d+)?:/;
68+
const errorRegex = /error( .\d+)?:/;
6669

67-
console.log("found", file, "detecting warnings...");
70+
const lines = jobLog.split("\n");
71+
console.log(`total lines: ${lines.length}`);
6872

69-
const compilationOutput = readFileSync(file).toString();
73+
let offset = 0;
74+
const offsetIdx = lines.findIndex((line) => line.match("CPPWARNINGNOTIFIER_LOG_MARKER"));
75+
if (offsetIdx !== -1) offset = offsetIdx;
7076

7177
let compileResult = "✅success";
72-
if (compilationOutput.match(/warning( .\d+)?:/)) {
78+
let firstIssueLine = 1;
79+
const warningIdx = lines.findIndex((line) => line.match(warningRegex));
80+
console.log(`warningIdx: ${warningIdx}`);
81+
if (warningIdx !== -1) {
7382
compileResult = "⚠️warning";
74-
} else if (compilationOutput.match(/error( .\d+)?:/)) {
75-
compileResult = "❌error";
83+
firstIssueLine = warningIdx - offset + 1;
84+
console.log(`matched warning line: ${lines[warningIdx]}`);
85+
} else {
86+
const errorIdx = lines.findIndex((line) => line.match(errorRegex));
87+
console.log(`errorIdx: ${errorIdx}`);
88+
if (errorIdx !== -1) {
89+
compileResult = "❌error";
90+
firstIssueLine = errorIdx - offset + 1;
91+
console.log(`matched error line: ${lines[errorIdx]}`);
92+
}
7693
}
7794

78-
const { data: job } = await octokit.rest.actions.getJobForWorkflowRun({
79-
owner,
80-
repo,
81-
job_id: parseInt(jobId),
82-
});
83-
8495
const steps = job.steps ?? [];
8596
const stepIndex = steps.findIndex(
8697
(step) =>
@@ -102,7 +113,7 @@ for (const file of readdirRecursively(".")) {
102113
}
103114

104115
rows.push({
105-
url: `https://github.com/${owner}/${repo}/actions/runs/${runId}/job/${jobId}#step:${stepId}:1`,
116+
url: `https://github.com/${owner}/${repo}/actions/runs/${current_run_id}/job/${job_id}#step:${stepId}:${firstIssueLine}`,
106117
status: compileResult,
107118
...jobMatch.groups,
108119
});

0 commit comments

Comments
 (0)