From 37968e48fc9a51c1658cab8af7a1b5d6e02ef0e8 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Thu, 7 May 2026 23:31:59 +0000 Subject: [PATCH] feat: add gdu static musl build + generalize publish_release.py --- .gitea/workflows/gdu.yml | 69 +++++++++++++++++++++++++++++++++++++ .gitea/workflows/iperf3.yml | 1 + scripts/build_gdu.sh | 57 ++++++++++++++++++++++++++++++ scripts/publish_release.py | 7 ++-- versions/gdu.version | 1 + 5 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 .gitea/workflows/gdu.yml create mode 100755 scripts/build_gdu.sh create mode 100644 versions/gdu.version diff --git a/.gitea/workflows/gdu.yml b/.gitea/workflows/gdu.yml new file mode 100644 index 0000000..c114ad5 --- /dev/null +++ b/.gitea/workflows/gdu.yml @@ -0,0 +1,69 @@ +name: gdu static musl build + +on: + push: + branches: + - main + paths: + - .gitea/workflows/gdu.yml + - scripts/build_gdu.sh + - versions/gdu.version + workflow_dispatch: + +permissions: + contents: write + +jobs: + build-and-release: + runs-on: alpine-latest + + steps: + - name: Bootstrap workspace + shell: sh + env: + REPO_URL: ${{ gitea.server_url }} + REPO_NAME: ${{ gitea.repository }} + GIT_SHA: ${{ gitea.sha }} + run: | + apk add --no-cache git + workdir="$(pwd)" + tmpdir="$(mktemp -d)" + git clone --depth 1 "$REPO_URL/$REPO_NAME.git" "$tmpdir/repo" + git -C "$tmpdir/repo" fetch --depth 1 origin "$GIT_SHA" + git -C "$tmpdir/repo" checkout "$GIT_SHA" + find "$workdir" -mindepth 1 -maxdepth 1 -exec rm -rf {} + + cp -a "$tmpdir/repo"/. "$workdir"/ + + - name: Read version + id: meta + shell: sh + working-directory: ${{ gitea.workspace }} + run: | + version="$(tr -d ' \n\r' < versions/gdu.version)" + artifact="gdu-${version}-linux-amd64-musl-static" + echo "version=${version}" >> "$GITHUB_OUTPUT" + echo "artifact=${artifact}" >> "$GITHUB_OUTPUT" + + - name: Build static gdu + shell: sh + working-directory: ${{ gitea.workspace }} + run: | + chmod +x scripts/build_gdu.sh + ./scripts/build_gdu.sh "${{ steps.meta.outputs.version }}" "$PWD/dist" + + - name: Publish release assets + shell: sh + env: + GITEA_TOKEN: ${{ gitea.token }} + GITEA_API_URL: ${{ gitea.api_url }} + REPO_OWNER: ${{ gitea.repository_owner }} + REPO_NAME: static-musl-builds + TOOL: gdu + VERSION: ${{ steps.meta.outputs.version }} + TARGET_SHA: ${{ gitea.sha }} + working-directory: ${{ gitea.workspace }} + run: | + python3 scripts/publish_release.py \ + "dist/${{ steps.meta.outputs.artifact }}" \ + "dist/${{ steps.meta.outputs.artifact }}.tar.gz" \ + "dist/${{ steps.meta.outputs.artifact }}.sha256" diff --git a/.gitea/workflows/iperf3.yml b/.gitea/workflows/iperf3.yml index 7c0fa64..484b82f 100644 --- a/.gitea/workflows/iperf3.yml +++ b/.gitea/workflows/iperf3.yml @@ -59,6 +59,7 @@ jobs: GITEA_API_URL: ${{ gitea.api_url }} REPO_OWNER: ${{ gitea.repository_owner }} REPO_NAME: static-musl-builds + TOOL: iperf3 VERSION: ${{ steps.meta.outputs.version }} TARGET_SHA: ${{ gitea.sha }} working-directory: ${{ gitea.workspace }} diff --git a/scripts/build_gdu.sh b/scripts/build_gdu.sh new file mode 100755 index 0000000..253bd61 --- /dev/null +++ b/scripts/build_gdu.sh @@ -0,0 +1,57 @@ +#!/bin/sh +set -eu + +VERSION="${1:?usage: build_gdu.sh [output_dir]}" +OUTPUT_DIR="${2:-$PWD/dist}" +PREFIX_NAME="gdu-${VERSION}-linux-amd64-musl-static" + +# strip leading 'v' if passed +VERSION="${VERSION#v}" + +mkdir -p "$OUTPUT_DIR" + +apk add --no-cache \ + curl \ + file \ + go \ + git \ + tar \ + xz + +# gdu uses Go modules, pull source from GitHub +SRCDIR="${TMPDIR:-/tmp}/gdu-src-${VERSION}" +rm -rf "$SRCDIR" +mkdir -p "$SRCDIR" + +curl -fsSL "https://github.com/dundee/gdu/archive/refs/tags/v${VERSION}.tar.gz" \ + | tar -xz -C "$SRCDIR" --strip-components=1 + +cd "$SRCDIR" + +# Build fully static with musl toolchain +# CGO_ENABLED=0 forces pure-Go, which means no C deps at all +# ldflags: strip debug + disable dynamic linking +CGO_ENABLED=0 GOARCH=amd64 GOOS=linux \ + go build \ + -trimpath \ + -ldflags="-s -w -extldflags=-static" \ + -o "$OUTPUT_DIR/$PREFIX_NAME" \ + ./cmd/gdu + +strip "$OUTPUT_DIR/$PREFIX_NAME" 2>/dev/null || true + +( + cd "$OUTPUT_DIR" + tar -czf "${PREFIX_NAME}.tar.gz" "$PREFIX_NAME" + sha256sum "$PREFIX_NAME" "${PREFIX_NAME}.tar.gz" > "${PREFIX_NAME}.sha256" +) + +file "$OUTPUT_DIR/$PREFIX_NAME" +ldd "$OUTPUT_DIR/$PREFIX_NAME" || true + +if file "$OUTPUT_DIR/$PREFIX_NAME" | grep -qi 'dynamically linked'; then + echo "error: output binary is still dynamically linked" >&2 + exit 1 +fi + +echo "build OK: $OUTPUT_DIR/$PREFIX_NAME" diff --git a/scripts/publish_release.py b/scripts/publish_release.py index a511025..398eff2 100755 --- a/scripts/publish_release.py +++ b/scripts/publish_release.py @@ -93,10 +93,11 @@ def main() -> int: if missing: raise SystemExit(f"missing files: {', '.join(missing)}") - tag = f"iperf3-v{version}" - title = f"iperf3 {version}" + tool = os.environ.get("TOOL", "iperf3") + tag = f"{tool}-v{version}" + title = f"{tool} {version}" body = ( - f"Static musl build for iperf3 {version}.\\n\\n" + f"Static musl build for {tool} {version}.\\n\\n" f"Repository: {owner}/{repo}\\n" f"Commit: {target}" ) diff --git a/versions/gdu.version b/versions/gdu.version new file mode 100644 index 0000000..eef9e99 --- /dev/null +++ b/versions/gdu.version @@ -0,0 +1 @@ +5.36.1