# ============================================================================= # Node.js CI Pipeline # Runs: lint (eslint), type check (tsc), test (vitest), build # ============================================================================= name: Node CI on: push: branches: [main] paths: - "**.ts" - "**.tsx" - "**.js" - "**.jsx" - "package.json" - "pnpm-lock.yaml" - "tsconfig.json" - ".github/workflows/ci-node.yaml" pull_request: branches: [main] paths: - "**.ts" - "**.tsx" - "**.js" - "**.jsx" - "package.json" - "pnpm-lock.yaml" - "tsconfig.json" - ".github/workflows/ci-node.yaml" permissions: contents: read env: NODE_VERSION: "22" jobs: # --------------------------------------------------------------------------- # Install dependencies (shared across jobs via cache) # --------------------------------------------------------------------------- install: name: Install runs-on: ubuntu-latest timeout-minutes: 5 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: version: latest - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" - name: Install dependencies run: pnpm install --frozen-lockfile # --------------------------------------------------------------------------- # Lint with ESLint # --------------------------------------------------------------------------- lint: name: Lint needs: install runs-on: ubuntu-latest timeout-minutes: 5 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: version: latest - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" - run: pnpm install --frozen-lockfile - run: pnpm lint # --------------------------------------------------------------------------- # Type check with TypeScript compiler # --------------------------------------------------------------------------- type-check: name: Type Check needs: install runs-on: ubuntu-latest timeout-minutes: 5 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: version: latest - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" - run: pnpm install --frozen-lockfile - run: pnpm tsc --noEmit # --------------------------------------------------------------------------- # Test with Vitest # --------------------------------------------------------------------------- test: name: Test needs: install runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: version: latest - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" - run: pnpm install --frozen-lockfile - name: Run tests with coverage run: pnpm vitest run --coverage --reporter=junit --outputFile=junit.xml - name: Upload coverage report if: always() uses: actions/upload-artifact@v4 with: name: coverage-report path: coverage/ retention-days: 7 - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: name: test-results path: junit.xml retention-days: 7 # --------------------------------------------------------------------------- # Build # --------------------------------------------------------------------------- build: name: Build needs: [lint, type-check, test] runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 with: version: latest - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" - run: pnpm install --frozen-lockfile - run: pnpm build - name: Upload build artifacts uses: actions/upload-artifact@v4 with: name: build-output path: dist/ retention-days: 7