dockdoe 0.12.0

A single-binary Docker host monitor with an embedded web UI
name: Release

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

jobs:
  # Fail fast on the classic "tagged but forgot to bump": the tag (minus its
  # `v`) must equal the version in Cargo.toml.
  verify-version:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Compare tag against Cargo.toml version
        run: |
          tag="${GITHUB_REF_NAME#v}"
          pkg=$(awk '/^\[package\]/{p=1;next} /^\[/{p=0} p&&/^[[:space:]]*version[[:space:]]*=/{gsub(/^[[:space:]]*version[[:space:]]*=[[:space:]]*"/,"");gsub(/".*$/,"");print;exit}' Cargo.toml)
          [ "$tag" = "$pkg" ] || { echo "::error::tag v$tag != Cargo.toml $pkg"; exit 1; }

  # Cross-compile a static musl binary per architecture on the (amd64) runner —
  # fast and native, no QEMU. Each build uploads its binary (for the image) and a
  # tarball (for the GitHub release).
  binaries:
    needs: verify-version
    runs-on: ubuntu-latest
    strategy:
      matrix:
        include:
          - target: x86_64-unknown-linux-musl
            arch: amd64
            label: x86_64-linux-musl
          - target: aarch64-unknown-linux-musl
            arch: arm64
            label: aarch64-linux-musl
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Install cross
        uses: taiki-e/install-action@v2
        with:
          tool: cross

      - name: Build static binary
        run: cross build --release --target ${{ matrix.target }}

      - name: Package tarball
        run: |
          install -Dm755 target/${{ matrix.target }}/release/dockdoe dist/dockdoe
          tar -C dist -czf dockdoe-${{ github.ref_name }}-${{ matrix.label }}.tar.gz dockdoe

      - name: Upload artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist-${{ matrix.arch }}
          path: |
            target/${{ matrix.target }}/release/dockdoe
            dockdoe-${{ github.ref_name }}-${{ matrix.label }}.tar.gz

  # Attach the tarballs to the release and assemble + push the multi-arch image
  # from the prebuilt binaries (pure COPY onto scratch — no compiler, no QEMU).
  publish:
    needs: binaries
    runs-on: ubuntu-latest
    permissions:
      contents: write
      packages: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Download built binaries
        uses: actions/download-artifact@v4
        with:
          path: artifacts

      - name: Stage image context and collect tarballs
        run: |
          mkdir -p binaries/amd64 binaries/arm64 data dist
          cp artifacts/dist-amd64/target/x86_64-unknown-linux-musl/release/dockdoe binaries/amd64/dockdoe
          cp artifacts/dist-arm64/target/aarch64-unknown-linux-musl/release/dockdoe binaries/arm64/dockdoe
          chmod +x binaries/amd64/dockdoe binaries/arm64/dockdoe
          cp artifacts/dist-amd64/*.tar.gz dist/
          cp artifacts/dist-arm64/*.tar.gz dist/

      # Release notes are the version's CHANGELOG.md section — the changelog is
      # the single curated source; auto-generated notes on a PR-less repo were
      # just a flat commit list.
      - name: Extract release notes from CHANGELOG
        run: |
          version="${GITHUB_REF_NAME#v}"
          awk -v ver="$version" '
              $0 ~ "^## \\[" ver "\\]" { grab=1; next }
              grab && /^## \[/          { exit }
              grab                      { print }
          ' CHANGELOG.md | sed -e '/./,$!d' > release-notes.md
          [ -s release-notes.md ] || { echo "::error::No CHANGELOG section for [$version]"; exit 1; }

      - name: Publish release with binaries
        uses: softprops/action-gh-release@v3
        with:
          files: dist/*.tar.gz
          body_path: release-notes.md

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v4

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v4
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@v6
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=raw,value=latest

      - name: Build and push image
        uses: docker/build-push-action@v7
        with:
          context: .
          file: Dockerfile.release
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}