name: Release
on:
push:
tags: ['v*']
permissions:
contents: write
jobs:
build:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: aarch64-apple-darwin
os: macos-latest
- target: x86_64-apple-darwin
os: macos-latest
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
musl: true
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
cross: true
steps:
- uses: actions/checkout@v4
- name: Install musl tools
if: matrix.musl
run: sudo apt-get update && sudo apt-get install -y musl-tools
- name: Install cross
if: matrix.cross
run: cargo install cross --version 0.2.5
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
- name: Build (native)
if: ${{ !matrix.cross }}
run: cargo build --release --target ${{ matrix.target }}
- name: Build (cross)
if: matrix.cross
run: cross build --release --target ${{ matrix.target }}
- name: Package
run: |
cd target/${{ matrix.target }}/release
tar czf ../../../beachcomber-${{ github.ref_name }}-${{ matrix.target }}.tar.gz comb
cd ../../..
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: beachcomber-${{ matrix.target }}
path: beachcomber-*.tar.gz
c-sdk-tarball:
name: Package C SDK
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create C SDK tarball
run: |
tar czf beachcomber-c-sdk-${{ github.ref_name }}.tar.gz \
-C sdks/c \
beachcomber.c beachcomber.h json.c json.h Makefile libbeachcomber.pc.in README.md
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: beachcomber-c-sdk
path: beachcomber-c-sdk-*.tar.gz
package-csdk:
name: Package C SDK (${{ matrix.format }})
runs-on: ubuntu-latest
strategy:
matrix:
include:
- format: deb
- format: rpm
steps:
- uses: actions/checkout@v4
- name: Extract version
id: version
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
- name: Build deb
if: matrix.format == 'deb'
run: bash packaging/deb-csdk/build.sh "${{ steps.version.outputs.version }}"
- name: Build rpm
if: matrix.format == 'rpm'
run: |
sudo apt-get update && sudo apt-get install -y rpm
bash packaging/rpm-csdk/build.sh "${{ steps.version.outputs.version }}"
- name: Upload package
uses: actions/upload-artifact@v4
with:
name: libbeachcomber-${{ matrix.format }}
path: |
*.deb
*.rpm
test-csdk-packages:
name: Test C SDK ${{ matrix.distro }} package
needs: package-csdk
runs-on: ubuntu-latest
strategy:
matrix:
include:
- distro: ubuntu
format: deb
image: ubuntu:latest
- distro: fedora
format: rpm
image: fedora:latest
steps:
- name: Download package
uses: actions/download-artifact@v4
with:
name: libbeachcomber-${{ matrix.format }}
path: pkg
- name: Test install and pkg-config
run: |
docker run --rm -v ${{ github.workspace }}/pkg:/pkg ${{ matrix.image }} bash -c '
if [ "${{ matrix.format }}" = "deb" ]; then
apt-get update && apt-get install -y pkg-config
dpkg -i /pkg/*.deb
else
dnf install -y pkg-config
rpm -i /pkg/*.rpm
fi
pkg-config --exists libbeachcomber
pkg-config --cflags libbeachcomber
pkg-config --libs libbeachcomber
test -f /usr/include/beachcomber.h
test -f /usr/include/json.h
test -f /usr/lib/libbeachcomber.so
test -f /usr/lib/libbeachcomber.a
echo "All checks passed"
'
package-linux:
name: Package Linux (${{ matrix.format }}-${{ matrix.arch }})
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
include:
- format: deb
arch: x86_64
target: x86_64-unknown-linux-gnu
- format: rpm
arch: x86_64
target: x86_64-unknown-linux-gnu
- format: deb
arch: aarch64
target: aarch64-unknown-linux-gnu
- format: rpm
arch: aarch64
target: aarch64-unknown-linux-gnu
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Download binary artifact
uses: actions/download-artifact@v4
with:
name: beachcomber-${{ matrix.target }}
- name: Extract binary
run: |
mkdir -p target/${{ matrix.target }}/release
tar xzf beachcomber-*.tar.gz -C target/${{ matrix.target }}/release
- name: Build deb
if: matrix.format == 'deb'
run: |
cargo install cargo-deb
cargo deb --no-build --target ${{ matrix.target }}
- name: Build rpm
if: matrix.format == 'rpm'
run: |
cargo install cargo-generate-rpm
cargo generate-rpm --target ${{ matrix.target }}
- name: Upload package
uses: actions/upload-artifact@v4
with:
name: beachcomber-${{ matrix.format }}-${{ matrix.arch }}
path: |
target/${{ matrix.target }}/debian/*.deb
target/${{ matrix.target }}/generate-rpm/*.rpm
test-packages:
name: Test ${{ matrix.distro }} package
needs: package-linux
runs-on: ubuntu-latest
strategy:
matrix:
include:
- distro: ubuntu
format: deb
image: ubuntu:latest
- distro: fedora
format: rpm
image: fedora:latest
steps:
- name: Download package
uses: actions/download-artifact@v4
with:
name: beachcomber-${{ matrix.format }}-x86_64
path: pkg
- name: Test install in container
run: |
docker run --rm -v ${{ github.workspace }}/pkg:/pkg ${{ matrix.image }} \
bash -c 'pkg_file=$(find /pkg -name "*.${{ matrix.format }}" -type f); echo "Installing $pkg_file"; if [ "${{ matrix.format }}" = "deb" ]; then dpkg -i "$pkg_file"; else rpm -i "$pkg_file"; fi && comb --version'
release:
name: Create Release
needs: [build, c-sdk-tarball, package-linux, test-packages, test-csdk-packages]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: |
beachcomber-*.tar.gz
*.deb
*.rpm
publish-crates:
name: Publish to crates.io
needs: release
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: rust-lang/crates-io-auth-action@v1
id: crates-auth
- name: Publish libbeachcomber
run: cargo publish -p libbeachcomber || echo "Already published, skipping"
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates-auth.outputs.token }}
- name: Publish beachcomber
run: cargo publish -p beachcomber || echo "Already published, skipping"
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates-auth.outputs.token }}
publish-pypi:
name: Publish to PyPI
needs: release
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
defaults:
run:
working-directory: sdks/python
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Build
run: pip install build && python -m build
- name: Publish
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: sdks/python/dist/
skip-existing: true
publish-npm:
name: Publish to npm
needs: release
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
defaults:
run:
working-directory: sdks/node
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Publish
run: unset NODE_AUTH_TOKEN && npm publish --access public --provenance || echo "Already published, skipping"
publish-rubygems:
name: Publish to RubyGems
needs: release
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
defaults:
run:
working-directory: sdks/ruby
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
- name: Build gem
run: gem build libbeachcomber.gemspec
- uses: rubygems/configure-rubygems-credentials@main
- name: Publish
run: gem push libbeachcomber-*.gem || echo "Already published, skipping"
publish-luarocks:
name: Publish to LuaRocks
needs: release
runs-on: ubuntu-latest
defaults:
run:
working-directory: sdks/lua
steps:
- uses: actions/checkout@v4
- uses: leafo/gh-actions-lua@v10
with:
luaVersion: '5.4'
- uses: leafo/gh-actions-luarocks@v4
- name: Install JSON library
run: luarocks install dkjson
- name: Publish
run: luarocks upload --skip-pack rockspec/libbeachcomber-0.5.0-1.rockspec --api-key=${{ secrets.LUAROCKS_API_KEY }} || echo "Already published, skipping"
publish-go:
name: Tag Go module
needs: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create Go module tag
run: |
git tag sdks/go/${{ github.ref_name }} || echo "Tag already exists, skipping"
git push origin sdks/go/${{ github.ref_name }} || echo "Tag already pushed, skipping"
publish-homebrew:
name: Update Homebrew tap
needs: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
repository: NavistAu/homebrew-tap
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: homebrew-tap
- name: Download macOS artifacts
uses: actions/download-artifact@v4
with:
pattern: beachcomber-*-apple-darwin
merge-multiple: true
path: artifacts
- name: Generate formula
run: |
VERSION="${{ github.ref_name }}"
VERSION="${VERSION#v}"
ARM_SHA=$(shasum -a 256 artifacts/beachcomber-${{ github.ref_name }}-aarch64-apple-darwin.tar.gz | cut -d' ' -f1)
INTEL_SHA=$(shasum -a 256 artifacts/beachcomber-${{ github.ref_name }}-x86_64-apple-darwin.tar.gz | cut -d' ' -f1)
cat > homebrew-tap/Formula/beachcomber.rb << FORMULA
class Beachcomber < Formula
desc "Daemon that caches shell environment state for instant prompt rendering"
homepage "https://github.com/NavistAu/beachcomber"
version "${VERSION}"
license "MIT"
if Hardware::CPU.arm?
url "https://github.com/NavistAu/beachcomber/releases/download/${{ github.ref_name }}/beachcomber-${{ github.ref_name }}-aarch64-apple-darwin.tar.gz"
sha256 "${ARM_SHA}"
else
url "https://github.com/NavistAu/beachcomber/releases/download/${{ github.ref_name }}/beachcomber-${{ github.ref_name }}-x86_64-apple-darwin.tar.gz"
sha256 "${INTEL_SHA}"
end
def install
bin.install "comb"
end
test do
assert_match "beachcomber", shell_output("#{bin}/comb --version")
end
end
FORMULA
- name: Push formula
run: |
cd homebrew-tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/beachcomber.rb
git commit -m "beachcomber ${{ github.ref_name }}"
git push
publish-npm-binary:
name: Publish beachcomber binary installer to npm
needs: release
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
defaults:
run:
working-directory: placeholders/npm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- name: Set version from tag
run: npm version --no-git-tag-version --allow-same-version "${GITHUB_REF_NAME#v}"
- name: Publish
run: unset NODE_AUTH_TOKEN && npm publish --access public --provenance || echo "Already published, skipping"
publish-pypi-binary:
name: Publish beachcomber binary installer to PyPI
needs: release
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
defaults:
run:
working-directory: placeholders/pypi
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Set version from tag
run: sed -i "s/^version = .*/version = \"${GITHUB_REF_NAME#v}\"/" pyproject.toml
- name: Build
run: pip install build && python -m build
- name: Publish
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: placeholders/pypi/dist/
skip-existing: true