Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
86399a2552 Chore(deps): Bump whitenoise from 6.10.0 to 6.11.0
Bumps [whitenoise](https://github.com/evansd/whitenoise) from 6.10.0 to 6.11.0.
- [Changelog](https://github.com/evansd/whitenoise/blob/main/docs/changelog.rst)
- [Commits](https://github.com/evansd/whitenoise/compare/6.10.0...6.11.0)

---
updated-dependencies:
- dependency-name: whitenoise
  dependency-version: 6.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-25 07:47:48 +00:00
2 changed files with 3 additions and 452 deletions

View File

@@ -322,455 +322,6 @@ jobs:
run: cd src-ui && pnpm exec playwright install
- name: Run Playwright e2e tests
run: cd src-ui && pnpm exec playwright test --shard ${{ matrix.shard-index }}/${{ matrix.shard-count }}
codecov-comment:
name: "Codecov PR Comment"
runs-on: ubuntu-24.04
needs:
- tests-backend
- tests-frontend
- tests-frontend-e2e
if: github.event_name == 'pull_request'
permissions:
contents: read
pull-requests: write
steps:
- name: Gather pull request context
id: pr
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
if (!pr) {
core.info('No associated pull request. Skipping.');
core.setOutput('shouldRun', 'false');
return;
}
core.setOutput('shouldRun', 'true');
core.setOutput('prNumber', pr.number.toString());
core.setOutput('headSha', pr.head.sha);
- name: Fetch Codecov coverage
id: coverage
if: steps.pr.outputs.shouldRun == 'true'
uses: actions/github-script@v7
env:
COMMIT_SHA: ${{ steps.pr.outputs.headSha }}
PR_NUMBER: ${{ steps.pr.outputs.prNumber }}
with:
script: |
const commitSha = process.env.COMMIT_SHA;
const prNumber = process.env.PR_NUMBER;
const owner = context.repo.owner;
const repo = context.repo.repo;
const service = 'gh';
const baseUrl = `https://api.codecov.io/api/v2/${service}/${owner}/repos/${repo}`;
const commitUrl = `${baseUrl}/commits/${commitSha}`;
const maxAttempts = 20;
const waitMs = 15000;
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
let data;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
core.info(`Fetching Codecov report (attempt ${attempt}/${maxAttempts})`);
let response;
try {
response = await fetch(commitUrl, {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
} catch (error) {
core.warning(`Codecov fetch failed: ${error}. Waiting before retrying.`);
await sleep(waitMs);
continue;
}
if (response.status === 404) {
core.info('Report not ready yet (404). Waiting before retrying.');
await sleep(waitMs);
continue;
}
if ([429, 500, 502, 503, 504].includes(response.status)) {
const text = await response.text().catch(() => '');
core.info(`Codecov API transient error ${response.status}: ${text}. Waiting before retrying.`);
await sleep(waitMs);
continue;
}
if (!response.ok) {
const text = await response.text().catch(() => '');
core.warning(`Codecov API returned ${response.status}: ${text}. Skipping comment.`);
core.setOutput('shouldComment', 'false');
return;
}
data = await response.json().catch((error) => {
core.warning(`Failed to parse Codecov response: ${error}.`);
return undefined;
});
if (data && Object.keys(data).length > 0) {
break;
}
core.info('Report payload empty. Waiting before retrying.');
await sleep(waitMs);
}
if (!data && prNumber) {
core.info('Attempting to retrieve coverage from PR endpoint.');
const prUrl = `${baseUrl}/pulls/${prNumber}`;
let prResponse;
try {
prResponse = await fetch(prUrl, {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
} catch (error) {
core.warning(`Codecov PR fetch failed: ${error}.`);
}
if (prResponse) {
if ([429, 500, 502, 503, 504].includes(prResponse.status)) {
const text = await prResponse.text().catch(() => '');
core.info(`Codecov PR endpoint transient error ${prResponse.status}: ${text}.`);
} else if (!prResponse.ok) {
const text = await prResponse.text().catch(() => '');
core.warning(`Codecov PR endpoint returned ${prResponse.status}: ${text}.`);
} else {
const prData = await prResponse.json().catch((error) => {
core.warning(`Failed to parse Codecov PR response: ${error}.`);
return undefined;
});
if (prData?.latest_report) {
data = { report: prData.latest_report };
} else if (prData?.head_totals) {
const headTotals = prData.head_totals;
const baseTotals = prData.base_totals;
let compareTotals;
if (baseTotals && headTotals) {
const headCoverage = Number(headTotals.coverage);
const baseCoverage = Number(baseTotals.coverage);
if (Number.isFinite(headCoverage) && Number.isFinite(baseCoverage)) {
compareTotals = {
base_coverage: baseCoverage,
coverage_change: headCoverage - baseCoverage,
};
}
}
data = {
report: {
totals: headTotals,
compare: compareTotals ? { totals: compareTotals } : undefined,
totals_by_flag: [],
},
head_totals: headTotals,
base_totals: baseTotals,
};
} else {
data = prData;
}
}
}
}
if (!data) {
core.warning('Unable to retrieve Codecov report after multiple attempts.');
core.setOutput('shouldComment', 'false');
return;
}
const toNumber = (value) => {
if (value === null || value === undefined || value === '') {
return undefined;
}
const num = Number(value);
return Number.isFinite(num) ? num : undefined;
};
const reportData = data.report || data;
const totals = reportData.totals ?? data.head_totals ?? data.totals;
if (!totals) {
core.warning('Codecov response does not contain coverage totals.');
core.setOutput('shouldComment', 'false');
return;
}
let compareTotals = reportData.compare?.totals ?? data.compare?.totals;
if (!compareTotals && data.base_totals) {
const baseCoverageValue = toNumber(data.base_totals.coverage);
if (baseCoverageValue !== undefined) {
const headCoverageValue = toNumber((data.head_totals ?? {}).coverage);
compareTotals = {
base_coverage: baseCoverageValue,
coverage_change:
headCoverageValue !== undefined ? headCoverageValue - baseCoverageValue : undefined,
};
}
}
const coverage = toNumber(totals.coverage);
const baseCoverage = toNumber(compareTotals?.base_coverage ?? compareTotals?.base);
let delta = toNumber(
compareTotals?.coverage_change ??
compareTotals?.coverage_diff ??
totals.delta ??
totals.diff ??
totals.change,
);
if (delta === undefined && coverage !== undefined && baseCoverage !== undefined) {
delta = coverage - baseCoverage;
}
const formatPercent = (value) => {
if (value === undefined) return '—';
return `${value.toFixed(2)}%`;
};
const formatDelta = (value) => {
if (value === undefined) return '—';
const sign = value >= 0 ? '+' : '';
return `${sign}${value.toFixed(2)}%`;
};
const shortSha = commitSha.slice(0, 7);
const reportBaseUrl = `https://app.codecov.io/gh/${owner}/${repo}`;
const commitReportUrl = `${reportBaseUrl}/commit/${commitSha}?src=pr&el=comment`;
const prReportUrl = prNumber
? `${reportBaseUrl}/pull/${prNumber}?src=pr&el=comment`
: commitReportUrl;
const findBaseCommitSha = () =>
data?.report?.compare?.base_commitid ??
data?.report?.compare?.base?.commitid ??
data?.report?.base_commitid ??
data?.compare?.base_commitid ??
data?.compare?.base?.commitid ??
data?.base_commitid ??
data?.base?.commitid;
const baseCommitSha = findBaseCommitSha();
const baseCommitUrl = baseCommitSha
? `${reportBaseUrl}/commit/${baseCommitSha}?src=pr&el=comment`
: undefined;
const baseShortSha = baseCommitSha ? baseCommitSha.slice(0, 7) : undefined;
const lines = ['<!-- codecov-coverage-comment -->'];
lines.push(`## [Codecov](${prReportUrl}) Report`);
lines.push('');
if (coverage !== undefined) {
lines.push(`:white_check_mark: Project coverage for \`${shortSha}\` is ${formatPercent(coverage)}.`);
} else {
lines.push(':warning: Coverage for the head commit is unavailable.');
}
if (baseCoverage !== undefined) {
const changeEmoji = delta === undefined ? ':grey_question:' : delta >= 0 ? ':white_check_mark:' : ':small_red_triangle_down:';
const baseCoverageText = `Base${baseShortSha ? ` \`${baseShortSha}\`` : ''} ${formatPercent(baseCoverage)}`;
const baseLink = baseCommitUrl ? `[${baseCoverageText}](${baseCommitUrl})` : baseCoverageText;
const changeText =
delta !== undefined
? `${baseLink} (${formatDelta(delta)})`
: `${baseLink} (change unknown)`;
lines.push(`${changeEmoji} ${changeText}.`);
}
lines.push(`:clipboard: [View full report on Codecov](${commitReportUrl}).`);
const normalizeTotals = (value) => {
if (!value) return undefined;
if (value.totals && typeof value.totals === 'object') return value.totals;
return value;
};
const headTotals = normalizeTotals(totals) ?? {};
const baseTotals =
normalizeTotals(data.base_totals) ??
normalizeTotals(reportData.base_totals) ??
normalizeTotals(reportData.compare?.base_totals) ??
normalizeTotals(reportData.compare?.base);
const formatInteger = (value) => {
if (value === undefined) return '—';
return value.toLocaleString('en-US');
};
const formatIntegerDelta = (value) => {
if (value === undefined) return '—';
const sign = value >= 0 ? '+' : '';
return `${sign}${value.toLocaleString('en-US')}`;
};
const getInteger = (value) => {
const num = toNumber(value);
return Number.isFinite(num) ? Math.round(num) : undefined;
};
const metrics = [];
metrics.push({
label: 'Coverage',
base: baseCoverage,
head: coverage,
diff: delta,
format: formatPercent,
formatDiff: formatDelta,
});
const pushIntegerMetric = (label, headValueRaw, baseValueRaw) => {
const headValue = getInteger(headValueRaw);
const baseValue = getInteger(baseValueRaw);
if (headValue === undefined && baseValue === undefined) {
return;
}
const diff = headValue !== undefined && baseValue !== undefined ? headValue - baseValue : undefined;
metrics.push({
label,
base: baseValue,
head: headValue,
diff,
format: formatInteger,
formatDiff: formatIntegerDelta,
});
};
pushIntegerMetric('Files', headTotals.files, baseTotals?.files);
pushIntegerMetric('Lines', headTotals.lines, baseTotals?.lines);
pushIntegerMetric('Branches', headTotals.branches, baseTotals?.branches);
pushIntegerMetric('Hits', headTotals.hits, baseTotals?.hits);
pushIntegerMetric('Misses', headTotals.misses, baseTotals?.misses);
const hasMetricData = metrics.some((metric) => metric.base !== undefined || metric.head !== undefined);
if (hasMetricData) {
lines.push('');
lines.push('<details><summary>Coverage summary</summary>');
lines.push('');
lines.push('| Metric | Base | Head | Δ |');
lines.push('| --- | --- | --- | --- |');
for (const metric of metrics) {
const baseValue = metric.base !== undefined ? metric.format(metric.base) : '—';
const headValue = metric.head !== undefined ? metric.format(metric.head) : '—';
const diffValue = metric.diff !== undefined ? metric.formatDiff(metric.diff) : '—';
lines.push(`| ${metric.label} | ${baseValue} | ${headValue} | ${diffValue} |`);
}
lines.push('');
lines.push('</details>');
}
const normalizeEntries = (raw) => {
if (!raw) return [];
if (Array.isArray(raw)) return raw;
if (typeof raw === 'object') {
return Object.entries(raw).map(([name, totals]) => ({ name, ...(typeof totals === 'object' ? totals : { coverage: totals }) }));
}
return [];
};
const buildTableRows = (entries) => {
const rows = [];
for (const entry of entries) {
const label = entry.flag ?? entry.name ?? entry.component ?? entry.id;
const entryTotals = entry.totals ?? entry;
const entryCoverage = toNumber(entryTotals?.coverage);
if (!label || entryCoverage === undefined) {
continue;
}
const entryDelta = toNumber(
entryTotals?.coverage_change ??
entryTotals?.coverage_diff ??
entryTotals?.delta ??
entryTotals?.diff ??
entryTotals?.change,
);
const coverageText = entryCoverage !== undefined ? `\`${formatPercent(entryCoverage)}\`` : '—';
const deltaText = entryDelta !== undefined ? `\`${formatDelta(entryDelta)}\`` : '—';
rows.push(`| ${label} | ${coverageText} | ${deltaText} |`);
}
return rows;
};
const componentEntries = normalizeEntries(reportData.components ?? data.components);
const flagEntries = normalizeEntries(reportData.totals_by_flag ?? data.totals_by_flag);
if (componentEntries.length) {
const componentsLink = prNumber
? `${reportBaseUrl}/pull/${prNumber}/components?src=pr&el=components`
: `${commitReportUrl}`;
const componentRows = buildTableRows(componentEntries);
if (componentRows.length) {
lines.push('');
lines.push(`[Components report](${componentsLink})`);
lines.push('');
lines.push('| Component | Coverage | Δ |');
lines.push('| --- | --- | --- |');
lines.push(...componentRows);
}
}
if (flagEntries.length) {
const flagsLink = prNumber
? `${reportBaseUrl}/pull/${prNumber}/flags?src=pr&el=flags`
: `${commitReportUrl}`;
const flagRows = buildTableRows(flagEntries);
if (flagRows.length) {
lines.push('');
lines.push(`[Flags report](${flagsLink})`);
lines.push('');
lines.push('| Flag | Coverage | Δ |');
lines.push('| --- | --- | --- |');
lines.push(...flagRows);
}
}
const commentBody = lines.join('\n');
const shouldComment = coverage !== undefined;
core.setOutput('shouldComment', shouldComment ? 'true' : 'false');
if (shouldComment) {
core.setOutput('commentBody', commentBody);
}
- name: Upsert coverage comment
if: steps.pr.outputs.shouldRun == 'true' && steps.coverage.outputs.shouldComment == 'true'
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.pr.outputs.prNumber }}
COMMENT_BODY: ${{ steps.coverage.outputs.commentBody }}
with:
script: |
const prNumber = Number(process.env.PR_NUMBER);
const body = process.env.COMMENT_BODY;
const marker = '<!-- codecov-coverage-comment -->';
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
per_page: 100,
});
const existing = comments.find((comment) => comment.body?.includes(marker));
if (existing) {
core.info(`Updating existing coverage comment (id: ${existing.id}).`);
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
core.info('Creating new coverage comment.');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body,
});
}
frontend-bundle-analysis:
name: "Frontend Bundle Analysis"
runs-on: ubuntu-24.04

6
uv.lock generated
View File

@@ -4095,11 +4095,11 @@ wheels = [
[[package]]
name = "whitenoise"
version = "6.10.0"
version = "6.11.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/27/9a/4f4b84ff1f3a5c3cbc8070b6ecbbab6cd121c385244c9d24d80bb284190f/whitenoise-6.10.0.tar.gz", hash = "sha256:7b7e53de65d749cb1ce4a7100e751d9742e323b52746f9f93944c0d348ea2d02", size = 26412, upload-time = "2025-09-09T11:07:24.694Z" }
sdist = { url = "https://files.pythonhosted.org/packages/15/95/8c81ec6b6ebcbf8aca2de7603070ccf37dbb873b03f20708e0f7c1664bc6/whitenoise-6.11.0.tar.gz", hash = "sha256:0f5bfce6061ae6611cd9396a8231e088722e4fc67bc13a111be74c738d99375f", size = 26432, upload-time = "2025-09-18T09:16:10.995Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/3b/4fa26e02935334fa0eb1422c938b1db796c55de7a432cc86b9d8cf97260c/whitenoise-6.10.0-py3-none-any.whl", hash = "sha256:bad74a40b33b055ba59731b6048dd08d5647f273b72bef922aa43ddd287b02da", size = 20194, upload-time = "2025-09-09T11:07:23.544Z" },
{ url = "https://files.pythonhosted.org/packages/6c/e9/4366332f9295fe0647d7d3251ce18f5615fbcb12d02c79a26f8dba9221b3/whitenoise-6.11.0-py3-none-any.whl", hash = "sha256:b2aeb45950597236f53b5342b3121c5de69c8da0109362aee506ce88e022d258", size = 20197, upload-time = "2025-09-18T09:16:09.754Z" },
]
[[package]]