smtp-test-tool 0.1.1

Cross-platform SMTP / IMAP / POP3 connectivity tester with IT-actionable diagnostics.
Documentation
name: Release

# Triggered by pushing a semver tag, e.g.:
#   git tag -a v0.1.0 -m "v0.1.0"
#   git push origin v0.1.0
on:
  push:
    tags: ["v*.*.*"]
  workflow_dispatch:
    inputs:
      version:
        description: "Tag (e.g. v0.1.0) - used only for manual reruns"
        required: true

concurrency:
  group: release-${{ github.ref }}
  cancel-in-progress: false

permissions:
  contents: write           # create GitHub Release + upload assets

env:
  CARGO_TERM_COLOR: always
  CARGO_INCREMENTAL: 0

jobs:

  # -------------------------------------------------------------------
  # Build the static binaries on each target OS.
  # -------------------------------------------------------------------
  build:
    name: build ${{ matrix.target }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            archive: tar.gz
          # Apple Silicon runner builds the native aarch64 binary.
          - os: macos-latest
            target: aarch64-apple-darwin
            archive: tar.gz
          # GitHub deprecated the macos-12 / macos-13 (Intel) runner
          # pools.  We cross-compile the x86_64 Mac binary from the
          # Apple-Silicon runner instead - cargo + rustup handle this
          # natively via the additional 'targets' entry, no extra
          # tooling needed for Rust-pure code.
          - os: macos-latest
            target: x86_64-apple-darwin
            archive: tar.gz
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            archive: zip
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}
      - uses: Swatinem/rust-cache@v2
        with:
          key: release-${{ matrix.target }}

      - name: Install Linux GUI build deps
        if: runner.os == 'Linux'
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
            libxkbcommon-dev libwayland-dev \
            libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
            libgl1-mesa-dev libegl1-mesa-dev libfontconfig-dev

      - name: cargo build --release
        run: cargo build --release --all-features --target ${{ matrix.target }}

      - name: Package (Unix)
        if: runner.os != 'Windows'
        shell: bash
        run: |
          set -euo pipefail
          NAME="smtp-test-tool-${{ matrix.target }}"
          mkdir -p "dist/$NAME"
          cp target/${{ matrix.target }}/release/smtp-test-tool          "dist/$NAME/"
          cp target/${{ matrix.target }}/release/smtp-test-tool-gui      "dist/$NAME/"
          cp README.md LICENSE-MIT LICENSE-APACHE CHANGELOG.md           "dist/$NAME/"
          cd dist
          tar -czf "$NAME.tar.gz" "$NAME"
          shasum -a 256 "$NAME.tar.gz" > "$NAME.tar.gz.sha256"

      - name: Package (Windows)
        if: runner.os == 'Windows'
        shell: pwsh
        run: |
          $name = "smtp-test-tool-${{ matrix.target }}"
          New-Item -ItemType Directory -Path "dist/$name" | Out-Null
          Copy-Item "target/${{ matrix.target }}/release/smtp-test-tool.exe"      "dist/$name/"
          Copy-Item "target/${{ matrix.target }}/release/smtp-test-tool-gui.exe"  "dist/$name/"
          Copy-Item README.md, LICENSE-MIT, LICENSE-APACHE, CHANGELOG.md         "dist/$name/"
          Compress-Archive -Path "dist/$name" -DestinationPath "dist/$name.zip"
          $hash = (Get-FileHash "dist/$name.zip" -Algorithm SHA256).Hash.ToLower()
          "$hash  $name.zip" | Out-File -FilePath "dist/$name.zip.sha256" -Encoding ascii

      - uses: actions/upload-artifact@v7
        with:
          name: ${{ matrix.target }}
          path: |
            dist/*.tar.gz
            dist/*.zip
            dist/*.sha256
          if-no-files-found: error

  # -------------------------------------------------------------------
  # Attach every archive to a GitHub Release.
  # -------------------------------------------------------------------
  release:
    name: GitHub Release
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/download-artifact@v8
        with:
          path: artifacts
      - name: Flatten artifact tree
        run: |
          mkdir -p release
          find artifacts -mindepth 2 -type f -exec mv {} release/ \;
          ls -la release/
      - name: Create / update GitHub Release
        uses: softprops/action-gh-release@v3
        with:
          files: release/*
          draft: false
          prerelease: ${{ contains(github.ref_name, '-') }}
          generate_release_notes: true

  # -------------------------------------------------------------------
  # Publish library + binaries to crates.io.
  #
  # ENABLEMENT: set the CARGO_REGISTRY_TOKEN repo secret first.  Until
  # that secret exists this job will fail in a non-blocking way (the
  # binary release above will still publish).
  # -------------------------------------------------------------------
  publish:
    name: crates.io publish
    needs: build
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
      - uses: actions/checkout@v6
      - uses: dtolnay/rust-toolchain@stable
      - name: Install Linux GUI build deps
        run: |
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
            libxkbcommon-dev libwayland-dev \
            libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev \
            libgl1-mesa-dev libegl1-mesa-dev libfontconfig-dev
      - name: Verify version matches tag
        run: |
          TAG="${GITHUB_REF#refs/tags/v}"
          CARGO_VER=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
          if [ "$TAG" != "$CARGO_VER" ]; then
            echo "::error::Tag v$TAG does not match Cargo.toml version $CARGO_VER"
            exit 1
          fi
      - name: cargo publish
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: cargo publish --all-features