name: CI
on:
  push:
    branches:
      - master
      - hotfix/**
      - release/**
  pull_request:
    branches:
      - master
permissions:
  id-token: write
  contents: read
jobs:
  codemetrics:
    runs-on: ubuntu-latest
    name: "Log Code Metrics"
    if: github.ref == 'refs/heads/master'
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 18.x
        uses: actions/setup-node@v4
        with:
          node-version: 18.x
      - run: npm ci
      - run: node utils/codeMetrics.js
        env:
          CODE_METRICS_APP_ID: ${{ secrets.CODE_METRICS_APP_ID }}
  compile:
    runs-on: ubuntu-latest
    name: "Compile TypeScript"
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 18.x
        uses: actions/setup-node@v4
        with:
          node-version: 18.x
      - run: npm ci
      - run: npm run compile
      - run: npm run compile:strict
  format:
    runs-on: ubuntu-latest
    name: "Check Format"
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 18.x
        uses: actions/setup-node@v4
        with:
          node-version: 18.x
      - run: npm ci
      - run: npm run format:check
  lint:
    runs-on: ubuntu-latest
    name: "Lint"
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 18.x
        uses: actions/setup-node@v4
        with:
          node-version: 18.x
      - run: npm ci
      - run: npm run lint
  unittest:
    runs-on: ubuntu-latest
    name: "Unit Tests"
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 18.x
        uses: actions/setup-node@v4
        with:
          node-version: 18.x
      - run: npm ci
      - run: npm run test
  build:
    runs-on: ubuntu-latest
    name: "Build"
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 18.x
        uses: actions/setup-node@v4
        with:
          node-version: 18.x
      - run: npm ci
      - run: npm run build:contracts
      - name: Restore Build Cache
        uses: actions/cache@v4
        with:
          path: .cache
          key: ${{ runner.os }}-build-cache
      - run: npm run pack:prod
        env:
          NODE_OPTIONS: "--max-old-space-size=4096"
      - run: cp -r ./Contracts ./dist/contracts
      - run: cp -r ./configs ./dist/configs
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
      - name: "Az CLI login"
        uses: azure/login@v1
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.PREVIEW_SUBSCRIPTION_ID }}
      - name: Upload build to preview blob storage
        run: az storage blob upload-batch -d '$web' -s 'dist' --account-name ${{ secrets.PREVIEW_STORAGE_ACCOUNT_NAME }} --destination-path "${{github.event.pull_request.head.sha || github.sha}}" --auth-mode login --overwrite true
      - name: Upload preview config to blob storage
        run: az storage blob upload -c '$web' -f ./preview/config.json --account-name ${{ secrets.PREVIEW_STORAGE_ACCOUNT_NAME }} --name "${{github.event.pull_request.head.sha || github.sha}}/config.json" --auth-mode login --overwrite true
  nuget:
    name: Publish Nuget
    if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
    needs: [build]
    runs-on: ubuntu-latest
    env:
      NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
      AZURE_DEVOPS_PAT: ${{ secrets.AZURE_DEVOPS_PAT }}
    steps:
      - name: Download Dist Folder
        uses: actions/download-artifact@v4
        with:
          name: dist
      - run: cp ./configs/prod.json config.json
      - run: dotnet nuget add source "$NUGET_SOURCE" --name "ADO" --username "jawelton@microsoft.com" --password "$AZURE_DEVOPS_PAT" --store-password-in-clear-text
      - run: dotnet pack DataExplorer.proj /p:PackageVersion="2.0.0-github-${GITHUB_SHA}"
      - run: dotnet nuget push "bin/Release/*.nupkg" --skip-duplicate --api-key Az --source="$NUGET_SOURCE"
      - run: dotnet nuget remove source "ADO"
      - uses: actions/upload-artifact@v4
        name: Upload package to Artifacts
        with:
          name: prod-package
          path: "bin/Release/*.nupkg"

  nugetmpac:
    name: Publish Nuget MPAC
    if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
    needs: [build]
    runs-on: ubuntu-latest
    env:
      NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
      AZURE_DEVOPS_PAT: ${{ secrets.AZURE_DEVOPS_PAT }}
    steps:
      - name: Download Dist Folder
        uses: actions/download-artifact@v4
        with:
          name: dist
      - run: cp ./configs/mpac.json config.json
      - run: sed -i 's/Azure.Cosmos.DB.Data.Explorer/Azure.Cosmos.DB.Data.Explorer.MPAC/g' DataExplorer.nuspec
      - run: dotnet nuget add source "$NUGET_SOURCE" --name "ADO" --username "jawelton@microsoft.com" --password "$AZURE_DEVOPS_PAT" --store-password-in-clear-text
      - run: dotnet pack DataExplorer.proj /p:PackageVersion="2.0.0-github-${GITHUB_SHA}"
      - run: dotnet nuget push "bin/Release/*.nupkg" --skip-duplicate --api-key Az --source="$NUGET_SOURCE"
      - run: dotnet nuget remove source "ADO"
      - uses: actions/upload-artifact@v4
        name: Upload package to Artifacts
        with:
          name: mpac-package
          path: "bin/Release/*.nupkg"

  playwright-tests:
    name: "Run Playwright Tests (Shard ${{ matrix.shardIndex }} of ${{ matrix.shardTotal }})"
    runs-on: ubuntu-latest
    env:
      NODE_TLS_REJECT_UNAUTHORIZED: 0
      AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
    strategy:
      fail-fast: false
      matrix:
        shardIndex: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
        shardTotal: [16]
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js 18.x
        uses: actions/setup-node@v4
        with:
          node-version: 18.x
      - run: npm ci
      - run: npx playwright install --with-deps
      - name: "Az CLI login"
        uses: Azure/login@v2
        with:
          client-id: ${{ secrets.E2E_TESTS_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      # We can't use MSAL within playwright so we acquire tokens prior to running the tests
      - name: "Acquire RBAC tokens for test accounts"
        uses: azure/cli@v2
        with:
          azcliversion: latest
          inlineScript: |
            NOSQL_TESTACCOUNT_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql.documents.azure.com/.default" -o tsv --query accessToken)
            echo "::add-mask::$NOSQL_TESTACCOUNT_TOKEN"
            echo NOSQL_TESTACCOUNT_TOKEN=$NOSQL_TESTACCOUNT_TOKEN >> $GITHUB_ENV
            NOSQL_READONLY_TESTACCOUNT_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-readonly.documents.azure.com/.default" -o tsv --query accessToken)
            echo "::add-mask::$NOSQL_READONLY_TESTACCOUNT_TOKEN"
            echo NOSQL_READONLY_TESTACCOUNT_TOKEN=$NOSQL_READONLY_TESTACCOUNT_TOKEN >> $GITHUB_ENV
            TABLE_TESTACCOUNT_TOKEN=$(az account get-access-token --scope "https://github-e2etests-tables.documents.azure.com/.default" -o tsv --query accessToken)
            echo "::add-mask::$TABLE_TESTACCOUNT_TOKEN"
            echo TABLE_TESTACCOUNT_TOKEN=$TABLE_TESTACCOUNT_TOKEN >> $GITHUB_ENV
            GREMLIN_TESTACCOUNT_TOKEN=$(az account get-access-token --scope "https://github-e2etests-gremlin.documents.azure.com/.default" -o tsv --query accessToken)
            echo "::add-mask::$GREMLIN_TESTACCOUNT_TOKEN"
            echo GREMLIN_TESTACCOUNT_TOKEN=$GREMLIN_TESTACCOUNT_TOKEN >> $GITHUB_ENV
      - name: Run test shard ${{ matrix['shardIndex'] }} of ${{ matrix['shardTotal']}}
        run: npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --workers=3
      - name: Upload blob report to GitHub Actions Artifacts
        if: ${{ !cancelled() }}
        uses: actions/upload-artifact@v4
        with:
          name: blob-report-${{ matrix.shardIndex }}
          path: blob-report
          retention-days: 1

  merge-playwright-reports:
    name: "Merge Playwright Reports"
    # Merge reports after playwright-tests, even if some shards have failed
    if: ${{ !cancelled() }}
    needs: [playwright-tests]

    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 18
      - name: Install dependencies
        run: npm ci

      - name: Download blob reports from GitHub Actions Artifacts
        uses: actions/download-artifact@v4
        with:
          path: all-blob-reports
          pattern: blob-report-*
          merge-multiple: true

      - name: Merge into HTML Report
        run: npx playwright merge-reports --reporter html ./all-blob-reports

      - name: Upload HTML report
        uses: actions/upload-artifact@v4
        with:
          name: html-report--attempt-${{ github.run_attempt }}
          path: playwright-report
          retention-days: 14
