tmpltool 1.5.0

A fast and simple command-line template rendering tool using MiniJinja templates with environment variables
Documentation
# Reusable workflow for building all package formats
# Called by ci.yml and release.yml

name: Build Packages

permissions:
  contents: read

on:
  workflow_call:
    inputs:
      ref:
        description: 'Git ref to checkout (commit SHA or tag)'
        required: true
        type: string
      version:
        description: 'Version string for package naming (optional, reads from Cargo.toml if not provided)'
        required: false
        type: string
      artifact-retention-days:
        description: 'Number of days to retain artifacts'
        required: false
        default: 7
        type: number

jobs:
  # ============================================
  # Linux Packages (DEB, RPM, APK)
  # ============================================
  build-linux-packages:
    name: Build Linux Packages (${{ matrix.arch }})
    runs-on: ubuntu-22.04
    strategy:
      fail-fast: false
      matrix:
        include:
          - arch: x86_64
            target: x86_64-unknown-linux-gnu
            musl_target: x86_64-unknown-linux-musl
            deb_arch: amd64
            rpm_arch: x86_64
            use_cross: false

          - arch: aarch64
            target: aarch64-unknown-linux-gnu
            musl_target: aarch64-unknown-linux-musl
            deb_arch: arm64
            rpm_arch: aarch64
            use_cross: true

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.ref }}

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }},${{ matrix.musl_target }}

      - name: Install cross
        if: matrix.use_cross
        run: cargo install cross --git https://github.com/cross-rs/cross

      - name: Install musl tools
        if: "!matrix.use_cross"
        run: |
          sudo apt-get update
          sudo apt-get install -y musl-tools

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: ~/.cargo/registry
          key: ${{ runner.os }}-${{ matrix.arch }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache cargo build
        uses: actions/cache@v4
        with:
          path: target
          key: ${{ runner.os }}-${{ matrix.arch }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}

      - name: Get version
        id: version
        run: |
          if [ -n "${{ inputs.version }}" ]; then
            echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
          else
            VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
            echo "version=$VERSION" >> $GITHUB_OUTPUT
          fi

      # Build glibc binary (for DEB/RPM)
      - name: Build glibc binary (cross)
        if: matrix.use_cross
        run: cross build --release --target ${{ matrix.target }}

      - name: Build glibc binary (cargo)
        if: "!matrix.use_cross"
        run: cargo build --release --target ${{ matrix.target }}

      # Build musl binary (for APK)
      - name: Build musl binary (cross)
        if: matrix.use_cross
        run: cross build --release --target ${{ matrix.musl_target }}

      - name: Build musl binary (cargo)
        if: "!matrix.use_cross"
        run: cargo build --release --target ${{ matrix.musl_target }}

      # DEB Package
      - name: Install cargo-deb
        run: cargo install cargo-deb

      - name: Build DEB package
        run: |
          if [ "${{ matrix.use_cross }}" = "true" ]; then
            cargo deb --no-build --no-strip --target ${{ matrix.target }}
          else
            cargo deb --no-build --target ${{ matrix.target }}
          fi
          cp target/${{ matrix.target }}/debian/*.deb tmpltool_${{ steps.version.outputs.version }}_${{ matrix.deb_arch }}.deb

      # RPM Package
      - name: Install cargo-generate-rpm
        run: cargo install cargo-generate-rpm

      - name: Build RPM package
        run: |
          cargo generate-rpm --target ${{ matrix.target }}
          cp target/${{ matrix.target }}/generate-rpm/*.rpm tmpltool-${{ steps.version.outputs.version }}-1.${{ matrix.rpm_arch }}.rpm

      # APK Package
      - name: Build APK package
        run: |
          VERSION=${{ steps.version.outputs.version }}
          ARCH=${{ matrix.arch }}
          PKGNAME="tmpltool-${VERSION}-r0-${ARCH}.apk"

          mkdir -p apk_pkg/usr/bin
          cp target/${{ matrix.musl_target }}/release/tmpltool apk_pkg/usr/bin/
          chmod 755 apk_pkg/usr/bin/tmpltool

          cat > apk_pkg/.PKGINFO << EOF
          pkgname = tmpltool
          pkgver = ${VERSION}-r0
          pkgdesc = A fast and simple command-line template rendering tool using MiniJinja templates
          url = https://github.com/bordeux/tmpltool
          arch = ${ARCH}
          license = MIT
          size = $(stat -c%s target/${{ matrix.musl_target }}/release/tmpltool)
          origin = tmpltool
          maintainer = Chris Bednarczyk <tmpltool@bordeux.net>
          builddate = $(date +%s)
          EOF

          cd apk_pkg
          tar -czf "../${PKGNAME}" .PKGINFO usr
          cd ..

      # Upload artifacts
      - name: Upload DEB artifact
        uses: actions/upload-artifact@v4
        with:
          name: tmpltool-deb-${{ matrix.deb_arch }}
          path: tmpltool_${{ steps.version.outputs.version }}_${{ matrix.deb_arch }}.deb
          retention-days: ${{ inputs.artifact-retention-days }}

      - name: Upload RPM artifact
        uses: actions/upload-artifact@v4
        with:
          name: tmpltool-rpm-${{ matrix.rpm_arch }}
          path: tmpltool-${{ steps.version.outputs.version }}-1.${{ matrix.rpm_arch }}.rpm
          retention-days: ${{ inputs.artifact-retention-days }}

      - name: Upload APK artifact
        uses: actions/upload-artifact@v4
        with:
          name: tmpltool-apk-${{ matrix.arch }}
          path: tmpltool-${{ steps.version.outputs.version }}-r0-${{ matrix.arch }}.apk
          retention-days: ${{ inputs.artifact-retention-days }}

  # ============================================
  # macOS DMG
  # ============================================
  build-dmg:
    name: Build DMG (${{ matrix.arch }})
    runs-on: macos-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          - arch: x86_64
            target: x86_64-apple-darwin
          - arch: aarch64
            target: aarch64-apple-darwin

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.ref }}

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: ~/.cargo/registry
          key: ${{ runner.os }}-${{ matrix.arch }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache cargo build
        uses: actions/cache@v4
        with:
          path: target
          key: ${{ runner.os }}-${{ matrix.arch }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}

      - name: Get version
        id: version
        run: |
          if [ -n "${{ inputs.version }}" ]; then
            echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
          else
            VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
            echo "version=$VERSION" >> $GITHUB_OUTPUT
          fi

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

      - name: Strip binary
        run: strip target/${{ matrix.target }}/release/tmpltool || true

      - name: Build DMG
        run: |
          VERSION=${{ steps.version.outputs.version }}
          ARCH=${{ matrix.arch }}
          DMG_NAME="tmpltool-${VERSION}-darwin-${ARCH}.dmg"

          STAGING_DIR=$(mktemp -d)

          cp target/${{ matrix.target }}/release/tmpltool "${STAGING_DIR}/tmpltool"
          chmod +x "${STAGING_DIR}/tmpltool"
          cp README.md "${STAGING_DIR}/"
          cp LICENSE "${STAGING_DIR}/"
          ln -s /Applications "${STAGING_DIR}/Applications"

          hdiutil create \
            -volname "tmpltool ${VERSION}" \
            -srcfolder "$STAGING_DIR" \
            -ov \
            -format UDZO \
            "$DMG_NAME"

          rm -rf "$STAGING_DIR"

      - name: Upload DMG artifact
        uses: actions/upload-artifact@v4
        with:
          name: tmpltool-dmg-${{ matrix.arch }}
          path: tmpltool-${{ steps.version.outputs.version }}-darwin-${{ matrix.arch }}.dmg
          retention-days: ${{ inputs.artifact-retention-days }}

  # ============================================
  # Windows MSI
  # ============================================
  build-msi:
    name: Build MSI (x64)
    runs-on: windows-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.ref }}

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry
        uses: actions/cache@v4
        with:
          path: ~/.cargo/registry
          key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

      - name: Cache cargo build
        uses: actions/cache@v4
        with:
          path: target
          key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}

      - name: Get version
        id: version
        shell: pwsh
        run: |
          if ("${{ inputs.version }}" -ne "") {
            echo "version=${{ inputs.version }}" >> $env:GITHUB_OUTPUT
          } else {
            $version = (Select-String -Path Cargo.toml -Pattern '^version = "(.+)"' | Select-Object -First 1).Matches.Groups[1].Value
            echo "version=$version" >> $env:GITHUB_OUTPUT
          }

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

      - name: Install cargo-wix
        run: cargo install cargo-wix

      - name: Build MSI
        run: cargo wix --no-build --nocapture

      - name: Rename MSI
        shell: pwsh
        run: |
          $version = "${{ steps.version.outputs.version }}"
          $msiFile = Get-ChildItem -Path "target/wix" -Filter "*.msi" | Select-Object -First 1
          Copy-Item $msiFile.FullName -Destination "tmpltool-$version-windows-x86_64.msi"

      - name: Upload MSI artifact
        uses: actions/upload-artifact@v4
        with:
          name: tmpltool-msi-x64
          path: tmpltool-${{ steps.version.outputs.version }}-windows-x86_64.msi
          retention-days: ${{ inputs.artifact-retention-days }}