chore(deps): bump com.puppycrawl.tools:checkstyle from 10.21.1 to 14.0.0 in /services/auth #118
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| # Single PR pipeline for the whole monorepo: | |
| # changes (dorny/paths-filter) → per-component jobs (only for what the PR | |
| # touches) → ci-ok aggregator gate. | |
| on: | |
| push: | |
| branches: | |
| - main | |
| pull_request: | |
| branches: | |
| - main | |
| permissions: | |
| contents: read | |
| # New pushes to the same PR cancel the still-running CI of the old commit. | |
| concurrency: | |
| group: ci-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| # Detects which components the PR touches. Runs on every PR (no `paths:` on | |
| # the trigger — a path-filtered workflow never reports, which breaks required | |
| # checks); gating happens per job via these outputs instead. | |
| changes: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| outputs: | |
| java_matrix: ${{ steps.java.outputs.matrix }} | |
| email: ${{ steps.filter.outputs.email }} | |
| genai: ${{ steps.filter.outputs.genai }} | |
| web-client: ${{ steps.filter.outputs.web-client }} | |
| openapi: ${{ steps.filter.outputs.openapi }} | |
| infra: ${{ steps.filter.outputs.infra }} | |
| e2e: ${{ steps.filter.outputs.e2e }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| # `shared` is not a job trigger — it's spliced into every component: | |
| # the spec regenerates committed DTOs/types (a spec change without | |
| # regenerated code must fail the builds), and a change to this | |
| # pipeline must re-run everything it gates. | |
| filters: | | |
| shared: &shared | |
| - api/openapi.yaml | |
| - .github/workflows/ci.yml | |
| auth: | |
| - *shared | |
| - services/auth/** | |
| application: | |
| - *shared | |
| - services/application/** | |
| document: | |
| - *shared | |
| - services/document/** | |
| gateway: | |
| - *shared | |
| - services/gateway/** | |
| email: | |
| - *shared | |
| - services/email/** | |
| genai: | |
| - *shared | |
| - services/genai/** | |
| web-client: | |
| - *shared | |
| - web-client/** | |
| openapi: | |
| - api/** | |
| - .github/workflows/ci.yml | |
| infra: | |
| - .github/workflows/** | |
| - "**/Dockerfile" | |
| - .pre-commit-config.yaml | |
| # The e2e suite drives the whole stack through the gateway, so any service | |
| # (or the compose wiring that stands them up) can break it. | |
| e2e: | |
| - *shared | |
| - services/auth/** | |
| - services/application/** | |
| - services/document/** | |
| - services/gateway/** | |
| - e2e_tests/** | |
| - docker-compose.yml | |
| - name: Build java matrix | |
| id: java | |
| run: | | |
| services=() | |
| if [ "${{ steps.filter.outputs.auth }}" = "true" ]; then services+=('"auth"'); fi | |
| if [ "${{ steps.filter.outputs.application }}" = "true" ]; then services+=('"application"'); fi | |
| if [ "${{ steps.filter.outputs.document }}" = "true" ]; then services+=('"document"'); fi | |
| if [ "${{ steps.filter.outputs.gateway }}" = "true" ]; then services+=('"gateway"'); fi | |
| if [ "${{ steps.filter.outputs.email }}" = "true" ]; then services+=('"email"'); fi | |
| matrix="[$(IFS=,; echo "${services[*]}")]" | |
| echo "matrix=$matrix" >> "$GITHUB_OUTPUT" | |
| echo "java matrix: $matrix" | |
| # One leg per changed Spring service. Postgres is provided to every leg — | |
| # auth/application/document/email run their test suites against it; gateway | |
| # simply ignores it (cheaper than templating the container per leg). | |
| java: | |
| name: java (${{ matrix.service }}) | |
| needs: changes | |
| if: needs.changes.outputs.java_matrix != '[]' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| service: ${{ fromJson(needs.changes.outputs.java_matrix) }} | |
| services: | |
| postgres: | |
| image: pgvector/pgvector:pg16 | |
| env: | |
| POSTGRES_USER: jobready | |
| POSTGRES_PASSWORD: jobready | |
| POSTGRES_DB: jobready | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Java 21 | |
| uses: actions/setup-java@v5 | |
| with: | |
| java-version: 21 | |
| distribution: temurin | |
| cache: maven | |
| cache-dependency-path: services/${{ matrix.service }}/pom.xml | |
| - name: Build and test | |
| run: ./mvnw verify | |
| working-directory: services/${{ matrix.service }} | |
| env: | |
| SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/jobready | |
| SPRING_DATASOURCE_USERNAME: jobready | |
| SPRING_DATASOURCE_PASSWORD: jobready | |
| genai: | |
| needs: changes | |
| if: needs.changes.outputs.genai == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| defaults: | |
| run: | |
| working-directory: services/genai | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python 3.12 | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 | |
| with: | |
| version: "0.11.18" | |
| enable-cache: true | |
| cache-dependency-glob: "services/genai/uv.lock" | |
| - name: Install dependencies | |
| run: uv sync --locked --all-groups | |
| - name: Lint (Ruff) | |
| run: uv run --locked ruff check . | |
| - name: Format check (Ruff) | |
| run: uv run --locked ruff format --check . | |
| - name: Typecheck (mypy) | |
| run: uv run --locked mypy src/ tests/ | |
| # Gate sits below the ~81% the suite currently reaches, so it blocks a real | |
| # regression without tripping on a line or two of churn. Raise it as coverage grows. | |
| - name: Test (pytest) | |
| run: uv run --locked python -m pytest tests/ --cov=src --cov-report=term-missing --cov-fail-under=78 | |
| web-client: | |
| needs: changes | |
| if: needs.changes.outputs.web-client == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| defaults: | |
| run: | |
| working-directory: web-client | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| cache-dependency-path: web-client/package-lock.json | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Lint (ESLint) | |
| run: npm run lint | |
| - name: Format check (Prettier) | |
| run: npm run format:check | |
| # tsc -b inside `build` is the typecheck. | |
| - name: Build | |
| run: npm run build | |
| - name: Test (Vitest) | |
| run: npm run test | |
| openapi: | |
| needs: changes | |
| if: needs.changes.outputs.openapi == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 20 | |
| - name: Lint OpenAPI spec | |
| run: make -C api lint | |
| # Lints the CI/CD surface itself: workflows (actionlint, via the pre-commit | |
| # hook so the version pin lives once in .pre-commit-config.yaml) and | |
| # Dockerfiles (hadolint binary — its pre-commit hook needs docker, so it is | |
| # pinned here and runs only in CI). | |
| infra-lint: | |
| needs: changes | |
| if: needs.changes.outputs.infra == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python 3.12 | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.12" | |
| - name: Cache pre-commit environments | |
| uses: actions/cache@v6 | |
| with: | |
| path: ~/.cache/pre-commit | |
| key: pre-commit-${{ hashFiles('.pre-commit-config.yaml') }} | |
| - name: Lint workflows (actionlint) | |
| run: | | |
| pip install pre-commit | |
| pre-commit run actionlint --all-files | |
| - name: Lint Dockerfiles (hadolint) | |
| run: | | |
| curl -fsSL -o /usr/local/bin/hadolint \ | |
| https://github.com/hadolint/hadolint/releases/download/v2.14.0/hadolint-linux-x86_64 | |
| chmod +x /usr/local/bin/hadolint | |
| git ls-files '*Dockerfile*' | xargs hadolint | |
| # Black-box tests through the gateway against the real stack. These cover the seams | |
| # the per-service suites structurally cannot: the jr_access cookie really becoming the | |
| # bearer header a downstream service accepts, refresh tokens really being single-use in | |
| # Redis, and ownership really holding with two users in one database. | |
| # | |
| # genai is deliberately not started — it calls a live LLM, which costs money per run and | |
| # is not deterministic. Its logic is covered by unit tests in services/genai/tests. | |
| e2e: | |
| needs: changes | |
| if: needs.changes.outputs.e2e == 'true' | |
| runs-on: ubuntu-latest | |
| # Four Spring services are built from source before anything can run. | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| persist-credentials: false | |
| - name: Write compose env | |
| # Throwaway CI credentials. Compose interpolates vars for every service in the | |
| # file — including ones this job never starts — but none are required-style | |
| # (${VAR:?}), so the unset ones only warn. JWT keys must be generated: auth | |
| # refuses to start without explicit keys (no ephemeral fallback), and a fresh | |
| # throwaway pair per run is exactly what a torn-down single-replica stack needs. | |
| run: | | |
| cat > .env <<'EOF' | |
| POSTGRES_USER=jobready | |
| POSTGRES_PASSWORD=jobready | |
| POSTGRES_DB=jobready | |
| JWT_KEY_ID=auth-key-1 | |
| AUTH_REGISTER_MAX_ATTEMPTS=1000 | |
| EOF | |
| ./scripts/gen-jwt-keys.sh >> .env | |
| - name: Start the stack | |
| run: | | |
| docker compose up -d --wait --quiet-pull \ | |
| postgres-db redis auth application document gateway | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 | |
| with: | |
| version: "0.11.18" | |
| - name: Run end-to-end tests | |
| env: | |
| # Without this the suite would skip when the stack is down, and a skipped | |
| # suite reports green — a stack that failed to boot must fail the build. | |
| E2E_REQUIRE_STACK: "1" | |
| run: uv run --with pytest --with httpx python -m pytest e2e_tests/ -v | |
| - name: Service logs on failure | |
| if: failure() | |
| run: docker compose logs --tail=120 auth application document gateway | |
| - name: Tear down | |
| if: always() | |
| run: docker compose down -v --remove-orphans | |
| # The single check branch protection should require. `if: always()` is | |
| # load-bearing: without it a failed dependency would SKIP this job, and | |
| # skipped counts as passing — a gate must always run to be a gate. | |
| ci-ok: | |
| needs: [changes, java, genai, web-client, openapi, infra-lint, e2e] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Fail if any needed job failed or was cancelled | |
| if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') | |
| run: | | |
| echo "::error::A CI job failed: ${{ toJSON(needs.*.result) }}" | |
| exit 1 | |
| - run: echo "All CI jobs passed or were skipped as not affected." |