diff --git a/.gitea/workflows/code_check.yml b/.gitea/workflows/code_check.yml index 124ecdd8..1b031315 100644 --- a/.gitea/workflows/code_check.yml +++ b/.gitea/workflows/code_check.yml @@ -1796,6 +1796,19 @@ jobs: name: orgfront-vitest-coverage-report path: badge-artifacts/orgfront + - name: Restore published badge state + run: | + git fetch origin "+refs/heads/badges:refs/remotes/origin/badges" || true + if git show-ref --verify --quiet refs/remotes/origin/badges && \ + git cat-file -e refs/remotes/origin/badges:latest/badges.json 2>/dev/null; then + mkdir -p docs/badges + git archive --format=tar refs/remotes/origin/badges latest | tar -x + cp latest/* docs/badges/ + rm -rf latest + else + echo "No published badge state found." + fi + - name: Update badge files env: LINT_RESULT: ${{ needs.lint.result }} diff --git a/.gitea/workflows/userfront_e2e_full_nightly.yml b/.gitea/workflows/userfront_e2e_full_nightly.yml index 2492ce54..83aa3d57 100644 --- a/.gitea/workflows/userfront_e2e_full_nightly.yml +++ b/.gitea/workflows/userfront_e2e_full_nightly.yml @@ -200,6 +200,19 @@ jobs: with: node-version: "24" + - name: Restore published badge state + run: | + git fetch origin "+refs/heads/badges:refs/remotes/origin/badges" || true + if git show-ref --verify --quiet refs/remotes/origin/badges && \ + git cat-file -e refs/remotes/origin/badges:latest/badges.json 2>/dev/null; then + mkdir -p docs/badges + git archive --format=tar refs/remotes/origin/badges latest | tar -x + cp latest/* docs/badges/ + rm -rf latest + else + echo "No published badge state found." + fi + - name: Update full E2E badge files env: USERFRONT_E2E_RESULT: ${{ needs.userfront-e2e-full.result }} diff --git a/scripts/update_code_check_badges.mjs b/scripts/update_code_check_badges.mjs index afc01b88..88672d37 100644 --- a/scripts/update_code_check_badges.mjs +++ b/scripts/update_code_check_badges.mjs @@ -382,7 +382,9 @@ if (process.env.BADGE_UPDATE_CODE_CHECK !== "false") { ); } -updateResultBadge(manifest, "biome", jobResults.biome); +if (jobResults.biome) { + updateResultBadge(manifest, "biome", jobResults.biome); +} const coverageSummaries = process.env.COVERAGE_SUMMARY_PATH ? [process.env.COVERAGE_SUMMARY_PATH] @@ -406,7 +408,7 @@ if (coverageJobResults.backend) { coverageJobResults.backend, coverageByPackage.get("backend"), ); -} else { +} else if (jobResults.backend) { updateCompactResultBadge(manifest, "backend-tests", jobResults.backend); } diff --git a/test/code_check_badge_branch_policy_test.sh b/test/code_check_badge_branch_policy_test.sh index 1de4f561..fd472d56 100644 --- a/test/code_check_badge_branch_policy_test.sh +++ b/test/code_check_badge_branch_policy_test.sh @@ -30,6 +30,8 @@ assert_contains "$WORKFLOW_FILE" 'push origin HEAD:${BADGE_BRANCH}' assert_contains "$WORKFLOW_FILE" 'BADGE_SOURCE_SHA: ${{ github.sha }}' assert_contains "$WORKFLOW_FILE" 'BADGE_LATEST_DIR="${BADGE_WORKTREE}/latest"' assert_contains "$WORKFLOW_FILE" 'BADGE_SHA_DIR="${BADGE_WORKTREE}/dev/${GITHUB_SHA}"' +assert_contains "$WORKFLOW_FILE" "Restore published badge state" +assert_contains "$WORKFLOW_FILE" "refs/remotes/origin/badges:latest/badges.json" assert_contains "$WORKFLOW_FILE" "userfront-flutter-coverage:" assert_contains "$WORKFLOW_FILE" "adminfront-vitest-coverage:" assert_contains "$WORKFLOW_FILE" "devfront-vitest-coverage:" @@ -82,6 +84,8 @@ assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_FIREFOX_MOBILE_RESU assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_WEBKIT_DESKTOP_RESULT:" assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "USERFRONT_E2E_WEBKIT_MOBILE_RESULT:" assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "BADGE_UPDATE_CODE_CHECK: \"false\"" +assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "Restore published badge state" +assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "refs/remotes/origin/badges:latest/badges.json" assert_contains "$FULL_NIGHTLY_WORKFLOW_FILE" "npx playwright test" echo "OK: Code Check badges are published to the badges branch" diff --git a/test/update_code_check_badges_preserve_existing_test.sh b/test/update_code_check_badges_preserve_existing_test.sh new file mode 100755 index 00000000..101e3094 --- /dev/null +++ b/test/update_code_check_badges_preserve_existing_test.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +WORK_DIR="$(mktemp -d)" +trap 'rm -rf "$WORK_DIR"' EXIT + +mkdir -p "$WORK_DIR/docs/badges" + +cat > "$WORK_DIR/docs/badges/badges.json" <<'JSON' +{ + "schemaVersion": 1, + "generatedBy": "scripts/update_code_check_badges.mjs", + "updatedAt": "2026-01-01T00:00:00.000Z", + "source": { + "branch": "dev", + "sha": "abc123456789", + "shortSha": "abc123456789", + "runId": "1", + "runNumber": "1" + }, + "badges": { + "code-check": { + "label": "code check", + "message": "passing", + "color": "#2ea043" + }, + "biome": { + "label": "biome", + "message": "passing", + "color": "#2ea043" + }, + "backend-tests": { + "label": "backend", + "message": "pass | 93.20%", + "color": "#2ea043" + }, + "userfront": { + "label": "userfront", + "message": "pass | 56.52%", + "color": "#bf8700" + }, + "adminfront": { + "label": "adminfront", + "message": "pass | 60.01%", + "color": "#bf8700" + }, + "devfront": { + "label": "devfront", + "message": "pass | 58.02%", + "color": "#bf8700" + }, + "orgfront": { + "label": "orgfront", + "message": "pass | 61.18%", + "color": "#bf8700" + }, + "userfront-chrome": { + "label": "chrome", + "message": "unknown", + "color": "#6e7781" + }, + "userfront-firefox": { + "label": "firefox", + "message": "unknown", + "color": "#6e7781" + }, + "userfront-safari": { + "label": "safari", + "message": "unknown", + "color": "#6e7781" + } + } +} +JSON + +( + cd "$WORK_DIR" + USERFRONT_E2E_RESULT=failure \ + USERFRONT_E2E_FULL=true \ + USERFRONT_E2E_CHROMIUM_DESKTOP_RESULT=success \ + USERFRONT_E2E_CHROMIUM_MOBILE_RESULT=success \ + USERFRONT_E2E_FIREFOX_DESKTOP_RESULT=success \ + USERFRONT_E2E_FIREFOX_MOBILE_RESULT=skipped \ + USERFRONT_E2E_WEBKIT_DESKTOP_RESULT=failure \ + USERFRONT_E2E_WEBKIT_MOBILE_RESULT=success \ + BADGE_UPDATE_CODE_CHECK=false \ + BADGE_SOURCE_BRANCH=dev \ + BADGE_SOURCE_SHA=abc123456789 \ + GITHUB_RUN_ID=2 \ + GITHUB_RUN_NUMBER=2 \ + node "$ROOT_DIR/scripts/update_code_check_badges.mjs" +) + +node - "$WORK_DIR/docs/badges/badges.json" <<'NODE' +const fs = require("node:fs"); + +const manifest = JSON.parse(fs.readFileSync(process.argv[2], "utf8")); +const badges = manifest.badges; + +function assertEqual(actual, expected, message) { + if (actual !== expected) { + throw new Error(`${message}: expected ${expected}, got ${actual}`); + } +} + +assertEqual(badges["code-check"].message, "passing", "full nightly must preserve code-check badge"); +assertEqual(badges.biome.message, "passing", "full nightly must preserve biome badge"); +assertEqual(badges["backend-tests"].message, "pass | 93.20%", "full nightly must preserve backend badge"); +assertEqual(badges.userfront.message, "pass | 56.52%", "full nightly must preserve userfront package badge"); +assertEqual(badges.adminfront.message, "pass | 60.01%", "full nightly must preserve adminfront badge"); +assertEqual(badges.devfront.message, "pass | 58.02%", "full nightly must preserve devfront badge"); +assertEqual(badges.orgfront.message, "pass | 61.18%", "full nightly must preserve orgfront badge"); +assertEqual(badges["userfront-chrome"].message, "pass | pass", "full nightly must update chrome badge"); +assertEqual(badges["userfront-firefox"].message, "pass | skip", "full nightly must update firefox badge"); +assertEqual(badges["userfront-safari"].message, "fail | pass", "full nightly must update safari badge"); +NODE + +echo "OK: full nightly preserves existing non-browser badges"