name: Checks

on: [push, pull_request]

jobs:
  check_tag:
    name: Tag name
    outputs:
      tagged: ${{ steps.check_tagged.outputs.tagged }}
      matrix: ${{ steps.check_tagged.outputs.matrix }}
    runs-on: ubuntu-latest
    steps:
      - name: Check the ref
        id: check_tagged
        run: |
          set -x
          printf '%s' '
          #!/usr/bin/env python3
          # -*- coding: utf-8 -*-

          import json
          import argparse

          matrix = json.loads(r"""
          {
            "BUILD_TYPE": [
              "check",
              "build"
            ],
            "os": [
              "ubuntu-latest",
              "macos-latest",
              "windows-latest"
            ],
            "python": [
              3.7
            ],
            "include": [
              {
                "os": "ubuntu-latest",
                "name": "Ubuntu",
                "SEP": "/",
                "PIP_WHEELS_DIR": "~/.cache/pip",
                "CARGO_INDEX_DIR": "~/.cargo/git",
                "CARGO_REGISTRY_DIR": "~/.cargo/registry",
                "ANKI_PYTHON_WHEELS": "anki_linux_python_wheels"
              },
              {
                "os": "macos-latest",
                "name": "Mac OS",
                "SEP": "/",
                "PIP_WHEELS_DIR": "~/Library/Caches/pip",
                "CARGO_INDEX_DIR": "~/.cargo/git",
                "CARGO_REGISTRY_DIR": "~/.cargo/registry",
                "ANKI_PYTHON_WHEELS": "anki_macos_python_wheels"
              },
              {
                "os": "windows-latest",
                "name": "Windows",
                "SEP": "\\",
                "PIP_WHEELS_DIR": "~\\AppData\\Local\\pip\\Cache",
                "CARGO_INDEX_DIR": "C:\\Rust\\.cargo\\git",
                "CARGO_REGISTRY_DIR": "C:\\Rust\\.cargo\\registry",
                "ANKI_PYTHON_WHEELS": "anki_windows_python_wheels"
              }
            ]
          }
          """)

          parser = argparse.ArgumentParser(description="Dynamically creates a build matrix for the GitHub Actions.")
          parser.add_argument("--tagged", action="store_true", default=False,
              help="Adds Python 3.8 builds into the matrix")

          args = parser.parse_args()

          if args.tagged:
            matrix["python"].append("3.8")

          print(json.dumps(matrix))
          ' > buildmatrix.py;

          if [[ ${{ github.ref }} == refs/tags/* ]];
          then
            printf '::set-output name=tagged::%s\n' "tagged"
            printf '::set-output name=matrix::%s\n' "$(python3 buildmatrix.py --tagged)"
          else
            printf '::set-output name=tagged::%s\n' ""
            printf '::set-output name=matrix::%s\n' "$(python3 buildmatrix.py)"
          fi

  contrib:
    name: Author in CONTRIBUTORS
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - name: Check
        run: |
          set -x
          .github/scripts/contrib.sh

  tests:
    needs:
      - check_tag
    name: ${{ matrix.name }} ${{ needs.check_tag.outputs.tagged }} ${{ matrix.BUILD_TYPE }} ${{ matrix.python }}
    runs-on: ${{ matrix.os }}
    strategy:
      # https://github.com/ankitects/anki/pull/598
      matrix: ${{ fromJson( needs.check_tag.outputs.matrix ) }}

      # Keep all systems running if something fails
      fail-fast: false

    steps:
      - run: git config --global core.autocrlf false
        if: matrix.os == 'windows-latest'

      - uses: actions/checkout@v2

      - name: Configure Linux environment variables
        if: matrix.os == 'ubuntu-latest'
        run: |
          # echo "::set-env name=SHELLFLAGS::-x"
          echo "::set-env name=BUILDFLAGS::"
          echo "::set-env name=RSPY_TARGET_DIR::${GITHUB_WORKSPACE}/target"
          echo "::set-env name=CARGO_TARGET_DIR::${GITHUB_WORKSPACE}/target"

      - name: Configure Mac OS environment variables
        if: matrix.os == 'macos-latest'
        run: |
          # echo "::set-env name=SHELLFLAGS::-x"
          echo "::set-env name=BUILDFLAGS::"

          # Disabled for Mac OS because it was not reusing the cached files
          # https://github.com/ankitects/anki/pull/528
          # echo "::set-env name=RSPY_TARGET_DIR::${GITHUB_WORKSPACE}/target"
          # echo "::set-env name=CARGO_TARGET_DIR::${GITHUB_WORKSPACE}/target"

          # Update make to use the new `.SHELLFLAGS` feature
          # https://stackoverflow.com/questions/43175529/updating-make-version-4-1-on-mac
          echo "::set-env name=PATH::/usr/local/opt/make/libexec/gnubin:$PATH"

          # https://stackoverflow.com/questions/59644349/msgmerge-on-macos-catalina
          echo "::set-env name=PATH::/usr/local/opt/gettext/bin:$PATH"

      - name: Configure Windows environment variables
        if: matrix.os == 'windows-latest'
        run: |
          # echo "::set-env name=SHELLFLAGS::-x"
          echo "::set-env name=BUILDFLAGS::"
          echo "::set-env name=RSPY_TARGET_DIR::$env:GITHUB_WORKSPACE\target"
          echo "::set-env name=CARGO_TARGET_DIR::$env:GITHUB_WORKSPACE\target"

          # https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio
          if( "3.7".equals( "${{ matrix.python }}" ) ) {
            $pyaudio=("PyAudio-0.2.11-cp37-cp37m-win_amd64.whl")
          }
          else {
            $pyaudio=("PyAudio-0.2.11-cp38-cp38-win_amd64.whl")
          }

          $new_path=("$env:GITHUB_WORKSPACE;$env:PATH")
          $new_path=("$env:GITHUB_WORKSPACE\shims;$new_path")

          echo "::set-env name=pacmanbin::pacman-5.1.1-3-x86_64.pkg.tar.xz"
          echo "::set-env name=pacmanmirror::pacman-mirrors-20200307-1-any.pkg.tar.xz"
          echo "::set-env name=pacmankeys::msys2-keyring-r9.397a52e-1-any.pkg.tar.xz"
          echo "::set-env name=pyaudio::$pyaudio"
          echo "::set-env name=PATH::$new_path"
          echo "::set-env name=RUST_BACKTRACE::full"
          echo "::set-env name=SCOOP::$env:GITHUB_WORKSPACE"
          echo "::set-env name=SCOOP_GLOBAL::$env:GITHUB_WORKSPACE"
          echo "::set-env name=ANKI_EXTRA_PIP::python -m pip install $pyaudio"

      # Necessary for now for the cargo cache:
      # https://github.com/actions/cache/issues/133#issuecomment-599102035
      - name: Fix ~/.cache permissions
        if: matrix.os == 'ubuntu-latest' && matrix.python == '3.7'
        run: |
          sudo chown -R $(whoami):$(id -ng) ~/.cargo/

      # Disable it for macos because it pyenv cache is bugged (https://github.com/ankitects/anki/pull/563)
      - name: Cache pyenv
        if: matrix.os != 'macos-latest' && matrix.python == '3.7'
        uses: actions/cache@v1
        with:
          path: ${{ github.workspace }}${{ matrix.SEP }}pyenv
          key: ${{ runner.os }}-pyenv-${{ hashFiles('**/requirements.*') }}-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/Makefile') }}-15-

      # # Disable it in attempt to reduce the overall cache size (https://github.com/ankitects/anki/pull/528)
      # - name: Cache pip wheels
      #   if: matrix.BUILD_TYPE == 'build' && matrix.python == '3.7'
      #   uses: actions/cache@v1
      #   with:
      #     path: ${{ matrix.PIP_WHEELS_DIR }}
      #     key: ${{ runner.os }}-pip-wheels-${{ hashFiles('**/requirements.txt') }}-${{ hashFiles('**/setup.py') }}-15-

      - name: Cache cargo index
        if: matrix.python == '3.7'
        uses: actions/cache@v1
        with:
          path: ${{ matrix.CARGO_INDEX_DIR }}
          key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/requirements.*') }}-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/Makefile') }}-${{ hashFiles('**/Cargo.toml') }}-15-

      - name: Cache cargo registry
        if: matrix.python == '3.7'
        uses: actions/cache@v1
        with:
          path: ${{ matrix.CARGO_REGISTRY_DIR }}
          key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/requirements.*') }}-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/Makefile') }}-${{ hashFiles('**/Cargo.toml') }}-15-

      - name: Cache cargo target
        if: matrix.python == '3.7'
        uses: actions/cache@v1
        with:
          path: ${{ github.workspace }}${{ matrix.SEP }}target
          key: ${{ runner.os }}-cargo-target-${{ hashFiles('**/requirements.*') }}-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/Makefile') }}-${{ hashFiles('**/Cargo.toml') }}-${{ matrix.BUILD_TYPE }}-15-

      - name: Cache cargo rslib
        if: matrix.python == '3.7'
        uses: actions/cache@v1
        with:
          path: ${{ github.workspace }}${{ matrix.SEP }}rslib${{ matrix.SEP }}target
          key: ${{ runner.os }}-cargo-rslib-${{ hashFiles('**/requirements.*') }}-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/Makefile') }}-${{ hashFiles('**/Cargo.toml') }}-${{ matrix.BUILD_TYPE }}-15-

      - name: Cache cargo rspy
        if: matrix.python == '3.7'
        uses: actions/cache@v1
        with:
          path: ${{ github.workspace }}${{ matrix.SEP }}rspy${{ matrix.SEP }}target
          key: ${{ runner.os }}-cargo-rspy-${{ hashFiles('**/requirements.*') }}-${{ hashFiles('**/setup.py') }}-${{ hashFiles('**/Makefile') }}-${{ hashFiles('**/Cargo.toml') }}-${{ matrix.BUILD_TYPE }}-15-

      - name: Cache pacman
        if: matrix.os == 'windows-latest'
        uses: actions/cache@v1
        id: cache-pacman
        with:
          path: C:\Program Files\Git
          key: ${{ runner.os }}-pacman-${{ hashFiles('**/checks.yml') }}-15-

      - name: Set up pacman, rsync
        if: matrix.os == 'windows-latest' && steps.cache-pacman.outputs.cache-hit != 'true'
        shell: cmd
        run: |
          echo on
          curl -LO http://repo.msys2.org/msys/x86_64/%pacmanbin%
          curl -LO http://repo.msys2.org/msys/x86_64/%pacmanmirror%
          curl -LO http://repo.msys2.org/msys/x86_64/%pacmankeys%

          :: https://stackoverflow.com/questions/1359793/programmatically-extract-tar-gz
          7z x "%pacmanbin%" -so | 7z x -aoa -si -ttar -o"%programfiles%\Git"
          7z x "%pacmanmirror%" -so | 7z x -aoa -si -ttar -o"%programfiles%\Git"
          7z x "%pacmankeys%" -so | 7z x -aoa -si -ttar -o"%programfiles%\Git"

          :: Manually Install Pacman Binaries
          :: https://github.com/Alexpux/MSYS2-pacman/issues/50
          set "PATH=%programfiles%\Git\usr\bin"
          bash pacman-key --init
          bash pacman-key --populate msys2
          bash pacman-key --refresh-keys
          pacman -Tv
          pacman -Syyuuv --overwrite='*'
          pacman -Syuuv --overwrite='*'
          pacman --version

          :: We must install bash first, otherwise we will have bash fork errors:
          :: https://github.com/evandroforks/anki/runs/524857054?check_suite_focus=true
          :: 0 [main] pacman 748 dofork: child -1 - forked process 2896 died unexpectedly
          pacman -Sv --noconfirm --overwrite='*' bash
          pacman -Sv --noconfirm --overwrite='*' rsync

          :: clean all packages to decrease image size
          pacman -Sccv --noconfirm
          pacman -Qsv --noconfirm

      - name: Set up curl pyaudio
        if: matrix.os == 'windows-latest'
        shell: cmd
        run: |
          echo on
          curl -LO https://download.lfd.uci.edu/pythonlibs/s2jqpv5t/%pyaudio%

      - name: Set up Windows scoop, gettext, ripgrep
        if: matrix.os == 'windows-latest'
        shell: cmd
        run: |
          echo on
          powershell -executionpolicy bypass "& Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')"
          scoop install -g gettext ripgrep

      - name: Set up Ubuntu ripgrep, pyaudio, gettext
        if: matrix.os == 'ubuntu-latest'
        run: |
          set -x
          sudo apt update
          sudo apt install portaudio19-dev gettext
          # https://github.com/BurntSushi/ripgrep/issues/1232
          # sudo apt-get install ripgrep
          curl -LO https://github.com/BurntSushi/ripgrep/releases/download/11.0.2/ripgrep_11.0.2_amd64.deb
          sudo dpkg -i ripgrep_11.0.2_amd64.deb

      - name: Set up brew ripgrep, pyaudio, gettext
        if: matrix.os == 'macos-latest'
        run: |
          set -x
          brew install portaudio protobuf gettext ripgrep make

      - name: Set up python
        uses: actions/setup-python@v1
        with:
          python-version: ${{ matrix.python }}

      - name: Set up protoc
        uses: ankitects/setup-protoc@master
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up node
        uses: actions/setup-node@v1
        with:
          node-version: 12

      - run: make develop
        if: matrix.BUILD_TYPE == 'build'

      - run: make build
        if: matrix.BUILD_TYPE == 'build'

      - name: Check Windows wheels
        if: matrix.BUILD_TYPE == 'build' && matrix.os == 'windows-latest'
        shell: cmd
        run: |
          echo on
          copy %pyaudio% dist
          cd dist
          setlocal EnableDelayedExpansion
          cmd /C set "wheels=" && for /f "delims=" %%i in ('dir /b *.*') DO set "wheels="%%i" !wheels!"

          python -m pip install pyqtwebengine %wheels%
          python -c "import aqt; # aqt.run()"

      - name: Check Linux/Mac OS wheels
        if: matrix.BUILD_TYPE == 'build' && ( matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' )
        run: |
          set -x
          cd dist
          python -m pip install pyqtwebengine *.*
          python -c "import aqt; # aqt.run()"

      - run: make check
        if: matrix.BUILD_TYPE == 'check'

      - name: Upload python wheels
        if: matrix.BUILD_TYPE == 'build'
        uses: actions/upload-artifact@v1
        with:
          name: ${{ matrix.ANKI_PYTHON_WHEELS }}
          path: dist

      - name: Upload to PyPi Windows
        if: matrix.BUILD_TYPE == 'build' && startsWith(github.ref, 'refs/tags/') && matrix.os == 'windows-latest'
        shell: cmd
        env:
          TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
          TWINE_USERNAME: __token__
        run: |
          echo on
          cd dist
          rm -f "%pyaudio%"
          setlocal EnableDelayedExpansion
          cmd /C set "wheels=" && for /f "delims=" %%i in ('dir /b *.*') DO set "wheels="%%i" !wheels!"

          :: https://github.com/ankitects/anki/pull/535
          perl ../scripts/rename -f "s@\+[\w\d]+-@-@g" %wheels%
          python -m pip install twine
          python -m twine upload --non-interactive --skip-existing --verbose ./*

      - name: Upload to PyPi Linux/Mac OS
        if: matrix.BUILD_TYPE == 'build' && startsWith(github.ref, 'refs/tags/') && ( matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest' )
        env:
          TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
          TWINE_USERNAME: __token__
        run: |
          set -x
          python -m pip install twine

          # https://github.com/ankitects/anki/pull/535
          perl scripts/rename -f "s@\+[\w\d]+-@-@g" dist/*
          python -m twine upload --non-interactive --skip-existing --verbose dist/*
