Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions .github/actions/report/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24703,7 +24703,7 @@ var METRIC_TO_FIELD = {
duplication: "duplication_pct",
maintainability: "maintainability"
};
async function report(workerUrl, metrics) {
async function report(workerUrl, metrics, category = "default") {
workerUrl = workerUrl.replace(/\/$/, "");
info(`Reporting ${metrics.length} metric(s): ${metrics.map((m) => m.name).join(", ")}`);
const eventName = process.env.GITHUB_EVENT_NAME ?? "";
Expand Down Expand Up @@ -24739,13 +24739,13 @@ async function report(workerUrl, metrics) {
}
if (isPR) {
const [owner, repo] = (process.env.GITHUB_REPOSITORY ?? "").split("/");
await runPRCheck(workerUrl, oidcToken, metrics, owner, repo);
await runPRCheck(workerUrl, oidcToken, metrics, owner, repo, category);
} else {
await runIngest(workerUrl, oidcToken, metrics);
await runIngest(workerUrl, oidcToken, metrics, category);
}
}
async function runIngest(workerUrl, oidcToken, metrics) {
const body = {};
async function runIngest(workerUrl, oidcToken, metrics, category = "default") {
const body = { category };
for (const m of metrics) {
const field = METRIC_TO_FIELD[m.name];
if (field) body[field] = m.value;
Expand All @@ -24765,14 +24765,14 @@ async function runIngest(workerUrl, oidcToken, metrics) {
}
info("Coverage report submitted.");
}
async function runPRCheck(workerUrl, oidcToken, metrics, owner, repo) {
async function runPRCheck(workerUrl, oidcToken, metrics, owner, repo, category = "default") {
const minCoverage = parseThreshold(process.env.MIN_COVERAGE);
const maxCoverageDrop = parseThreshold(process.env.MAX_COVERAGE_DROP);
const maxComplexity = parseThreshold(process.env.MAX_COMPLEXITY);
const maxDuplication = parseThreshold(process.env.MAX_DUPLICATION);
const baselines = {};
for (const m of metrics) {
const url = `${workerUrl}/api/baseline/${owner}/${repo}?metric=${encodeURIComponent(m.name)}`;
const url = `${workerUrl}/api/baseline/${owner}/${repo}?metric=${encodeURIComponent(m.name)}&category=${encodeURIComponent(category)}`;
const res = await fetch(url, { headers: { Authorization: `Bearer ${oidcToken}` } });
if (res.ok) {
try {
Expand Down Expand Up @@ -24823,25 +24823,26 @@ async function runPRCheck(workerUrl, oidcToken, metrics, owner, repo) {
}
const githubToken = process.env.GITHUB_TOKEN ?? "";
if (githubToken) {
await postCheckRun(githubToken, owner, repo, results, anyFailed);
await postCheckRun(githubToken, owner, repo, results, anyFailed, category);
} else {
warning("GITHUB_TOKEN not available \u2014 cannot post Check Run.");
}
if (anyFailed) {
setFailed("One or more coverage thresholds were not met.");
}
}
async function postCheckRun(githubToken, owner, repo, results, failed) {
async function postCheckRun(githubToken, owner, repo, results, failed, category = "default") {
const octokit = getOctokit(githubToken);
const headSha = context2.payload.pull_request?.head?.sha ?? context2.sha;
const summary2 = buildSummary(results);
const conclusion = failed ? "failure" : "success";
const title = failed ? "Coverage thresholds not met" : "All coverage thresholds passed";
const name = category === "default" ? "Coverage Tracker" : `Coverage Tracker (${category})`;
try {
await octokit.rest.checks.create({
owner,
repo,
name: "Coverage Tracker",
name,
head_sha: headSha,
status: "completed",
conclusion,
Expand Down Expand Up @@ -30383,7 +30384,8 @@ async function main() {
metrics.push({ name: "duplication", value: dup.duplication_pct, unit: "%" });
info(`Duplication from ${duplicationPath}: ${dup.duplication_pct}%`);
}
await report(workerUrl, metrics);
const category = getInput("category") || "default";
await report(workerUrl, metrics, category);
}
function warnCoberturaTool() {
const tool = getInput("coverage-tool").trim().toLowerCase();
Expand Down
15 changes: 15 additions & 0 deletions .github/actions/report/src/__tests__/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,14 @@ describe('runPRCheck()', () => {
expect(url).toContain('category=frontend');
});

it('posts a Check Run named after the category, so backend and frontend do not collide', async () => {
mockFetch.mockResolvedValue(errFetchResponse(404));
await runPRCheck(WORKER, TOKEN, coverageMetric, 'owner', 'repo', 'frontend');
expect(mockChecksCreate).toHaveBeenCalledWith(
expect.objectContaining({ name: 'Coverage Tracker (frontend)' }),
);
});

it('posts a failure Check Run when coverage is below min-coverage', async () => {
vi.stubEnv('MIN_COVERAGE', '80'); // 75 < 80
mockFetch.mockResolvedValue(errFetchResponse(404));
Expand Down Expand Up @@ -420,6 +428,13 @@ describe('postCheckRun()', () => {
expect(vi.mocked(core.info)).toHaveBeenCalledWith('Check Run posted: success');
});

it('suffixes the Check Run name with a non-default category', async () => {
await postCheckRun('ghs_mock', 'owner', 'repo', results, false, 'frontend');
expect(mockChecksCreate).toHaveBeenCalledWith(
expect.objectContaining({ name: 'Coverage Tracker (frontend)' }),
);
});

it('creates a failure Check Run when failed=true', async () => {
await postCheckRun('ghs_mock', 'owner', 'repo', results, true);
expect(mockChecksCreate).toHaveBeenCalledWith(
Expand Down
8 changes: 6 additions & 2 deletions .github/actions/report/src/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export async function runPRCheck(
// Post Check Run using GITHUB_TOKEN (Option A — Appendix B.3)
const githubToken = process.env.GITHUB_TOKEN ?? '';
if (githubToken) {
await postCheckRun(githubToken, owner, repo, results, anyFailed);
await postCheckRun(githubToken, owner, repo, results, anyFailed, category);
} else {
core.warning('GITHUB_TOKEN not available — cannot post Check Run.');
}
Expand All @@ -259,6 +259,7 @@ export async function postCheckRun(
repo: string,
results: ThresholdResult[],
failed: boolean,
category: string = 'default',
): Promise<void> {
const octokit = github.getOctokit(githubToken);

Expand All @@ -270,12 +271,15 @@ export async function postCheckRun(
const summary = buildSummary(results);
const conclusion = failed ? 'failure' : 'success';
const title = failed ? 'Coverage thresholds not met' : 'All coverage thresholds passed';
// "default" keeps the pre-category check name so single-series repos see no
// change; other categories get their own distinct, filterable check name.
const name = category === 'default' ? 'Coverage Tracker' : `Coverage Tracker (${category})`;

try {
await octokit.rest.checks.create({
owner,
repo,
name: 'Coverage Tracker',
name,
head_sha: headSha,
status: 'completed',
conclusion,
Expand Down
2 changes: 1 addition & 1 deletion wrangler.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"d1_databases": [
{
"binding": "DB",
"database_name": "coverage",
"database_name": "coverage-demo",
"migrations_dir": "migrations"
}
],
Expand Down
Loading