liepress 0.1.4

A Markdown to PDF/SVG/PNG converter with CSS styling support
Documentation
name: release

on:
  workflow_dispatch:
    inputs:
      upload_artifacts:
        description: "Upload build artifacts"
        required: false
        default: "true"
        type: choice
        options: ["true", "false"]
      release_tag:
        description: "Tag to publish the release under (required when run manually, e.g. v0.1.3)"
        required: false
        default: ""
        type: string
  push:
    tags: ["v*"]

env:
  CARGO_TERM_COLOR: always
  BINARY_NAME: liepress

jobs:
  build-x86_64-linux:
    name: Build x86_64 Linux (gnu)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Compute version
        id: version
        shell: bash
        run: |
          # 版本号提取(支持语义化版本,含预发布/构建后缀,如 v0.1.4-beta.1)
          if [[ "${{ github.event_name }}" == "push" ]]; then
            TAG="${{ github.ref_name }}"
          else
            TAG="${{ github.event.inputs.release_tag }}"
          fi
          VER="${TAG#v}"
          # 完整 SemVer 匹配:MAJOR.MINOR.PATCH[-pre][+build],未匹配则回退 Cargo.toml
          if [[ ! "$VER" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
            VER="$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?)".*/\1/')"
          fi
          echo "version=v${VER}" >> "$GITHUB_OUTPUT"

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-unknown-linux-gnu

      - uses: Swatinem/rust-cache@v2
        with:
          key: x86_64-gnu-217

      - name: Install system deps
        run: |
          sudo apt-get update
          sudo apt-get install -y \
            libfontconfig1-dev libfreetype6-dev libexpat1-dev pkg-config

      - uses: mlugg/setup-zig@v2
        with:
          version: "0.13.0"

      - name: Install cargo-zigbuild
        run: pip3 install cargo-zigbuild

      - name: Build
        run: cargo zigbuild --release --target x86_64-unknown-linux-gnu.2.17

      - name: Sanity check
        run: |
          BIN=target/x86_64-unknown-linux-gnu/release/${{ env.BINARY_NAME }}
          readelf -W --version-info "$BIN" | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -1
          nm -D --undefined-only "$BIN" 2>/dev/null | grep -E 'Fc[A-Z].*@FONTCCONFIG_2\.(1[1-9]|[2-9][0-9])' && exit 1 || echo "fontconfig symbols OK"

      - uses: actions/upload-artifact@v4
        if: ${{ github.event.inputs.upload_artifacts != 'false' }}
        with:
          name: ${{ env.BINARY_NAME }}-${{ steps.version.outputs.version }}-x86_64-linux-gnu
          path: target/x86_64-unknown-linux-gnu/release/${{ env.BINARY_NAME }}
          retention-days: 30

  build-aarch64-linux:
    name: Build aarch64 Linux (gnu)
    runs-on: ubuntu-24.04-arm
    steps:
      - uses: actions/checkout@v4

      - name: Compute version
        id: version
        shell: bash
        run: |
          # 版本号提取(支持语义化版本,含预发布/构建后缀,如 v0.1.4-beta.1)
          if [[ "${{ github.event_name }}" == "push" ]]; then
            TAG="${{ github.ref_name }}"
          else
            TAG="${{ github.event.inputs.release_tag }}"
          fi
          VER="${TAG#v}"
          # 完整 SemVer 匹配:MAJOR.MINOR.PATCH[-pre][+build],未匹配则回退 Cargo.toml
          if [[ ! "$VER" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
            VER="$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?)".*/\1/')"
          fi
          echo "version=v${VER}" >> "$GITHUB_OUTPUT"

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: aarch64-unknown-linux-gnu

      - uses: Swatinem/rust-cache@v2
        with:
          key: aarch64-gnu-228

      - name: Install system deps
        run: |
          sudo apt-get update
          sudo apt-get install -y \
            libfontconfig1-dev libfreetype6-dev libexpat1-dev pkg-config

      - uses: mlugg/setup-zig@v2
        with:
          version: "0.13.0"

      - name: Install cargo-zigbuild
        run: pip3 install cargo-zigbuild

      - name: Build
        run: cargo zigbuild --release --target aarch64-unknown-linux-gnu.2.28

      - name: Sanity check
        run: |
          BIN=target/aarch64-unknown-linux-gnu/release/${{ env.BINARY_NAME }}
          readelf -W --version-info "$BIN" | grep -o 'GLIBC_[0-9.]*' | sort -Vu | tail -1
          nm -D --undefined-only "$BIN" 2>/dev/null | grep -E 'Fc[A-Z].*@FONTCCONFIG_2\.(1[1-9]|[2-9][0-9])' && exit 1 || echo "fontconfig symbols OK"

      - uses: actions/upload-artifact@v4
        if: ${{ github.event.inputs.upload_artifacts != 'false' }}
        with:
          name: ${{ env.BINARY_NAME }}-${{ steps.version.outputs.version }}-aarch64-linux-gnu
          path: target/aarch64-unknown-linux-gnu/release/${{ env.BINARY_NAME }}
          retention-days: 30

  build-x86_64-windows:
    name: Build x86_64 Windows (MSVC)
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4

      - name: Compute version
        id: version
        shell: bash
        run: |
          # 版本号提取(支持语义化版本,含预发布/构建后缀,如 v0.1.4-beta.1)
          if [[ "${{ github.event_name }}" == "push" ]]; then
            TAG="${{ github.ref_name }}"
          else
            TAG="${{ github.event.inputs.release_tag }}"
          fi
          VER="${TAG#v}"
          # 完整 SemVer 匹配:MAJOR.MINOR.PATCH[-pre][+build],未匹配则回退 Cargo.toml
          if [[ ! "$VER" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
            VER="$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?)".*/\1/')"
          fi
          echo "version=v${VER}" >> "$GITHUB_OUTPUT"

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: x86_64-pc-windows-msvc

      - uses: Swatinem/rust-cache@v2
        with:
          key: x86_64-windows-msvc

      - name: Install NASM (for some native deps)
        run: |
          choco install nasm -y
          echo "C:\Program Files\NASM" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

      - name: Build
        run: cargo build --release --target x86_64-pc-windows-msvc

      - name: Sanity check
        run: |
          $BIN = "target\x86_64-pc-windows-msvc\release\${{ env.BINARY_NAME }}.exe"
          if (Test-Path $BIN) {
            Write-Host "Binary exists: $BIN"
            $size = (Get-Item $BIN).Length
            Write-Host "Binary size: $([math]::Round($size / 1MB, 2)) MB"
          } else {
            Write-Error "Binary not found: $BIN"
            exit 1
          }

      - uses: actions/upload-artifact@v4
        if: ${{ github.event.inputs.upload_artifacts != 'false' }}
        with:
          name: ${{ env.BINARY_NAME }}-${{ steps.version.outputs.version }}-x86_64-windows-msvc
          path: target\x86_64-pc-windows-msvc\release\${{ env.BINARY_NAME }}.exe
          retention-days: 30

  release:
    name: Package and publish GitHub Release
    needs:
      - build-x86_64-linux
      - build-aarch64-linux
      - build-x86_64-windows
    runs-on: ubuntu-latest
    if: >-
      github.event_name == 'push' ||
      github.event.inputs.upload_artifacts != 'false'
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4

      - name: Compute version
        id: version
        shell: bash
        run: |
          # 版本号优先级:
          #   1) push tag(如 v0.1.4-beta.1)→ github.ref_name
          #   2) 手动触发的 release_tag input(如 v0.1.4-beta.1 或 0.1.4-beta.1)
          #   3) 兜底:Cargo.toml 的 package.version
          # 统一带 v 前缀(如 v0.1.4-beta.1),支持语义化版本(含预发布/构建后缀)
          if [[ "${{ github.event_name }}" == "push" ]]; then
            TAG="${{ github.ref_name }}"
          else
            TAG="${{ github.event.inputs.release_tag }}"
          fi
          VER="${TAG#v}"
          # 完整 SemVer 匹配:MAJOR.MINOR.PATCH[-pre][+build],未匹配则回退 Cargo.toml
          if [[ ! "$VER" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$ ]]; then
            VER="$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?)".*/\1/')"
          fi
          echo "version=v${VER}" >> "$GITHUB_OUTPUT"
          echo "Release version: v${VER}"

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

      - name: Package artifacts
        shell: bash
        run: |
          set -euo pipefail
          VER="${{ steps.version.outputs.version }}"
          mkdir -p dist
          cd artifacts

          # x86_64 Linux
          tar -czf "../dist/${{ env.BINARY_NAME }}-${VER}-x86_64-linux-gnu.tar.gz" -C "${{ env.BINARY_NAME }}-${VER}-x86_64-linux-gnu" "${{ env.BINARY_NAME }}"

          # aarch64 Linux
          tar -czf "../dist/${{ env.BINARY_NAME }}-${VER}-aarch64-linux-gnu.tar.gz" -C "${{ env.BINARY_NAME }}-${VER}-aarch64-linux-gnu" "${{ env.BINARY_NAME }}"

          # x86_64 Windows
          cd "${{ env.BINARY_NAME }}-${VER}-x86_64-windows-msvc"
          zip -q "../../dist/${{ env.BINARY_NAME }}-${VER}-x86_64-windows-msvc.zip" "${{ env.BINARY_NAME }}.exe"
          cd ../..

          # Checksums
          cd dist
          sha256sum *.tar.gz *.zip > sha256.txt
          cat sha256.txt

      - name: Publish GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ github.event.inputs.release_tag != '' && github.event.inputs.release_tag || github.ref_name }}
          files: |
            dist/*.tar.gz
            dist/*.zip
            dist/sha256.txt
          generate_release_notes: true
          fail_on_unmatched_files: true