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
34 changes: 3 additions & 31 deletions .github/workflows/update-integration-data.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ jobs:
git add -- \
src/frontend/src/data/aspire-integrations.json \
src/frontend/src/data/integration-docs.json \
src/frontend/src/data/api-generation-failures.json \
src/frontend/src/data/github-stats.json \
src/frontend/src/data/github-contributors.json \
src/frontend/src/data/samples.json \
Expand Down Expand Up @@ -206,42 +207,13 @@ jobs:
fi

- name: Track API generation failures
if: ${{ always() && steps.update.outcome == 'success' && steps.update.outputs.regen_ran == 'true' }}
if: ${{ always() && steps.update.outputs.api_failures_checked == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
FAILURES: ${{ steps.update.outputs.api_failures }}
shell: bash
run: |
set -euo pipefail

# One long-lived issue. Its body always lists the current failing
# packages; a comment is added only when that list changes, and the issue
# is closed once nothing fails, so the same failures never create noise.
title="Integration Data Updater: API generation failures"
existing=$(gh issue list \
--state open \
--search "\"$title\" in:title" \
--json number,title \
--jq "map(select(.title == \"$title\")) | .[0].number // empty")

if [ -z "$FAILURES" ]; then
if [ -n "$existing" ]; then
gh issue close "$existing" --comment "No packages failed API generation in $RUN_URL."
fi
exit 0
fi

marker="<!-- failures:$(printf '%s' "$FAILURES" | sha256sum | cut -d' ' -f1) -->"
body=$(printf '%s\n\nThese packages failed API generation in the latest [Integration Data Updater run](%s). Their previous API data is kept and the rest of the data still updates. This issue updates itself and closes when nothing fails.\n\n```\n%s\n```\n' "$marker" "$RUN_URL" "$FAILURES")

if [ -z "$existing" ]; then
gh issue create --title "$title" --body "$body"
elif ! gh issue view "$existing" --json body --jq .body | grep -qF "$marker"; then
gh issue edit "$existing" --body "$body"
gh issue comment "$existing" --body "The set of failing packages changed: $RUN_URL"
fi
run: node src/frontend/scripts/report-api-generation-failures.mjs

- name: Summary
if: ${{ always() }}
Expand Down
68 changes: 68 additions & 0 deletions src/frontend/scripts/report-api-generation-failures.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { execFileSync } from 'node:child_process';
import { createHash } from 'node:crypto';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const title = 'Integration Data Updater: API generation failures';

export function reportApiGenerationFailures(failures, runUrl, gh = runGh) {
const issues = JSON.parse(
gh([
'issue',
'list',
'--state',
'all',
'--search',
`"${title}" in:title`,
'--json',
'number,title,state,body',
'--limit',
'100',
])
).filter((issue) => issue.title === title);
const existing = issues.find((issue) => issue.state === 'OPEN') ?? issues[0];

if (!failures.trim()) {
if (existing?.state === 'OPEN') {
gh([
'issue',
'close',
String(existing.number),
'--comment',
`All packages passed API generation in ${runUrl}.`,
]);
}
return;
}

const normalized = failures.trim().split(/\r?\n/).sort().join('\n');
const marker = `<!-- failures:${createHash('sha256').update(normalized).digest('hex')} -->`;
const body = [
marker,
`API generation failures observed in [this updater run](${runUrl}).`,
'Successful packages can still update. Failed packages retain their last-good API data when available. A later validation or infrastructure failure can still block publication.',
`\`\`\`text\n${normalized}\n\`\`\``,
'This issue is reused when failures recur and closes only after a complete generation pass succeeds.',
].join('\n\n');

if (!existing) {
gh(['issue', 'create', '--title', title, '--body', body]);
return;
}
if (existing.state !== 'OPEN') {
gh(['issue', 'reopen', String(existing.number)]);
} else if (existing.body.includes(marker)) {
return;
}
gh(['issue', 'edit', String(existing.number), '--body', body]);
// Keep the actual diagnostics in the history, not just a link to expiring logs.
gh(['issue', 'comment', String(existing.number), '--body', body]);
}

function runGh(args) {
return execFileSync('gh', args, { encoding: 'utf8' });
}

if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
reportApiGenerationFailures(process.env.FAILURES ?? '', process.env.RUN_URL);
}
Loading
Loading