chore: Allow .claude config files in gitignore #261
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 | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| JAVA_VERSION: '17' | |
| NODE_VERSION: '22.x' | |
| PNPM_VERSION: '10' | |
| jobs: | |
| # --- Changes detection --- | |
| changes: | |
| name: Detect Changes | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| outputs: | |
| backend: ${{ steps.filter.outputs.backend }} | |
| console: ${{ steps.filter.outputs.console }} | |
| management: ${{ steps.filter.outputs.management }} | |
| docker: ${{ steps.filter.outputs.docker }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Detect changed paths | |
| id: filter | |
| uses: dorny/paths-filter@v4 | |
| with: | |
| filters: | | |
| backend: | |
| - 'backend-spring/**' | |
| - 'db-manager/migrations/**' | |
| - '.github/workflows/ci.yml' | |
| console: | |
| - 'console/**' | |
| - '.github/workflows/ci.yml' | |
| management: | |
| - 'management/**' | |
| - '.github/workflows/ci.yml' | |
| docker: | |
| - 'backend-spring/Dockerfile' | |
| - 'console/Dockerfile' | |
| - 'management/Dockerfile' | |
| - 'docker-compose*.yml' | |
| - '.dockerignore' | |
| - 'console/nginx.conf' | |
| - 'management/nginx.conf' | |
| - '.github/workflows/ci.yml' | |
| # --- Backend: Build --- | |
| backend-build: | |
| name: Backend Build | |
| needs: changes | |
| if: needs.changes.outputs.backend == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Setup JDK 17 | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: ${{ env.JAVA_VERSION }} | |
| cache: 'maven' | |
| - name: Grant Maven wrapper execute permission | |
| run: chmod +x backend-spring/mvnw | |
| - name: Build with Maven | |
| run: cd backend-spring && ./mvnw compile -B | |
| # --- Backend: Test --- | |
| backend-test: | |
| name: Backend Test | |
| needs: [changes, backend-build] | |
| if: needs.changes.outputs.backend == 'true' | |
| runs-on: ubuntu-latest | |
| services: | |
| mysql: | |
| image: mysql:9.1 | |
| env: | |
| MYSQL_ROOT_PASSWORD: root | |
| MYSQL_DATABASE: ulticode_test | |
| MYSQL_USER: ulticode | |
| MYSQL_PASSWORD: ulticode | |
| ports: | |
| - 23306:3306 | |
| options: >- | |
| --health-cmd="mysqladmin ping -h localhost -u root -proot" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=5 | |
| redis: | |
| image: redis:7-alpine | |
| ports: | |
| - 26379:6379 | |
| options: >- | |
| --health-cmd="redis-cli ping" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=5 | |
| env: | |
| DB_HOST: localhost | |
| DB_PORT: 23306 | |
| DB_USER: ulticode | |
| DB_PASSWORD: ulticode | |
| DB_NAME: ulticode_test | |
| REDIS_HOST: localhost | |
| REDIS_PORT: 26379 | |
| JWT_SECRET: test-jwt-secret-key-for-ci-minimum-32-characters-long | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Setup JDK 17 | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: ${{ env.JAVA_VERSION }} | |
| cache: 'maven' | |
| - name: Grant Maven wrapper execute permission | |
| run: chmod +x backend-spring/mvnw | |
| - name: Run tests with CI profile | |
| run: cd backend-spring && ./mvnw test -Dspring.profiles.active=ci -Dtest='!*IT' -B | |
| - name: Upload test results on failure | |
| if: failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: test-results-backend | |
| path: backend-spring/target/surefire-reports/ | |
| retention-days: 7 | |
| # --- Backend: Validate Migrations --- | |
| migrate-validate: | |
| name: Validate Migrations | |
| needs: changes | |
| if: needs.changes.outputs.backend == 'true' | |
| runs-on: ubuntu-latest | |
| services: | |
| mysql: | |
| image: mysql:9.1 | |
| env: | |
| MYSQL_ROOT_PASSWORD: root | |
| MYSQL_DATABASE: ulticode_test | |
| MYSQL_USER: ulticode | |
| MYSQL_PASSWORD: ulticode | |
| ports: | |
| - 23306:3306 | |
| options: >- | |
| --health-cmd="mysqladmin ping -h localhost -u root -proot" | |
| --health-interval=10s | |
| --health-timeout=5s | |
| --health-retries=5 | |
| env: | |
| DB_HOST: localhost | |
| DB_PORT: 23306 | |
| DB_USER: ulticode | |
| DB_PASSWORD: ulticode | |
| DB_NAME: ulticode_test | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Setup Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| - name: Install db-manager | |
| run: pip install -e ./db-manager | |
| - name: Install Flyway CLI | |
| run: | | |
| # The maven central flyway 11.3.4 bundle has a broken Alpine JRE on Ubuntu. | |
| # We extract the bundle, then write a wrapper that invokes Java directly | |
| # with the correct classpath (skipping the broken shell script JRE detection). | |
| curl -L https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/10.17.0/flyway-commandline-10.17.0-linux-x64.tar.gz -o /tmp/flyway.tar.gz | |
| tar -xzf /tmp/flyway.tar.gz -C /tmp | |
| # Write a wrapper that bypasses the broken JRE detection entirely | |
| cat > /tmp/flyway-wrapper.sh << 'WRAPPER' | |
| #!/usr/bin/env bash | |
| FLYWAY_DIR="${FLYWAY_DIR:-/tmp/flyway-10.17.0}" | |
| JAVA_CMD="${JAVA_HOME:-$(which java)}/bin/java" | |
| CP="$FLYWAY_DIR/lib/*:$FLYWAY_DIR/lib/flyway/*:$FLYWAY_DIR/lib/aad/*:$FLYWAY_DIR/lib/plugins/*:$FLYWAY_DIR/lib/netty/*:$FLYWAY_DIR/lib/opentelemetry/*:$FLYWAY_DIR/drivers/*" | |
| exec "$JAVA_CMD" -Djava.security.egd=file:/dev/../dev/urandom -cp "$CP" org.flywaydb.commandline.Main "$@" | |
| WRAPPER | |
| chmod +x /tmp/flyway-wrapper.sh | |
| sudo cp /tmp/flyway-wrapper.sh /usr/local/bin/flyway | |
| sudo chmod +x /usr/local/bin/flyway | |
| flyway --version | |
| - name: Wait for MySQL | |
| run: | | |
| for i in $(seq 1 30); do | |
| if mysqladmin ping -h localhost -P 23306 -u ulticode -pulticode 2>/dev/null; then | |
| echo "MySQL is ready" | |
| break | |
| fi | |
| echo "Waiting for MySQL... ($i/30)" | |
| sleep 2 | |
| done | |
| - name: Run and validate migrations | |
| run: | | |
| cd db-manager | |
| python -m db_manager.cli migrate | |
| python -m db_manager.cli validate || echo "Validate command not available, migrations applied successfully" | |
| # --- Frontend: Lint --- | |
| frontend-lint: | |
| name: Lint (${{ matrix.app }}) | |
| needs: changes | |
| if: needs.changes.outputs.console == 'true' || needs.changes.outputs.management == 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| app: [console, management] | |
| steps: | |
| - name: Check if app changed | |
| id: should-run | |
| if: (matrix.app == 'console' && needs.changes.outputs.console == 'true') || (matrix.app == 'management' && needs.changes.outputs.management == 'true') | |
| run: echo "run=true" >> $GITHUB_OUTPUT | |
| - name: Checkout repository | |
| if: steps.should-run.outputs.run == 'true' | |
| uses: actions/checkout@v6 | |
| - name: Enable pnpm via corepack | |
| if: steps.should-run.outputs.run == 'true' | |
| run: corepack enable && corepack prepare pnpm@${{ env.PNPM_VERSION }} --activate | |
| - name: Setup Node.js | |
| if: steps.should-run.outputs.run == 'true' | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| cache-dependency-path: ${{ matrix.app }}/pnpm-lock.yaml | |
| - name: Install dependencies | |
| if: steps.should-run.outputs.run == 'true' | |
| working-directory: ${{ matrix.app }} | |
| env: | |
| CI: "false" | |
| GITHUB_ACTIONS: "false" | |
| run: pnpm install | |
| - name: Run lint | |
| if: steps.should-run.outputs.run == 'true' | |
| working-directory: ${{ matrix.app }} | |
| run: pnpm lint | |
| # --- Frontend: Type Check --- | |
| frontend-type-check: | |
| name: Type Check (${{ matrix.app }}) | |
| needs: changes | |
| if: needs.changes.outputs.console == 'true' || needs.changes.outputs.management == 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| app: [console, management] | |
| steps: | |
| - name: Check if app changed | |
| id: should-run | |
| if: (matrix.app == 'console' && needs.changes.outputs.console == 'true') || (matrix.app == 'management' && needs.changes.outputs.management == 'true') | |
| run: echo "run=true" >> $GITHUB_OUTPUT | |
| - name: Checkout repository | |
| if: steps.should-run.outputs.run == 'true' | |
| uses: actions/checkout@v6 | |
| - name: Enable pnpm via corepack | |
| if: steps.should-run.outputs.run == 'true' | |
| run: corepack enable && corepack prepare pnpm@${{ env.PNPM_VERSION }} --activate | |
| - name: Setup Node.js | |
| if: steps.should-run.outputs.run == 'true' | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| cache-dependency-path: ${{ matrix.app }}/pnpm-lock.yaml | |
| - name: Install dependencies | |
| if: steps.should-run.outputs.run == 'true' | |
| working-directory: ${{ matrix.app }} | |
| env: | |
| CI: "false" | |
| GITHUB_ACTIONS: "false" | |
| run: pnpm install | |
| - name: Run type-check | |
| if: steps.should-run.outputs.run == 'true' | |
| working-directory: ${{ matrix.app }} | |
| run: pnpm type-check | |
| # --- Frontend: Test --- | |
| frontend-test: | |
| name: Test (${{ matrix.app }}) | |
| needs: changes | |
| if: needs.changes.outputs.console == 'true' || needs.changes.outputs.management == 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| app: [console, management] | |
| steps: | |
| - name: Check if app changed | |
| id: should-run | |
| if: (matrix.app == 'console' && needs.changes.outputs.console == 'true') || (matrix.app == 'management' && needs.changes.outputs.management == 'true') | |
| run: echo "run=true" >> $GITHUB_OUTPUT | |
| - name: Checkout repository | |
| if: steps.should-run.outputs.run == 'true' | |
| uses: actions/checkout@v6 | |
| - name: Enable pnpm via corepack | |
| if: steps.should-run.outputs.run == 'true' | |
| run: corepack enable && corepack prepare pnpm@${{ env.PNPM_VERSION }} --activate | |
| - name: Setup Node.js | |
| if: steps.should-run.outputs.run == 'true' | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| cache-dependency-path: ${{ matrix.app }}/pnpm-lock.yaml | |
| - name: Install dependencies | |
| if: steps.should-run.outputs.run == 'true' | |
| working-directory: ${{ matrix.app }} | |
| env: | |
| CI: "false" | |
| GITHUB_ACTIONS: "false" | |
| run: pnpm install | |
| - name: Run tests | |
| if: steps.should-run.outputs.run == 'true' | |
| working-directory: ${{ matrix.app }} | |
| run: pnpm test | |
| # --- Frontend: i18n Check (management only) --- | |
| frontend-i18n-check: | |
| name: i18n Check (management) | |
| needs: changes | |
| if: needs.changes.outputs.management == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Enable pnpm via corepack | |
| run: corepack enable && corepack prepare pnpm@${{ env.PNPM_VERSION }} --activate | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| cache-dependency-path: management/pnpm-lock.yaml | |
| - name: Install dependencies | |
| working-directory: management | |
| env: | |
| CI: "false" | |
| GITHUB_ACTIONS: "false" | |
| run: pnpm install | |
| - name: Run i18n completeness check | |
| working-directory: management | |
| run: pnpm check:i18n --json | |
| - name: Run i18n tests | |
| working-directory: management | |
| run: pnpm vitest run -- src/i18n/__tests__/ | |
| # --- Docker Build Verification --- | |
| docker-verify: | |
| name: Docker Build (${{ matrix.service.name }}) | |
| needs: changes | |
| if: needs.changes.outputs.docker == 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| service: | |
| - name: backend | |
| dockerfile: ./backend-spring/Dockerfile | |
| - name: console | |
| dockerfile: ./console/Dockerfile | |
| - name: management | |
| dockerfile: ./management/Dockerfile | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Build Docker image (no push) | |
| uses: docker/build-push-action@v7 | |
| with: | |
| context: . | |
| file: ${{ matrix.service.dockerfile }} | |
| push: false | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max |