From 969662b88d348767a794537fc8aadc2255abfa76 Mon Sep 17 00:00:00 2001 From: Eugene Blikh Date: Tue, 26 May 2026 00:14:30 +0300 Subject: [PATCH] Add goreleaser + CHANGELOG.md; cross-platform downloads on site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * .goreleaser.yml — builds linux/{amd64,arm64} and darwin/{amd64,arm64} as raw binaries (formats: binary) with CGO_ENABLED=0, trimpath, version ldflag injection. GitHub release disabled; we publish via pages.sr.ht. * CHANGELOG.md — Keep-a-Changelog format. v0.1.0 entry summarizes the full surface (init/doctor, single-file/docker/dir caching, --hash-from, Garage compat, e2e suite, CI manifests). * .builds/publish.yml — installs goreleaser binary release (pinned to v2.7.0), runs `goreleaser release --clean --skip=publish`, flattens the 4 dist/cacher___v/cacher paths into pages/cacher--, regenerates checksums.txt to match the published filenames, renders CHANGELOG.md to HTML via cmark with heading demotion (h1→drop, h2→h3, h3→h4), substitutes per-platform sha256s into docs/index.html, and ships everything to bigbes.pages.srht.bigb.es/ci-cacher/ plus the build artifacts list. * docs/index.html — Download section is now a 4-row table with per- platform sha256s, plus a Changelog section that embeds the rendered CHANGELOG.md inline. --- .builds/publish.yml | 102 ++++++++++++++++++++++++++++++-------------- .goreleaser.yml | 52 ++++++++++++++++++++++ CHANGELOG.md | 59 +++++++++++++++++++++++++ docs/index.html | 60 +++++++++++++++++++++++--- 4 files changed, 234 insertions(+), 39 deletions(-) create mode 100644 .goreleaser.yml create mode 100644 CHANGELOG.md diff --git a/.builds/publish.yml b/.builds/publish.yml index a3d9f3d7cb99f7fe3302b43ffac4c743bb2b8a62..c7cd21719d8880904d03f57814e68e1f0ffbba7c 100644 --- a/.builds/publish.yml +++ b/.builds/publish.yml @@ -1,26 +1,25 @@ -# Publish a linux-amd64 binary on every tag push. Two destinations: +# Build cross-platform binaries via goreleaser, ship them three ways on +# every tag push: # -# 1. Build artifact (cacher-linux-amd64 visible on the job page, -# pruned by builds.sr.ht after 90 days). -# -# 2. pages.sr.ht under bigbes.pages.srht.bigb.es/ci-cacher/, so -# downstream projects can `wget` from a stable URL. We publish -# with `hut pages publish -s /ci-cacher` so this manifest only -# touches files under that subpath — other projects sharing the -# user-level pages domain stay intact. Latest tag overwrites the -# previous publish under /ci-cacher; historical versions remain -# available via the artifact link during the 90-day window. +# 1. Build artifacts (visible on the job page, 90-day TTL). +# 2. pages.sr.ht under bigbes.pages.srht.bigb.es/ci-cacher/ via +# `hut pages publish -s /ci-cacher` (subpath-scoped, so other +# projects sharing the user-level pages domain stay intact). +# 3. A landing page rendered from docs/index.html with CHANGELOG.md +# embedded inline. # # Auto-submission is restricted to tag refs only. image: ubuntu/noble packages: - curl - ca-certificates + - cmark # CHANGELOG.md → HTML oauth: pages.sr.ht/PAGES:RW sources: - https://git.srht.bigb.es/~bigbes/ci-cacher environment: GO_VERSION: "1.26.3" + GORELEASER_VERSION: "v2.7.0" PATH: /home/build/.local/go/bin:/home/build/.local/bin:/home/build/go/bin:/usr/local/bin:/usr/bin:/bin GOPATH: /home/build/go PAGES_DOMAIN: bigbes.pages.srht.bigb.es @@ -39,38 +38,77 @@ tasks: rm "/tmp/$GO_TARBALL" go version - install_hut: | - # hut isn't in ubuntu/noble's repos; build it from source with the - # Go we just installed. ~5s on a warm GOPATH, ~30s cold. go install git.sr.ht/~xenrox/hut@latest hut --version + - install_goreleaser: | + # Pinned binary release, not `go install` — goreleaser's release + # binaries are stripped + statically linked and ~10x smaller than + # a from-source build. + curl -sSL "https://github.com/goreleaser/goreleaser/releases/download/${GORELEASER_VERSION}/goreleaser_Linux_x86_64.tar.gz" \ + | tar -xz -C ~/.local/bin goreleaser + goreleaser --version - build: | cd ci-cacher - VERSION=$(git describe --tags --abbrev=0 2>/dev/null || cat VERSION) - echo "Building $VERSION" - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 \ - go build -ldflags "-s -w -X go.bigb.es/cacher/internal/version.version=${VERSION}" \ - -o /home/build/cacher-linux-amd64 . - /home/build/cacher-linux-amd64 version - sha256sum /home/build/cacher-linux-amd64 + goreleaser release --clean --skip=publish + ls dist/ - package_pages: | - # pages.sr.ht expects a tarball whose top-level contents map to the - # publish path — so `tar -C dist .`, not `tar dist/`. With - # `-s /ci-cacher` the binary lands at - # https://$PAGES_DOMAIN/ci-cacher/cacher-linux-amd64. docs/index.html - # is the project landing page; the three {{PLACEHOLDERS}} get - # substituted at publish time with the values from this build. + # Goreleaser writes binaries under dist/cacher___v/cacher. + # Flatten + rename to the pages-facing /ci-cacher/cacher-- + # naming. Regenerate checksums.txt against the renamed files so the + # published file matches the URLs people will wget. VERSION=$(cd ci-cacher && (git describe --tags --abbrev=0 2>/dev/null || cat VERSION)) - SUM=$(sha256sum /home/build/cacher-linux-amd64 | awk '{print $1}') BUILT=$(date -u +%Y-%m-%dT%H:%M:%SZ) - mkdir -p /home/build/dist - cp /home/build/cacher-linux-amd64 /home/build/dist/cacher-linux-amd64 + mkdir -p /home/build/pages + cp ci-cacher/dist/cacher_linux_amd64_v1/cacher /home/build/pages/cacher-linux-amd64 + cp ci-cacher/dist/cacher_linux_arm64_v8.0/cacher /home/build/pages/cacher-linux-arm64 + cp ci-cacher/dist/cacher_darwin_amd64_v1/cacher /home/build/pages/cacher-darwin-amd64 + cp ci-cacher/dist/cacher_darwin_arm64_v8.0/cacher /home/build/pages/cacher-darwin-arm64 + chmod +x /home/build/pages/cacher-* + ( cd /home/build/pages && sha256sum cacher-* > checksums.txt ) + cat /home/build/pages/checksums.txt + + SHA_LA=$( awk '/cacher-linux-amd64$/ {print $1}' /home/build/pages/checksums.txt) + SHA_LAR=$(awk '/cacher-linux-arm64$/ {print $1}' /home/build/pages/checksums.txt) + SHA_DA=$( awk '/cacher-darwin-amd64$/ {print $1}' /home/build/pages/checksums.txt) + SHA_DAR=$(awk '/cacher-darwin-arm64$/ {print $1}' /home/build/pages/checksums.txt) + + # Render CHANGELOG.md to an HTML fragment for inline embedding. + # Drop the file's top-level `# Changelog` h1 (we already have an + #

Changelog

in the template) and demote remaining + # headings one level so they nest under the outer h2. + cmark --to html ci-cacher/CHANGELOG.md \ + | sed '/

Changelog<\/h1>/d' \ + | sed -e 's||

|g; s|||g' \ + > /tmp/changelog.html + + # Substitute scalar placeholders, then insert the changelog at the + # {{CHANGELOG}} marker via sed's read+delete trick. sed -e "s|{{VERSION}}|$VERSION|g" \ - -e "s|{{SHA256}}|$SUM|g" \ -e "s|{{BUILT}}|$BUILT|g" \ - ci-cacher/docs/index.html > /home/build/dist/index.html - cd /home/build/dist + -e "s|{{SHA_LINUX_AMD64}}|$SHA_LA|g" \ + -e "s|{{SHA_LINUX_ARM64}}|$SHA_LAR|g" \ + -e "s|{{SHA_DARWIN_AMD64}}|$SHA_DA|g" \ + -e "s|{{SHA_DARWIN_ARM64}}|$SHA_DAR|g" \ + ci-cacher/docs/index.html \ + | sed -e '/{{CHANGELOG}}/r /tmp/changelog.html' -e '/{{CHANGELOG}}/d' \ + > /home/build/pages/index.html + + cd /home/build/pages tar -czvf /home/build/site.tar.gz . - publish_pages: | hut pages publish -d "$PAGES_DOMAIN" -s "$PAGES_SUBPATH" /home/build/site.tar.gz + - stage_artifacts: | + # `artifacts:` paths resolve relative to /home/build. Copy the four + # binaries + checksums.txt into the top level so they're easy to + # reference (and to keep the page tarball clean of duplicates). + cp /home/build/pages/cacher-linux-amd64 /home/build/ + cp /home/build/pages/cacher-linux-arm64 /home/build/ + cp /home/build/pages/cacher-darwin-amd64 /home/build/ + cp /home/build/pages/cacher-darwin-arm64 /home/build/ + cp /home/build/pages/checksums.txt /home/build/ artifacts: - cacher-linux-amd64 + - cacher-linux-arm64 + - cacher-darwin-amd64 + - cacher-darwin-arm64 + - checksums.txt diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000000000000000000000000000000000000..a91b4cab550566a21754a9ffe9f558b779777139 --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,52 @@ +# Goreleaser config for cross-platform cacher builds. +# +# Invoked from .builds/publish.yml as `goreleaser release --clean --skip=publish` +# on tag pushes — we only want the binaries + checksums, not a GitHub +# release (we publish to pages.sr.ht and the build artifacts list). +version: 2 + +project_name: cacher + +before: + hooks: + - go mod tidy + +builds: + - id: cacher + main: . + binary: cacher + env: + - CGO_ENABLED=0 + flags: + - -trimpath + ldflags: + - -s -w + - -X go.bigb.es/cacher/internal/version.version={{ .Version }} + goos: [linux, darwin] + goarch: [amd64, arm64] + +archives: + # Ship raw binaries rather than tarballs so the wget URL + # `…/cacher-linux-amd64` works directly. The {{ .Version }} prefix lives + # in the goreleaser dist/ filenames but we strip it when copying into + # the pages tree (see .builds/publish.yml). + - id: binary + formats: [binary] + name_template: "cacher_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + +checksum: + name_template: "checksums.txt" + algorithm: sha256 + +snapshot: + version_template: "{{ .Tag }}-snapshot" + +changelog: + # We maintain CHANGELOG.md by hand. Don't autogenerate from git log. + disable: true + +release: + # We publish via pages.sr.ht + build artifacts; there's no GitHub repo to + # release to. `goreleaser release --skip=publish` already inhibits the + # release step, but disabling here keeps `goreleaser check` happy. + disable: true diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..0d453b551cf87f25f0e177d74c6c3c5f864716a2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,59 @@ +# Changelog + +All notable changes to this project will be documented in this file. The format +is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this +project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0] — 2026-05-26 + +First public release. Replaces the `s3_cache_or_curl` / +`s3_cache_docker_image` shell helpers in `tarantool-protobuf/.builds/lib/ci-lib.sh` +with a single static Go binary. + +### Added +- `cacher init` / `cacher doctor` — persist config to + `~/.config/cacher/config.toml` and smoke-test S3 credentials (HEAD bucket + + 1-byte canary write/read/delete). +- `cacher download` / `upload` / `exists` / `list` / `delete` for single + files. Download falls back to `--url` on cache miss and back-fills the + cache. Optional `--sha256` verifies the fetched content. +- `cacher docker {exists,download,upload}` — streamed `docker save | zstd` + → S3 multipart upload (and inverse). Pure-Go zstd via + [klauspost/compress](https://github.com/klauspost/compress), no external + `zstd` binary on the host. +- `cacher dir {download,upload}` — tar+zstd of a directory tree keyed by + content hash. Closes the gap left by the shell version, which only + cached single files. +- `cacher key` — resolve a key template (substituting `{hash}`) for shell + scripting. +- `--hash-from ` (repeatable; files or directories) on every command. + For a single file path the digest exactly matches `sha256sum file | cut -c1-N`, + so existing keys migrate without recomputation. +- `--arch-suffix` opt-in to suffix every key with `--`. +- `list --recursive` for flat listing; `list --root` to ignore the + configured prefix and list at bucket root. Default output style mirrors + `aws s3 ls` (delimited by `/`). +- Garage-compatible defaults: path-style addressing, signature v4, + request/response checksum calculation set to `when_required` (Garage + doesn't implement boto3 1.36+ trailing CRC32 checksums). +- End-to-end test suite (`go test -tags=e2e`) against a real Garage + container via `testcontainers-go` using `dxflrs/garage:v2.3.0`'s + `--single-node --default-bucket` mode. +- builds.sr.ht CI: `unit.yml` (every push), `e2e.yml` (every push, with + Docker), `publish.yml` (tags only, ships cross-platform binaries via + goreleaser to pages.sr.ht and as build artifacts). +- Static landing page at + [bigbes.pages.srht.bigb.es/ci-cacher/](https://bigbes.pages.srht.bigb.es/ci-cacher/). + +### Fixed +- `doctor` uses ListObjectsV2 (1-key) instead of HeadBucket — Garage + rejects HeadBucket with 403 even for valid credentials. +- Config path is `~/.config/cacher/config.toml` on every platform + (previously fell into `~/Library/Application Support/cacher` on macOS + via `os.UserConfigDir`). cacher is a CI tool; dev-macs and Linux runners + must look in the same place. + +[Unreleased]: https://git.srht.bigb.es/~bigbes/ci-cacher/log/master +[0.1.0]: https://git.srht.bigb.es/~bigbes/ci-cacher/refs/v0.1.0 diff --git a/docs/index.html b/docs/index.html index 919087e96139edb6b4543e3213e7522ec4f05d66..983271549cf52857d69eb91770e67aef2abc695f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -31,10 +31,19 @@ padding: 0 1.25rem 4rem; font: 16px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif; } - h1, h2, h3 { line-height: 1.25; } + h1, h2, h3, h4 { line-height: 1.25; } h1 { font-size: 1.7rem; margin-bottom: 0.15rem; } h2 { font-size: 1.15rem; margin-top: 2.2rem; padding-bottom: .2rem; border-bottom: 1px solid var(--rule); } h3 { font-size: 1rem; margin-top: 1.4rem; } + h4 { font-size: .95rem; margin-top: 1rem; color: var(--muted); } + table { border-collapse: collapse; width: 100%; margin: .7rem 0; font-size: .92em; } + th, td { text-align: left; padding: .35rem .6rem; border-bottom: 1px solid var(--rule); } + th { color: var(--muted); font-weight: 600; } + td code { font-size: .85em; word-break: break-all; } + .changelog ul { padding-left: 1.25rem; } + .changelog li { margin: .25rem 0; } + .changelog h2 { font-size: 1.05rem; margin-top: 1.4rem; } + .changelog h3 { font-size: .95rem; margin-top: 1rem; color: var(--muted); border-bottom: none; } p, ul, ol { margin: .7rem 0; } a { color: var(--link); text-decoration: none; } a:hover { text-decoration: underline; } @@ -66,13 +75,46 @@ anywhere you can run a binary and reach an S3 endpoint.

-

Install

-
wget https://bigbes.pages.srht.bigb.es/ci-cacher/cacher-linux-amd64 \
-  -O ~/.local/bin/cacher
-chmod +x ~/.local/bin/cacher
+

Download

+

+ Pre-built binaries for {{VERSION}}. The shipping URL is stable; the + SHA-256s below are specific to this build — paste them into your + pin if you care. +

+ + + + + + + + + + + + + + + + + + + + + + + + +
PlatformBinarySHA-256
linux/amd64cacher-linux-amd64{{SHA_LINUX_AMD64}}
linux/arm64cacher-linux-arm64{{SHA_LINUX_ARM64}}
darwin/amd64cacher-darwin-amd64{{SHA_DARWIN_AMD64}}
darwin/arm64cacher-darwin-arm64{{SHA_DARWIN_ARM64}}

- Verify the binary against the sha256 below before using it. + All four hashes plus filenames are also available in a single + checksums.txt for piping into sha256sum -c:

+
wget https://bigbes.pages.srht.bigb.es/ci-cacher/cacher-linux-amd64 \
+  -O ~/.local/bin/cacher
+chmod +x ~/.local/bin/cacher
+wget -qO- https://bigbes.pages.srht.bigb.es/ci-cacher/checksums.txt \
+  | sha256sum -c --ignore-missing

The loop it replaces

# before — install awscli, write ~/.aws/config, then in every task:
@@ -112,10 +154,14 @@ cacher download "$key" "$out" --url "$url"
the shell version only ever handled single files.

+

Changelog

+
+{{CHANGELOG}} +
+

This build

Version
{{VERSION}}
-
SHA-256
{{SHA256}}
Built
{{BUILT}}
Source
git.srht.bigb.es/~bigbes/ci-cacher
License
BSD-2-Clause