diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index 688caacae..77f7a5027 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -1,5 +1,8 @@ name: Build -on: + +# 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 @@ -8,23 +11,56 @@ on: branches: - main - develop - - 'feature/**' + - "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: 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: 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: | - if ! docker-compose build; then - echo "Docker Compose build failed." - exit 1 # This will cause the workflow to fail + 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 new file mode 100644 index 000000000..c9c2a9113 --- /dev/null +++ b/.github/workflows/client-ci.yml @@ -0,0 +1,78 @@ +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 + pull_request: + branches: + - main + - develop + - "feature/**" + +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/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 + - name: Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: 20.17.0 + cache: "npm" + cache-dependency-path: angular-client/package-lock.json + - name: Install modules + run: npm ci + - name: Run linting check + 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/client-flutter-ci.yml b/.github/workflows/client-flutter-ci.yml index faeeb1c8d..eff2130b4 100644 --- a/.github/workflows/client-flutter-ci.yml +++ b/.github/workflows/client-flutter-ci.yml @@ -3,8 +3,18 @@ name: Flutter Format Check on: push: branches: [ main, develop ] + paths: + - "flutter-client/**" + - ".github/workflows/client-flutter-ci.yml" pull_request: branches: [ main, develop ] + paths: + - "flutter-client/**" + - ".github/workflows/client-flutter-ci.yml" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: format-verify: diff --git a/.github/workflows/lint-check.yml b/.github/workflows/lint-check.yml deleted file mode 100644 index 7b7971bac..000000000 --- a/.github/workflows/lint-check.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Linting Check -on: - push: - branches: - - main - - develop - pull_request: - branches: - - main - - develop - - "feature/**" - -jobs: - run-linting-check: - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Checkout repository - uses: actions/checkout@v7 - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: 20.17.0 - cache: "npm" - cache-dependency-path: ./angular-client/package-lock.json - - name: Install modules - working-directory: ./angular-client - run: npm install - - name: Run linting check - working-directory: ./angular-client - run: npm run lint --max-warnings=0 diff --git a/.github/workflows/prettier-check.yml b/.github/workflows/prettier-check.yml deleted file mode 100644 index 8fba4e566..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@v7 - - 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 ba95dbd10..b1c0e81e6 100644 --- a/.github/workflows/scylla-ci.yml +++ b/.github/workflows/scylla-ci.yml @@ -1,49 +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 - pull_request: - branches: - - main - - develop - - 'feature/**' - - -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 f1dc6e3a1..9ceef986a 100644 --- a/.github/workflows/test-check.yml +++ b/.github/workflows/test-check.yml @@ -1,4 +1,7 @@ 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: @@ -10,8 +13,31 @@ on: - develop - "feature/**" +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: @@ -29,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": {