name: CI
on:
  pull_request:
  push:
    branches:
      - master
      - main
      - dev
    tags:
      - "*"

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

env:
  NODE_OPTIONS: --enable-source-maps

jobs:
  Build:
    runs-on: ${{ matrix.os }}
    name: Build
    if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-22.04
        node:
          - 22.6.0
        pnpm:
          - 9.10.0
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}

      - name: Setup Pnpm
        uses: pnpm/action-setup@v2
        with:
          version: ${{ matrix.pnpm }}

      - name: Install
        run: |
          pnpm install

      - name: Build
        run: |
          pnpm build
          pnpm build.docker-ci

      - name: Lint
        run: |
          pnpm run test.lint

      - name: Validate Dist
        run: |
          if [ "$(git diff --ignore-space-at-eol --text dist/ | wc -l)" -gt "0" ]; then
            echo "Detected uncommitted changes after build. See status below:"
            git diff --ignore-space-at-eol --text dist/ ':(exclude)*.js.map'
            exit 1
          fi

      - name: Upload Dist
        uses: actions/upload-artifact@v3
        if: always()
        with:
          name: dist
          path: |
            ./dist
            ./packages/*/dist
            ./dev/docker/__tests__/
          retention-days: 1

  BuildExecutable:
    name: Build-Executable-${{ matrix.os }}
    needs: [Build]
    if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os:
          - windows-2022
          - ubuntu-24.04
          - macos-13
          - macos-14 # arm64
        node:
          - 22
        pnpm:
          - 9.10.0
    steps:
      - uses: actions/checkout@v4

      - name: Download Artifacts
        uses: actions/download-artifact@v3
        with:
          name: dist

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}

      - name: Setup Pnpm
        uses: pnpm/action-setup@v2
        with:
          version: ${{ matrix.pnpm }}

      - name: Cache node_modules
        uses: actions/cache@v4
        with:
          path: |
            ~/.pnpm-store
            D:\.pnpm-store
            ./node_modules
          key: "setupcpp-node_modules-cache-OS:${{ matrix.os }}-node:${{ matrix.node }}-pnpm:${{ matrix.pnpm }}-${{ hashFiles('./.npmrc') }}-deps:${{ hashFiles('./package.json') }}"
          restore-keys: |
            "setupcpp-node_modules-cache-OS:${{ matrix.os }}-"

      - name: Install
        run: |
          pnpm install

      # Create self-contained executable that bundles Nodejs
      - name: Create Executable
        run: |
          pnpm run pack.exe

      - name: Upload Executables
        uses: actions/upload-artifact@v3
        with:
          name: exe
          path: |
            ./exe
          retention-days: 1

  Test:
    name: Test-${{ matrix.os }}
    if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
    needs: [Build]
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os:
          - windows-2022
          - windows-2019
          - ubuntu-24.04
          - ubuntu-22.04
          - ubuntu-20.04
          - macos-14
          - macos-13
          - macos-12
        node:
          - 22
        pnpm:
          - 9.10.0
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true

      - name: Download Dist
        uses: actions/download-artifact@v3
        with:
          name: dist

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}

      - name: Setup Pnpm
        uses: pnpm/action-setup@v2
        with:
          version: ${{ matrix.pnpm }}

      - name: Cache node_modules
        uses: actions/cache@v4
        with:
          path: |
            ~/.pnpm-store
            D:\.pnpm-store
            ./node_modules
          key: "setupcpp-node_modules-cache-OS:${{ matrix.os }}-node:${{ matrix.node }}-pnpm:${{ matrix.pnpm }}-${{ hashFiles('./.npmrc') }}-deps:${{ hashFiles('./package.json') }}"
          restore-keys: |
            "setupcpp-node_modules-cache-OS:${{ matrix.os }}-"

      - name: Install
        run: |
          pnpm install

      # - name: Setup SSH debugging session
      #   uses: mxschmitt/action-tmate@v3

      - name: Tests
        if: ${{ !contains(github.event.head_commit.message, '[skip test]') }}
        run: |
          pnpm run test
        env:
          RUNNER_OS_NAME: ${{ matrix.os }}

      - name: Setup Node 20
        uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Smoke Test Modern Bundle
        if: ${{ !contains(github.event.head_commit.message, '[skip test]') }}
        run: |
          node ./dist/modern/setup-cpp.mjs --help
          node ./dist/modern/setup-cpp.mjs --gcc true --cmake true
        env:
          RUNNER_OS_NAME: ${{ matrix.os }}

      - name: Setup Node 12
        if: ${{ !contains(matrix.os, 'macos-14') }}
        uses: actions/setup-node@v4
        with:
          node-version: 12
      - name: Smoke Test Legacy Bundle
        run: |
          node ./dist/legacy/setup-cpp.js --help
          node ./dist/legacy/setup-cpp.js --gcc true --cmake true

  Docker:
    name: Docker-${{ matrix.container.image }}
    if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
    needs: [Build]
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-24.04
        node:
          - 22
        pnpm:
          - 9.10.0
        container:
          - { file: "ubuntu-llvm.dockerfile", image: "setup-cpp-ubuntu-llvm", tag: "22.04-0.41.1" }
          - { file: "fedora-llvm.dockerfile", image: "setup-cpp-fedora-llvm", tag: "40-0.41.1" }
          - { file: "arch-llvm.dockerfile", image: "setup-cpp-arch-llvm", tag: "base-0.41.1" }
          - { file: "ubuntu-mingw.dockerfile", image: "setup-cpp-ubuntu-mingw", tag: "22.04-0.41.1" }
          # - { file: "fedora-mingw.dockerfile", image: "setup-cpp-fedora-mingw", tag: "40-0.41.1" }
          # - { file: "arch-mingw.dockerfile", image: "setup-cpp-arch-mingw", tag: "base-0.41.1" }
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true

      - name: Download Dist
        uses: actions/download-artifact@v3
        with:
          name: dist

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        if: ${{ github.event_name != 'pull_request' }}
        with:
          username: aminya
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./dev/docker/ci/${{ matrix.container.file }}
          push: ${{ github.event_name != 'pull_request' }}
          tags: aminya/${{ matrix.container.image }}:${{ matrix.container.tag }},aminya/${{ matrix.container.image }}:latest

      - name: Test
        uses: docker/build-push-action@v6
        with:
          context: .
          file: ./dev/docker/examples/${{ matrix.container.file }}
          push: false
          tags: aminya/test-${{ matrix.container.image }}:${{ matrix.container.tag }}

  Release:
    if: startsWith(github.ref, 'refs/tags/')
    needs: [Build, BuildExecutable, Test, Docker]
    runs-on: ubuntu-24.04
    steps:
      - name: Download All Artifacts
        uses: actions/download-artifact@v3

      - name: Place Artifacts
        shell: bash
        run: |
          mv -v ./dist/ ./dist-artifacts
          mv -v ./dist-artifacts/* ./

          chmod +x -R ./exe/

      - name: Draft the release
        uses: meeDamian/github-release@2.0
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          gzip: folders
          draft: true
          files: >
            ./exe/setup-cpp-x64-windows.exe
            ./exe/setup-cpp-x64-linux
            ./exe/setup-cpp-x64-macos
            ./dist/legacy/
            ./dist/modern/
