From 5e4dcd2f3d8a99fc4e155921b9c09a0f5ee27c85 Mon Sep 17 00:00:00 2001 From: Jason Stirnaman Date: Thu, 7 May 2026 16:28:40 -0500 Subject: [PATCH 1/2] fix(ci): surface skipped clients in sync workflow; bump to Node 24 actions Treat parse failures (no version headings) as fatal so upstream CHANGELOG format changes don't silently leave a client stale. Missing CHANGELOG files remain non-fatal (annotated only) so a newly-added client without a published CHANGELOG can't break the nightly. Surface per-client status in the PR body and assign the Copilot coding agent when something needs attention. Bump checkout/setup-node and peter-evans/create-pull-request to versions running on Node 24, and move the script's setup-node input from Node 20 to 22 LTS. --- .../sync-client-library-release-notes.yml | 75 +++++++++++------ .../client-libraries/sync-release-notes.js | 82 ++++++++++++++++++- 2 files changed, 130 insertions(+), 27 deletions(-) diff --git a/.github/workflows/sync-client-library-release-notes.yml b/.github/workflows/sync-client-library-release-notes.yml index c6f6609879..59068163d1 100644 --- a/.github/workflows/sync-client-library-release-notes.yml +++ b/.github/workflows/sync-client-library-release-notes.yml @@ -28,12 +28,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout docs-v2 - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: path: docs-v2 - name: Checkout influxdb3-python - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: InfluxCommunity/influxdb3-python path: sources/influxdb3-python @@ -41,7 +41,7 @@ jobs: CHANGELOG.md - name: Checkout influxdb3-go - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: InfluxCommunity/influxdb3-go path: sources/influxdb3-go @@ -49,7 +49,7 @@ jobs: CHANGELOG.md - name: Checkout influxdb3-js - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: InfluxCommunity/influxdb3-js path: sources/influxdb3-js @@ -57,7 +57,7 @@ jobs: CHANGELOG.md - name: Checkout influxdb3-csharp - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: InfluxCommunity/influxdb3-csharp path: sources/influxdb3-csharp @@ -65,7 +65,7 @@ jobs: CHANGELOG.md - name: Checkout influxdb3-java - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: InfluxCommunity/influxdb3-java path: sources/influxdb3-java @@ -73,9 +73,9 @@ jobs: CHANGELOG.md - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: - node-version: '20' + node-version: '22' - name: Run sync id: sync @@ -99,28 +99,55 @@ jobs: --docs-root "$GITHUB_WORKSPACE/docs-v2" fi + - name: Compose PR body + id: body + env: + NEEDS_ATTENTION: ${{ steps.sync.outputs.needs_attention }} + SUMMARY: ${{ steps.sync.outputs.summary }} + run: | + BODY_FILE="$RUNNER_TEMP/pr-body.md" + { + if [ "$NEEDS_ATTENTION" = "true" ]; then + echo '> [!Warning]' + echo '> One or more client libraries were skipped or failed to parse.' + echo '> Investigate upstream CHANGELOG changes (rename, format change)' + echo '> before merging — assigned to @Copilot for triage.' + echo + fi + echo 'Automated sync from the v3 client library CHANGELOGs.' + echo + echo '## Sync results' + echo + printf '%s\n' "$SUMMARY" + echo + echo '## Sources' + echo + echo '- https://github.com/InfluxCommunity/influxdb3-python/blob/main/CHANGELOG.md' + echo '- https://github.com/InfluxCommunity/influxdb3-go/blob/main/CHANGELOG.md' + echo '- https://github.com/InfluxCommunity/influxdb3-js/blob/main/CHANGELOG.md' + echo '- https://github.com/InfluxCommunity/influxdb3-csharp/blob/main/CHANGELOG.md' + echo '- https://github.com/InfluxCommunity/influxdb3-java/blob/main/CHANGELOG.md' + echo + echo 'Changed files include body-only release notes under' + echo '`content/shared/influxdb-client-libraries-reference/v3/release-notes/`' + echo 'and `latest_version` / `latest_release_date` frontmatter updates' + echo 'on the per-product stubs under' + echo '`content/influxdb3/*/reference/client-libraries/v3/*/release-notes.md`.' + } > "$BODY_FILE" + echo "path=$BODY_FILE" >> "$GITHUB_OUTPUT" + - name: Create or update pull request - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v8 with: path: docs-v2 branch: sync/client-library-release-notes commit-message: 'sync(client-libs): update release notes' title: 'sync(client-libs): update release notes' - body: | - Automated sync from the v3 client library CHANGELOGs. - - Sources: - - https://github.com/InfluxCommunity/influxdb3-python/blob/main/CHANGELOG.md - - https://github.com/InfluxCommunity/influxdb3-go/blob/main/CHANGELOG.md - - https://github.com/InfluxCommunity/influxdb3-js/blob/main/CHANGELOG.md - - https://github.com/InfluxCommunity/influxdb3-csharp/blob/main/CHANGELOG.md - - https://github.com/InfluxCommunity/influxdb3-java/blob/main/CHANGELOG.md - - Changed files include body-only release notes under - `content/shared/influxdb-client-libraries-reference/v3/release-notes/` - and `latest_version` / `latest_release_date` frontmatter updates - on the per-product stubs under - `content/influxdb3/*/reference/client-libraries/v3/*/release-notes.md`. + body-path: ${{ steps.body.outputs.path }} + # Assign the Copilot coding agent only when a client was skipped or + # failed to parse, so it can investigate upstream CHANGELOG drift. + # Requires Copilot coding agent to be enabled on the repository. + assignees: ${{ steps.sync.outputs.needs_attention == 'true' && 'Copilot' || '' }} labels: | sync client-libraries diff --git a/helper-scripts/client-libraries/sync-release-notes.js b/helper-scripts/client-libraries/sync-release-notes.js index 07a938d664..afdba03bec 100644 --- a/helper-scripts/client-libraries/sync-release-notes.js +++ b/helper-scripts/client-libraries/sync-release-notes.js @@ -2,7 +2,14 @@ // Reads a client repo's CHANGELOG.md, runs the transform, and writes the // shared source file. Designed to run from the docs-v2 repo root. -import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs'; +import { + readFileSync, + writeFileSync, + appendFileSync, + existsSync, + mkdirSync, +} from 'node:fs'; +import { randomBytes } from 'node:crypto'; import { dirname, join, resolve } from 'node:path'; import { parseArgs } from 'node:util'; import { CLIENTS, getClient } from './clients.js'; @@ -139,6 +146,65 @@ function syncOne(client, sourcePath, docsRoot) { }; } +// `warning` and `error` indicate likely upstream drift (renamed CHANGELOG, +// changed heading format) and must fail the job. `skipped` means the source +// file is genuinely absent — surfaced but non-fatal so onboarding a new client +// before its first CHANGELOG ships doesn't break the nightly. +const FATAL_STATUSES = new Set(['warning', 'error']); +const ATTENTION_STATUSES = new Set(['skipped', 'warning', 'error']); + +function formatSummary(results) { + const rows = results.map((r) => { + const detail = + r.status === 'updated' + ? `latest: \`${r.latestVersion}\`` + : r.status === 'unchanged' + ? `latest: \`${r.latestVersion}\`` + : (r.reason ?? ''); + return `| \`${r.client}\` | ${r.status} | ${detail} |`; + }); + return [ + '| Client | Status | Detail |', + '| --- | --- | --- |', + ...rows, + ].join('\n'); +} + +function emitAnnotations(results) { + for (const r of results) { + if (r.status === 'error' || r.status === 'warning') { + console.log( + `::error title=Client release-notes sync (${r.client})::${r.reason}` + ); + } else if (r.status === 'skipped') { + console.log( + `::warning title=Client release-notes sync (${r.client})::${r.reason}` + ); + } + } +} + +function writeStepOutputs(outputs) { + const file = process.env.GITHUB_OUTPUT; + if (!file) return; + const lines = []; + for (const [key, value] of Object.entries(outputs)) { + if (typeof value === 'string' && value.includes('\n')) { + const delim = `EOF_${randomBytes(8).toString('hex')}`; + lines.push(`${key}<<${delim}`, value, delim); + } else { + lines.push(`${key}=${value}`); + } + } + appendFileSync(file, lines.join('\n') + '\n'); +} + +function writeStepSummary(markdown) { + const file = process.env.GITHUB_STEP_SUMMARY; + if (!file) return; + appendFileSync(file, markdown + '\n'); +} + function main() { const args = parseCliArgs(); const results = []; @@ -164,8 +230,18 @@ function main() { console.log(JSON.stringify(results, null, 2)); - const hadError = results.some((r) => r.status === 'error'); - process.exit(hadError ? 1 : 0); + const summary = formatSummary(results); + const needsAttention = results.some((r) => ATTENTION_STATUSES.has(r.status)); + + emitAnnotations(results); + writeStepSummary(`## Client library release-notes sync\n\n${summary}`); + writeStepOutputs({ + needs_attention: needsAttention ? 'true' : 'false', + summary, + }); + + const hadFatal = results.some((r) => FATAL_STATUSES.has(r.status)); + process.exit(hadFatal ? 1 : 0); } main(); From eb0bec86ed5e3c9bad9026d3dbdcbd48bc71fa1e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 7 May 2026 22:01:17 +0000 Subject: [PATCH 2/2] fix: escape workflow command chars and sanitize markdown table cells Agent-Logs-Url: https://github.com/influxdata/docs-v2/sessions/4825ef09-1133-406c-87ae-af40af3129ec Co-authored-by: jstirnaman <212227+jstirnaman@users.noreply.github.com> --- .../client-libraries/sync-release-notes.js | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/helper-scripts/client-libraries/sync-release-notes.js b/helper-scripts/client-libraries/sync-release-notes.js index afdba03bec..db0cffe53c 100644 --- a/helper-scripts/client-libraries/sync-release-notes.js +++ b/helper-scripts/client-libraries/sync-release-notes.js @@ -153,14 +153,47 @@ function syncOne(client, sourcePath, docsRoot) { const FATAL_STATUSES = new Set(['warning', 'error']); const ATTENTION_STATUSES = new Set(['skipped', 'warning', 'error']); +/** + * Escape special characters in GitHub Actions workflow command properties + * (title, etc.). Colons and commas delimit command metadata fields. + */ +function escapeWorkflowCommandProperty(s) { + return String(s) + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A') + .replace(/:/g, '%3A') + .replace(/,/g, '%2C'); +} + +/** + * Escape special characters in GitHub Actions workflow command message bodies. + */ +function escapeWorkflowCommandData(s) { + return String(s) + .replace(/%/g, '%25') + .replace(/\r/g, '%0D') + .replace(/\n/g, '%0A'); +} + +/** + * Sanitize a value for use inside a GitHub Flavored Markdown table cell. + * Pipe characters would break the column structure; newlines would break the row. + */ +function sanitizeTableCell(s) { + return String(s ?? '') + .replace(/\|/g, '\\|') + .replace(/\r?\n/g, ' '); +} + function formatSummary(results) { const rows = results.map((r) => { const detail = r.status === 'updated' - ? `latest: \`${r.latestVersion}\`` + ? `latest: \`${sanitizeTableCell(r.latestVersion)}\`` : r.status === 'unchanged' - ? `latest: \`${r.latestVersion}\`` - : (r.reason ?? ''); + ? `latest: \`${sanitizeTableCell(r.latestVersion)}\`` + : sanitizeTableCell(r.reason ?? ''); return `| \`${r.client}\` | ${r.status} | ${detail} |`; }); return [ @@ -174,11 +207,11 @@ function emitAnnotations(results) { for (const r of results) { if (r.status === 'error' || r.status === 'warning') { console.log( - `::error title=Client release-notes sync (${r.client})::${r.reason}` + `::error title=${escapeWorkflowCommandProperty(`Client release-notes sync (${r.client})`)}::${escapeWorkflowCommandData(r.reason)}` ); } else if (r.status === 'skipped') { console.log( - `::warning title=Client release-notes sync (${r.client})::${r.reason}` + `::warning title=${escapeWorkflowCommandProperty(`Client release-notes sync (${r.client})`)}::${escapeWorkflowCommandData(r.reason)}` ); } }