name: CI on: push: branches: - main paths-ignore: - "**.md" - "LICENSE" - ".gitignore" - ".editorconfig" - ".vscode/**" - "docs/**" - ".prettierrc*" - ".eslintrc*" - ".github/ISSUE_TEMPLATE/**" - ".github/PULL_REQUEST_TEMPLATE/**" pull_request: branches: - main paths-ignore: - "**.md" - "LICENSE" - ".gitignore" - ".editorconfig" - ".vscode/**" - "docs/**" - ".prettierrc*" - ".eslintrc*" - ".github/ISSUE_TEMPLATE/**" - ".github/PULL_REQUEST_TEMPLATE/**" workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: contents: read jobs: lint: name: Lint runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v6 - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: "24" cache: "npm" - name: Install dependencies run: npm ci - name: Run ESLint run: npm run lint - name: Check formatting run: npm run format:check test: name: Test and Coverage runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v6 - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: "24" cache: "npm" - name: Install dependencies run: npm ci - name: Run tests run: npm run test:run env: CI: true - name: Generate coverage report run: npm run test:coverage env: CI: true - name: Normalize coverage paths for Codecov if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} run: | python - <<'PY' from pathlib import Path path = Path("coverage/lcov.info") lines = path.read_text(encoding="utf-8").splitlines() normalized = [] for line in lines: if line.startswith("SF:"): normalized.append("SF:" + line[3:].replace("\\", "/")) else: normalized.append(line) path.write_text("\n".join(normalized) + "\n", encoding="utf-8") PY - name: Show normalized coverage file entries if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} run: grep '^SF:' coverage/lcov.info | head - name: Upload coverage to Codecov if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} uses: codecov/codecov-action@v6 with: files: ./coverage/lcov.info flags: unit name: unit-coverage disable_search: true fail_ci_if_error: true verbose: true env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} typecheck: name: Type Check runs-on: ubuntu-latest timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v6 - name: Setup Node.js uses: actions/setup-node@v6 with: node-version: "24" cache: "npm" - name: Install dependencies run: npm ci - name: Run type check run: npm run type-check