name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
publish_crate:
description: "Publish to crates.io"
type: boolean
default: true
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
jobs:
build-linux:
name: Build Linux (${{ matrix.target }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- x86_64-unknown-linux-musl
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
with:
key: linux-${{ matrix.target }}
- name: Install cross
run: cargo install cross --locked
- name: Build binary
run: cross build --release --target ${{ matrix.target }} --package markdown-tui-explorer
- name: Strip binary
run: |
TARGET_STRIP=""
case "${{ matrix.target }}" in
aarch64-unknown-linux-gnu)
TARGET_STRIP="aarch64-linux-gnu-strip"
sudo apt-get install -y binutils-aarch64-linux-gnu
;;
*)
TARGET_STRIP="strip"
;;
esac
$TARGET_STRIP target/${{ matrix.target }}/release/markdown-reader
- name: Package tarball
run: |
VERSION=${GITHUB_REF_NAME#v}
TARBALL="markdown-reader-${VERSION}-${{ matrix.target }}.tar.gz"
tar -czf "$TARBALL" -C target/${{ matrix.target }}/release markdown-reader
echo "TARBALL=$TARBALL" >> "$GITHUB_ENV"
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: markdown-reader-${{ matrix.target }}
path: ${{ env.TARBALL }}
retention-days: 1
build-macos:
name: Build macOS (${{ matrix.target }})
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
target:
- x86_64-apple-darwin
- aarch64-apple-darwin
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
key: macos-${{ matrix.target }}
- name: Build binary
run: cargo build --release --target ${{ matrix.target }} --package markdown-tui-explorer
- name: Strip binary
run: strip target/${{ matrix.target }}/release/markdown-reader
- name: Package tarball
run: |
VERSION=${GITHUB_REF_NAME#v}
TARBALL="markdown-reader-${VERSION}-${{ matrix.target }}.tar.gz"
tar -czf "$TARBALL" -C target/${{ matrix.target }}/release markdown-reader
echo "TARBALL=$TARBALL" >> "$GITHUB_ENV"
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: markdown-reader-${{ matrix.target }}
path: ${{ env.TARBALL }}
retention-days: 1
release:
name: Create GitHub Release
needs: [build-linux, build-macos]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Download all artifacts
uses: actions/download-artifact@v8
with:
path: artifacts
merge-multiple: true
- name: Generate SHA-256 checksums
working-directory: artifacts
run: sha256sum *.tar.gz > SHA256SUMS
- name: Extract changelog section
id: changelog
run: |
VERSION=${GITHUB_REF_NAME#v}
if [ -f CHANGELOG.md ]; then
# Extract the block between ## [version] and the next ## [
BODY=$(awk "/^## \[${VERSION}\]/{found=1; next} found && /^## \[/{exit} found{print}" CHANGELOG.md)
else
BODY="Release ${GITHUB_REF_NAME}"
fi
printf '%s' "$BODY" > release_notes.md
- name: Publish GitHub Release
uses: softprops/action-gh-release@v3
with:
body_path: release_notes.md
files: |
artifacts/*.tar.gz
artifacts/SHA256SUMS
token: ${{ secrets.GITHUB_TOKEN }}
publish-crate:
name: Publish parent crate to crates.io
needs: [release]
runs-on: ubuntu-latest
if: >
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')) ||
(github.event_name == 'workflow_dispatch' && inputs.publish_crate == true)
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Publish parent crate
run: cargo publish --package markdown-tui-explorer --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
publish-homebrew:
name: Update Homebrew tap
needs: [release]
runs-on: ubuntu-latest
env:
HAS_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN != '' && 'true' || 'false' }}
steps:
- name: Report skip reason
if: env.HAS_TOKEN != 'true'
run: echo "HOMEBREW_TAP_TOKEN is not set on this repo — skipping Homebrew formula publish."
- name: Checkout source repo
if: env.HAS_TOKEN == 'true'
uses: actions/checkout@v6
- name: Download release checksums
if: env.HAS_TOKEN == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p artifacts
gh release download "$GITHUB_REF_NAME" \
-R "$GITHUB_REPOSITORY" \
-p SHA256SUMS \
-D artifacts
- name: Checkout tap repo
if: env.HAS_TOKEN == 'true'
uses: actions/checkout@v6
with:
repository: leboiko/homebrew-tap
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: homebrew-tap
- name: Render formula
if: env.HAS_TOKEN == 'true'
run: |
VERSION=${GITHUB_REF_NAME#v}
mkdir -p homebrew-tap/Formula
./scripts/render-homebrew-formula.sh "$VERSION" artifacts/SHA256SUMS \
> homebrew-tap/Formula/markdown-reader.rb
- name: Commit and push
if: env.HAS_TOKEN == 'true'
working-directory: homebrew-tap
run: |
VERSION=${GITHUB_REF_NAME#v}
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Stage first, then check the index. Plain `git diff --quiet`
# misses brand-new files (Formula/markdown-reader.rb on a
# first-ever release wouldn't exist in the tap yet — the file
# would be untracked, so unstaged-diff returns clean and the
# workflow would exit thinking it was a no-op).
git add Formula/markdown-reader.rb
if git diff --cached --quiet; then
echo "Formula already up to date for v${VERSION}"
exit 0
fi
git commit -m "markdown-reader ${VERSION}"
git push
publish-aur:
name: Publish AUR -bin package
needs: [release]
runs-on: ubuntu-latest
env:
HAS_KEY: ${{ secrets.AUR_SSH_KEY != '' && 'true' || 'false' }}
steps:
- name: Report skip reason
if: env.HAS_KEY != 'true'
run: echo "AUR_SSH_KEY is not set on this repo — skipping AUR publish."
- name: Checkout source repo
if: env.HAS_KEY == 'true'
uses: actions/checkout@v6
- name: Download release checksums
if: env.HAS_KEY == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p artifacts
gh release download "$GITHUB_REF_NAME" \
-R "$GITHUB_REPOSITORY" \
-p SHA256SUMS \
-D artifacts
- name: Set up SSH for AUR
if: env.HAS_KEY == 'true'
env:
AUR_SSH_KEY: ${{ secrets.AUR_SSH_KEY }}
run: |
mkdir -p ~/.ssh
echo "$AUR_SSH_KEY" > ~/.ssh/aur
chmod 600 ~/.ssh/aur
# Pin the AUR host key fingerprint to prevent MITM. Pulled
# from `ssh-keyscan -H aur.archlinux.org` and verified
# against the published fingerprint at
# https://wiki.archlinux.org/title/Aurweb_RPC_interface.
ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null
{
echo "Host aur.archlinux.org"
echo " IdentityFile ~/.ssh/aur"
echo " User aur"
echo " StrictHostKeyChecking yes"
} > ~/.ssh/config
chmod 600 ~/.ssh/config
- name: Clone AUR repo
if: env.HAS_KEY == 'true'
run: |
# Clone (creates a local copy of the AUR-side repo for this
# package). On first publish the AUR-side repo must exist —
# see docs/RELEASING-AUR.md for the manual one-time setup.
git clone ssh://aur@aur.archlinux.org/markdown-reader-bin.git aur-pkg
- name: Render PKGBUILD + .SRCINFO
if: env.HAS_KEY == 'true'
run: |
VERSION=${GITHUB_REF_NAME#v}
./scripts/render-aur-pkgbuild.sh "$VERSION" artifacts/SHA256SUMS aur-pkg
- name: Commit and push
if: env.HAS_KEY == 'true'
working-directory: aur-pkg
run: |
VERSION=${GITHUB_REF_NAME#v}
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add PKGBUILD .SRCINFO
if git diff --cached --quiet; then
echo "AUR PKGBUILD already up to date for v${VERSION}"
exit 0
fi
git commit -m "markdown-reader ${VERSION}"
git push