From fe0296f8bebed0e8594c9c1c87d1e9f94b92fd3e Mon Sep 17 00:00:00 2001 From: wyattb Date: Thu, 12 Mar 2026 05:46:04 -0400 Subject: [PATCH 1/4] #229 Optimize CI workflows: combine lint/prettier, add path filters - Combine lint-check.yml and prettier-check.yml into a single client-ci.yml that runs both checks in one job (single npm install), with path filter on angular-client/ so it only triggers on client changes - Add scylla-server/ path filter to scylla-ci.yml so it skips on unrelated changes - Add path filters to build-check.yml (angular-client/, scylla-server/, compose/) to skip Docker Compose builds on unrelated changes - Standardize Node.js version to 20.17.0 (was 18.17.1 for prettier) - Use npm ci instead of npm install for faster, deterministic installs Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/build-check.yml | 10 +++++- .../{lint-check.yml => client-ci.yml} | 14 +++++++-- .github/workflows/prettier-check.yml | 31 ------------------- .github/workflows/scylla-ci.yml | 4 +++ 4 files changed, 24 insertions(+), 35 deletions(-) rename .github/workflows/{lint-check.yml => client-ci.yml} (72%) delete mode 100644 .github/workflows/prettier-check.yml diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index c5aa7aba3..a3e448ba6 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -1,14 +1,22 @@ name: Build -on: +on: push: branches: - main - develop + paths: + - "angular-client/**" + - "scylla-server/**" + - "compose/**" pull_request: branches: - main - develop - 'feature/**' + paths: + - "angular-client/**" + - "scylla-server/**" + - "compose/**" jobs: run-build: runs-on: ubuntu-latest diff --git a/.github/workflows/lint-check.yml b/.github/workflows/client-ci.yml similarity index 72% rename from .github/workflows/lint-check.yml rename to .github/workflows/client-ci.yml index ebafd6600..1f48300d6 100644 --- a/.github/workflows/lint-check.yml +++ b/.github/workflows/client-ci.yml @@ -1,17 +1,22 @@ -name: Linting Check +name: Client CI + on: push: branches: - main - develop + paths: + - "angular-client/**" pull_request: branches: - main - develop - "feature/**" + paths: + - "angular-client/**" jobs: - run-linting-check: + lint-and-format: runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -25,7 +30,10 @@ jobs: cache-dependency-path: ./angular-client/package-lock.json - name: Install modules working-directory: ./angular-client - run: npm install + run: npm ci - name: Run linting check working-directory: ./angular-client run: npm run lint --max-warnings=0 + - name: Run prettier check + working-directory: ./angular-client + run: npm run prettier-check diff --git a/.github/workflows/prettier-check.yml b/.github/workflows/prettier-check.yml deleted file mode 100644 index 9e7a961dc..000000000 --- a/.github/workflows/prettier-check.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Prettier Check -on: - push: - branches: - - main - - develop - pull_request: - branches: - - main - - develop - - "feature/**" - -jobs: - run-prettier-check: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: 18.17.1 - cache: "npm" - cache-dependency-path: ./angular-client/package-lock.json - - name: Install modules - working-directory: ./angular-client - run: npm install - - name: Run prettier check - working-directory: ./angular-client - run: npm run prettier-check diff --git a/.github/workflows/scylla-ci.yml b/.github/workflows/scylla-ci.yml index 3a059c71c..960b8a49a 100644 --- a/.github/workflows/scylla-ci.yml +++ b/.github/workflows/scylla-ci.yml @@ -5,11 +5,15 @@ on: branches: - main - develop + paths: + - "scylla-server/**" pull_request: branches: - main - develop - 'feature/**' + paths: + - "scylla-server/**" defaults: From e7f85026aa807c4d575cbfe8cb53389edba04f7f Mon Sep 17 00:00:00 2001 From: wyattb Date: Sun, 29 Mar 2026 14:20:08 -0400 Subject: [PATCH 2/4] #229 Add self-trigger paths and use docker compose v2 --- .github/workflows/build-check.yml | 12 +++--------- .github/workflows/client-ci.yml | 2 ++ .github/workflows/scylla-ci.yml | 2 ++ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index a3e448ba6..2f7e4ab1a 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -8,6 +8,7 @@ on: - "angular-client/**" - "scylla-server/**" - "compose/**" + - ".github/workflows/build-check.yml" pull_request: branches: - main @@ -17,6 +18,7 @@ on: - "angular-client/**" - "scylla-server/**" - "compose/**" + - ".github/workflows/build-check.yml" jobs: run-build: runs-on: ubuntu-latest @@ -25,14 +27,6 @@ jobs: - name: Checkout code uses: actions/checkout@v6 - - name: Set up Docker Compose - run: | - sudo apt-get -y update - sudo apt-get -y install docker-compose - name: Build Docker Compose working-directory: compose - run: | - if ! docker-compose build; then - echo "Docker Compose build failed." - exit 1 # This will cause the workflow to fail - fi + run: docker compose build diff --git a/.github/workflows/client-ci.yml b/.github/workflows/client-ci.yml index 1f48300d6..8564e713d 100644 --- a/.github/workflows/client-ci.yml +++ b/.github/workflows/client-ci.yml @@ -7,6 +7,7 @@ on: - develop paths: - "angular-client/**" + - ".github/workflows/client-ci.yml" pull_request: branches: - main @@ -14,6 +15,7 @@ on: - "feature/**" paths: - "angular-client/**" + - ".github/workflows/client-ci.yml" jobs: lint-and-format: diff --git a/.github/workflows/scylla-ci.yml b/.github/workflows/scylla-ci.yml index 960b8a49a..2acf1d1ff 100644 --- a/.github/workflows/scylla-ci.yml +++ b/.github/workflows/scylla-ci.yml @@ -7,6 +7,7 @@ on: - develop paths: - "scylla-server/**" + - ".github/workflows/scylla-ci.yml" pull_request: branches: - main @@ -14,6 +15,7 @@ on: - 'feature/**' paths: - "scylla-server/**" + - ".github/workflows/scylla-ci.yml" defaults: From e9166ce14760adab71498025116ea35976cf95ed Mon Sep 17 00:00:00 2001 From: wyattb Date: Sun, 29 Mar 2026 14:20:48 -0400 Subject: [PATCH 3/4] #229 Fix lint flag passthrough and DRY working-directory --- .github/workflows/client-ci.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/client-ci.yml b/.github/workflows/client-ci.yml index 8564e713d..7cca63f4a 100644 --- a/.github/workflows/client-ci.yml +++ b/.github/workflows/client-ci.yml @@ -17,6 +17,10 @@ on: - "angular-client/**" - ".github/workflows/client-ci.yml" +defaults: + run: + working-directory: angular-client + jobs: lint-and-format: runs-on: ubuntu-latest @@ -29,13 +33,10 @@ jobs: with: node-version: 20.17.0 cache: "npm" - cache-dependency-path: ./angular-client/package-lock.json + cache-dependency-path: angular-client/package-lock.json - name: Install modules - working-directory: ./angular-client run: npm ci - name: Run linting check - working-directory: ./angular-client - run: npm run lint --max-warnings=0 + run: npm run lint -- --max-warnings=0 - name: Run prettier check - working-directory: ./angular-client run: npm run prettier-check From 706c8dad22c42da1c76c1c5b73feda6dcefad6b4 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 15 Jul 2026 20:30:32 +0000 Subject: [PATCH 4/4] #229 - add CI gate jobs, concurrency, and hardened karma launcher Fix path-filter + required-check deadlock: client-ci, test-check, scylla-ci, and build-check now always trigger, gate real work behind a dorny/paths-filter changes job, and expose an always-run *-gate job (green when skipped, red on failure) to use as the required status check. Add concurrency groups to scylla-ci/build-check. Harden frontend tests with a ChromeHeadlessCI karma launcher (--no-sandbox, --disable-dev-shm-usage) for reliable CI runs. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01DbmqjZpN8tex2sPd1h9HTU --- .github/workflows/build-check.yml | 58 +++++++++++--- .github/workflows/client-ci.yml | 52 +++++++++--- .github/workflows/scylla-ci.yml | 127 +++++++++++++++++++----------- .github/workflows/test-check.yml | 44 +++++++++-- angular-client/angular.json | 3 +- angular-client/karma.conf.js | 47 +++++++++++ angular-client/package.json | 2 +- 7 files changed, 255 insertions(+), 78 deletions(-) create mode 100644 angular-client/karma.conf.js diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index 3d64f883a..77f7a5027 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -1,32 +1,66 @@ name: Build + +# Always triggers so the required "build-gate" check is never left pending on unrelated PRs. +# The changes job decides whether the compose build runs; the gate reflects the result. on: push: branches: - main - develop - paths: - - "angular-client/**" - - "scylla-server/**" - - "compose/**" - - ".github/workflows/build-check.yml" pull_request: branches: - main - develop - - 'feature/**' - paths: - - "angular-client/**" - - "scylla-server/**" - - "compose/**" - - ".github/workflows/build-check.yml" + - "feature/**" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: + changes: + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + build: ${{ steps.filter.outputs.build }} + steps: + - name: Checkout code + uses: actions/checkout@v7 + - name: Detect build-relevant changes + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + build: + - "angular-client/**" + - "scylla-server/**" + - "compose/**" + - ".github/workflows/build-check.yml" + run-build: + needs: changes + if: ${{ needs.changes.outputs.build == 'true' }} runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout code uses: actions/checkout@v7 - - name: Build Docker Compose working-directory: compose run: docker compose build + + build-gate: + # Required status check. Always runs; green when the build is skipped or passes, red on failure. + needs: [changes, run-build] + if: always() + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Gate + run: | + result="${{ needs.run-build.result }}" + if [ "$result" = "failure" ] || [ "$result" = "cancelled" ]; then + echo "Build failed (result: $result)" + exit 1 + fi + echo "Build gate passed (result: $result)" diff --git a/.github/workflows/client-ci.yml b/.github/workflows/client-ci.yml index 63a161cf4..c9c2a9113 100644 --- a/.github/workflows/client-ci.yml +++ b/.github/workflows/client-ci.yml @@ -1,34 +1,49 @@ name: Client CI +# Always triggers so the required "client-ci-gate" check is never left pending on PRs that +# don't touch the client (path filters on the trigger would block required-check merges). +# The changes job decides whether the real work runs; the gate reflects its result. on: push: branches: - main - develop - paths: - - "angular-client/**" - - ".github/workflows/client-ci.yml" pull_request: branches: - main - develop - "feature/**" - paths: - - "angular-client/**" - - ".github/workflows/client-ci.yml" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -defaults: - run: - working-directory: angular-client - jobs: + changes: + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + client: ${{ steps.filter.outputs.client }} + steps: + - name: Checkout repository + uses: actions/checkout@v7 + - name: Detect client changes + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + client: + - "angular-client/**" + - ".github/workflows/client-ci.yml" + lint-and-format: + needs: changes + if: ${{ needs.changes.outputs.client == 'true' }} runs-on: ubuntu-latest timeout-minutes: 10 + defaults: + run: + working-directory: angular-client steps: - name: Checkout repository uses: actions/checkout@v7 @@ -44,3 +59,20 @@ jobs: run: npm run lint -- --max-warnings=0 - name: Run prettier check run: npm run prettier-check + + client-ci-gate: + # Required status check. Always runs; passes when the client job is skipped or succeeds, + # fails only when it actually fails, so path-filtered work never deadlocks a required check. + needs: [changes, lint-and-format] + if: always() + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Gate + run: | + result="${{ needs.lint-and-format.result }}" + if [ "$result" = "failure" ] || [ "$result" = "cancelled" ]; then + echo "Client CI failed (result: $result)" + exit 1 + fi + echo "Client CI gate passed (result: $result)" diff --git a/.github/workflows/scylla-ci.yml b/.github/workflows/scylla-ci.yml index e374f4e01..b1c0e81e6 100644 --- a/.github/workflows/scylla-ci.yml +++ b/.github/workflows/scylla-ci.yml @@ -1,55 +1,86 @@ name: Scylla CI +# Always triggers so the required "scylla-gate" check is never left pending on non-scylla PRs. +# The changes job decides whether the Rust build/test runs; the gate reflects the result. on: - push: - branches: - - main - - develop - paths: - - "scylla-server/**" - - ".github/workflows/scylla-ci.yml" - pull_request: - branches: - - main - - develop - - 'feature/**' - paths: - - "scylla-server/**" - - ".github/workflows/scylla-ci.yml" - - -defaults: - run: - working-directory: scylla-server + push: + branches: + - main + - develop + pull_request: + branches: + - main + - develop + - "feature/**" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - build: - runs-on: ubuntu-latest + changes: + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + scylla: ${{ steps.filter.outputs.scylla }} + steps: + - name: Checkout repository + uses: actions/checkout@v7 + - name: Detect scylla changes + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + scylla: + - "scylla-server/**" + - ".github/workflows/scylla-ci.yml" + + build: + needs: changes + if: ${{ needs.changes.outputs.scylla == 'true' }} + runs-on: ubuntu-latest + defaults: + run: + working-directory: scylla-server + steps: + - name: Setup Rust + uses: actions/checkout@v7 + with: + submodules: recursive + - name: Clippy + run: cargo clippy --all-targets --locked + - name: Fmt + run: cargo fmt --check + - name: Start DB + working-directory: compose + run: docker compose up -d odyssey-db + - name: Build + run: cargo build --verbose --locked + - name: Run # so we can migrate the database, run for a little than bail + env: + DATABASE_URL: postgresql://postgres:password@127.0.0.1:5432/postgres + run: | + cargo run --locked & ID=$!; sleep 10s; kill $ID + - name: Test + env: + DATABASE_URL: postgresql://postgres:password@127.0.0.1:5432/postgres + run: cargo test --locked -- --test-threads=1 + - name: Cleanup + working-directory: compose + run: docker compose down - steps: - - name: Setup Rust - uses: actions/checkout@v7 - with: - submodules: recursive - - name: Clippy - run: cargo clippy --all-targets --locked - - name: Fmt - run: cargo fmt --check - - name: Start DB - working-directory: compose - run: docker compose up -d odyssey-db - - name: Build - run: cargo build --verbose --locked - - name: Run # so we can migrate the database, run for a little than bail - env: - DATABASE_URL: postgresql://postgres:password@127.0.0.1:5432/postgres - run: | - cargo run --locked & ID=$!; sleep 10s; kill $ID - - name: Test - env: - DATABASE_URL: postgresql://postgres:password@127.0.0.1:5432/postgres - run: cargo test --locked -- --test-threads=1 - - name: Cleanup - working-directory: compose - run: docker compose down + scylla-gate: + # Required status check. Always runs; green when the build is skipped or passes, red on failure. + needs: [changes, build] + if: always() + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Gate + run: | + result="${{ needs.build.result }}" + if [ "$result" = "failure" ] || [ "$result" = "cancelled" ]; then + echo "Scylla CI failed (result: $result)" + exit 1 + fi + echo "Scylla gate passed (result: $result)" diff --git a/.github/workflows/test-check.yml b/.github/workflows/test-check.yml index e0c714477..9ceef986a 100644 --- a/.github/workflows/test-check.yml +++ b/.github/workflows/test-check.yml @@ -1,27 +1,43 @@ name: Frontend Unit Tests + +# Always triggers so the required "test-gate" check is never left pending on PRs that don't +# touch the client. The changes job decides whether the tests run; the gate reflects the result. on: push: branches: - main - develop - paths: - - "angular-client/**" - - ".github/workflows/test-check.yml" pull_request: branches: - main - develop - "feature/**" - paths: - - "angular-client/**" - - ".github/workflows/test-check.yml" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: + changes: + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + client: ${{ steps.filter.outputs.client }} + steps: + - name: Checkout repository + uses: actions/checkout@v7 + - name: Detect client changes + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + client: + - "angular-client/**" + - ".github/workflows/test-check.yml" + run-frontend-tests: + needs: changes + if: ${{ needs.changes.outputs.client == 'true' }} runs-on: ubuntu-latest timeout-minutes: 15 steps: @@ -39,3 +55,19 @@ jobs: - name: Run unit tests working-directory: ./angular-client run: npm run test:ci + + test-gate: + # Required status check. Always runs; green when tests are skipped or pass, red only on failure. + needs: [changes, run-frontend-tests] + if: always() + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Gate + run: | + result="${{ needs.run-frontend-tests.result }}" + if [ "$result" = "failure" ] || [ "$result" = "cancelled" ]; then + echo "Frontend unit tests failed (result: $result)" + exit 1 + fi + echo "Test gate passed (result: $result)" diff --git a/angular-client/angular.json b/angular-client/angular.json index b03b9c249..87408b125 100644 --- a/angular-client/angular.json +++ b/angular-client/angular.json @@ -84,7 +84,8 @@ "tsConfig": "tsconfig.spec.json", "assets": ["src/favicon.ico", "src/assets"], "styles": ["@angular/material/prebuilt-themes/rose-red.css", "src/styles.css"], - "scripts": [] + "scripts": [], + "karmaConfig": "karma.conf.js" } }, "lint": { diff --git a/angular-client/karma.conf.js b/angular-client/karma.conf.js new file mode 100644 index 000000000..7a4ee2078 --- /dev/null +++ b/angular-client/karma.conf.js @@ -0,0 +1,47 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, './coverage/angular-client'), + subdir: '.', + reporters: [ + { type: 'html' }, + { type: 'text-summary' } + ] + }, + reporters: ['progress', 'kjhtml'], + browsers: ['Chrome'], + // CI launcher: headless Chrome hardened for containerized runners. + // --no-sandbox (runners forbid the sandbox) and --disable-dev-shm-usage (small /dev/shm + // otherwise crashes Chrome mid-run) are the two flags that make CI test runs reliable. + customLaunchers: { + ChromeHeadlessCI: { + base: 'ChromeHeadless', + flags: ['--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'] + } + }, + restartOnFileChange: true + }); +}; diff --git a/angular-client/package.json b/angular-client/package.json index b6ca4f284..0d367d814 100644 --- a/angular-client/package.json +++ b/angular-client/package.json @@ -12,7 +12,7 @@ "install-dependencies": "npm install", "watch": "ng build --watch --configuration development", "test": "ng test", - "test:ci": "ng test --watch=false --browsers=ChromeHeadless" + "test:ci": "ng test --watch=false --browsers=ChromeHeadlessCI" }, "private": true, "dependencies": {