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 @@ tar -xz -C ~/.local -f "/tmp/$GO_TARBALL"
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_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 |
wget https://bigbes.pages.srht.bigb.es/ci-cacher/cacher-linux-amd64 \
- -O ~/.local/bin/cacher
-chmod +x ~/.local/bin/cacher
+- Verify the binary against the sha256 below before using it. + 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.
+| Platform | Binary | SHA-256 |
|---|---|---|
| linux/amd64 | +cacher-linux-amd64 | +{{SHA_LINUX_AMD64}} |
+
| linux/arm64 | +cacher-linux-arm64 | +{{SHA_LINUX_ARM64}} |
+
| darwin/amd64 | +cacher-darwin-amd64 | +{{SHA_DARWIN_AMD64}} |
+
| darwin/arm64 | +cacher-darwin-arm64 | +{{SHA_DARWIN_ARM64}} |
+
+ 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
# before — install awscli, write ~/.aws/config, then in every task:
@@ -112,10 +154,14 @@ plus a config file. The directory caching is the genuinely new capability —
the shell version only ever handled single files.
+Changelog
+
+{{CHANGELOG}}
+
+
This build