Skip to content
14 changes: 5 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,9 @@ jobs:
- name: configure
run: cmake -S. -Bbuild
- name: build-${{ matrix.os.name }}
run: cmake --build build >> compilation.log 2>&1
- uses: actions/upload-artifact@v6
with:
name: compilation_${{ github.run_id }}_${{ job.check_run_id }}_log
path: compilation*.log
- run: ./build/hello_world
run: |
echo "CPPWARNINGNOTIFIER_LOG_MARKER"
cmake --build build

run-notifier:
needs:
Expand All @@ -45,12 +42,11 @@ jobs:
name: CppWarningNotifier
steps:
- uses: actions/checkout@v6
- uses: actions/download-artifact@v7
- uses: ./
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
ARTIFACT_REGEX: compilation_(?<runId>\d+)_(?<jobId>\d+)_log
RUN_ID: ${{ github.run_id }}
JOB_ID: ${{ job.check_run_id }}
STEP_REGEX: build-.*
JOB_REGEX: compile \((?<osName>.+?), (?<osVersion>.+?), (?<config>.+?), (?<cppVersion>.+?), (?<vendorName>.+?), (?<vendorVersion>.+?)\)
ROW_HEADERS: '["osName","osVersion","vendorName","vendorVersion","config"]'
Expand Down
6 changes: 3 additions & 3 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ author: yaito3014
description: Notifies about C++ warnings in GitHub Actions

inputs:
GITHUB_TOKEN:
RUN_ID:
requird: true
JOB_ID:
required: true
PRIVATE_KEY:
required: true
JOB_REGEX:
required: true
STEP_REGEX:
required: true
ARTIFACT_REGEX:
required: true
ROW_HEADERS:
required: true
COLUMN_HEADER:
Expand Down
74 changes: 42 additions & 32 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

77 changes: 44 additions & 33 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { readdirSync, readFileSync } from "fs";
import { App } from "octokit";

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

const current_run_id = parseInt(requireEnv("INPUT_RUN_ID"));
const current_job_id = parseInt(requireEnv("INPUT_JOB_ID"));

const [owner, repo] = githubRepository.split("/");
const pull_request_number = parseInt(githubRef.split("/")[2]);

const artifact_regex = requireEnv("INPUT_ARTIFACT_REGEX");
const job_regex = requireEnv("INPUT_JOB_REGEX");
const step_regex = requireEnv("INPUT_STEP_REGEX");

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

let body: string | null = null;

const readdirRecursively = (dir: string): string[] => {
const files: string[] = [];
for (const dirent of readdirSync(dir, { withFileTypes: true })) {
const path = `${dir}/${dirent.name}`;
if (dirent.isDirectory()) files.push(...readdirRecursively(path));
else if (dirent.isFile()) files.push(path);
}
return files;
};

interface Row {
url: string;
status: string;
Expand All @@ -49,38 +40,58 @@ interface Row {

const rows: Row[] = [];

for (const file of readdirRecursively(".")) {
console.log("looking", file, "deciding whether skip or not...");
const { data: jobList } = await octokit.rest.actions.listJobsForWorkflowRun({
owner,
repo,
run_id: current_run_id,
});

const artifactMatch = file.match(artifact_regex);
for (const job of jobList.jobs) {
const job_id = job.id;

if (artifactMatch === null) {
continue;
}
if (job_id === current_job_id) continue;

const { url: redirectUrl } = await octokit.rest.actions.downloadJobLogsForWorkflowRun({
owner,
repo,
job_id,
});

if (!artifactMatch.groups?.runId || !artifactMatch.groups?.jobId) {
console.log("artifact regex matched but missing runId/jobId named groups, skipping", file);
const response = await fetch(redirectUrl);
if (!response.ok) {
console.log(`failed to retrieve job log for ${job_id}`);
continue;
}
const { runId, jobId } = artifactMatch.groups;
const jobLog = await response.text();

const warningRegex = /warning( .\d+)?:/;
const errorRegex = /error( .\d+)?:/;

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

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

let compileResult = "✅success";
if (compilationOutput.match(/warning( .\d+)?:/)) {
let firstIssueLine = 1;
const warningIdx = lines.findIndex((line) => line.match(warningRegex));
console.log(`warningIdx: ${warningIdx}`);
if (warningIdx !== -1) {
compileResult = "⚠️warning";
} else if (compilationOutput.match(/error( .\d+)?:/)) {
compileResult = "❌error";
firstIssueLine = warningIdx - offset + 1;
console.log(`matched warning line: ${lines[warningIdx]}`);
} else {
const errorIdx = lines.findIndex((line) => line.match(errorRegex));
console.log(`errorIdx: ${errorIdx}`);
if (errorIdx !== -1) {
compileResult = "❌error";
firstIssueLine = errorIdx - offset + 1;
console.log(`matched error line: ${lines[errorIdx]}`);
}
}

const { data: job } = await octokit.rest.actions.getJobForWorkflowRun({
owner,
repo,
job_id: parseInt(jobId),
});

const steps = job.steps ?? [];
const stepIndex = steps.findIndex(
(step) =>
Expand All @@ -102,7 +113,7 @@ for (const file of readdirRecursively(".")) {
}

rows.push({
url: `https://github.com/${owner}/${repo}/actions/runs/${runId}/job/${jobId}#step:${stepId}:1`,
url: `https://github.com/${owner}/${repo}/actions/runs/${current_run_id}/job/${job_id}#step:${stepId}:${firstIssueLine}`,
status: compileResult,
...jobMatch.groups,
});
Expand Down