name: CI Pipeline for the Backend and Frontend

on:
  pull_request:
    types: [opened, review_requested, synchronize]
  push:
    branches:
      - master

jobs:
  backend:
    if: "(github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')) || github.event_name == 'push'"
    strategy:
      matrix:
        node: ["22.14.0"]
        flavor: ["dev", "prod"]
      fail-fast: false
    runs-on: ubuntu-latest

    name: Backend (${{ matrix.flavor }}) - node ${{ matrix.node }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          path: ${{ matrix.node }}/${{ matrix.flavor }}

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node }}
          registry-url: "https://registry.npmjs.org"

      - name: Read rust-toolchain file from repository
        id: gettoolchain
        run: echo "::set-output name=toolchain::$(cat ./rust/gbt/rust-toolchain)"
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}

      - name: Install ${{ steps.gettoolchain.outputs.toolchain }} Rust toolchain
        # Latest version available on this commit is 1.71.1
        # Commit date is Aug 3, 2023
        uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a
        with:
          toolchain: ${{ steps.gettoolchain.outputs.toolchain }}

      - name: Install
        if: ${{ matrix.flavor == 'dev'}}
        run: npm ci
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend

      - name: Install (Prod dependencies only)
        if: ${{ matrix.flavor == 'prod'}}
        run: npm ci --omit=dev --omit=optional
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend

      - name: Lint
        if: ${{ matrix.flavor == 'dev'}}
        run: npm run lint
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend

      - name: Unit Tests
        if: ${{ matrix.flavor == 'dev'}}
        run: npm run test:ci
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend

      - name: Build
        run: npm run build
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend


  cache:
    name: "Cache assets for builds"
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          path: assets

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node }}
          registry-url: "https://registry.npmjs.org"

      - name: Install (Prod dependencies only)
        run: npm ci --omit=dev --omit=optional
        working-directory: assets/frontend

      - name: Restore cached mining pool assets
        continue-on-error: true
        id: cache-mining-pool-restore
        uses: actions/cache/restore@v4
        with:
          path: |
            mining-pool-assets.zip
          key: mining-pool-assets-cache

      - name: Restore promo video assets
        continue-on-error: true
        id: cache-promo-video-restore
        uses: actions/cache/restore@v4
        with:
          path: |
            promo-video-assets.zip
          key: promo-video-assets-cache

      - name: Unzip assets before building (src/resources)
        continue-on-error: true
        run: unzip -o mining-pool-assets.zip -d assets/frontend/src/resources/mining-pools

      - name: Unzip assets before building (src/resources)
        continue-on-error: true
        run: unzip -o promo-video-assets.zip -d assets/frontend/src/resources/promo-video

      # - name: Unzip assets before building (dist)
      #   continue-on-error: true
      #   run: unzip assets.zip -d assets/frontend/dist/mempool/browser/resources

      - name: Sync-assets
        run: npm run sync-assets-dev
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          MEMPOOL_CDN: 1
          VERBOSE: 1
        working-directory: assets/frontend

      - name: Zip mining-pool assets
        run: zip -jrq mining-pool-assets.zip assets/frontend/src/resources/mining-pools/*

      - name: Zip promo-video assets
        run: zip -jrq promo-video-assets.zip assets/frontend/src/resources/promo-video/*

      - name: Upload mining pool assets as artifact
        uses: actions/upload-artifact@v4
        with:
          name: mining-pool-assets
          path: mining-pool-assets.zip

      - name: Upload promo video assets as artifact
        uses: actions/upload-artifact@v4
        with:
          name: promo-video-assets
          path: promo-video-assets.zip

      - name: Save mining pool assets cache
        id: cache-mining-pool-save
        uses: actions/cache/save@v4
        with:
          path: |
            mining-pool-assets.zip
          key: mining-pool-assets-cache

      - name: Save promo video assets cache
        id: cache-promo-video-save
        uses: actions/cache/save@v4
        with:
          path: |
            promo-video-assets.zip
          key: promo-video-assets-cache

  frontend:
    needs: cache
    if: "(github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')) || github.event_name == 'push'"
    strategy:
      matrix:
        node: ["22.14.0"]
        flavor: ["dev", "prod"]
      fail-fast: false
    runs-on: ubuntu-latest

    name: Frontend (${{ matrix.flavor }}) - node ${{ matrix.node }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          path: ${{ matrix.node }}/${{ matrix.flavor }}

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node }}
          registry-url: "https://registry.npmjs.org"

      - name: Install (Prod dependencies only)
        run: npm ci --omit=dev --omit=optional
        if: ${{ matrix.flavor == 'prod'}}
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/frontend

      - name: Install
        if: ${{ matrix.flavor == 'dev'}}
        run: npm ci
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/frontend

      - name: Lint
        if: ${{ matrix.flavor == 'dev'}}
        run: npm run lint
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/frontend

      # - name: Test
      #   run: npm run test

      - name: Restore cached mining pool assets
        continue-on-error: true
        id: cache-mining-pool-restore
        uses: actions/cache/restore@v4
        with:
          path: |
            mining-pool-assets.zip
          key: mining-pool-assets-cache

      - name: Restore promo video assets
        continue-on-error: true
        id: cache-promo-video-restore
        uses: actions/cache/restore@v4
        with:
          path: |
            promo-video-assets.zip
          key: promo-video-assets-cache

      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: mining-pool-assets

      - name: Unzip assets before building (src/resources)
        run: unzip -o mining-pool-assets.zip -d ${{ matrix.node }}/${{ matrix.flavor }}/frontend/src/resources/mining-pools

      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: promo-video-assets

      - name: Unzip assets before building (src/resources)
        run: unzip -o promo-video-assets.zip -d ${{ matrix.node }}/${{ matrix.flavor }}/frontend/src/resources/promo-video

      # - name: Unzip assets before building (dist)
      #   run: unzip assets.zip -d ${{ matrix.node }}/${{ matrix.flavor }}/frontend/dist/mempool/browser/resources

      - name: Display resulting source tree
        run: ls -R

      - name: Build
        run: npm run build
        working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/frontend
        env: 
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          MEMPOOL_CDN: 1
          VERBOSE: 1
  
  e2e:
    if: "(github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')) || github.event_name == 'push'"
    runs-on: ubuntu-latest
    needs: frontend
    strategy:
      fail-fast: false
      matrix:
        module: ["mempool", "liquid", "testnet4"]

    name: E2E tests for ${{ matrix.module }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          path: ${{ matrix.module }}

      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: 22
          cache: "npm"
          cache-dependency-path: ${{ matrix.module }}/frontend/package-lock.json

      - name: Restore cached mining pool assets
        continue-on-error: true
        id: cache-mining-pool-restore
        uses: actions/cache/restore@v4
        with:
          path: |
            mining-pool-assets.zip
          key: mining-pool-assets-cache
  
      - name: Restore cached promo video assets
        continue-on-error: true
        id: cache-promo-video-restore
        uses: actions/cache/restore@v4
        with:
          path: |
            promo-video-assets.zip
          key: promo-video-assets-cache

      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: mining-pool-assets

      - name: Unzip assets before building (src/resources)
        run: unzip -o mining-pool-assets.zip -d ${{ matrix.module }}/frontend/src/resources/mining-pools

      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: promo-video-assets

      - name: Unzip assets before building (src/resources)
        run: unzip -o promo-video-assets.zip -d ${{ matrix.module }}/frontend/src/resources/promo-video

      # mempool
      - name: Chrome browser tests (${{ matrix.module }})
        if: ${{ matrix.module == 'mempool' }}
        uses: cypress-io/github-action@v5
        with:
          tag: ${{ github.event_name }}
          working-directory: ${{ matrix.module }}/frontend
          build: npm run config:defaults:${{ matrix.module }}
          start: npm run start:parameterized
          wait-on: "http://localhost:4200"
          wait-on-timeout: 120
          record: true
          parallel: true
          spec: |
            cypress/e2e/mainnet/*.spec.ts
            cypress/e2e/signet/*.spec.ts
          group: Tests on Chrome (${{ matrix.module }})
          browser: "chrome"
          ci-build-id: "${{ github.sha }}-${{ github.workflow }}-${{ github.event_name }}"
        env:
          COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }}
          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}

      # liquid
      - name: Chrome browser tests (${{ matrix.module }})
        if: ${{ matrix.module == 'liquid' }}
        uses: cypress-io/github-action@v5
        with:
          tag: ${{ github.event_name }}
          working-directory: ${{ matrix.module }}/frontend
          build: npm run config:defaults:${{ matrix.module }}
          start: npm run start:parameterized
          wait-on: "http://localhost:4200"
          wait-on-timeout: 120
          record: true
          parallel: true
          spec: |
            cypress/e2e/liquid/liquid.spec.ts
            cypress/e2e/liquidtestnet/liquidtestnet.spec.ts
          group: Tests on Chrome (${{ matrix.module }})
          browser: "chrome"
          ci-build-id: "${{ github.sha }}-${{ github.workflow }}-${{ github.event_name }}"
        env:
          COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }}
          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}

      # testnet
      - name: Chrome browser tests (${{ matrix.module }})
        if: ${{ matrix.module == 'testnet4' }}
        uses: cypress-io/github-action@v5
        with:
          tag: ${{ github.event_name }}
          working-directory: ${{ matrix.module }}/frontend
          build: npm run config:defaults:mempool
          start: npm run start:parameterized
          wait-on: "http://localhost:4200"
          wait-on-timeout: 120
          record: true
          parallel: true
          spec: |
            cypress/e2e/testnet4/*.spec.ts
          group: Tests on Chrome (${{ matrix.module }})
          browser: "chrome"
          ci-build-id: "${{ github.sha }}-${{ github.workflow }}-${{ github.event_name }}"
        env:
          CYPRESS_REROUTE_TESTNET: true
          COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }}
          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }}
  validate_docker_json:
    if: "(github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')) || github.event_name == 'push'"
    runs-on: ubuntu-latest
    name: Validate generated backend Docker JSON

    steps: 
      - name: Checkout
        uses: actions/checkout@v3
        with:
          path: docker
      
      - name: Install jq
        run: sudo apt-get install jq -y

      - name: Create new start script to run on CI
        run: |
          sed '$d' start.sh > start_ci.sh
        working-directory: docker/docker/backend

      - name: Run the script to generate the sample JSON
        run: |
          sh start_ci.sh
        working-directory: docker/docker/backend

      - name: Validate JSON syntax
        run: |
          cat mempool-config.json | jq
        working-directory: docker/docker/backend