name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to build and publish (e.g. v0.1.0)'
required: true
permissions: {}
env:
CARGO_TERM_COLOR: always
jobs:
build:
name: Build (${{ matrix.target }})
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
- os: macos-latest
target: x86_64-apple-darwin
- os: macos-latest
target: aarch64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with:
persist-credentials: false
- name: Install Rust (stable)
shell: bash
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustup target add ${{ matrix.target }}
- name: Build
run: cargo build --release --target ${{ matrix.target }}
- name: Package (unix)
if: runner.os != 'Windows'
run: |
cd target/${{ matrix.target }}/release
tar -czf "$GITHUB_WORKSPACE/shipsafe-${{ matrix.target }}.tar.gz" shipsafe
cd "$GITHUB_WORKSPACE"
shasum -a 256 "shipsafe-${{ matrix.target }}.tar.gz" > "shipsafe-${{ matrix.target }}.tar.gz.sha256"
- name: Package (windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
Compress-Archive -Path "target/${{ matrix.target }}/release/shipsafe.exe" -DestinationPath "shipsafe-${{ matrix.target }}.zip"
$hash = (Get-FileHash "shipsafe-${{ matrix.target }}.zip" -Algorithm SHA256).Hash.ToLower()
"$hash shipsafe-${{ matrix.target }}.zip" | Out-File -Encoding ascii "shipsafe-${{ matrix.target }}.zip.sha256"
- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 with:
name: release-${{ matrix.target }}
path: shipsafe-${{ matrix.target }}.*
release:
name: Create GitHub Release
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with:
persist-credentials: false
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 with:
pattern: release-*
merge-multiple: true
- name: Combined checksums
run: cat ./*.sha256 > SHA256SUMS
- name: Create Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ inputs.tag || github.ref_name }}
run: |
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release upload "$TAG" --repo "$GITHUB_REPOSITORY" --clobber \
shipsafe-*.tar.gz shipsafe-*.tar.gz.sha256 \
shipsafe-*.zip shipsafe-*.zip.sha256 \
SHA256SUMS
else
gh release create "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--title "$TAG" \
--generate-notes \
shipsafe-*.tar.gz shipsafe-*.tar.gz.sha256 \
shipsafe-*.zip shipsafe-*.zip.sha256 \
SHA256SUMS
fi
docker:
name: Push Docker image to ghcr.io
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with:
persist-credentials: false
- name: Log in to ghcr.io
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: echo "$GH_TOKEN" | docker login ghcr.io -u "$GITHUB_ACTOR" --password-stdin
- name: Build and push
env:
TAG: ${{ inputs.tag || github.ref_name }}
run: |
VERSION="${TAG#v}"
MAJOR_MINOR="${VERSION%.*}"
IMAGE="ghcr.io/baneido/shipsafe"
docker build \
--label org.opencontainers.image.revision="$GITHUB_SHA" \
--label org.opencontainers.image.version="$VERSION" \
-t "$IMAGE:$VERSION" -t "$IMAGE:$MAJOR_MINOR" -t "$IMAGE:latest" .
docker push "$IMAGE:$VERSION"
docker push "$IMAGE:$MAJOR_MINOR"
docker push "$IMAGE:latest"
- name: Smoke test image
run: |
docker run --rm ghcr.io/baneido/shipsafe:latest version
docker run --rm ghcr.io/baneido/shipsafe:latest doctor
crates:
name: Publish to crates.io
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with:
persist-credentials: false
- name: Install Rust (stable)
run: rustup toolchain install stable --profile minimal && rustup default stable
- name: Authenticate to crates.io (Trusted Publishing / OIDC)
id: auth
uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 - name: Publish
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
run: cargo publish --locked
homebrew:
name: Update Homebrew formula
needs: release
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 with:
persist-credentials: false
- name: Update baneido/homebrew-tap
env:
TAP_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
TAG: ${{ inputs.tag || github.ref_name }}
run: |
if [ -z "$TAP_TOKEN" ]; then
echo "::warning::TAP_GITHUB_TOKEN not set — skipping Homebrew formula update"
exit 0
fi
VERSION="${TAG#v}"
URL="https://github.com/baneido/shipsafe/archive/refs/tags/${TAG}.tar.gz"
curl -fsSL "$URL" -o source.tar.gz
SHA=$(sha256sum source.tar.gz | awk '{print $1}')
git clone "https://x-access-token:${TAP_TOKEN}@github.com/baneido/homebrew-tap.git" tap
mkdir -p tap/Formula
sed -e "s|{{VERSION}}|${VERSION}|g" \
-e "s|{{URL}}|${URL}|g" \
-e "s|{{SHA256}}|${SHA}|g" \
scripts/shipsafe.rb.tmpl > tap/Formula/shipsafe.rb
cd tap
git config user.name "shipsafe-release-bot"
git config user.email "contact@baneido.com"
git add Formula/shipsafe.rb
git commit -m "shipsafe ${VERSION}" || echo "no changes"
git push