diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 294ae34..b62fe3a 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -1,45 +1,32 @@ name: build +# One version per run. Two ways in, no cron: +# - push a vX.Y.Z tag to this repo -> builds upstream versitygw vX.Y.Z +# - run manually (workflow_dispatch) -> builds the tag you enter on: push: tags: - 'v*' - schedule: - # Daily — rebuilds the supported matrix (cheap; publish is idempotent). - - cron: '0 6 * * *' workflow_dispatch: + inputs: + tag: + description: "Upstream versitygw tag to build (e.g. v1.5.0)" + required: true jobs: build: - # Self-hosted Gitea Act Runner. Reuse your scoutfs-ci runner by - # adding an `s3-gateway-ci` label to it, or change this to a label - # your runner already advertises. - runs-on: s3-gateway-ci - - # Deterministic build env: upstream is pure Go (CGO disabled), and - # GoReleaser builds deb/rpm via its bundled nfpm — no rpmbuild/dpkg - # needed — so a stock golang image is enough. + # Any Linux runner — the Go toolchain comes from the golang + # container below, so the runner only needs Docker. + runs-on: ubuntu-latest container: image: golang:latest options: --user 0:0 - strategy: - fail-fast: false - # STATIC matrix — mirror ci/support-matrix.yaml by hand. Gitea - # Act Runner does not support `matrix: ${{ fromJSON(...) }}` - # (dynamic matrices): the parser bails and downstream jobs see an - # empty matrix context. When you edit one, edit the other. - # `bash ci/matrix.sh` prints what this should contain. - matrix: - include: - - tag: v1.5.0 - patches: v1.5.0 - steps: - name: Checkout CI scripts + patches env: - # Stored Gitea PAT. read:repository is enough to clone this - # repo; the publish step below needs write:repository. + # Stored Gitea PAT. read:repository is enough to clone this + # repo; the publish step needs write:repository. GITEA_TOKEN: ${{ secrets.TOKEN_GITEA }} run: | set -eu @@ -55,6 +42,8 @@ jobs: git config --global \ url."${SCHEME}://x-access-token:${GITEA_TOKEN}@${SERVER_HOST}/".insteadOf \ "${SCHEME}://${SERVER_HOST}/" + # On a tag push GITHUB_REF_NAME is the tag (carries the matching + # patches//); on dispatch it's the default branch. git clone --depth 1 --branch "${GITHUB_REF_NAME:-main}" \ "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git" /tmp/ci-repo cp -a /tmp/ci-repo/ci /tmp/ci-repo/patches . @@ -70,31 +59,28 @@ jobs: - name: Clone upstream versitygw env: VGW_REPO_URL: ${{ vars.VGW_REPO_URL || 'https://github.com/versity/versitygw.git' }} - VGW_TAG: ${{ matrix.tag }} + # Empty on a tag push -> clone-source.sh falls back to the + # pushed tag. Set on dispatch -> builds exactly that tag. + VGW_TAG: ${{ inputs.tag }} run: bash ci/clone-source.sh + # apply / build / publish read VGW_TAG, VGW_SRC_DIR and VGW_DIST_DIR + # from $GITHUB_ENV, which clone-source.sh / build.sh populate. - name: Apply de-brand patches - env: - VGW_TAG: ${{ matrix.tag }} run: bash ci/apply-patches.sh - name: Build release artifacts - env: - VGW_TAG: ${{ matrix.tag }} run: bash ci/build.sh - name: Publish to Gitea release env: - VGW_TAG: ${{ matrix.tag }} GITEA_API_URL: ${{ github.server_url }}/api/v1 GITEA_OWNER: ${{ github.repository_owner }} GITEA_REPO: ${{ github.event.repository.name }} - # Needs write:repository scope to create releases + upload assets. + # Needs write:repository to create releases + upload assets. GITEA_TOKEN: ${{ secrets.TOKEN_GITEA }} run: bash ci/publish-release.sh - name: Summary if: always() - run: | - echo "=== ${{ matrix.tag }} ===" - ls -1 src/dist/*.tar.gz src/dist/*.deb src/dist/*.rpm 2>/dev/null || true + run: ls -1 src/dist/*.tar.gz src/dist/*.deb src/dist/*.rpm 2>/dev/null || true diff --git a/README.md b/README.md index cb3a682..5056253 100644 --- a/README.md +++ b/README.md @@ -23,20 +23,19 @@ drop-in compatible with existing configs, systemd units, and the (shallow clone tag) (git am --3way) (goreleaser) (Gitea release assets) ``` -`ci/support-matrix.yaml` is the single source of truth for which -upstream versions get built. +`ci/support-matrix.yaml` records which upstream versions have a curated +patch set and maps each to its patch directory. ## Layout ``` s3-gateway/ ├── ci/ -│ ├── support-matrix.yaml # which upstream tags we build (source of truth) +│ ├── support-matrix.yaml # upstream tag -> patch directory (registry) │ ├── clone-source.sh # shallow-clone upstream versitygw at a tag │ ├── apply-patches.sh # git am --3way patches//*.patch │ ├── build.sh # goreleaser release (binaries + deb/rpm) │ ├── publish-release.sh # upload dist/* to a Gitea release -│ ├── matrix.sh # print the CI matrix from support-matrix.yaml (local/preview) │ └── run.sh # local end-to-end: clone + patch + build one tag ├── patches/ │ └── v1.5.0/ @@ -96,30 +95,37 @@ copyright. ## Adding / refreshing a version When upstream cuts a new release you want a build of, you rebase the -patch series onto it and add a matrix row. See +patch series onto it and add a patch directory. See [docs/multi-version-pipeline.md](docs/multi-version-pipeline.md) for the full recipe. In short: ```bash -# Rebase the series onto the new tag, re-export, drop into patches/vX.Y.Z/ +# Rebase the series onto the new tag, re-export into patches/vX.Y.Z/ git clone https://github.com/versity/versitygw && cd versitygw -git checkout -b debrand vX.Y.Z +git -c core.autocrlf=false checkout -b debrand vX.Y.Z git am --3way /path/to/s3-gateway/patches//*.patch # resolve any conflicts -git format-patch vX.Y.Z..HEAD -o /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/ ``` -Then add the tag to **both** `ci/support-matrix.yaml` and the static -`matrix:` in `.gitea/workflows/build.yml` (the Gitea Act Runner can't -read a dynamic matrix — see the comment in the workflow). +Then add the tag to `ci/support-matrix.yaml`, commit, and build it (see +below). ## CI -`.gitea/workflows/build.yml` runs on tag push, daily, and manual -dispatch. It builds every entry in the static matrix and publishes each -to a Gitea release in this repo. +`.gitea/workflows/build.yml` builds **one version per run** and +publishes it to a Gitea release in this repo. It triggers two ways — no +scheduled/cron builds: -- **Runner**: targets the `s3-gateway-ci` label — add that label to your - existing `scoutfs-ci` runner, or edit `runs-on`. +- **By new tag** — push a `vX.Y.Z` tag to this repo; CI builds upstream + versitygw `vX.Y.Z` with `patches/vX.Y.Z/`. +- **One-shot** — run the **build** workflow manually (workflow_dispatch) + and enter the upstream tag to build. + +Configuration: + +- **Runner**: any Linux runner (`runs-on: ubuntu-latest`). The Go + toolchain comes from the `golang` container, so the runner only needs + Docker. - **Secret**: `TOKEN_GITEA` — a Gitea PAT with **write:repository** (clones this repo + creates releases / uploads assets). - **Variable (optional)**: `VGW_REPO_URL` to override the upstream URL. diff --git a/ci/clone-source.sh b/ci/clone-source.sh index f30c0b9..fd66f4a 100644 --- a/ci/clone-source.sh +++ b/ci/clone-source.sh @@ -24,8 +24,8 @@ VGW_SRC_DIR="${VGW_SRC_DIR:-src}" if [[ -n "${VGW_TAG:-}" ]]; then TAG="${VGW_TAG}" echo ">>> Using VGW_TAG from env: ${TAG}" -elif [[ -n "${GITHUB_REF_NAME:-}" && "${GITHUB_REF_TYPE:-}" == "tag" ]]; then - TAG="${GITHUB_REF_NAME}" +elif [[ "${GITHUB_REF:-}" == refs/tags/* ]]; then + TAG="${GITHUB_REF_NAME:-${GITHUB_REF#refs/tags/}}" echo ">>> Using tag from push event: ${TAG}" else echo ">>> Discovering latest release tag from ${VGW_REPO_URL}..." diff --git a/ci/matrix.sh b/ci/matrix.sh deleted file mode 100644 index 1c585e8..0000000 --- a/ci/matrix.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# Emit the CI build matrix as JSON from ci/support-matrix.yaml. -# -# If VGW_TAG is set (manual single-version run) the matrix collapses to -# that one tag. Otherwise every entry in support-matrix.yaml is built. -# -# Prints the matrix object to stdout and, under Gitea/GitHub Actions, -# writes `matrix=...` to GITHUB_OUTPUT for use with fromJSON(). -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -MATRIX_FILE="${REPO_ROOT}/ci/support-matrix.yaml" - -if [[ -n "${VGW_TAG:-}" ]]; then - json="$(jq -cn --arg tag "$VGW_TAG" '{include:[{tag:$tag, patches:$tag}]}')" -else - arr="$(yq -o=json '[.versitygw[] | {tag: .tag, patches: .patches}]' "${MATRIX_FILE}")" - json="$(echo "$arr" | jq -c '{include: [.[] | {tag, patches: (.patches // .tag)}]}')" -fi - -echo "${json}" -[[ -n "${GITHUB_OUTPUT:-}" ]] && echo "matrix=${json}" >> "${GITHUB_OUTPUT}" -exit 0 diff --git a/docs/multi-version-pipeline.md b/docs/multi-version-pipeline.md index 68b7a75..d4400cd 100644 --- a/docs/multi-version-pipeline.md +++ b/docs/multi-version-pipeline.md @@ -5,14 +5,17 @@ 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 per upstream tag: +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` (set by the CI matrix or a manual run), - 2. the pushed tag (`GITHUB_REF_NAME` when `GITHUB_REF_TYPE=tag`), + 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. @@ -33,9 +36,9 @@ Each build is four steps, run per upstream tag: 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 replaces existing assets, so daily rebuilds are safe. + re-running for the same tag replaces existing assets. -## The source of truth: `ci/support-matrix.yaml` +## Patch registry: `ci/support-matrix.yaml` ```yaml versitygw: @@ -43,19 +46,14 @@ versitygw: patches: v1.5.0 ``` -- `tag` — upstream git tag to build. +- `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. -The highest-version entry is "latest". `bash ci/matrix.sh` prints the -matrix this file implies. - -> **Act Runner caveat.** Gitea's Act Runner does not support dynamic -> matrices (`matrix: ${{ fromJSON(...) }}`). The workflow therefore -> carries a **static** `matrix:` that you must keep in sync with this -> file by hand — same compromise scoutfs-build makes. `ci/matrix.sh` -> exists to diff/preview, not to feed CI. +`apply-patches.sh` consults this to find the patch directory for the tag +being built; with the default `patches//` naming it doubles as a +human-readable record of which versions are maintained. ## Adding a new upstream version @@ -86,11 +84,11 @@ When upstream releases `vX.Y.Z`: patches: v1.5.0 ``` -3. **Mirror it** into the static `matrix.include` in - `.gitea/workflows/build.yml`. +3. **Commit and push** `ci/support-matrix.yaml` + `patches/vX.Y.Z/`. -4. Commit and push. The next CI run builds and publishes the new - version alongside the existing ones. +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 @@ -100,25 +98,26 @@ 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. -## Aging out a version +## Removing a version -Remove its entry from `ci/support-matrix.yaml` and the workflow matrix. -CI stops building it; releases already published in this repo stay until -you delete them manually. You can keep the `patches//` directory -for history or remove it. +Delete its `patches//` directory and its `ci/support-matrix.yaml` +entry. Releases already published in this repo stay until you delete +them by hand. ## CI configuration -- **Runner**: `runs-on: s3-gateway-ci`. Add that label to your existing - scoutfs-ci Act Runner, or change the label. +- **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, mirroring scoutfs-build, since a stock container has no Node - for `actions/checkout`) and to publish releases. -- **Variable `VGW_REPO_URL`** (optional): override the upstream URL, - e.g. to build from a mirror. + 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