# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
# Based on ~/code/xcookie/xcookie/rc/tests.yml.in
# Now based on ~/code/xcookie/xcookie/builders/github_actions.py

name: BinPy Build and Test

on:
  push:
  pull_request:
    branches: [ main ]

jobs:
  lint_job:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout source
      uses: actions/checkout@v3
    - name: Set up Python 3.8
      uses: actions/setup-python@v4.3.0
      with:
        python-version: 3.8
    - name: Install dependencies
      run: |-
        python -m pip install --upgrade pip
        python -m pip install flake8
    - name: Lint with flake8
      run: |-
        # stop the build if there are Python syntax errors or undefined names
        flake8 ./line_profiler --count --select=E9,F63,F7,F82 --show-source --statistics
    - name: Typecheck with mypy
      run: |-
        python -m pip install mypy
        mypy --install-types --non-interactive ./line_profiler
        mypy ./line_profiler
  build_and_test_sdist:
    name: Test sdist Python 3.8
    runs-on: ubuntu-latest
    steps:
    - name: Checkout source
      uses: actions/checkout@v3
    - name: Set up Python 3.8
      uses: actions/setup-python@v4.3.0
      with:
        python-version: 3.8
    - name: Upgrade pip
      run: |-
        python -m pip install --upgrade pip
        python -m pip install -r requirements/tests.txt
        python -m pip install -r requirements/runtime.txt
        true
    - name: Build sdist
      shell: bash
      run: |-
        python -m pip install pip -U
        python -m pip install setuptools>=0.8 wheel build
        python -m build --sdist --outdir wheelhouse
    - name: Install sdist
      run: |-
        ls -al ./wheelhouse
        pip install wheelhouse/line_profiler*.tar.gz -v
    - name: Test minimal loose sdist
      run: |-
        pwd
        ls -al
        # Run in a sandboxed directory
        WORKSPACE_DNAME="testsrcdir_minimal_${CI_PYTHON_VERSION}_${GITHUB_RUN_ID}_${RUNNER_OS}"
        mkdir -p $WORKSPACE_DNAME
        cd $WORKSPACE_DNAME
        # Run the tests
        # Get path to installed package
        MOD_DPATH=$(python -c "import line_profiler, os; print(os.path.dirname(line_profiler.__file__))")
        echo "MOD_DPATH = $MOD_DPATH"
        python -m pytest --cov={self.mod_name} $MOD_DPATH ../tests
        cd ..
    - name: Test full loose sdist
      run: |-
        pwd
        ls -al
        python -m pip install -r requirements/ipython.txt
        # Run in a sandboxed directory
        WORKSPACE_DNAME="testsrcdir_full_${CI_PYTHON_VERSION}_${GITHUB_RUN_ID}_${RUNNER_OS}"
        mkdir -p $WORKSPACE_DNAME
        cd $WORKSPACE_DNAME
        # Run the tests
        # Get path to installed package
        MOD_DPATH=$(python -c "import line_profiler, os; print(os.path.dirname(line_profiler.__file__))")
        echo "MOD_DPATH = $MOD_DPATH"
        python -m pytest --cov={self.mod_name} $MOD_DPATH ../tests
        cd ..
    - name: Upload sdist artifact
      uses: actions/upload-artifact@v3
      with:
        name: wheels
        path: ./wheelhouse/*.tar.gz
  build_and_test_binpy_wheels:
    name: ${{ matrix.os }}, arch=${{ matrix.arch }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os:
        - windows-latest
        - ubuntu-latest
        - macOS-latest
        cibw_skip:
        - '*-win32'
        arch:
        - auto
        include:
        - os: windows-latest
          arch: auto
          cibw_skip: '*-win_amd64'
    steps:
    - name: Checkout source
      uses: actions/checkout@v3
    - name: Enable MSVC 64bit
      uses: ilammy/msvc-dev-cmd@v1
      if: matrix.os == 'windows-latest' && matrix.cibw_skip == '*-win32'
    - name: Enable MSVC 32bit
      uses: ilammy/msvc-dev-cmd@v1
      if: matrix.os == 'windows-latest' && matrix.cibw_skip == '*-win_amd64'
      with:
        arch: x86
    - name: Set up QEMU
      uses: docker/setup-qemu-action@v2
      if: runner.os == 'Linux' && matrix.arch != 'auto'
      with:
        platforms: all
    - name: Build binary wheels
      uses: pypa/cibuildwheel@v2.11.2
      with:
        output-dir: wheelhouse
        config-file: pyproject.toml
      env:
        CIBW_SKIP: ${{ matrix.cibw_skip }}
        CIBW_ARCHS_LINUX: ${{ matrix.arch }}
    - name: Show built files
      shell: bash
      run: ls -la wheelhouse
    - name: Set up Python 3.8 to combine coverage Linux
      uses: actions/setup-python@v4.3.0
      if: runner.os == 'Linux'
      with:
        python-version: 3.8
    - name: Combine coverage Linux
      if: runner.os == 'Linux'
      run: |-
        echo '############ PWD'
        pwd
        cp .wheelhouse/.coverage* . || true
        ls -al
        python -m pip install coverage[toml]
        echo '############ combine'
        coverage combine . || true
        echo '############ XML'
        coverage xml -o ./tests/coverage.xml || true
        echo '############ FIND'
        find . -name .coverage.* || true
        find . -name coverage.xml  || true
    - uses: codecov/codecov-action@v3
      name: Codecov Upload
      with:
        file: ./tests/coverage.xml
    - uses: actions/upload-artifact@v3
      name: Upload wheels artifact
      with:
        name: wheels
        path: ./wheelhouse/line_profiler*.whl
  test_deploy:
    name: Uploading Test to PyPi
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && ! startsWith(github.event.ref, 'refs/tags') && ! startsWith(github.event.ref, 'refs/heads/release')
    needs:
    - build_and_test_sdist
    - build_and_test_binpy_wheels
    steps:
    - name: Checkout source
      uses: actions/checkout@v3
    - uses: actions/download-artifact@v3
      name: Download wheels and sdist
      with:
        name: wheels
        path: wheelhouse
    - name: Show files to upload
      shell: bash
      run: ls -la wheelhouse
    - name: Sign and Publish
      env:
        TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/
        TWINE_USERNAME: ${{ secrets.TEST_TWINE_USERNAME }}
        TWINE_PASSWORD: ${{ secrets.TEST_TWINE_PASSWORD }}
        CI_SECRET: ${{ secrets.CI_SECRET }}
      run: |-
        GPG_EXECUTABLE=gpg
        $GPG_EXECUTABLE --version
        openssl version
        $GPG_EXECUTABLE --list-keys
        echo "Decrypting Keys"
        openssl enc -aes-256-cbc -pbkdf2 -md SHA512 -pass env:CI_SECRET -d -a -in dev/ci_public_gpg_key.pgp.enc | $GPG_EXECUTABLE --import
        openssl enc -aes-256-cbc -pbkdf2 -md SHA512 -pass env:CI_SECRET -d -a -in dev/gpg_owner_trust.enc | $GPG_EXECUTABLE --import-ownertrust
        openssl enc -aes-256-cbc -pbkdf2 -md SHA512 -pass env:CI_SECRET -d -a -in dev/ci_secret_gpg_subkeys.pgp.enc | $GPG_EXECUTABLE --import
        echo "Finish Decrypt Keys"
        $GPG_EXECUTABLE --list-keys || true
        $GPG_EXECUTABLE --list-keys  || echo "first invocation of gpg creates directories and returns 1"
        $GPG_EXECUTABLE --list-keys
        VERSION=$(python -c "import setup; print(setup.VERSION)")
        pip install urllib3 requests[security] twine -U
        GPG_KEYID=$(cat dev/public_gpg_key)
        echo "GPG_KEYID = '$GPG_KEYID'"
        MODE=binary DO_GPG=True GPG_KEYID=$GPG_KEYID TWINE_REPOSITORY_URL=${TWINE_REPOSITORY_URL} TWINE_PASSWORD=$TWINE_PASSWORD TWINE_USERNAME=$TWINE_USERNAME GPG_EXECUTABLE=$GPG_EXECUTABLE DO_BUILD=False DO_UPLOAD=True DO_TAG=False ./publish.sh
  live_deploy:
    name: Uploading Live to PyPi
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && (startsWith(github.event.ref, 'refs/tags') || startsWith(github.event.ref, 'refs/heads/release'))
    needs:
    - build_and_test_sdist
    - build_and_test_binpy_wheels
    steps:
    - name: Checkout source
      uses: actions/checkout@v3
    - uses: actions/download-artifact@v3
      name: Download wheels and sdist
      with:
        name: wheels
        path: wheelhouse
    - name: Show files to upload
      shell: bash
      run: ls -la wheelhouse
    - name: Sign and Publish
      env:
        TWINE_REPOSITORY_URL: https://upload.pypi.org/legacy/
        TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
        TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
        CI_SECRET: ${{ secrets.CI_SECRET }}
      run: |-
        GPG_EXECUTABLE=gpg
        $GPG_EXECUTABLE --version
        openssl version
        $GPG_EXECUTABLE --list-keys
        echo "Decrypting Keys"
        openssl enc -aes-256-cbc -pbkdf2 -md SHA512 -pass env:CI_SECRET -d -a -in dev/ci_public_gpg_key.pgp.enc | $GPG_EXECUTABLE --import
        openssl enc -aes-256-cbc -pbkdf2 -md SHA512 -pass env:CI_SECRET -d -a -in dev/gpg_owner_trust.enc | $GPG_EXECUTABLE --import-ownertrust
        openssl enc -aes-256-cbc -pbkdf2 -md SHA512 -pass env:CI_SECRET -d -a -in dev/ci_secret_gpg_subkeys.pgp.enc | $GPG_EXECUTABLE --import
        echo "Finish Decrypt Keys"
        $GPG_EXECUTABLE --list-keys || true
        $GPG_EXECUTABLE --list-keys  || echo "first invocation of gpg creates directories and returns 1"
        $GPG_EXECUTABLE --list-keys
        VERSION=$(python -c "import setup; print(setup.VERSION)")
        pip install urllib3 requests[security] twine -U
        GPG_KEYID=$(cat dev/public_gpg_key)
        echo "GPG_KEYID = '$GPG_KEYID'"
        MODE=binary DO_GPG=True GPG_KEYID=$GPG_KEYID TWINE_REPOSITORY_URL=${TWINE_REPOSITORY_URL} TWINE_PASSWORD=$TWINE_PASSWORD TWINE_USERNAME=$TWINE_USERNAME GPG_EXECUTABLE=$GPG_EXECUTABLE DO_BUILD=False DO_UPLOAD=True DO_TAG=False ./publish.sh


###
# Unfortunately we cant (yet) use the yaml docstring trick here
# https://github.community/t/allow-unused-keys-in-workflow-yaml-files/172120
#__doc__: |
#    # How to run locally
#    # https://packaging.python.org/guides/using-testpypi/
#    git clone https://github.com/nektos/act.git $HOME/code/act
#    chmod +x $HOME/code/act/install.sh
#    (cd $HOME/code/act && ./install.sh -b $HOME/.local/opt/act)
#
#    load_secrets
#    unset GITHUB_TOKEN
#    $HOME/.local/opt/act/act \
#        --secret=EROTEMIC_TWINE_PASSWORD=$EROTEMIC_TWINE_PASSWORD \
#        --secret=EROTEMIC_TWINE_USERNAME=$EROTEMIC_TWINE_USERNAME \
#        --secret=EROTEMIC_CI_SECRET=$EROTEMIC_CI_SECRET \
#        --secret=EROTEMIC_TEST_TWINE_USERNAME=$EROTEMIC_TEST_TWINE_USERNAME \
#        --secret=EROTEMIC_TEST_TWINE_PASSWORD=$EROTEMIC_TEST_TWINE_PASSWORD
