name: Release
on:
push:
tags:
- "mmdflux-v*"
workflow_dispatch:
inputs:
tag:
description: "Tag to release (e.g., mmdflux-v2.1.0)"
required: true
type: string
permissions:
contents: write
concurrency:
group: release-${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.ref_name }}
cancel-in-progress: false
jobs:
build:
name: Build ${{ matrix.artifact_suffix }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact_suffix: linux-x86_64
- os: macos-15-intel
target: x86_64-apple-darwin
artifact_suffix: darwin-x86_64
- os: macos-latest
target: aarch64-apple-darwin
artifact_suffix: darwin-arm64
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact_suffix: windows-x86_64
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Resolve tag and version
id: meta
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_TAG: ${{ github.event.inputs.tag }}
REF_NAME: ${{ github.ref_name }}
run: |
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
TAG="$INPUT_TAG"
else
TAG="$REF_NAME"
fi
TAG="${TAG#refs/tags/}"
if [[ "$TAG" != mmdflux-v* ]]; then
TAG="mmdflux-v${TAG#v}"
fi
VERSION="${TAG#mmdflux-v}"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Resolved tag: $TAG"
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
with:
shared-key: release-${{ matrix.target }}
- name: Build binary
run: cargo build --release --locked --target ${{ matrix.target }}
- name: Package (unix)
if: runner.os != 'Windows'
shell: bash
run: |
mkdir -p dist
ARCHIVE="mmdflux-v${{ steps.meta.outputs.version }}-${{ matrix.artifact_suffix }}.tar.gz"
tar -C "target/${{ matrix.target }}/release" -czf "dist/$ARCHIVE" mmdflux
- name: Package (windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Path dist -Force | Out-Null
Copy-Item "target/${{ matrix.target }}/release/mmdflux.exe" "dist/mmdflux.exe" -Force
$Archive = "mmdflux-v${{ steps.meta.outputs.version }}-${{ matrix.artifact_suffix }}.zip"
Compress-Archive -Path "dist/mmdflux.exe" -DestinationPath "dist/$Archive" -Force
Remove-Item "dist/mmdflux.exe" -Force
- name: Upload packaged artifact
uses: actions/upload-artifact@v5
with:
name: release-${{ matrix.artifact_suffix }}
path: dist/*
if-no-files-found: error
retention-days: 7
publish:
name: Publish GitHub Release
runs-on: ubuntu-latest
needs: build
steps:
- name: Resolve tag and version
id: meta
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_TAG: ${{ github.event.inputs.tag }}
REF_NAME: ${{ github.ref_name }}
run: |
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
TAG="$INPUT_TAG"
else
TAG="$REF_NAME"
fi
TAG="${TAG#refs/tags/}"
if [[ "$TAG" != mmdflux-v* ]]; then
TAG="mmdflux-v${TAG#v}"
fi
VERSION="${TAG#mmdflux-v}"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Resolved tag: $TAG"
- name: Download build artifacts
uses: actions/download-artifact@v6
with:
path: dist
pattern: release-*
merge-multiple: true
- name: Generate checksums
shell: bash
run: |
cd dist
sha256sum * > checksums.txt
- name: Publish release assets
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.meta.outputs.tag }}
name: mmdflux v${{ steps.meta.outputs.version }}
generate_release_notes: true
overwrite_files: true
files: |
dist/*
homebrew:
name: Update Homebrew Formula
runs-on: ubuntu-latest
needs: publish
steps:
- name: Check for tap token
id: check
env:
HAS_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN != '' }}
run: |
if [ "$HAS_TOKEN" != "true" ]; then
echo "::warning::HOMEBREW_TAP_TOKEN not configured, skipping formula update"
echo "skip=true" >> "$GITHUB_OUTPUT"
fi
- name: Resolve tag and version
if: steps.check.outputs.skip != 'true'
id: meta
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_TAG: ${{ github.event.inputs.tag }}
REF_NAME: ${{ github.ref_name }}
run: |
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
TAG="$INPUT_TAG"
else
TAG="$REF_NAME"
fi
TAG="${TAG#refs/tags/}"
if [[ "$TAG" != mmdflux-v* ]]; then
TAG="mmdflux-v${TAG#v}"
fi
VERSION="${TAG#mmdflux-v}"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Download checksums
if: steps.check.outputs.skip != 'true'
uses: actions/download-artifact@v6
with:
path: dist
pattern: release-*
merge-multiple: true
- name: Parse checksums
if: steps.check.outputs.skip != 'true'
id: checksums
shell: bash
run: |
cd dist
sha256sum * > checksums.txt
cat checksums.txt
for suffix in darwin-arm64 darwin-x86_64 linux-x86_64; do
sha=$(grep "${suffix}.tar.gz" checksums.txt | awk '{print $1}')
key=$(echo "$suffix" | tr '-' '_')
echo "${key}=${sha}" >> "$GITHUB_OUTPUT"
done
- name: Clone Homebrew tap
if: steps.check.outputs.skip != 'true'
env:
HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
run: |
git clone "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/kevinswiber/homebrew-mmdflux.git" tap
- name: Update formula
if: steps.check.outputs.skip != 'true'
env:
VERSION: ${{ steps.meta.outputs.version }}
TAG: ${{ steps.meta.outputs.tag }}
SHA_DARWIN_ARM64: ${{ steps.checksums.outputs.darwin_arm64 }}
SHA_DARWIN_X86_64: ${{ steps.checksums.outputs.darwin_x86_64 }}
SHA_LINUX_X86_64: ${{ steps.checksums.outputs.linux_x86_64 }}
shell: bash
run: |
cat > tap/Formula/mmdflux.rb << FORMULA
class Mmdflux < Formula
desc "Render Mermaid diagrams as Unicode text, ASCII, SVG, and MMDS JSON"
homepage "https://github.com/kevinswiber/mmdflux"
version "${VERSION}"
license "MIT"
if OS.mac?
if Hardware::CPU.arm?
url "https://github.com/kevinswiber/mmdflux/releases/download/${TAG}/mmdflux-v${VERSION}-darwin-arm64.tar.gz"
sha256 "${SHA_DARWIN_ARM64}"
else
url "https://github.com/kevinswiber/mmdflux/releases/download/${TAG}/mmdflux-v${VERSION}-darwin-x86_64.tar.gz"
sha256 "${SHA_DARWIN_X86_64}"
end
elsif OS.linux?
if Hardware::CPU.intel?
url "https://github.com/kevinswiber/mmdflux/releases/download/${TAG}/mmdflux-v${VERSION}-linux-x86_64.tar.gz"
sha256 "${SHA_LINUX_X86_64}"
else
odie "Linux ARM64 binaries are not published yet."
end
end
def install
bin.install "mmdflux"
end
test do
assert_match "Usage: mmdflux", shell_output("#{bin}/mmdflux --help")
end
end
FORMULA
# Heredoc indents with spaces — strip them to match the original format
sed -i 's/^ //' tap/Formula/mmdflux.rb
- name: Commit and push
if: steps.check.outputs.skip != 'true'
working-directory: tap
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Formula/mmdflux.rb
git diff --staged --quiet && echo "No changes to commit" && exit 0
git commit -m "Update mmdflux to v${{ steps.meta.outputs.version }}"
git push