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>
162 lines
6.3 KiB
Markdown
162 lines
6.3 KiB
Markdown
# Multi-version build pipeline
|
|
|
|
How s3-gateway turns an upstream [versitygw](https://github.com/versity/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:
|
|
|
|
1. **`ci/clone-source.sh`** — shallow-clones upstream versitygw at a
|
|
tag into `src/`. Tag selection priority:
|
|
1. `VGW_TAG` (the dispatch input, or a manual run),
|
|
2. the pushed tag (`GITHUB_REF` = `refs/tags/...`),
|
|
3. the latest remote `vX.Y.Z` tag.
|
|
The checkout forces `core.autocrlf=false` so the tree is byte-for-
|
|
byte upstream (LF) and the LF patches apply on any host.
|
|
|
|
2. **`ci/apply-patches.sh`** — resolves the patch directory for the tag
|
|
from `ci/support-matrix.yaml` (`patches:` field, default = tag name)
|
|
and applies `patches/<dir>/*.patch` with `git am --whitespace=nowarn
|
|
--3way`, in filename order. The `--3way` fallback 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.
|
|
|
|
3. **`ci/build.sh`** — runs `goreleaser release --clean
|
|
--skip=validate,publish` in `src/`, producing binaries + deb/rpm in
|
|
`src/dist/`. Because the patch commits sit on top of the tag, HEAD is
|
|
no longer exactly the tag, so we set `GORELEASER_CURRENT_TAG` to pin
|
|
the stamped version and `--skip=validate` to bypass the dirty/tag
|
|
checks. Upstream's `.goreleaser.yaml` is used unmodified — artifact
|
|
names stay `versitygw`.
|
|
|
|
4. **`ci/publish-release.sh`** — creates (or reuses) a Gitea release for
|
|
the tag in this repo and uploads `src/dist/*` as assets. Idempotent:
|
|
re-running for the same tag replaces existing assets.
|
|
|
|
## Patch registry: `ci/support-matrix.yaml`
|
|
|
|
```yaml
|
|
versitygw:
|
|
- tag: v1.11.0
|
|
patches: v1.11.0
|
|
```
|
|
|
|
- `tag` — upstream git tag.
|
|
- `patches` — directory under `patches/` to apply (defaults to `tag`).
|
|
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`:
|
|
|
|
1. **Rebase the patch series** onto the new tag in a throwaway clone:
|
|
|
|
```bash
|
|
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
|
|
```
|
|
|
|
`--binary` is required because the series deletes PNG logo assets.
|
|
|
|
2. **Register it** in `ci/support-matrix.yaml`:
|
|
|
|
```yaml
|
|
versitygw:
|
|
- tag: vX.Y.Z
|
|
patches: vX.Y.Z
|
|
```
|
|
|
|
Leave 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).
|
|
|
|
3. **Commit and push** `ci/support-matrix.yaml` + `patches/vX.Y.Z/`.
|
|
|
|
4. **Build it** — either push a `vX.Y.Z` tag to this repo, or run the
|
|
**build** workflow manually and enter `vX.Y.Z`. CI builds that one
|
|
version and publishes it.
|
|
|
|
### Sanity-check a series before committing
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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`](../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:
|
|
|
|
```bash
|
|
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 the `golang:latest` container, 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 for `actions/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.
|