From 41fc0cd34b2a72ea8ba50345c4b2321ea5f59a40 Mon Sep 17 00:00:00 2001 From: Tsubasa Azumagakito Date: Fri, 2 Oct 2026 02:46:39 +0900 Subject: [PATCH 1/2] fix: make D1 post-apply audit compatible with wrangler --- .github/workflows/d1-migrate.yml | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/.github/workflows/d1-migrate.yml b/.github/workflows/d1-migrate.yml index 742ba2526..e59748e95 100644 --- a/.github/workflows/d1-migrate.yml +++ b/.github/workflows/d1-migrate.yml @@ -68,30 +68,17 @@ jobs: - name: Confirm no migrations remain pending (audit log) # wrangler d1 migrations list exits 0 even when migrations remain - # unapplied, so parse --json and fail the job explicitly (issue #3024). - # Verified output schema (wrangler 4.x, 2026-08): array of objects with - # `name`, `created_at`, and `applied_at` (null when pending). The jq - # filter also tolerates `applied`/`AppliedAt` variants defensively, and - # if the schema is completely unknown (no recognized field) it fails - # closed rather than silently passing (issue #3075). + # unapplied, so require the current no-pending sentinel explicitly. + # Wrangler 4.144.0 rejects `--json` for this command, so keep the + # audit on the supported text output and fail closed if the sentinel + # disappears or the list command itself fails. run: | set -euo pipefail - npm run db:migrations:list -- --json > pending.json || true - if command -v jq >/dev/null; then - pending_count=$(jq '[.[] | select((.applied_at // .applied // .AppliedAt) == null)] | length' pending.json) - echo "Pending migration count: ${pending_count}" - total_count=$(jq 'length' pending.json) - recognized=$(jq '[.[] | has("applied_at") or has("applied") or has("AppliedAt")] | any' pending.json) - if [ "${recognized}" != "true" ] && [ "${total_count}" -gt 0 ]; then - echo "::error::wrangler d1 migrations list --json output schema is unrecognized. Inspect the output above and update this step." - exit 1 - fi - if [ "${pending_count}" -gt 0 ]; then - echo "::error::D1 migrations remain unapplied after apply. See logs above." - exit 1 - fi - else - npm run db:migrations:list + output="$(npm run db:migrations:list 2>&1)" + printf '%s\n' "${output}" + if ! grep -Fq "No migrations to apply!" <<<"${output}"; then + echo "::error::D1 migrations may remain unapplied after apply. Inspect the list output above." + exit 1 fi env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} From af385f7e18838365b395dddb66a72d3e189f9417 Mon Sep 17 00:00:00 2001 From: Tsubasa Azumagakito Date: Fri, 2 Oct 2026 02:46:42 +0900 Subject: [PATCH 2/2] test: cover D1 text-output pending audit --- .../__tests__/docs/d1-migrate-npm-toolchain.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/smkc-score-app/__tests__/docs/d1-migrate-npm-toolchain.test.ts b/smkc-score-app/__tests__/docs/d1-migrate-npm-toolchain.test.ts index 92f399440..af8e39a99 100644 --- a/smkc-score-app/__tests__/docs/d1-migrate-npm-toolchain.test.ts +++ b/smkc-score-app/__tests__/docs/d1-migrate-npm-toolchain.test.ts @@ -44,26 +44,34 @@ describe('D1 migration npm toolchain', () => { const installStep = steps?.find((step) => step.name === 'Install dependencies'); const listStep = steps?.find((step) => step.name === 'List pending migrations'); const applyStep = steps?.find((step) => step.name === 'Apply migrations'); + const auditStep = steps?.find((step) => step.name === 'Confirm no migrations remain pending (audit log)'); expect(pinStep).toBeDefined(); expect(installStep).toBeDefined(); expect(listStep).toBeDefined(); expect(applyStep).toBeDefined(); + expect(auditStep).toBeDefined(); expect(pinStep?.run).toContain(`npm install --global --ignore-scripts --no-audit --no-fund ${packageManager}`); const expectedVersion = packageManager?.replace(/^npm@/, ''); expect(pinStep?.run).toContain(`test "$(npm --version)" = "${expectedVersion}"`); expect(installStep?.run?.trim()).toBe('npm ci'); expect(installStep?.env?.HUSKY).toBe('0'); + expect(auditStep?.run).toContain('npm run db:migrations:list 2>&1'); + expect(auditStep?.run).toContain('grep -Fq "No migrations to apply!"'); + expect(auditStep?.run).not.toContain('--json'); + expect(auditStep?.run).not.toContain('|| true'); const pinIndex = steps?.indexOf(pinStep as WorkflowStep) ?? -1; const installIndex = steps?.indexOf(installStep as WorkflowStep) ?? -1; const listIndex = steps?.indexOf(listStep as WorkflowStep) ?? -1; const applyIndex = steps?.indexOf(applyStep as WorkflowStep) ?? -1; + const auditIndex = steps?.indexOf(auditStep as WorkflowStep) ?? -1; expect(pinIndex).toBeGreaterThanOrEqual(0); expect(pinIndex).toBeLessThan(installIndex); expect(installIndex).toBeLessThan(listIndex); expect(listIndex).toBeLessThan(applyIndex); + expect(applyIndex).toBeLessThan(auditIndex); }); });