name: Release

on:
  push:
    tags:
      - "v*.*.*"

env:
  CARGO_TERM_COLOR: always

jobs:
  test-ubuntu:
    name: Build and Text on Linux
    runs-on: ubuntu-latest
    environment:
      name: pre-release
    strategy:
      matrix:
        toolchain:
          - stable
          - beta
          - nightly
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup Rust
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: ${{ matrix.toolchain }}
          cache-key: ${{ runner.os }}-${{ matrix.toolchain }}

      - name: Test
        run: cargo test --release --verbose

      - name: Build
        run: cargo build --release --verbose

      - name: Get the runner architecture
        if: ${{ matrix.toolchain == 'stable' }}
        uses: actions/github-script@v8
        id: arch
        with:
          script: |
            const targetTest = /host:\s([\w-]+)/;
            const out = await exec.getExecOutput('rustc', ['-v', '-V']);
            const matchResult = out.stdout.match(targetTest);
            if (matchResult && matchResult.length >= 2) {
              core.setOutput("target-triple", matchResult[1]);
            } else {
              core.setFailed(`Unable to determine the target triple from ${out.stdout}`);
            }

      - name: Create the release directory
        if: ${{ matrix.toolchain == 'stable' }}
        run: |
          mkdir "./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}"
          cp ./target/release/pipe "./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}/pipe"
          cp ./target/release/pipe.1 "./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}/pipe.1"

      - name: Create a tarball
        if: ${{ matrix.toolchain == 'stable' }}
        uses: a7ul/tar-action@v1.2.0
        id: compress
        with:
          command: c
          files: |
            ./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}
          outPath: pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}.tgz

      - name: Upload artifacts
        if: ${{ matrix.toolchain == 'stable' }}
        uses: actions/upload-artifact@v5
        with:
          name: "build-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}"
          path: pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}.tgz

  test-windows:
    name: Build and Text on Windows
    runs-on: windows-latest
    environment:
      name: pre-release
    strategy:
      matrix:
        toolchain:
          - stable
          - beta
          - nightly
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup Rust
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: ${{ matrix.toolchain }}
          cache-key: ${{ runner.os }}-${{ matrix.toolchain }}

      - name: Test
        run: cargo test --release --verbose

      - name: Build
        run: cargo build --release --verbose

      - name: Get the runner triple
        if: ${{ matrix.toolchain == 'stable' }}
        uses: actions/github-script@v8
        id: arch
        with:
          script: |
            const targetTest = /host:\s([\w-]+)/;
            const out = await exec.getExecOutput('rustc', ['-v', '-V']);
            const matchResult = out.stdout.match(targetTest);
            if (matchResult && matchResult.length >= 2) {
              core.setOutput("target-triple", matchResult[1]);
            } else {
              core.setFailed(`Unable to determine the target triple from ${out.stdout}`);
            }

      - name: Create the release directory
        if: ${{ matrix.toolchain == 'stable' }}
        run: |
          mkdir "./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}"
          cp ./target/release/pipe.exe "./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}/pipe.exe"
          cp ./target/release/pipe.1 "./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}/pipe.1"

      - name: Create a tarball
        if: ${{ matrix.toolchain == 'stable' }}
        uses: a7ul/tar-action@v1.2.0
        id: compress
        with:
          command: c
          files: |
            ./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}
          outPath: pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}.tgz

      - name: Upload artifacts
        if: ${{ matrix.toolchain == 'stable' }}
        uses: actions/upload-artifact@v5
        with:
          name: "build-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}"
          path: pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}.tgz

  test-macos:
    name: Build and Text on MacOS
    runs-on: macos-latest
    environment:
      name: pre-release
    strategy:
      matrix:
        toolchain:
          - stable
          - beta
          - nightly
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup Rust
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: ${{ matrix.toolchain }}
          cache-key: ${{ runner.os }}-${{ matrix.toolchain }}

      - name: Test
        run: cargo test --release --verbose

      - name: Build
        run: cargo build --release --verbose

      - name: Get the runner triple
        if: ${{ matrix.toolchain == 'stable' }}
        uses: actions/github-script@v8
        id: arch
        with:
          script: |
            const targetTest = /host:\s([\w-]+)/;
            const out = await exec.getExecOutput('rustc', ['-v', '-V']);
            const matchResult = out.stdout.match(targetTest);
            if (matchResult && matchResult.length >= 2) {
              core.setOutput("target-triple", matchResult[1]);
            } else {
              core.setFailed(`Unable to determine the target triple from ${out.stdout}`);
            }

      - name: Create the release directory
        if: ${{ matrix.toolchain == 'stable' }}
        run: |
          mkdir "./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}"
          cp ./target/release/pipe "./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}/pipe"
          cp ./target/release/pipe.1 "./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}/pipe.1"

      - name: Create a tarball
        if: ${{ matrix.toolchain == 'stable' }}
        uses: a7ul/tar-action@v1.2.0
        id: compress
        with:
          command: c
          files: |
            ./pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}
          outPath: pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}.tgz

      - name: Upload artifacts
        if: ${{ matrix.toolchain == 'stable' }}
        uses: actions/upload-artifact@v5
        with:
          name: "build-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}"
          path: pipe-${{ github.ref_name }}-${{ steps.arch.outputs.target-triple }}.tgz

  publish:
    name: Publish package
    runs-on: ubuntu-latest
    environment:
      name: crates-io
    needs:
      - test-ubuntu
      - test-windows
      - test-macos
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Setup Rust
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: stable
          cache-key: ${{ runner.os }}-stable

      - name: Login into crates.io
        run: echo "${{ secrets.CRATES_IO }}" | cargo login

      - name: Build binaries in "release" mode
        run: cargo build --release --verbose

      - name: "Package for crates.io"
        run: cargo package --allow-dirty # publishes a package as a tarball
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO }}

      - name: "Publish to crates.io"
        run: cargo publish --allow-dirty # publishes the crate
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO }}

  changelog:
    name: Generate changelog
    runs-on: ubuntu-latest
    needs:
      - test-ubuntu
      - test-windows
      - test-macos
    outputs:
      changelog: ${{ steps.git-cliff.outputs.content }}
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Generate a changelog
        uses: orhun/git-cliff-action@v4
        id: git-cliff
        with:
          config: cliff.toml
          args: -vv --latest --strip header
        env:
          OUTPUT: CHANGELOG.md
          GITHUB_REPO: ${{ github.repository }}

  upload:
    name: Upload the release
    needs:
      - changelog
    runs-on: ubuntu-latest
    permissions:
      contents: write
      actions: write
      packages: write
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v6
        with:
          pattern: build-${{ github.ref_name }}-*
          path: ./build/
          merge-multiple: true

      - name: Create a checksum for each file
        shell: bash
        working-directory: ./build
        run: |
          for file in ./*.tgz; do
            if [[ ! -f "$file" ]]; then
              echo -e "::error::\033[1;31mMissing $file! Unable to create checksums.\033[0m"
              exit 1
            fi
            echo -e "::info::\033[0;36mCalculating the checksum for $file.\033[0m"
            shasum -a 256 "$file" > "$file.sha256sum.txt"
          done

      - name: Release
        uses: softprops/action-gh-release@v2
        with:
          fail_on_unmatched_files: true
          make_latest: true
          name: ${{ github.ref_name }}
          tag_name: ${{ github.ref_name }}
          body: ${{ needs.changelog.outputs.changelog }}
          files: |
            ./build/pipe-*
