name: Test

on:
  push:
  pull_request:
  workflow_dispatch:

env:
  CI: true
  DOCKER_BUILDKIT: 1

jobs:

#
# Doc
#

  doc:
    name: '๐Ÿ““ Docs'
    runs-on: ubuntu-latest

    steps:

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - name: 'โ›ด Build ghdl/doc'
        run: |
          docker build -t ghdl/doc . -f- <<-EOF
          FROM ghdl/debug:base
          ENV PYTHONPATH=/opt/ghdl/pyGHDL
          COPY . /opt/ghdl
          RUN cd /opt/ghdl && ./configure && make && make install
          EOF

      - name: '๐Ÿ“š Run gnatdoc'
        run: |
          cat > run.sh <<-EOF
          #!/usr/bin/env sh
          gnatdoc -P./ghdl
          mkdir /src/public
          mv gnatdoc /src/public/gnatdoc
          EOF
          chmod +x run.sh
          docker run --rm -v $(pwd):/src -w /opt/ghdl ghdl/doc /src/run.sh

      - name: '๐Ÿ““ BuildTheDocs (BTD)'
        if: github.event_name != 'pull_request'
        uses: buildthedocs/btd@v0
        with:
          token: ${{ github.token }}

      #- run: nroff -man doc/_build/man/ghdl.1

      - name: '๐Ÿ“ค Upload artifact: HTML and LaTeX'
        if: github.event_name != 'pull_request'
        uses: actions/upload-artifact@v2
        with:
          name: doc
          path: |
            doc/_build/html
            doc/_build/latex
            doc/_build/man

      - name: '๐Ÿ“ค Upload artifact: ghdl.1'
        if: github.event_name != 'pull_request'
        uses: actions/upload-artifact@v2
        with:
          name: man
          path: doc/_build/man/ghdl.1

#
# pyGHDL Bindings, Formatting and Wheel
#

  pyGHDL:
    name: '๐Ÿ pyGHDL'
    runs-on: ubuntu-latest

    steps:

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - name: '๐Ÿ Setup Python'
        uses: actions/setup-python@v2
        with:
          python-version: 3.8

      - name: '๐Ÿ”ง Install dependencies'
        run: |
          sudo apt update -qq
          sudo apt install -y gnat
          python -m pip install --upgrade pip
          python -m pip install black wheel

      - name: '๐Ÿšง Update Python bindings'
        run: ./scripts/update_py_bindings.sh

      - name: '๐Ÿšฆ Check if Python bindings changed'
        run: |
          git diff --stat
          echo "NOTE: Bindings can be updated by executing ./scripts/update_py_bindings.sh (see previous step)"
          git diff --exit-code

      - name: '๐Ÿšฆ Check if python follows code formatting standards'
        run: python -m black --check pyGHDL

      - name: ๐Ÿ”จ Build Python package (source distribution)
        run: python setup.py sdist

      - name: ๐Ÿ”จ Build Python package (binary distribution - wheel)
        run: python setup.py bdist_wheel

      - name: '๐Ÿ“ค Upload artifact: pyGHDL'
        uses: actions/upload-artifact@v2
        with:
          name: pyGHDL
          path: dist/
          if-no-files-found: error

#
# GPL
#

  gpl:
    name: '๐Ÿšง๐Ÿšฆ๐Ÿง GPL ยท mcode'
    runs-on: ubuntu-latest

    steps:

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - run: TASK=bullseye+mcode ./scripts/ci-run.sh -c --gplcompat

#
# GNU/Linux
#

  lin:
    name: '๐Ÿšง๐Ÿšฆ๐Ÿง Ubuntu ${{ matrix.os }} ยท ${{ matrix.backend }}'
    runs-on: ubuntu-${{ matrix.os }}.04

    strategy:
      fail-fast: false
      matrix:
        include:
          - { os: 18, backend: mcode }
          - { os: 20, backend: mcode }
          - { os: 18, backend: llvm-5.0 }
          - { os: 20, backend: llvm-10 }
          - { os: 18, backend: gcc-8.3.0 }
          - { os: 20, backend: gcc-9.3.0 }

    steps:

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - name: '๐Ÿ›ณ Build and test GHDL in containers'
        run: |
          TASK=ubuntu${{ matrix.os }}+${{ matrix.backend }} ./scripts/ci-run.sh -c
          mv ghdl-*-ubuntu${{ matrix.os }}-*.tgz ghdl-gha-ubuntu-${{ matrix.os }}.04-$(echo ${{ matrix.backend }} | sed 's#-.*##g').tgz

      - name: '๐Ÿ“ค Upload artifact: package'
        uses: actions/upload-artifact@v2
        with:
          name: ubuntu${{ matrix.os }}-${{ matrix.backend }}
          path: ghdl-gha-ubuntu-*.tgz
          if-no-files-found: error

#
# MacOS
#

  osx:
    name: '๐Ÿšง๐Ÿšฆ๐ŸŽ macOS 10.15 ยท ${{ matrix.backend }}'
    runs-on: 'macOS-10.15'

    strategy:
      fail-fast: false
      matrix:
        backend:
          - mcode
          - llvm

    steps:

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - name: '๐Ÿ’พ Cache gnat'
        id: cache-gnat
        uses: actions/cache@v2
        with:
          path: gnat
          key: ${{ runner.os }}-gnat

      # Although we cache this, we let the script run to check if the cache is valid (without conditions)
      - name: 'โš™ Dependencies (brew)'
        run: ./scripts/macosx/install-ada.sh

      - name: '๐Ÿšง Build and ๐Ÿšฆ Test GHDL'
        run: |
          PATH=$PWD/gnat/bin:$PATH
          ./scripts/ci-run.sh -c
          mv ghdl-*.tgz ghdl-macos-10.15-${{ matrix.backend }}.tgz
        env:
          TASK: macosx+${{ matrix.backend }}
          GITHUB_OS: ${{ runner.os }}

      - name: '๐Ÿ“ค Upload artifact: package'
        uses: actions/upload-artifact@v2
        with:
          name: macos10.15-${{ matrix.backend }}
          path: ghdl-macos*${{ matrix.backend }}.tgz
          if-no-files-found: error

#
# Windows MSYS2 Build
#

  win-msys2-build-package:
    name: '๐Ÿšง${{ matrix.icon }} ยท ${{ matrix.pkg }}${{ matrix.bits }}'
    runs-on: windows-latest

    strategy:
      fail-fast: false
      matrix:
        include:
#          - {icon: '๐ŸŸช', pkg: 'llvm',  bits: '32', arch: i686   } ! not yet functional
          - {icon: '๐ŸŸฆ', pkg: 'llvm',  bits: '64', arch: x86_64 }
          - {icon: '๐ŸŸช', pkg: 'mcode', bits: '32', arch: i686   }
          - {icon: '๐ŸŸฆ', pkg: 'mcode', bits: '64', arch: x86_64 } #! simulation with mcode is not yet supported on win64

    env:
      MINGW_ARCH: MINGW${{ matrix.bits }}
    defaults:
      run:
        shell: msys2 {0}

    steps:

      - name: '${{ matrix.icon }} Setup MSYS2'
        uses: msys2/setup-msys2@v2
        with:
          msystem: MSYS
          update: true
          install: >
            base-devel
            git
            mingw-w64-${{ matrix.arch }}-toolchain

      - name: 'โš™ git config'
        run: git config --global core.autocrlf input
        shell: bash

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2
        with:
          # The command 'git describe' (used for version) needs the history.
          fetch-depth: 0

      - name: '๐Ÿšง Build package'
        run: |
          cd scripts/msys2-${{ matrix.pkg }}
          makepkg-mingw --noconfirm --noprogressbar -sCLf

      - name: '๐Ÿ“ค Upload artifact: builddir'
        uses: actions/upload-artifact@v2
        with:
          name: MINGW${{ matrix.bits }}-${{ matrix.pkg }}-builddir
          path: |
            scripts/msys2-${{ matrix.pkg }}/src/
            scripts/msys2-${{ matrix.pkg }}/pkg/

      - name: '๐Ÿ“ค Upload artifact: package'
        uses: actions/upload-artifact@v2
        with:
          name: MINGW${{ matrix.bits }}-${{ matrix.pkg }}
          path: scripts/msys2-${{ matrix.pkg }}/mingw-*ghdl*.pkg.tar.zst
          if-no-files-found: error

#
# Windows MSYS2 Test
#

  win-msys2-test:
    name: '๐Ÿšฆ${{ matrix.sys.icon }} ${{ matrix.sys.pkg }}${{ matrix.sys.bits }} ยท ${{ matrix.suite }}'
    runs-on: windows-latest

    needs:
      - win-msys2-build-package

    strategy:
      fail-fast: false
      matrix:
        sys:
#          - {icon: '๐ŸŸช', pkg: 'llvm',  bits: '32', arch: i686 } ! not yet functional
          - {icon: '๐ŸŸฆ', pkg: 'llvm',  bits: '64', arch: x86_64 }
          - {icon: '๐ŸŸช', pkg: 'mcode', bits: '32', arch: i686,   }
#          - {icon: '๐ŸŸฆ', pkg: 'mcode', bits: '64', arch: x86_64, } ! simulation with mcode is not yet supported on win64
        suite:
          - 'sanity pyunit vpi vhpi'
          - 'gna'
          - 'vests'
          - 'synth'

    defaults:
      run:
        shell: msys2 {0}

    steps:

      - name: '${{ matrix.sys.icon }} Setup MSYS2'
        uses: msys2/setup-msys2@v2
        with:
          msystem: MINGW${{ matrix.sys.bits }}
          update: true
          install: >
            mingw-w64-${{ matrix.sys.arch }}-diffutils
            mingw-w64-${{ matrix.sys.arch }}-gcc
            mingw-w64-${{ matrix.sys.arch }}-python-pip
            mingw-w64-${{ matrix.sys.arch }}-python-setuptools

      - name: 'โš™ git config'
        run: git config --global core.autocrlf input
        shell: bash

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - name: '๐Ÿ“ฅ Download artifact: package'
        uses: actions/download-artifact@v2
        with:
          path: artifact
          name: MINGW${{ matrix.sys.bits }}-${{ matrix.sys.pkg }}

      - name: '๐Ÿ›  Install package and ๐Ÿ Python dependencies'
        run: |
          pacman --noconfirm -U artifact/mingw-w64-${{ matrix.sys.arch }}-ghdl-${{ matrix.sys.pkg }}-*.zst
          pip3 install -r testsuite/requirements.txt

      - name: '๐Ÿšฆ Test package'
        run: GHDL=ghdl ./testsuite/testsuite.sh ${{ matrix.suite }}

#
# Windows Generate Standalone ZipFile
#

  win-generate-standalone-zip:
    name: '๐Ÿšง๐Ÿฅก${{ matrix.icon }} ยท mcode${{ matrix.bits }}'
    runs-on: windows-latest

    needs:
      - win-msys2-build-package

    strategy:
      fail-fast: false
      matrix:
        include:
          - {icon: '๐ŸŸช', bits: '32', arch: i686,   }
          - {icon: '๐ŸŸฆ', bits: '64', arch: x86_64, } #! simulation with mcode is not yet supported on win64

    defaults:
      run:
        shell: msys2 {0}

    steps:

      - name: '${{ matrix.icon }} Setup MSYS2'
        uses: msys2/setup-msys2@v2
        with:
          msystem: MINGW${{ matrix.bits }}
          update: true
          install: >-
            tree
            zstd
            zip
            tar

      - name: 'โš™ git config'
        run: git config --global core.autocrlf input
        shell: bash

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - name: '๐Ÿ“ฅ Download artifact: package'
        uses: actions/download-artifact@v2
        with:
          path: artifact
          name: MINGW${{ matrix.bits }}-mcode

      - name: '๐Ÿ›  Install package'
        run: pacman --noconfirm -U artifact/mingw-w64-${{ matrix.arch }}-ghdl-mcode-*.zst

      - name: '๐Ÿฅก Generate standalone zipfile'
        run: |
          _zipdir='MINGW${{ matrix.bits }}-mcode-standalone'
          mkdir -p "${_zipdir}"-extract
          tar xf artifact/mingw-w64-${{ matrix.arch }}-ghdl-mcode-*.zst -C "${_zipdir}"-extract
          cd "${_zipdir}-extract/MINGW${{ matrix.bits }}"/bin
          ../../../scripts/msys2-mcode/GetStandaloneDeps.sh
          cd ../../..
          mv "${_zipdir}"-extract/mingw${{ matrix.bits }} "${_zipdir}"
          tree "${_zipdir}"
          zip "${_zipdir}".zip -r "${_zipdir}"

      - name: '๐Ÿ“ค Upload artifact: zipfile'
        uses: actions/upload-artifact@v2
        with:
          name: MINGW${{ matrix.bits }}-mcode-standalone
          path: MINGW${{ matrix.bits }}-mcode-standalone.zip

#
# Windows CPython pyGHDL Test with MSYS2 installation
#

  win-cpython-msys2:
    name: '๐Ÿšฆ๐Ÿ${{ matrix.icon }} ยท ${{ matrix.pkg }}${{ matrix.bits }}'
    runs-on: windows-latest

    needs:
      - win-msys2-build-package

    strategy:
      fail-fast: false
      matrix:
        include:
#          - {icon: '๐ŸŸช', pkg: 'llvm',  bits: '32', arch: i686 }, ! not yet functional
          - {icon: '๐ŸŸฆ', pkg: 'llvm',  bits: '64', arch: x86_64, pyarch: x64 }
          - {icon: '๐ŸŸช', pkg: 'mcode', bits: '32', arch: i686,   pyarch: x86 }
          - {icon: '๐ŸŸฆ', pkg: 'mcode', bits: '64', arch: x86_64, pyarch: x64 } #! simulation with mcode is not yet supported on win64

    defaults:
      run:
        shell: pwsh

    steps:

      - name: '${{ matrix.icon }} Setup MSYS2'
        uses: msys2/setup-msys2@v2
        with:
          msystem: MINGW${{ matrix.bits }}
          update: true

      - name: 'โš™ git config'
        run: git config --global core.autocrlf input

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - name: '๐Ÿ“ฅ Download artifact: package'
        uses: actions/download-artifact@v2
        with:
          path: artifact
          name: MINGW${{ matrix.bits }}-${{ matrix.pkg }}

      - name: '๐Ÿ›  Install package'
        shell: msys2 {0}
        run: |
          pacman --noconfirm -U artifact/mingw-w64-${{ matrix.arch }}-ghdl-${{ matrix.pkg }}-*.zst

      - name: '๐Ÿ›  Set envvars'
        run: |
          $GHDL = (& msys2 -c 'cygpath -w /') + 'MINGW${{ matrix.bits }}\bin\ghdl.exe'
          $GHDL_HASH = (& $GHDL version hash)
          echo "GHDL_HASH=$GHDL_HASH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
          $GHDL_PREFIX = (& msys2 -c 'cygpath -w /') + 'MINGW${{ matrix.bits }}\lib\ghdl\'
          echo "GHDL_PREFIX=$GHDL_PREFIX" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

      - name: '๐Ÿ Setup Python'
        uses: actions/setup-python@v2
        with:
          python-version: 3.8
          architecture: ${{ matrix.pyarch }}

      - name: '๐Ÿ Install Python dependencies'
        run: |
          pip3 install -r testsuite/requirements.txt

      - name: '๐Ÿšฆ Test installation of pyGHDL through pip'
        run: pip install ("git+https://github.com/ghdl/ghdl.git@" + $env:GHDL_HASH)

      - name: '๐Ÿšฆ Test pyGHDL entrypoints'
        run: |
          ghdl-dom help
          ghdl-ls --help

      - name: '๐Ÿšฆ Test pyunit testsuite'
        run: |
          cd testsuite
          python3 -m pytest -vsrA pyunit

#
# Windows CPython pyGHDL Test with standalone zipfile and pyGHDL wheel
#

  win-cpython-standalone:
    name: '๐Ÿšฆ๐Ÿ๐Ÿฅก ${{ matrix.pkg }}${{ matrix.bits }}'
    runs-on: windows-latest

    needs:
      - win-generate-standalone-zip
      - pyGHDL

    strategy:
      fail-fast: false
      matrix:
        include:
#          - {icon: '๐ŸŸช', pkg: 'llvm',  bits: '32', arch: i686 }, ! not yet functional
#          - {icon: '๐ŸŸฆ', pkg: 'llvm',  bits: '64', arch: x86_64, pyarch: x64 }
#          - {icon: '๐ŸŸช', pkg: 'mcode', bits: '32', arch: i686,   pyarch: x86 }
          - {icon: '๐ŸŸฆ', pkg: 'mcode', bits: '64', arch: x86_64, pyarch: x64 } #! simulation with mcode is not yet supported on win64

    defaults:
      run:
        shell: pwsh

    steps:

      - name: 'โš™ git config'
        run: git config --global core.autocrlf input

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - name: '๐Ÿ“ฅ Download artifact: package'
        uses: actions/download-artifact@v2
        with:
          path: artifact
          name: MINGW${{ matrix.bits }}-${{ matrix.pkg }}-standalone

      - name: 'โš™ Extract package'
        run: |
          unzip artifact\MINGW${{ matrix.bits }}-${{ matrix.pkg }}-standalone.zip
          mv 'MINGW${{ matrix.bits }}-${{ matrix.pkg }}-standalone\' GHDL-standalone

      - name: '๐Ÿ›  Set envvars'
        run: |
          $GHDL = (pwd).Path + '\GHDL-standalone\bin\ghdl.exe'
          $GHDL_HASH = (& $GHDL version hash)
          echo "GHDL_HASH=$GHDL_HASH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
          $GHDL_PREFIX = (pwd).Path + '\GHDL-standalone\lib\ghdl'
          echo "GHDL_PREFIX=$GHDL_PREFIX" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append

      - name: '๐Ÿ Setup Python'
        uses: actions/setup-python@v2
        with:
          python-version: 3.8
          architecture: ${{ matrix.pyarch }}

      - name: '๐Ÿ“ฅ Download artifact: pyGHDL'
        uses: actions/download-artifact@v2
        with:
          name: pyGHDL

      - name: '๐Ÿ Install pyGHDL'
        run: |
          python -m pip install --upgrade pip
          python -m pip install wheel (& ls *.whl)
          python -m pip install -r testsuite/requirements.txt

      - name: '๐Ÿšฆ Test pyGHDL entrypoints'
        run: |
          ghdl-dom help
          ghdl-ls --help

      - name: '๐Ÿšฆ Test pyunit testsuite'
        run: |
          cd testsuite
          python3 -m pytest -vsrA pyunit

#
# Release
#

  Release:
    name: '๐Ÿ“ฆ Release'
    runs-on: ubuntu-latest

    needs:
      - doc
      - lin
      - osx
      - win-msys2-test
      - win-generate-standalone-zip
      - win-cpython-msys2
      - win-cpython-standalone

    if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/master' || contains(github.ref, 'refs/tags/'))

    steps:

      - name: '๐Ÿ“ฅ Download artifacts'
        if: "!contains(github.ref, 'refs/tags/')"
        uses: actions/download-artifact@v2
        with:
          path: artifacts

      # Do not upload assets to tagged releases
      - name: Set list of files for uploading
        id: files
        shell: python
        run: |
          print('None'
              if '${{ github.ref }}'.startswith('refs/tags/')
              else'::set-output name=list::**/*.zst **/*.tgz **/*-standalone.zip'
          )

      # Tagged: create a pre-release or a release (semver)
      # Untagged: update the assets of pre-release 'nightly'
      - uses: eine/tip@master
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          tag: 'nightly'
          files: ${{ steps.files.outputs.list }}

      - name: '๐Ÿ”” Trigger ghdl/docker'
        run: |
          curl -X POST https://api.github.com/repos/ghdl/docker/dispatches \
          -H 'Content-Type: application/json' \
          -H 'Accept: application/vnd.github.everest-preview+json' \
          -H "Authorization: token ${{ secrets.GHDL_BOT }}" \
          --data '{"event_type": "ghdl"}'

#
# Coverage (MINGW64)
#

  coverage:
    name: '๐Ÿ“ˆ Coverage'
    runs-on: windows-latest

    needs:
      - win-msys2-build-package

    defaults:
      run:
        shell: msys2 {0}

    steps:

      - name: '๐ŸŸช Setup MSYS2'
        uses: msys2/setup-msys2@v2
        with:
          msystem: MINGW64
          update: true
          install: >
            mingw-w64-x86_64-python-pip
            mingw-w64-x86_64-python-setuptools

      - name: 'โš™ git config'
        run: git config --global core.autocrlf input
        shell: bash

      - name: '๐Ÿงฐ Checkout'
        uses: actions/checkout@v2

      - name: '๐Ÿ“ฅ Download artifact: package'
        uses: actions/download-artifact@v2
        with:
          path: artifact
          name: MINGW64-llvm

      - name: '๐Ÿ›  Install package and ๐Ÿ Python dependencies'
        run: |
          pacman --noconfirm -U artifact/mingw-w64-x86_64-ghdl-llvm-*.zst
          pip3 install -r testsuite/requirements.txt

      - name: '๐Ÿšฆ Run tests to generate coverage report'
        run: PYTHONPATH=$(pwd) python3 -m pytest -rA --cov=.. --cov-config=.coveragerc testsuite/pyunit

      - name: Generate XML coverage report
        if: always()
        run: coverage xml

      - name: '๐Ÿ“ค Upload artifact: coverage report'
        if: always()
        uses: actions/upload-artifact@v2
        with:
          name: coverage
          path: coverage.xml

#
# Coverage Publish (Ubuntu)
#

  coverage-publish:
    name: '๐Ÿ“ฎ Publish coverage report'
    runs-on: ubuntu-latest

    needs:
      - coverage

    if: always() && github.repository == 'ghdl/ghdl' && github.event_name != 'pull_request'

    steps:

      - name: '๐Ÿ“ฅ Download artifact: coverage report'
        uses: actions/download-artifact@v2
        with:
          path: .
          name: coverage

      - name: CodeCov
        uses: codecov/codecov-action@v1
        with:
          file: coverage.xml
          flags: unittests

      - name: Codacy
        uses: codacy/codacy-coverage-reporter-action@master
        with:
          project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
          coverage-reports: coverage.xml

#---

# TODO:
# - Re-package a MINGW/MSYS2 package to provide a 'standalone' tarball/zipfile.
#  - https://github.com/ghdl/ghdl/issues/318#issuecomment-286246287
#
# - Add GNAT GPL 32-bit build job with mcode backend