.github/workflows/cmake-multi-platform.yml
raw ยท 16538 bytes
name: tinyproxy CI
on:
workflow_dispatch:
push:
branches: ["main"]
tags: ["v*"]
pull_request:
branches: ["main"]
concurrency:
group: tinyproxy-${{ github.ref }}
cancel-in-progress: false
env:
ARTIFACT_RETENTION_DAYS: 30
LIBEVENT_VERSION: 2.1.12-stable
LIBEVENT_TARBALL: libevent-2.1.12-stable.tar.gz
LIBEVENT_URL: https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz
jobs:
libevent-source:
name: Prepare libevent source
runs-on: ubuntu-latest
env:
LIBEVENT_VERSION: 2.1.12-stable
LIBEVENT_TARBALL: libevent-2.1.12-stable.tar.gz
LIBEVENT_URL: https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz
steps:
- name: Cache libevent tarball
id: cache-libevent-tarball
uses: actions/cache@v4
with:
path: .cache/libevent/libevent-2.1.12-stable.tar.gz
key: libevent-tarball-2.1.12-stable
- name: Download libevent tarball
if: steps.cache-libevent-tarball.outputs.cache-hit != 'true'
run: |
set -eu
mkdir -p .cache/libevent
curl -fL --retry 5 --retry-delay 2 --retry-all-errors \
"$LIBEVENT_URL" \
-o ".cache/libevent/$LIBEVENT_TARBALL"
- name: Upload libevent tarball
uses: actions/upload-artifact@v4
with:
name: libevent-tarball
path: .cache/libevent/libevent-2.1.12-stable.tar.gz
linux-musl-x86_64:
name: Linux musl x86_64 static
runs-on: ubuntu-latest
needs: libevent-source
container:
image: &alpine_image alpine:3.23
steps:
- &checkout
uses: actions/checkout@v4
- &download_libevent_source
name: Download libevent tarball
uses: actions/download-artifact@v4
with:
name: libevent-tarball
path: .cache/libevent
- &extract_libevent
name: Extract libevent source
run: |
set -eu
rm -rf libevent
mkdir -p libevent
tar xf .cache/libevent/libevent-2.1.12-stable.tar.gz \
-C libevent \
--strip-components=1
- &install_linux_deps
name: Install deps
run: |
apk add --no-cache \
build-base \
python3 \
strace \
haproxy
- &set_build_version
name: Set Build Version
run: |
if [ "${GITHUB_REF_TYPE:-}" = "tag" ]; then
BUILD_VER="${GITHUB_REF_NAME}"
else
BUILD_VER="dev-${GITHUB_SHA::12}"
fi
echo "BUILD_VER=${BUILD_VER}" >> "$GITHUB_ENV"
- &build_static
name: Build
shell: sh
run: |
set -eu
mkdir -p dist/debug dist/prod
make clean all \
STATIC=1 \
EXTRA_CFLAGS="-Og -g3 -Wpedantic" \
LIBEVENT_SRC=./libevent \
VERSION="$BUILD_VER"
cp bin/tinyproxy dist/debug/tinyproxy
make clean all \
STATIC=1 \
LIBEVENT_SRC=./libevent \
VERSION="$BUILD_VER"
cp bin/tinyproxy dist/prod/tinyproxy
strip dist/prod/tinyproxy
- &verify_static
name: Verify static binary
shell: sh
run: |
set -eu
apk add --no-cache pax-utils
file dist/prod/tinyproxy
scanelf -n dist/prod/tinyproxy
if scanelf -n dist/prod/tinyproxy | grep -q 'lib'; then
echo "prod binary has dynamic library dependencies"
exit 1
fi
file dist/debug/tinyproxy
scanelf -n dist/debug/tinyproxy
if scanelf -n dist/debug/tinyproxy | grep -q 'lib'; then
echo "debug binary has dynamic library dependencies"
exit 1
fi
- &test
name: Test
run: make test
- &package_name
name: Set package names
shell: sh
run: |
os="$(printf '%s' '${{ runner.os }}' | tr '[:upper:]' '[:lower:]')"
arch="$(printf '%s' '${{ runner.arch }}' | tr '[:upper:]' '[:lower:]')"
echo "TINYPROXY_PACKAGE=tinyproxy-${os}-${arch}" >> "$GITHUB_ENV"
- &package_unix
name: Package artifact
shell: sh
run: |
mkdir -p dist/tinyproxy
cp dist/prod/tinyproxy dist/tinyproxy/
cp -r examples dist/tinyproxy/
tar -C dist -czf "${TINYPROXY_PACKAGE}.tar.gz" tinyproxy
mkdir -p dist/tinyproxy-debug
cp dist/debug/tinyproxy dist/tinyproxy-debug/
cp -r examples dist/tinyproxy-debug/
tar -C dist -czf "${TINYPROXY_PACKAGE}-debug.tar.gz" tinyproxy-debug
- &upload_unix
name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.TINYPROXY_PACKAGE }}
path: |
${{ env.TINYPROXY_PACKAGE }}.tar.gz
${{ env.TINYPROXY_PACKAGE }}-debug.tar.gz
if-no-files-found: error
retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }}
linux-musl-arm64:
name: Linux musl arm64 static
runs-on: ubuntu-24.04-arm
needs: libevent-source
container:
image: *alpine_image
permissions:
contents: read
steps:
- uses: laverdet/alpine-arm64@7f0f72ee2f71eb2324e5888e8b6e42b1b53e6160
if: runner.arch == 'ARM64'
- *checkout
- *download_libevent_source
- *extract_libevent
- *install_linux_deps
- *set_build_version
- *build_static
- *verify_static
- *test
- *package_name
- *package_unix
- *upload_unix
linux-riscv64:
name: Linux riscv64 (test only)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
with:
platforms: riscv64
- name: Build and test under riscv64
run: |
docker run --rm \
--platform linux/riscv64 \
-v "$PWD:/work" \
-w /work \
riscv64/debian:unstable \
sh -euxc '
apt-get update
apt-get install -y --no-install-recommends \
build-essential \
libevent-dev \
pkg-config \
python3 \
ca-certificates
make clean all
make test \
CONCURRENCY=20 \
TOTAL=20 \
FD_LIMIT=512 \
LARGE_ROUNDTRIP_SIZE=4096 \
SEQUENTIAL_CONNECTIONS=20
'
freebsd-amd64:
name: FreeBSD amd64
runs-on: ubuntu-latest
steps:
- *checkout
- name: Build and test on FreeBSD
uses: vmactions/freebsd-vm@v1
with:
release: "14.2"
usesh: true
prepare: |
pkg install -y gmake pkgconf libevent python3 pcre2 haproxy
run: |
set -eu
gmake clean all EXTRA_CFLAGS="-Og -g3 -Wpedantic"
# BSD is running in a VM. Lower the requirements.
# GitHub Actions runner VM
# -> FreeBSD VM/emulator
gmake test \
CONCURRENCY=100 TOTAL=100 FD_LIMIT=2560 \
LARGE_ROUNDTRIP_SIZE=65536 SEQUENTIAL_CONNECTIONS=100
gmake clean all
mkdir -p dist/tinyproxy
cp bin/tinyproxy dist/tinyproxy/
cp -r examples dist/tinyproxy/
tar -C dist -czf tinyproxy-freebsd-amd64.tar.gz tinyproxy
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: tinyproxy-freebsd-amd64
path: tinyproxy-freebsd-amd64.tar.gz
if-no-files-found: error
retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }}
macos:
name: macOS build
runs-on: macos-15
steps:
- *checkout
- name: Install deps
run: |
brew list libevent >/dev/null 2>&1 || brew install libevent
brew list haproxy >/dev/null 2>&1 || brew install haproxy
- *set_build_version
- name: Build
run: |
set -eu
mkdir -p dist/debug dist/prod
make clean all STATIC=0 EXTRA_CFLAGS="-Og -g3 -Wpedantic"
cp bin/tinyproxy dist/debug/tinyproxy
make clean all STATIC=0
cp bin/tinyproxy dist/prod/tinyproxy
strip dist/prod/tinyproxy
- *test
- *package_name
- *package_unix
- *upload_unix
windows:
name: Windows build
runs-on: windows-2022
continue-on-error: true
steps:
- *checkout
- name: Set up MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: >-
base-devel
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-pkgconf
mingw-w64-ucrt-x86_64-libevent
mingw-w64-ucrt-x86_64-python
- name: Build
shell: msys2 {0}
run: |
make clean
make all
- name: Test
shell: msys2 {0}
run: make test
- name: Package artifact
shell: msys2 {0}
run: |
set -eu
mkdir -p dist/tinyproxy
if [ -f bin/tinyproxy.exe ]; then
cp bin/tinyproxy.exe dist/tinyproxy/
else
cp bin/tinyproxy dist/tinyproxy/tinyproxy.exe
fi
copy_deps() {
local file="$1"
ldd "$file" |
awk '
/=>/ {
dll = $3
if (dll ~ /^\/ucrt64\/bin\//) {
print dll
}
}
/^[[:space:]]*\/ucrt64\/bin\// {
print $1
}
' |
sort -u |
while read -r dll; do
base="$(basename "$dll")"
if [ ! -f "dist/tinyproxy/$base" ]; then
echo "Copying DLL: $dll"
cp "$dll" dist/tinyproxy/
copy_deps "dist/tinyproxy/$base"
fi
done
}
echo "Runtime DLL dependencies:"
ldd dist/tinyproxy/tinyproxy.exe || true
copy_deps dist/tinyproxy/tinyproxy.exe
echo "Packaged files:"
find dist/tinyproxy -maxdepth 1 -type f -printf '%f\n' | sort
powershell.exe -NoProfile -Command \
"Compress-Archive -Path dist/tinyproxy -DestinationPath tinyproxy-windows-x64.zip -Force"
- name: Upload CI artifact
uses: actions/upload-artifact@v4
with:
name: tinyproxy-windows-x64
path: tinyproxy-windows-x64.zip
if-no-files-found: error
retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }}
release:
name: GitHub Release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs:
- linux-musl-x86_64
- linux-musl-arm64
- freebsd-amd64
- macos
- windows
permissions:
contents: write
steps:
- name: Download CI artifacts
uses: actions/download-artifact@v4
with:
path: release-assets
pattern: tinyproxy-*
merge-multiple: true
- name: Show release assets
run: |
find release-assets -type f -maxdepth 2 -print
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
set -eu
tag="${GITHUB_REF_NAME}"
body_file="$(mktemp)"
if printf '%s\n' "$tag" | grep -Eq '^v0\.'; then
cat > "$body_file" <<'EOF'
> [!WARNING]
> This is an experimental v0.x release.
>
> APIs, config formats, behavior, and compatibility may change without notice.
EOF
else
: > "$body_file"
fi
if ! gh release view "$tag" >/dev/null 2>&1; then
gh release create "$tag" \
--title "$tag" \
--notes-file "$body_file" \
--generate-notes
fi
echo "Assets currently on release:"
gh release view "$tag" --json assets --jq '.assets[].name'
for asset in release-assets/*; do
name="$(basename "$asset")"
existing="$(
gh release view "$tag" --json assets --jq '.assets[].name' |
awk -v target="$name" 'tolower($0) == tolower(target) { print; exit }'
)"
if [ -n "$existing" ]; then
echo "Deleting existing release asset: $existing"
gh release delete-asset "$tag" "$existing" -y
fi
echo "Uploading release asset: $name"
gh release upload "$tag" "$asset"
done
docker-min:
name: Docker image (minimal)
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs:
- linux-musl-x86_64
- linux-musl-arm64
permissions:
contents: read
packages: write
steps:
- *checkout
- name: Download Linux artifacts
uses: actions/download-artifact@v4
with:
path: docker-artifacts
pattern: tinyproxy-linux-*
merge-multiple: true
- name: Prepare Docker rootfs
run: |
mkdir -p rootfs-amd64 rootfs-arm64
mkdir -p tmp/amd64 tmp/arm64
tar -xzf docker-artifacts/tinyproxy-linux-x64.tar.gz -C tmp/amd64
tar -xzf docker-artifacts/tinyproxy-linux-arm64.tar.gz -C tmp/arm64
mkdir -p rootfs-amd64/usr/bin rootfs-amd64/etc
mkdir -p rootfs-arm64/usr/bin rootfs-arm64/etc
cp tmp/amd64/tinyproxy/tinyproxy rootfs-amd64/usr/bin/tinyproxy
cp tmp/arm64/tinyproxy/tinyproxy rootfs-arm64/usr/bin/tinyproxy
chmod 0755 rootfs-amd64/usr/bin/tinyproxy
chmod 0755 rootfs-arm64/usr/bin/tinyproxy
file rootfs-amd64/usr/bin/tinyproxy
file rootfs-arm64/usr/bin/tinyproxy
- &set_image_name
name: Set image name
run: |
image="ghcr.io/${GITHUB_REPOSITORY}"
echo "IMAGE_NAME=${image,,}" >> "$GITHUB_ENV"
- &setup_buildx
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- &login_ghcr
name: Login to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Build and push image
uses: docker/build-push-action@v7
with:
context: .
file: ./dockerfiles/github-minimal.Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
${{ env.IMAGE_NAME }}:${{ github.ref_name }}
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.version=${{ github.ref_name }}
org.opencontainers.image.revision=${{ github.sha }}
docker-perf:
name: Docker image (performance)
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
needs:
- libevent-source
permissions:
contents: read
packages: write
steps:
- *checkout
- *download_libevent_source
- name: Stage libevent tarball for Docker build
run: |
cp ".cache/libevent/${LIBEVENT_TARBALL}" "./${LIBEVENT_TARBALL}"
- *set_image_name
- *set_build_version
- *setup_buildx
- *login_ghcr
- name: Build and push image
uses: docker/build-push-action@v7
with:
context: .
file: ./dockerfiles/github-perf.Dockerfile
platforms: linux/amd64,linux/arm64
push: true
build-args: |
LIBEVENT_TARBALL=${{ env.LIBEVENT_TARBALL }}
BUILD_VER=${{ env.BUILD_VER }}
tags: |
${{ env.IMAGE_NAME }}:${{ github.ref_name }}-debian-slim
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.version=${{ github.ref_name }}-debian-slim
org.opencontainers.image.revision=${{ github.sha }}