Upstream released v1.11.0 (e42ae7a, 2026-11-06): 42 commits, mostly
fixes, plus two WebUI features that add ~415 lines to explorer.html
(on-demand bucket size calculation, restore archived objects).
The series needed no content changes — the regenerated patches differ
from the v1.10.0 ones only in their `index <blob>..<blob>` lines, since
the de-brand edits sit above the regions upstream touched. Regenerating
them is still worthwhile: the v1.10.0 patches' pre-image blobs do not
exist in a v1.11.0 clone, so `git am --3way` could not use its 3-way
fallback and was silently applying them directly.
Verified before committing:
- round-trips from a clean clone to tree 8d509fe
- residual branding identical to the patched v1.10.0 tree (23
occurrences, same per-file spread, no regressions)
- all 5 light-mode Tailwind classes in the new explorer markup are
overridden in theme.css
- series touches only webui/; file count 1049 -> 1051
- goreleaser builds all 8 targets plus deb/rpm
- matrix accepts v1.11.0, refuses v1.10.0, PATCH_DIR still rebuilds
the archived series
v1.10.0 moves to patches/archive/ as *superseded*, not vulnerable: it is
the release carrying upstream's CVE-2026-111943 notice, and that fix
comes from the Go toolchain (>= 1.26.10 / 1.27.3) rather than from the
tag. The archive README and the top-level README now say so, instead of
implying every archived series predates a security fix.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
6.3 KiB
Multi-version build pipeline
How s3-gateway turns an upstream versitygw release into a de-branded build, and how to keep it tracking new upstream versions. This mirrors the scoutfs-build / scoutfs-notify model, collapsed into one repo because the patch set is small.
CI builds one version per run — triggered by a tag push or a manual dispatch, never on a schedule.
The flow
Each build is four steps, run for a single upstream tag:
-
ci/clone-source.sh— shallow-clones upstream versitygw at a tag intosrc/. Tag selection priority:VGW_TAG(the dispatch input, or a manual run),- the pushed tag (
GITHUB_REF=refs/tags/...), - the latest remote
vX.Y.Ztag. The checkout forcescore.autocrlf=falseso the tree is byte-for- byte upstream (LF) and the LF patches apply on any host.
-
ci/apply-patches.sh— resolves the patch directory for the tag fromci/support-matrix.yaml(patches:field, default = tag name) and appliespatches/<dir>/*.patchwithgit am --whitespace=nowarn --3way, in filename order. The--3wayfallback is what lets a series rebase across minor upstream drift. A tag the matrix does not list is refused (exit 1), as is a patch directory that turns out to be empty — either would otherwise publish an un-de-branded or superseded build. -
ci/build.sh— runsgoreleaser release --clean --skip=validate,publishinsrc/, producing binaries + deb/rpm insrc/dist/. Because the patch commits sit on top of the tag, HEAD is no longer exactly the tag, so we setGORELEASER_CURRENT_TAGto pin the stamped version and--skip=validateto bypass the dirty/tag checks. Upstream's.goreleaser.yamlis used unmodified — artifact names stayversitygw. -
ci/publish-release.sh— creates (or reuses) a Gitea release for the tag in this repo and uploadssrc/dist/*as assets. Idempotent: re-running for the same tag replaces existing assets.
Patch registry: ci/support-matrix.yaml
versitygw:
- tag: v1.11.0
patches: v1.11.0
tag— upstream git tag.patches— directory underpatches/to apply (defaults totag). Point several tags at one directory if the same series applies to a range of upstream releases.
apply-patches.sh consults this to find the patch directory for the tag
being built; with the default patches/<tag>/ naming it doubles as a
human-readable record of which versions are maintained.
It is also an allowlist, which is the mechanism that keeps
superseded versions from being rebuilt: a tag absent from the matrix
makes apply-patches.sh exit 1. Only PATCH_DIR bypasses it, and only
explicitly — that is how an archived series is rebuilt on purpose.
The matrix is read with yq when it is installed and with a small
awk parse otherwise, so the allowlist still applies in the stock
golang CI container, which has no yq.
Adding a new upstream version
When upstream releases vX.Y.Z:
-
Rebase the patch series onto the new tag in a throwaway clone:
git clone https://github.com/versity/versitygw vgw && cd vgw git -c core.autocrlf=false checkout -b debrand vX.Y.Z git config user.email you@example.com && git config user.name you git am --3way /path/to/s3-gateway/patches/<previous-tag>/*.patch # If a hunk conflicts: fix files, `git add -A`, `git am --continue`. mkdir -p /path/to/s3-gateway/patches/vX.Y.Z git format-patch --binary vX.Y.Z..HEAD \ -o /path/to/s3-gateway/patches/vX.Y.Z--binaryis required because the series deletes PNG logo assets. -
Register it in
ci/support-matrix.yaml:versitygw: - tag: vX.Y.Z patches: vX.Y.ZLeave the previous entry in place only if you still want builds of it. If the new release supersedes it — a security fix, say — retire the old one at the same time (see Retiring a version below).
-
Commit and push
ci/support-matrix.yaml+patches/vX.Y.Z/. -
Build it — either push a
vX.Y.Ztag to this repo, or run the build workflow manually and entervX.Y.Z. CI builds that one version and publishes it.
Sanity-check a series before committing
VGW_REPO_URL="/path/to/local/versitygw" VGW_TAG=vX.Y.Z bash ci/run.sh
A clean git am plus a populated src/dist/ means the series is good.
Retiring a version
Drop its ci/support-matrix.yaml entry — that alone stops it being
built, since the matrix is the allowlist — and git mv its directory
into patches/archive/<tag>/ rather than deleting it, so the series
stays available for a deliberate rebuild:
git mv patches/v1.8.0 patches/archive/v1.8.0
# then remove the v1.8.0 entry from ci/support-matrix.yaml
Update the table in patches/archive/README.md
and the supported-versions table in the top-level README to match.
Releases already published in this repo are not affected: retiring the patches stops future builds but leaves existing release assets downloadable until you delete them by hand in Gitea.
To rebuild an archived version deliberately, pass PATCH_DIR instead
of re-adding it to the matrix:
PATCH_DIR=patches/archive/v1.8.0 VGW_TAG=v1.8.0 bash ci/apply-patches.sh
CI configuration
- Triggers: a
v*tag push (builds that tag) or manual dispatch with a tag input (one-shot). No cron. - Runner: any Linux runner —
runs-on: ubuntu-latest. The Go toolchain comes from thegolang:latestcontainer, so the runner only needs Docker; nothing version-specific to install. - Container:
golang:latest— pure-Go build, GoReleaser's bundled nfpm makes deb/rpm without rpmbuild/dpkg. - Secret
TOKEN_GITEA: Gitea PAT with write:repository. Used both to clone this repo (the workflow does a manual token-rewritten clone, since a stock container has no Node foractions/checkout) and to publish releases. - Variable
VGW_REPO_URL(optional): override the upstream URL.
Release tagging
Releases are created in this repo with the upstream tag name
(v1.11.0). If you need to ship a rebuild of the same upstream version
(e.g. a patch fix), set RELEASE_TAG in ci/publish-release.sh's
environment to something like v1.11.0-acg2 to avoid clobbering.