From aec6f5047925e54bbc7262ecca1e90ff15ed9266 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Thu, 22 Oct 2026 04:43:39 -0700 Subject: [PATCH 1/6] ci: split required tests into path-filtered parallel jobs Co-authored-by: CI Doctor Agent-Model: codex/gpt-6-sol/medium --- .github/workflows/smoke-test.yml | 4 +- .github/workflows/tests.yml | 170 +++++++++++++++++++++++++-- scripts/ci/select_test_paths.py | 60 ++++++++++ scripts/ci/test_select_test_paths.py | 28 +++++ 4 files changed, 252 insertions(+), 10 deletions(-) create mode 100644 scripts/ci/select_test_paths.py create mode 100644 scripts/ci/test_select_test_paths.py diff --git a/.github/workflows/smoke-test.yml b/.github/workflows/smoke-test.yml index ea31b1d61d..7ca4df5e06 100644 --- a/.github/workflows/smoke-test.yml +++ b/.github/workflows/smoke-test.yml @@ -8,7 +8,7 @@ on: default: '300' required: false workflow_run: - workflows: ["Tests"] + workflows: ["Deploy Dev"] branches: [main] types: [completed] # ADR-009 Phase 2: gate Tier 2 on PRs that touch deployment surfaces. @@ -46,7 +46,7 @@ jobs: name: kind cluster smoke test runs-on: ubuntu-latest # Run on manual dispatch, on any PR that passed the path filter above, - # or on a successful Tests workflow_run on main. + # or after a successful Deploy Dev run on main. if: > github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 32af94a1ac..2af87cbe85 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,7 +2,7 @@ name: Tests on: push: - branches: [ main, v1.0.x ] + branches: [ v1.0.x ] # No branches filter on pull_request: stacked PRs (base = another feature # branch) previously got ZERO test runs — every number on them was # single-sourced to the author's local sweep, and the 2026-08-22 threading @@ -27,16 +27,15 @@ permissions: contents: read # The push fallback is github.sha, NOT github.ref. On a push event `github.ref` -# is the *branch*, so every commit merged to main shared one concurrency group -# and each merge cancelled the previous commit's still-running verification. -# Measured across 39 Tests runs on main (2026-08-04 → 08-06): 18 cancelled. +# is the branch, so concurrent commits would cancel each other. This caused +# 18 of 39 Tests runs on main to be cancelled (2026-08-04 → 08-06). # # The loss is ordered by job depth, not random, which is what makes it worth # fixing rather than tolerating: # # Chart Lint no needs, ~8s survived 12 of 14 -# Test & Coverage no needs, ~5.5min survived 3 of 14 -# Service Tests needs:test, starts ~5.5min in survived 0 of 14 +# old Test & Coverage no needs, ~5.5min survived 3 of 14 +# Service Tests formerly needs:test survived 0 of 14 # # Service Tests is the ADR-009 Tier 1 real-DB tier — the deepest job, and the # only one that never once completed in a cancelled run. So the tier main was @@ -49,8 +48,149 @@ concurrency: cancel-in-progress: true jobs: - test: + paths: + name: Select test paths + runs-on: ubuntu-latest + outputs: + backend: ${{ steps.select.outputs.backend }} + frontend: ${{ steps.select.outputs.frontend }} + tools: ${{ steps.select.outputs.tools }} + chart: ${{ steps.select.outputs.chart }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - id: select + name: Classify changed paths + env: + EVENT_NAME: ${{ github.event_name }} + BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }} + run: python3 scripts/ci/select_test_paths.py + - run: python3 -m unittest discover -s scripts/ci -p 'test_select_test_paths.py' + + backend-tests: + name: Backend tests (${{ matrix.shard }}/3) + needs: paths + if: needs.paths.outputs.backend == 'true' + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3] + runs-on: ubuntu-latest + env: + JWT_SECRET: test-jwt-secret + SENDGRID_API_KEY: fake-api-key + SENDGRID_FROM_EMAIL: test@example.com + FRONTEND_URL: http://localhost:3000 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: npm + cache-dependency-path: backend/package-lock.json + - run: cd backend && npm ci --include=dev + - name: Run backend tests with coverage + run: cd backend && npx jest --coverage --forceExit --shard=${{ matrix.shard }}/3 + - uses: actions/upload-artifact@v4 + with: + name: backend-coverage-${{ matrix.shard }} + path: backend/coverage/ + + backend-checks: + name: Backend typecheck and lint + needs: paths + if: needs.paths.outputs.backend == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: npm + cache-dependency-path: backend/package-lock.json + - run: cd backend && npm ci --include=dev + - run: cd backend && npm run tsc:check + - run: cd packages/types && ../../backend/node_modules/.bin/tsc --noEmit -p tsconfig.json + - run: cd backend && npm run lint:ts + + frontend-tests: + name: Frontend tests + needs: paths + if: needs.paths.outputs.frontend == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: npm + cache-dependency-path: frontend/package-lock.json + - run: cd frontend && npm install --legacy-peer-deps + - run: cd frontend && npm run typecheck + - run: cd frontend && npx jest --coverage --watchAll=false --forceExit + - run: cd frontend && node --test scripts/generate-seo-pages.test.mjs scripts/nginx-routing.test.mjs + + tool-tests: + name: CLI, MCP and hosted runtime tests + needs: paths + if: needs.paths.outputs.tools == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: npm + cache-dependency-path: | + package-lock.json + commonly-mcp/package-lock.json + cli/package-lock.json + workers/agent-runtime/package-lock.json + - run: npm ci --include=dev + - run: cd commonly-mcp && npm ci --include=dev + - run: cd cli && npm ci --include=dev + - run: cd workers/agent-runtime && npm ci --include=dev + - run: npm run verify:moltbot-tools + - run: npm run verify:litellm-patch-runner + - run: cd commonly-mcp && npm test + - run: cd cli && npm run lint && npm test + - run: cd workers/agent-runtime && npm run typecheck && npm test + + test-gate: name: Test & Coverage + if: always() + needs: [paths, backend-tests, backend-checks, frontend-tests, tool-tests, service-test, chart-lint] + runs-on: ubuntu-latest + env: + NEEDS_JSON: ${{ toJSON(needs) }} + steps: + - name: Verify every selected check passed + run: | + echo "$NEEDS_JSON" | jq -e ' + . as $jobs | + $jobs.paths.result == "success" and + $jobs["service-test"].result == "success" and + ($jobs["chart-lint"].result == "success" or + ($jobs.paths.outputs.chart == "false" and $jobs["chart-lint"].result == "skipped")) and + (if $jobs.paths.outputs.backend == "true" then + $jobs["backend-tests"].result == "success" and $jobs["backend-checks"].result == "success" + else + $jobs["backend-tests"].result == "skipped" and $jobs["backend-checks"].result == "skipped" + end) and + (if $jobs.paths.outputs.frontend == "true" then + $jobs["frontend-tests"].result == "success" + else $jobs["frontend-tests"].result == "skipped" end) and + (if $jobs.paths.outputs.tools == "true" then + $jobs["tool-tests"].result == "success" + else $jobs["tool-tests"].result == "skipped" end) + ' + + legacy-test: + # Retire only after the new gate passes a real merge_group run. + name: Legacy test and coverage runs-on: ubuntu-latest env: @@ -196,7 +336,6 @@ jobs: service-test: name: Service Tests (Tier 1 — real DBs) runs-on: ubuntu-latest - needs: test services: mongo: @@ -238,8 +377,19 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v3 + with: + fetch-depth: 0 + + # This job has no needs, so it starts with the other suites. Classify here + # independently; a docs-only PR still starts the job but runs no tests. + - id: select + env: + EVENT_NAME: ${{ github.event_name }} + BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }} + run: python3 scripts/ci/select_test_paths.py - name: Set up Node.js + if: steps.select.outputs.backend == 'true' uses: actions/setup-node@v4 with: node-version: '22' @@ -247,15 +397,19 @@ jobs: cache-dependency-path: '**/package-lock.json' - name: Install backend dependencies + if: steps.select.outputs.backend == 'true' run: cd backend && npm ci --include=dev - name: Run service tests (Tier 1) + if: steps.select.outputs.backend == 'true' run: | cd backend npx jest --testPathPattern="__tests__/service" --forceExit --runInBand chart-lint: name: Chart Lint (Tier 1.5) + needs: paths + if: needs.paths.outputs.chart == 'true' runs-on: ubuntu-latest env: diff --git a/scripts/ci/select_test_paths.py b/scripts/ci/select_test_paths.py new file mode 100644 index 0000000000..cbf9c623f6 --- /dev/null +++ b/scripts/ci/select_test_paths.py @@ -0,0 +1,60 @@ +"""Select CI suites from the actual PR or merge-group diff. + +Unknown paths and diff failures run every suite. A missing check must never +turn into a green required gate. +""" + +import os +import subprocess +from pathlib import Path + + +SUITES = ("backend", "frontend", "tools", "chart") + + +def select(paths): + selected = {suite: False for suite in SUITES} + if not paths: + return {suite: True for suite in SUITES} + + for path in paths: + if path.startswith("docs/") or ("/" not in path and path.endswith(".md")): + continue + if path.startswith("backend/"): + selected["backend"] = True + selected["chart"] = True + elif path.startswith("frontend/"): + selected["frontend"] = True + elif path.startswith(("cli/", "commonly-mcp/", "workers/agent-runtime/")): + selected["tools"] = True + elif path.startswith("k8s/"): + selected["chart"] = True + else: + return {suite: True for suite in SUITES} + return selected + + +def main(): + event = os.environ.get("EVENT_NAME") + base = os.environ.get("BASE_SHA") + head = os.environ.get("GITHUB_SHA") + if event not in ("pull_request", "merge_group") or not base or not head: + result = select([]) + else: + try: + changed = subprocess.check_output( + ["git", "diff", "--name-only", "-z", base, head], + stderr=subprocess.DEVNULL, + ).decode().rstrip("\0").split("\0") + result = select(changed) + except (subprocess.CalledProcessError, UnicodeDecodeError): + result = select([]) + + output = Path(os.environ["GITHUB_OUTPUT"]) + with output.open("a") as stream: + for suite, enabled in result.items(): + stream.write(f"{suite}={str(enabled).lower()}\n") + + +if __name__ == "__main__": + main() diff --git a/scripts/ci/test_select_test_paths.py b/scripts/ci/test_select_test_paths.py new file mode 100644 index 0000000000..a22c189e2e --- /dev/null +++ b/scripts/ci/test_select_test_paths.py @@ -0,0 +1,28 @@ +import unittest + +from select_test_paths import select + + +class SelectTestPathsTest(unittest.TestCase): + def test_docs_only_selects_no_suite(self): + self.assertEqual(select(["docs/README.md", "README.md"]), { + "backend": False, "frontend": False, "tools": False, "chart": False, + }) + + def test_frontend_only_does_not_select_backend(self): + self.assertEqual(select(["frontend/src/App.tsx"]), { + "backend": False, "frontend": True, "tools": False, "chart": False, + }) + + def test_backend_change_also_checks_chart(self): + self.assertEqual(select(["backend/src/server.ts"]), { + "backend": True, "frontend": False, "tools": False, "chart": True, + }) + + def test_unknown_and_empty_diff_fail_open(self): + for paths in ([], ["packages/types/src/index.ts"]): + self.assertTrue(all(select(paths).values())) + + +if __name__ == "__main__": + unittest.main() From 88f3b915f640bd0c61768d040a47273c3839a5bd Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Thu, 22 Oct 2026 04:53:22 -0700 Subject: [PATCH 2/6] ci: install backend dependencies for frontend and CLI suites Co-authored-by: CI Doctor Agent-Model: codex/gpt-6-sol/medium --- .github/workflows/tests.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2af87cbe85..9247911570 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -125,7 +125,11 @@ jobs: with: node-version: '22' cache: npm - cache-dependency-path: frontend/package-lock.json + cache-dependency-path: | + backend/package-lock.json + frontend/package-lock.json + # Frontend typecheck follows shared imports into backend TypeScript. + - run: cd backend && npm ci --include=dev - run: cd frontend && npm install --legacy-peer-deps - run: cd frontend && npm run typecheck - run: cd frontend && npx jest --coverage --watchAll=false --forceExit @@ -146,10 +150,13 @@ jobs: cache: npm cache-dependency-path: | package-lock.json + backend/package-lock.json commonly-mcp/package-lock.json cli/package-lock.json workers/agent-runtime/package-lock.json - run: npm ci --include=dev + # CLI tests load backend TypeScript through ts-node. + - run: cd backend && npm ci --include=dev - run: cd commonly-mcp && npm ci --include=dev - run: cd cli && npm ci --include=dev - run: cd workers/agent-runtime && npm ci --include=dev From 25bdaeabf8556ebfedc6e78b321ef0fa5101e10a Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Thu, 22 Oct 2026 05:11:04 -0700 Subject: [PATCH 3/6] Keep alerting policy check on runbook edits Co-authored-by: CI Doctor Agent-Model: codex/gpt-6-sol/medium --- scripts/ci/select_test_paths.py | 3 +++ scripts/ci/test_select_test_paths.py | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/scripts/ci/select_test_paths.py b/scripts/ci/select_test_paths.py index cbf9c623f6..047febee49 100644 --- a/scripts/ci/select_test_paths.py +++ b/scripts/ci/select_test_paths.py @@ -18,6 +18,9 @@ def select(paths): return {suite: True for suite in SUITES} for path in paths: + if path == "docs/runbooks/alerting.md": + selected["chart"] = True + continue if path.startswith("docs/") or ("/" not in path and path.endswith(".md")): continue if path.startswith("backend/"): diff --git a/scripts/ci/test_select_test_paths.py b/scripts/ci/test_select_test_paths.py index a22c189e2e..f363e48216 100644 --- a/scripts/ci/test_select_test_paths.py +++ b/scripts/ci/test_select_test_paths.py @@ -14,6 +14,11 @@ def test_frontend_only_does_not_select_backend(self): "backend": False, "frontend": True, "tools": False, "chart": False, }) + def test_alerting_runbook_checks_chart_policy(self): + self.assertEqual(select(["docs/runbooks/alerting.md"]), { + "backend": False, "frontend": False, "tools": False, "chart": True, + }) + def test_backend_change_also_checks_chart(self): self.assertEqual(select(["backend/src/server.ts"]), { "backend": True, "frontend": False, "tools": False, "chart": True, From 1b81992c873d03ac388e2ecbe3ce2e6b1bedff71 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Thu, 22 Oct 2026 05:17:54 -0700 Subject: [PATCH 4/6] Run frontend contracts for backend changes Co-authored-by: CI Doctor Agent-Model: codex/gpt-6-sol/medium --- scripts/ci/select_test_paths.py | 2 ++ scripts/ci/test_select_test_paths.py | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/ci/select_test_paths.py b/scripts/ci/select_test_paths.py index 047febee49..8706cfa25d 100644 --- a/scripts/ci/select_test_paths.py +++ b/scripts/ci/select_test_paths.py @@ -25,6 +25,8 @@ def select(paths): continue if path.startswith("backend/"): selected["backend"] = True + # Frontend typecheck and catalogue tests import backend modules. + selected["frontend"] = True selected["chart"] = True elif path.startswith("frontend/"): selected["frontend"] = True diff --git a/scripts/ci/test_select_test_paths.py b/scripts/ci/test_select_test_paths.py index f363e48216..c0d166d517 100644 --- a/scripts/ci/test_select_test_paths.py +++ b/scripts/ci/test_select_test_paths.py @@ -19,9 +19,9 @@ def test_alerting_runbook_checks_chart_policy(self): "backend": False, "frontend": False, "tools": False, "chart": True, }) - def test_backend_change_also_checks_chart(self): + def test_backend_change_also_checks_frontend_contracts_and_chart(self): self.assertEqual(select(["backend/src/server.ts"]), { - "backend": True, "frontend": False, "tools": False, "chart": True, + "backend": True, "frontend": True, "tools": False, "chart": True, }) def test_unknown_and_empty_diff_fail_open(self): From fd25bb8ae2d4b90f172e8e16dfcdb1f0601c7560 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Thu, 22 Oct 2026 05:24:35 -0700 Subject: [PATCH 5/6] Run every split CI suite on each PR Co-authored-by: CI Doctor Agent-Model: codex/gpt-6-sol/medium --- .github/workflows/tests.yml | 62 ++------------------------ scripts/ci/select_test_paths.py | 65 ---------------------------- scripts/ci/test_select_test_paths.py | 33 -------------- 3 files changed, 3 insertions(+), 157 deletions(-) delete mode 100644 scripts/ci/select_test_paths.py delete mode 100644 scripts/ci/test_select_test_paths.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9247911570..717475e079 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -48,30 +48,8 @@ concurrency: cancel-in-progress: true jobs: - paths: - name: Select test paths - runs-on: ubuntu-latest - outputs: - backend: ${{ steps.select.outputs.backend }} - frontend: ${{ steps.select.outputs.frontend }} - tools: ${{ steps.select.outputs.tools }} - chart: ${{ steps.select.outputs.chart }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - id: select - name: Classify changed paths - env: - EVENT_NAME: ${{ github.event_name }} - BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }} - run: python3 scripts/ci/select_test_paths.py - - run: python3 -m unittest discover -s scripts/ci -p 'test_select_test_paths.py' - backend-tests: name: Backend tests (${{ matrix.shard }}/3) - needs: paths - if: needs.paths.outputs.backend == 'true' strategy: fail-fast: false matrix: @@ -99,8 +77,6 @@ jobs: backend-checks: name: Backend typecheck and lint - needs: paths - if: needs.paths.outputs.backend == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -116,8 +92,6 @@ jobs: frontend-tests: name: Frontend tests - needs: paths - if: needs.paths.outputs.frontend == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -137,8 +111,6 @@ jobs: tool-tests: name: CLI, MCP and hosted runtime tests - needs: paths - if: needs.paths.outputs.tools == 'true' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -169,30 +141,15 @@ jobs: test-gate: name: Test & Coverage if: always() - needs: [paths, backend-tests, backend-checks, frontend-tests, tool-tests, service-test, chart-lint] + needs: [backend-tests, backend-checks, frontend-tests, tool-tests, service-test, chart-lint] runs-on: ubuntu-latest env: NEEDS_JSON: ${{ toJSON(needs) }} steps: - - name: Verify every selected check passed + - name: Verify every check passed run: | echo "$NEEDS_JSON" | jq -e ' - . as $jobs | - $jobs.paths.result == "success" and - $jobs["service-test"].result == "success" and - ($jobs["chart-lint"].result == "success" or - ($jobs.paths.outputs.chart == "false" and $jobs["chart-lint"].result == "skipped")) and - (if $jobs.paths.outputs.backend == "true" then - $jobs["backend-tests"].result == "success" and $jobs["backend-checks"].result == "success" - else - $jobs["backend-tests"].result == "skipped" and $jobs["backend-checks"].result == "skipped" - end) and - (if $jobs.paths.outputs.frontend == "true" then - $jobs["frontend-tests"].result == "success" - else $jobs["frontend-tests"].result == "skipped" end) and - (if $jobs.paths.outputs.tools == "true" then - $jobs["tool-tests"].result == "success" - else $jobs["tool-tests"].result == "skipped" end) + [.[].result] | all(. == "success") ' legacy-test: @@ -387,16 +344,7 @@ jobs: with: fetch-depth: 0 - # This job has no needs, so it starts with the other suites. Classify here - # independently; a docs-only PR still starts the job but runs no tests. - - id: select - env: - EVENT_NAME: ${{ github.event_name }} - BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }} - run: python3 scripts/ci/select_test_paths.py - - name: Set up Node.js - if: steps.select.outputs.backend == 'true' uses: actions/setup-node@v4 with: node-version: '22' @@ -404,19 +352,15 @@ jobs: cache-dependency-path: '**/package-lock.json' - name: Install backend dependencies - if: steps.select.outputs.backend == 'true' run: cd backend && npm ci --include=dev - name: Run service tests (Tier 1) - if: steps.select.outputs.backend == 'true' run: | cd backend npx jest --testPathPattern="__tests__/service" --forceExit --runInBand chart-lint: name: Chart Lint (Tier 1.5) - needs: paths - if: needs.paths.outputs.chart == 'true' runs-on: ubuntu-latest env: diff --git a/scripts/ci/select_test_paths.py b/scripts/ci/select_test_paths.py deleted file mode 100644 index 8706cfa25d..0000000000 --- a/scripts/ci/select_test_paths.py +++ /dev/null @@ -1,65 +0,0 @@ -"""Select CI suites from the actual PR or merge-group diff. - -Unknown paths and diff failures run every suite. A missing check must never -turn into a green required gate. -""" - -import os -import subprocess -from pathlib import Path - - -SUITES = ("backend", "frontend", "tools", "chart") - - -def select(paths): - selected = {suite: False for suite in SUITES} - if not paths: - return {suite: True for suite in SUITES} - - for path in paths: - if path == "docs/runbooks/alerting.md": - selected["chart"] = True - continue - if path.startswith("docs/") or ("/" not in path and path.endswith(".md")): - continue - if path.startswith("backend/"): - selected["backend"] = True - # Frontend typecheck and catalogue tests import backend modules. - selected["frontend"] = True - selected["chart"] = True - elif path.startswith("frontend/"): - selected["frontend"] = True - elif path.startswith(("cli/", "commonly-mcp/", "workers/agent-runtime/")): - selected["tools"] = True - elif path.startswith("k8s/"): - selected["chart"] = True - else: - return {suite: True for suite in SUITES} - return selected - - -def main(): - event = os.environ.get("EVENT_NAME") - base = os.environ.get("BASE_SHA") - head = os.environ.get("GITHUB_SHA") - if event not in ("pull_request", "merge_group") or not base or not head: - result = select([]) - else: - try: - changed = subprocess.check_output( - ["git", "diff", "--name-only", "-z", base, head], - stderr=subprocess.DEVNULL, - ).decode().rstrip("\0").split("\0") - result = select(changed) - except (subprocess.CalledProcessError, UnicodeDecodeError): - result = select([]) - - output = Path(os.environ["GITHUB_OUTPUT"]) - with output.open("a") as stream: - for suite, enabled in result.items(): - stream.write(f"{suite}={str(enabled).lower()}\n") - - -if __name__ == "__main__": - main() diff --git a/scripts/ci/test_select_test_paths.py b/scripts/ci/test_select_test_paths.py deleted file mode 100644 index c0d166d517..0000000000 --- a/scripts/ci/test_select_test_paths.py +++ /dev/null @@ -1,33 +0,0 @@ -import unittest - -from select_test_paths import select - - -class SelectTestPathsTest(unittest.TestCase): - def test_docs_only_selects_no_suite(self): - self.assertEqual(select(["docs/README.md", "README.md"]), { - "backend": False, "frontend": False, "tools": False, "chart": False, - }) - - def test_frontend_only_does_not_select_backend(self): - self.assertEqual(select(["frontend/src/App.tsx"]), { - "backend": False, "frontend": True, "tools": False, "chart": False, - }) - - def test_alerting_runbook_checks_chart_policy(self): - self.assertEqual(select(["docs/runbooks/alerting.md"]), { - "backend": False, "frontend": False, "tools": False, "chart": True, - }) - - def test_backend_change_also_checks_frontend_contracts_and_chart(self): - self.assertEqual(select(["backend/src/server.ts"]), { - "backend": True, "frontend": True, "tools": False, "chart": True, - }) - - def test_unknown_and_empty_diff_fail_open(self): - for paths in ([], ["packages/types/src/index.ts"]): - self.assertTrue(all(select(paths).values())) - - -if __name__ == "__main__": - unittest.main() From 1238dad445ea8347195acdd0b38ee13496c18fff Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Thu, 22 Oct 2026 05:25:25 -0700 Subject: [PATCH 6/6] Preserve nightly-only coverage in split jobs Co-authored-by: CI Doctor Agent-Model: codex/gpt-6-sol/medium --- .github/workflows/tests.yml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 717475e079..5356493591 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -68,9 +68,16 @@ jobs: cache: npm cache-dependency-path: backend/package-lock.json - run: cd backend && npm ci --include=dev - - name: Run backend tests with coverage - run: cd backend && npx jest --coverage --forceExit --shard=${{ matrix.shard }}/3 + - name: Run backend tests (coverage on the nightly schedule only) + run: | + cd backend + if [ "${{ github.event_name }}" = "schedule" ]; then + npx jest --coverage --forceExit --shard=${{ matrix.shard }}/3 + else + npx jest --forceExit --shard=${{ matrix.shard }}/3 + fi - uses: actions/upload-artifact@v4 + if: github.event_name == 'schedule' with: name: backend-coverage-${{ matrix.shard }} path: backend/coverage/ @@ -106,7 +113,14 @@ jobs: - run: cd backend && npm ci --include=dev - run: cd frontend && npm install --legacy-peer-deps - run: cd frontend && npm run typecheck - - run: cd frontend && npx jest --coverage --watchAll=false --forceExit + - name: Run frontend tests (coverage on the nightly schedule only) + run: | + cd frontend + if [ "${{ github.event_name }}" = "schedule" ]; then + npx jest --coverage --watchAll=false --forceExit + else + npx jest --watchAll=false --forceExit + fi - run: cd frontend && node --test scripts/generate-seo-pages.test.mjs scripts/nginx-routing.test.mjs tool-tests: