greentic-deployer 0.4.45

Greentic deployer runtime for plan construction and deployment-pack dispatch
Documentation
name: Publish and Release

on:
  push:
    branches:
      - main
  workflow_dispatch:

permissions:
  contents: read

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

jobs:
  ci:
    uses: ./.github/workflows/ci.yml

  binary-release-assets:
    name: Build binary release assets
    runs-on: ${{ matrix.os }}
    needs: ci
    permissions:
      contents: write
    if: |
      github.event_name == 'workflow_dispatch' ||
      (github.event_name == 'push' && github.ref == 'refs/heads/main')
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            archive_ext: tar.gz
            asset_suffix: linux-amd64
            binary_name: greentic-deployer
          - os: ubuntu-24.04-arm
            target: aarch64-unknown-linux-gnu
            archive_ext: tar.gz
            asset_suffix: linux-arm64
            binary_name: greentic-deployer
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            archive_ext: zip
            asset_suffix: windows-amd64
            binary_name: greentic-deployer.exe
          - os: windows-11-arm
            target: aarch64-pc-windows-msvc
            archive_ext: zip
            asset_suffix: windows-arm64
            binary_name: greentic-deployer.exe
          - os: macos-15-intel
            target: x86_64-apple-darwin
            archive_ext: tar.gz
            asset_suffix: macos-amd64
            binary_name: greentic-deployer
          - os: macos-15
            target: aarch64-apple-darwin
            archive_ext: tar.gz
            asset_suffix: macos-arm64
            binary_name: greentic-deployer
    steps:
      - uses: actions/checkout@v4
      - name: Read crate version
        id: version
        shell: bash
        run: |
          set -euo pipefail
          version=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)
          if [ -z "$version" ]; then
            echo "Failed to read version from Cargo.toml" >&2
            exit 1
          fi
          echo "value=$version" >> "$GITHUB_OUTPUT"
          echo "tag=v$version" >> "$GITHUB_OUTPUT"
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: 1.91.1
          targets: ${{ matrix.target }}
      - uses: Swatinem/rust-cache@v2
      - name: Build release binary
        run: cargo build --locked --release --target ${{ matrix.target }}
      - name: Package Unix asset
        if: matrix.archive_ext == 'tar.gz'
        shell: bash
        env:
          ASSET_BASENAME: greentic-deployer-${{ matrix.target }}-${{ steps.version.outputs.tag }}
        run: |
          set -euo pipefail
          mkdir "$ASSET_BASENAME"
          cp "target/${{ matrix.target }}/release/${{ matrix.binary_name }}" "$ASSET_BASENAME/"
          tar -czf "${ASSET_BASENAME}.tar.gz" "$ASSET_BASENAME"
      - name: Package Windows ARM asset
        if: matrix.archive_ext == 'zip'
        shell: pwsh
        env:
          ASSET_BASENAME: greentic-deployer-${{ matrix.target }}-${{ steps.version.outputs.tag }}
        run: |
          New-Item -ItemType Directory -Path $env:ASSET_BASENAME | Out-Null
          Copy-Item "target/${{ matrix.target }}/release/${{ matrix.binary_name }}" "$env:ASSET_BASENAME/"
          Compress-Archive -Path $env:ASSET_BASENAME -DestinationPath "$env:ASSET_BASENAME.zip"
      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: greentic-deployer-${{ matrix.target }}-${{ steps.version.outputs.tag }}
          path: greentic-deployer-${{ matrix.target }}-${{ steps.version.outputs.tag }}.${{ matrix.archive_ext }}

  publish-version-release:
    name: Publish version release
    runs-on: ubuntu-latest
    needs: binary-release-assets
    permissions:
      contents: write
    if: |
      github.event_name == 'workflow_dispatch' ||
      (github.event_name == 'push' && github.ref == 'refs/heads/main')
    steps:
      - uses: actions/checkout@v4
      - name: Read crate version
        id: version
        shell: bash
        run: |
          set -euo pipefail
          version=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)
          if [ -z "$version" ]; then
            echo "Failed to read version from Cargo.toml" >&2
            exit 1
          fi
          echo "value=$version" >> "$GITHUB_OUTPUT"
          echo "tag=v$version" >> "$GITHUB_OUTPUT"
      - uses: actions/download-artifact@v4
        with:
          pattern: greentic-deployer-*-${{ steps.version.outputs.tag }}
          path: dist
          merge-multiple: true
      - name: Publish GitHub release assets
        uses: softprops/action-gh-release@v2
        with:
          tag_name: v${{ steps.version.outputs.value }}
          target_commitish: ${{ github.sha }}
          name: v${{ steps.version.outputs.value }}
          prerelease: false
          make_latest: true
          fail_on_unmatched_files: true
          overwrite_files: true
          files: |
            dist/*.tar.gz
            dist/*.zip

  crate-publish:
    runs-on: ubuntu-latest
    needs: ci
    permissions:
      contents: read
    if: github.event_name != 'pull_request'
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: 1.91.1
          components: clippy,rustfmt
      - uses: Swatinem/rust-cache@v2
      - name: Publish to crates.io
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: |
          set -euo pipefail
          publish_output=$(cargo publish --locked 2>&1) || status=$?
          echo "$publish_output"
          if [ "${status:-0}" -ne 0 ]; then
            if echo "$publish_output" | grep -qi "already uploaded"; then
              echo "Version already published; skipping error."
              exit 0
            fi
            if echo "$publish_output" | grep -qi "already exists on crates.io index"; then
              echo "Crate version already on crates.io; skipping publish error."
              exit 0
            fi
            exit ${status:-1}
          fi

  gtpack-publish:
    runs-on: ubuntu-latest
    needs: ci
    permissions:
      contents: read
      packages: write
    if: |
      github.event_name == 'push' ||
      github.event_name == 'workflow_dispatch'
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          toolchain: 1.91.1
      - uses: Swatinem/rust-cache@v2
      - uses: oras-project/setup-oras@v1
      - name: Build fixture gtpacks
        id: build-gtpacks
        run: |
          set -euo pipefail
          cargo run --features internal-tools --bin build_fixture_gtpacks | tee /tmp/build_fixture_gtpacks.log
      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Publish gtpacks to GHCR
        env:
          GHCR_NAMESPACE: ghcr.io/${{ github.repository_owner }}/packs/deployer
          REVISION: ${{ github.sha }}
        run: |
          set -euo pipefail
          mapfile -t pack_lines < <(grep $'^PACK\t' /tmp/build_fixture_gtpacks.log || true)
          if [ "${#pack_lines[@]}" -eq 0 ]; then
            echo "No PACK metadata found in build output"
            exit 1
          fi

          for pack_line in "${pack_lines[@]}"; do
            IFS=$'\t' read -r _ pack_id pack_version pack_path <<<"${pack_line}"
            pack_file="$(basename "$pack_path")"
            version_ref="${GHCR_NAMESPACE}/${pack_id}:${pack_version}"
            latest_ref="${GHCR_NAMESPACE}/${pack_id}:latest"

            echo "Publishing ${pack_file} -> ${version_ref}"
            oras push "${version_ref}" \
              --artifact-type application/vnd.greentic.gtpack.v1 \
              --annotation "org.opencontainers.image.title=${pack_file}" \
              --annotation "org.opencontainers.image.revision=${REVISION}" \
              "${pack_path}:application/vnd.greentic.gtpack.layer.v1+tar"

            echo "Publishing ${pack_file} -> ${latest_ref}"
            oras push "${latest_ref}" \
              --artifact-type application/vnd.greentic.gtpack.v1 \
              --annotation "org.opencontainers.image.title=${pack_file}" \
              --annotation "org.opencontainers.image.revision=${REVISION}" \
              "${pack_path}:application/vnd.greentic.gtpack.layer.v1+tar"
          done