name: Release
on:
release:
types: [created]
workflow_dispatch:
inputs:
tag_name:
description: "Release tag to build (e.g. v2.1.0)"
required: true
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
TAG_NAME: ${{ github.event.release.tag_name || inputs.tag_name }}
permissions:
contents: write
jobs:
build-musl:
name: Build musl (${{ matrix.target }})
runs-on: ${{ matrix.runs-on }}
strategy:
matrix:
include:
- target: x86_64-unknown-linux-musl
artifact: structured-proxy-linux-amd64
runs-on: ubuntu-latest
- target: aarch64-unknown-linux-musl
artifact: structured-proxy-linux-arm64
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v6
with:
ref: ${{ env.TAG_NAME }}
- name: Install Rust + musl target
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install musl tools
run: |
sudo apt-get update
sudo apt-get install -y musl-tools
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Build static binary
run: |
# `redis` is compiled in so the packaged `shield.redis_url` config
# works (multi-instance shared rate limits) instead of silently
# falling back to per-process counters. It is a pure-Rust dependency,
# so it stays musl-static-clean.
cargo build --release --target ${{ matrix.target }} --features redis --bin structured-proxy
strip target/${{ matrix.target }}/release/structured-proxy || true
- name: Package
run: |
cp target/${{ matrix.target }}/release/structured-proxy \
structured-proxy-${{ env.TAG_NAME }}-${{ matrix.artifact }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: structured-proxy-${{ env.TAG_NAME }}-${{ matrix.artifact }}
retention-days: 1
- name: Attach binary to release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.TAG_NAME }}
files: structured-proxy-${{ env.TAG_NAME }}-${{ matrix.artifact }}
build-rpm:
name: Build RPM (${{ matrix.fedora }}/${{ matrix.arch }})
runs-on: ${{ matrix.runs-on }}
needs: build-musl
container:
image: registry.fedoraproject.org/fedora:${{ matrix.fedora }}
strategy:
fail-fast: false
matrix:
include:
- { fedora: "42", arch: x86_64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 }
- { fedora: "42", arch: aarch64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 }
- { fedora: "43", arch: x86_64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 }
- { fedora: "43", arch: aarch64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 }
- { fedora: "44", arch: x86_64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 }
- { fedora: "44", arch: aarch64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 }
steps:
- name: Install rpmbuild + helpers
run: |
dnf install -y --setopt=install_weak_deps=False \
rpm-build rpmdevtools systemd-rpm-macros findutils tar
rpmdev-setuptree
- uses: actions/checkout@v6
with:
ref: ${{ env.TAG_NAME }}
- name: Download prebuilt binary
uses: actions/download-artifact@v4
with:
name: ${{ matrix.bin_artifact }}
path: /tmp/bin/
- name: Stage sources
run: |
VERSION=$(echo "${{ env.TAG_NAME }}" | sed 's/^v//')
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
BIN=$(find /tmp/bin -type f -name 'structured-proxy-*' | head -1)
install -m 0755 "$BIN" ~/rpmbuild/SOURCES/structured-proxy
install -m 0644 packaging/structured-proxy.service ~/rpmbuild/SOURCES/structured-proxy.service
install -m 0644 packaging/config.yaml ~/rpmbuild/SOURCES/config.yaml
install -m 0644 packaging/structured-proxy.sysusers ~/rpmbuild/SOURCES/structured-proxy.sysusers
install -m 0644 LICENSE ~/rpmbuild/SOURCES/LICENSE
install -m 0644 README.md ~/rpmbuild/SOURCES/README.md
- name: Build RPM
run: |
rpmbuild -bb \
--define "_topdir $HOME/rpmbuild" \
--define "version $VERSION" \
--target ${{ matrix.arch }} \
packaging/rpm/structured-proxy.spec
find ~/rpmbuild/RPMS -name '*.rpm' -print
- name: Lint with rpmlint (advisory)
continue-on-error: true
run: |
dnf install -y --setopt=install_weak_deps=False rpmlint || true
rpmlint $(find ~/rpmbuild/RPMS -name '*.rpm') || true
- name: Stage artifact
run: |
mkdir -p /tmp/artifacts
cp ~/rpmbuild/RPMS/${{ matrix.arch }}/*.rpm /tmp/artifacts/
- name: Upload RPM artifact
uses: actions/upload-artifact@v4
with:
name: rpm-fc${{ matrix.fedora }}-${{ matrix.arch }}
path: /tmp/artifacts/*.rpm
if-no-files-found: error
- name: Attach RPM to release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.TAG_NAME }}
files: /tmp/artifacts/*.rpm
build-deb:
name: Build DEB (${{ matrix.codename }}/${{ matrix.arch }})
runs-on: ${{ matrix.runs-on }}
needs: build-musl
container:
image: ${{ matrix.image }}
strategy:
fail-fast: false
matrix:
include:
- { codename: bookworm, image: "debian:bookworm", arch: amd64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 }
- { codename: bookworm, image: "debian:bookworm", arch: arm64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 }
- { codename: jammy, image: "ubuntu:jammy", arch: amd64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 }
- { codename: jammy, image: "ubuntu:jammy", arch: arm64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 }
- { codename: noble, image: "ubuntu:noble", arch: amd64, runs-on: ubuntu-latest, bin_artifact: structured-proxy-linux-amd64 }
- { codename: noble, image: "ubuntu:noble", arch: arm64, runs-on: ubuntu-24.04-arm, bin_artifact: structured-proxy-linux-arm64 }
steps:
- name: Install debhelper + dpkg-dev
env:
DEBIAN_FRONTEND: noninteractive
run: |
apt-get update
# build-essential satisfies the implicit Build-Depends pulled in by
# debhelper-compat (= 13); without it dpkg-checkbuilddeps aborts.
apt-get install -y --no-install-recommends \
debhelper dpkg-dev dh-make ca-certificates findutils \
build-essential adduser
- uses: actions/checkout@v6
with:
ref: ${{ env.TAG_NAME }}
- name: Download prebuilt binary
uses: actions/download-artifact@v4
with:
name: ${{ matrix.bin_artifact }}
path: /tmp/bin/
- name: Assemble source tree
run: |
VERSION=$(echo "${{ env.TAG_NAME }}" | sed 's/^v//')
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
BUILD=/tmp/structured-proxy-$VERSION
mkdir -p "$BUILD/packaging"
BIN=$(find /tmp/bin -type f -name 'structured-proxy-*' | head -1)
install -m 0755 "$BIN" "$BUILD/structured-proxy"
cp -r packaging/structured-proxy.service packaging/config.yaml \
packaging/structured-proxy.sysusers \
"$BUILD/packaging/"
cp -r packaging/deb/debian "$BUILD/"
cp LICENSE README.md "$BUILD/"
# Rewrite the placeholder changelog with the actual version.
cat > "$BUILD/debian/changelog" <<CHANGELOG
structured-proxy ($VERSION) unstable; urgency=medium
* Automated release $VERSION; see CHANGELOG.md upstream.
-- Release Bot <oss@sw.foundation> $(date -R)
CHANGELOG
echo "BUILD_DIR=$BUILD" >> "$GITHUB_ENV"
- name: Build DEB
working-directory: ${{ env.BUILD_DIR }}
run: |
dpkg-buildpackage -us -uc -b -a${{ matrix.arch }}
ls -la ..
- name: Lint with lintian (advisory)
continue-on-error: true
run: |
apt-get install -y --no-install-recommends lintian || true
lintian /tmp/structured-proxy_*_${{ matrix.arch }}.deb || true
- name: Stage artifact
run: |
mkdir -p /tmp/artifacts
cp /tmp/structured-proxy_${VERSION}_${{ matrix.arch }}.deb /tmp/artifacts/
- name: Upload DEB artifact
uses: actions/upload-artifact@v4
with:
name: deb-${{ matrix.codename }}-${{ matrix.arch }}
path: /tmp/artifacts/*.deb
if-no-files-found: error
- name: Attach DEB to release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.TAG_NAME }}
files: /tmp/artifacts/*.deb
publish-repo:
name: Publish to repo.sw.foundation
runs-on: ubuntu-latest
needs: [build-rpm, build-deb]
steps:
- uses: actions/checkout@v6
with:
ref: ${{ env.TAG_NAME }}
- name: Repo metadata
run: |
mkdir -p /tmp/repo-meta
cp packaging/manifest.json /tmp/repo-meta/
- name: Upload repo-meta artifact
uses: actions/upload-artifact@v4
with:
name: repo-meta-structured-proxy
path: /tmp/repo-meta/
- name: Generate release bot token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.RELEASER_APP_ID }}
private-key: ${{ secrets.RELEASER_APP_PRIVATE_KEY }}
repositories: repo
- name: Trigger repo publish
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
gh api repos/structured-world/repo/dispatches \
--method POST \
-f event_type=publish-from-structured-proxy \
-f client_payload[structured_proxy_run_id]="${{ github.run_id }}" \
-f client_payload[structured_proxy_repo]="${{ github.repository }}"