on:
  workflow_dispatch:
  push:
    branches: [ main, "v*" ]
    tags:
      - 'v*'

name: Release

env:
  RUNTIME_MANIFEST: runtime/Cargo.toml
  RUNTIME_CRATE: libextism
  RUSTFLAGS: -C target-feature=-crt-static
  ARTIFACT_DIR: release-artifacts

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

jobs:
  release:
    name: ${{ matrix.os }} ${{ matrix.target }}
    runs-on: ${{ matrix.os }}-latest
    strategy:
      matrix:
        include:
          - os: 'macos'
            target: 'x86_64-apple-darwin'
            artifact: 'libextism.dylib'
            static-artifact: 'libextism.a'
            pc-in: 'extism.pc.in'
            static-pc-in: 'extism-static.pc.in'
          - os: 'macos'
            target: 'aarch64-apple-darwin'
            artifact: 'libextism.dylib'
            static-artifact: 'libextism.a'
            pc-in: 'extism.pc.in'
            static-pc-in: 'extism-static.pc.in'
          - os: 'ubuntu'
            target: 'aarch64-unknown-linux-gnu'
            artifact: 'libextism.so'
            static-artifact: 'libextism.a'
            pc-in: 'extism.pc.in'
            static-pc-in: 'extism-static.pc.in'
          - os: 'ubuntu'
            target: 'aarch64-unknown-linux-musl'
            artifact: 'libextism.so'
            static-artifact: 'libextism.a'
            pc-in: 'extism.pc.in'
            static-pc-in: 'extism-static.pc.in'
          - os: 'ubuntu'
            target: 'x86_64-unknown-linux-gnu'
            artifact: 'libextism.so'
            static-artifact: 'libextism.a'
            pc-in: 'extism.pc.in'
            static-pc-in: 'extism-static.pc.in'
          - os: 'ubuntu'
            target: 'x86_64-unknown-linux-musl'
            artifact: ''
            static-artifact: 'libextism.a'
            pc-in: ''
            static-pc-in: 'extism-static.pc.in'
          - os: 'windows'
            target: 'x86_64-pc-windows-gnu'
            artifact: 'extism.dll'
            static-artifact: 'libextism.a'
            pc-in: 'extism.pc.in'
            static-pc-in: 'extism-static.pc.in'
          - os: 'windows'
            target: 'x86_64-pc-windows-msvc'
            artifact: 'extism.dll'
            static-artifact: 'extism.lib'
            pc-in: ''
            static-pc-in: ''

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Set version
        shell: bash
        run: |
          version="${{ github.ref }}"
          if [[ "$version" = "refs/heads/main" ]]; then
            version="0.0.0-dev"
          else
            version="${version/refs\/tags\/v/}"
          fi
          sed -i -e "s/0.0.0+replaced-by-ci/${version}/g" Cargo.toml
          pyproject="$(cat extism-maturin/pyproject.toml)"
          <<<"$pyproject" >extism-maturin/pyproject.toml sed -e 's/^version = "0.0.0.replaced-by-ci"/version = "'"$version"'"/g'

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          override: true
          target: ${{ matrix.target }}

      - uses: Swatinem/rust-cache@v2
        with:
          prefix-key: "${{matrix.os}}-${{matrix.target}}"
          save-if: ${{ github.ref == 'refs/heads/main' }}
          cache-on-failure: "true"

      - name: Build Target (${{ matrix.os }} ${{ matrix.target }})
        uses: actions-rs/cargo@v1
        with:
          use-cross: ${{ matrix.os != 'windows' }}
          command: build
          args: --release --target ${{ matrix.target }} -p ${{ env.RUNTIME_CRATE }}

      - uses: actions/setup-python@v4
        with:
          python-version: '3.10'

      - name: Build wheels
        uses: PyO3/maturin-action@v1
        # maturin's cffi integration struggles with gnu headers on windows.
        # there's partial work towards fixing this in `extism-maturin/build.rs`, but it's
        # not sufficient to get it to work. omit it for now!
        if: ${{ matrix.target != 'x86_64-pc-windows-gnu' && matrix.target != 'aarch64-unknown-linux-gnu' }}
        with:
          target: ${{ matrix.target }}
          args: --release --out dist --find-interpreter -m extism-maturin/Cargo.toml
          sccache: 'true'
          manylinux: auto

      - name: Build GNU Linux wheels
        uses: PyO3/maturin-action@v1
        # One of our deps, "ring", needs a newer sysroot than what "manylinux: auto" provides.
        if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
        with:
          target: ${{ matrix.target }}
          args: --release --out dist --find-interpreter -m extism-maturin/Cargo.toml
          sccache: 'true'
          manylinux: 2_28

      - name: Add pkg-config files except on MSVC
        if: ${{ matrix.target != 'x86_64-pc-windows-msvc' }}
        shell: bash
        run: |
          SRC_DIR=target/${{ matrix.target }}/release
          cp libextism/extism*.pc.in ${SRC_DIR}

      - name: Prepare Artifact
        shell: bash
        run: |
          SRC_DIR=target/${{ matrix.target }}/release
          DEST_DIR=${{ env.ARTIFACT_DIR }}
          RELEASE_NAME=libextism-${{ matrix.target }}-${{ github.ref_name }}
          ARCHIVE=${RELEASE_NAME}.tar.gz
          CHECKSUM=${RELEASE_NAME}.checksum.txt

          # compress the shared library & create checksum
          cp runtime/extism.h ${SRC_DIR}
          cp LICENSE ${SRC_DIR}
          tar -C ${SRC_DIR} -czvf ${ARCHIVE} extism.h \
            ${{ matrix.artifact }} ${{ matrix.static-artifact }}  \
            ${{ matrix.pc-in }} ${{ matrix.static-pc-in }}
          ls -ll ${ARCHIVE}

          if &>/dev/null which shasum; then
            shasum -a 256 ${ARCHIVE} > ${CHECKSUM}
          else
            # windows doesn't have shasum available, so we use certutil instead.
            certutil -hashfile ${ARCHIVE} SHA256 >${CHECKSUM}
          fi

          # copy archive and checksum into release artifact directory
          mkdir -p ${DEST_DIR}
          cp ${ARCHIVE} ${DEST_DIR}
          cp ${CHECKSUM} ${DEST_DIR}

          # copy any built wheels.
          if [ -e dist/*.whl ]; then
            cp dist/*.whl ${DEST_DIR}
          fi

          ls -ll ${DEST_DIR}

      - name: Upload Artifact to Summary
        uses: actions/upload-artifact@v3
        with:
          name: ${{ env.ARTIFACT_DIR }}
          path: ${{ env.ARTIFACT_DIR }}

      - name: Upload Artifact to Draft Release
        uses: softprops/action-gh-release@v1
        with:
          draft: true
          files: |
            ${{ env.ARTIFACT_DIR }}/*
        if: startsWith(github.ref, 'refs/tags/')

  release-latest:
    name: create latest release
    runs-on: ubuntu-latest
    needs: [release]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/download-artifact@v3
        with:
          name: ${{ env.ARTIFACT_DIR }}

      - uses: "marvinpinto/action-automatic-releases@latest"
        with:
          repo_token: "${{ secrets.GITHUB_TOKEN }}"
          automatic_release_tag: "latest"
          prerelease: true
          title: "Development Build"
          files: |
            *.tar.gz
            *.txt
            *.whl
        if: github.ref == 'refs/heads/main'
