name: CI

on:
  push:
    branches:
      - main
      - '[0-9]+.[0-9]+.x'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions: {}

defaults:
  run:
    shell: bash

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel
        uses: angular/dev-infra/github-actions/bazel/setup@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Generate JSON schema types
        # Schema types are required to correctly lint the TypeScript code
        run: pnpm run build-schema
      - name: Run ESLint
        run: pnpm lint --cache-strategy content
      - name: Validate NgBot Configuration
        run: pnpm ng-dev ngbot verify
      - name: Validate Circular Dependencies
        run: pnpm ts-circular-deps check
      - name: Run Validation
        run: pnpm admin validate
      - name: Check tooling setup
        run: pnpm check-tooling-setup

  build:
    runs-on: ubuntu-latest
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel
        uses: angular/dev-infra/github-actions/bazel/setup@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel RBE
        uses: angular/dev-infra/github-actions/bazel/configure-remote@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
        with:
          google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Build release targets
        run: pnpm ng-dev release build

  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel
        uses: angular/dev-infra/github-actions/bazel/setup@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel RBE
        uses: angular/dev-infra/github-actions/bazel/configure-remote@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
        with:
          google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Run module and package tests
        run: pnpm bazel test -- //... -//tests/...

  e2e:
    needs: test
    strategy:
      fail-fast: false
      matrix:
        node: [20, 22, 24]
        subset: [esbuild, webpack]
        shard: [0, 1, 2, 3, 4, 5]
    runs-on: ubuntu-latest
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Setup Bazel
        uses: angular/dev-infra/github-actions/bazel/setup@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel RBE
        uses: angular/dev-infra/github-actions/bazel/configure-remote@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
        with:
          google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
      - name: Run CLI E2E tests
        run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }}

  build-e2e-windows:
    runs-on: ubuntu-latest
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel
        uses: angular/dev-infra/github-actions/bazel/setup@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel RBE
        uses: angular/dev-infra/github-actions/bazel/configure-remote@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
        with:
          google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Build E2E tests for Windows on Linux
        run: |
          pnpm bazel build \
            --config=e2e \
            //tests:e2e.webpack_node24 \
            //tests:e2e.esbuild_node24 \
            --platforms=tools:windows_x64
      - name: Store built Windows E2E tests
        uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
        with:
          name: win-e2e-build-artifacts
          path: |
            dist/bin/tests/**
            !**/node_modules/**
          retention-days: 1
          if-no-files-found: 'error'

  e2e-windows:
    needs: build-e2e-windows
    strategy:
      fail-fast: false
      matrix:
        node: [24]
        subset: [esbuild, webpack]
        shard: [0, 1, 2, 3, 4, 5]
    runs-on: windows-2025
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Download built Windows E2E tests
        uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
        with:
          name: win-e2e-build-artifacts
          path: dist/bin/tests/
      - name: Run CLI E2E tests
        uses: ./.github/shared-actions/windows-bazel-test
        with:
          test_target_name: e2e.${{ matrix.subset }}_node${{ matrix.node }}
        env:
          E2E_SHARD_TOTAL: 6
          E2E_SHARD_INDEX: ${{ matrix.shard }}

  e2e-package-managers:
    needs: test
    strategy:
      fail-fast: false
      matrix:
        node: [22]
        subset: [yarn, pnpm, bun]
        shard: [0, 1, 2]
    runs-on: ubuntu-latest
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Setup Bazel
        uses: angular/dev-infra/github-actions/bazel/setup@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel RBE
        uses: angular/dev-infra/github-actions/bazel/configure-remote@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
        with:
          google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
      - name: Run CLI E2E tests
        run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=3 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.${{ matrix.subset }}_node${{ matrix.node }}

  e2e-snapshots:
    needs: test
    if: github.ref == 'refs/heads/main'
    strategy:
      fail-fast: false
      matrix:
        node: [22]
        subset: [esbuild, webpack]
        shard: [0, 1, 2, 3, 4, 5]
    runs-on: ubuntu-latest
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Setup Bazel
        uses: angular/dev-infra/github-actions/bazel/setup@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel RBE
        uses: angular/dev-infra/github-actions/bazel/configure-remote@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
        with:
          google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
      - name: Run CLI E2E tests
        run: pnpm bazel test --test_env=E2E_SHARD_TOTAL=6 --test_env=E2E_SHARD_INDEX=${{ matrix.shard }} --config=e2e //tests:e2e.snapshots.${{ matrix.subset }}_node${{ matrix.node }}

  browsers:
    needs: build
    runs-on: ubuntu-latest
    name: Browser Compatibility Tests
    env:
      SAUCE_TUNNEL_IDENTIFIER: angular-cli-${{ github.workflow }}-${{ github.run_number }}
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Setup Bazel
        uses: angular/dev-infra/github-actions/bazel/setup@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Setup Bazel RBE
        uses: angular/dev-infra/github-actions/bazel/configure-remote@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
        with:
          google_credential: ${{ secrets.RBE_TRUSTED_BUILDS_USER }}
      - name: Run E2E Browser tests
        env:
          SAUCE_USERNAME: ${{ vars.SAUCE_USERNAME }}
          SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
          SAUCE_LOG_FILE: /tmp/angular/sauce-connect.log
          SAUCE_READY_FILE: /tmp/angular/sauce-connect-ready-file.lock
          SAUCE_PID_FILE: /tmp/angular/sauce-connect-pid-file.lock
          SAUCE_TUNNEL_IDENTIFIER: 'angular-${{ github.run_number }}'
          SAUCE_READY_FILE_TIMEOUT: 120
        run: |
          ./scripts/saucelabs/start-tunnel.sh &
          ./scripts/saucelabs/wait-for-tunnel.sh
          pnpm bazel test --config=saucelabs //tests:e2e.saucelabs
          ./scripts/saucelabs/stop-tunnel.sh
      - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
        if: ${{ failure() }}
        with:
          name: sauce-connect-log
          path: ${{ env.SAUCE_CONNECT_DIR_IN_HOST }}/sauce-connect.log

  publish-snapshots:
    needs: build
    runs-on: ubuntu-latest
    env:
      CIRCLE_BRANCH: ${{ github.ref_name }}
    steps:
      - name: Initialize environment
        uses: angular/dev-infra/github-actions/npm/checkout-and-setup-node@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - name: Install node modules
        run: pnpm install --frozen-lockfile
      - name: Setup Bazel
        uses: angular/dev-infra/github-actions/bazel/setup@55af1f65dbeb0fe6a3de1d1134bd0dd8bc5e60cc
      - run: pnpm admin snapshots --verbose
        env:
          SNAPSHOT_BUILDS_GITHUB_TOKEN: ${{ secrets.SNAPSHOT_BUILDS_GITHUB_TOKEN }}
