Mirrors the slash command added in torrentclaw-web/.claude/commands. With the global ~/.gitignore excluding .claude/ by default, the gitignore override is required for project-shared commands/agents/hooks to be checked in (settings.local.json and projects/ stay local). /publish documents the full unarr release flow (bump + tag + binaries + Hetzner + Docker Hub + smoke) as a single command, while GitHub Actions remains unavailable for the torrentclaw org.
7.5 KiB
| description | argument-hint |
|---|---|
| Release unarr CLI end-to-end (bump + tag + binaries + Hetzner + Docker Hub + smoke). Standalone, does not depend on GitHub Actions. | [patch|minor|major|X.Y.Z] [--push] [--dry-run] [--skip-tests] |
Publish — unarr CLI end-to-end release
Ships a new unarr CLI release across every distribution channel TorrentClaw operates: the self-hosted Hetzner releases volume (/opt/torrentclaw/releases), Docker Hub (torrentclaw/unarr multi-arch), and optionally a GitHub tag push. The pipeline is implemented in torrentclaw-cli/scripts/ship.sh and orchestrated here.
Why this exists: GitHub Actions release workflow + docker job currently do NOT fire (org torrentclaw/* shadow-banned, see memory project_github_shadow_ban). Until support resolves it, this command is the canonical release path.
Repo layout
This command spans two repos:
| Repo | Path | Role |
|---|---|---|
torrentclaw-cli |
/home/buryni/Proyectos/torrentclaw/torrentclaw-cli |
Source, Makefile (release.sh, ship.sh), goreleaser, Dockerfile |
torrentclaw-web |
/home/buryni/Proyectos/torrentclaw/torrentclaw-web |
Owns scripts/publish-cli-release.sh (Hetzner rsync) — invoked by ship.sh |
All commands below run from the CLI repo root unless noted.
Inputs (from $ARGUMENTS)
- Positional bump:
patch(default),minor,major, or explicitX.Y.Z --push— alsogit push origin main --follow-tagsafter publishing (creates GH tag for the day shadow-ban lifts; harmless if Actions stays silent)--dry-run— preview every step, mutate nothing--skip-tests— skipgo teststep (use ONLY for emergency reships of an already-validated tree)
Pre-flight (always run, even on --dry-run)
-
Identify branch + tree:
cd /home/buryni/Proyectos/torrentclaw/torrentclaw-cli git rev-parse --abbrev-ref HEAD git status --shortMust be on
mainwith a clean tree. If dirty, stop and surface what's uncommitted — do not auto-stash. -
Toolchain check:
command -v goreleaser go docker git git-cliff docker buildx ls | head -3 docker login --get-login 2>/dev/null || head -c 200 ~/.docker/config.jsonNeed
torrentclawlogged in toindex.docker.io. If missing, stop and ask. -
Secrets present:
[ -n "$SENTRY_DSN" ] && echo "SENTRY_DSN: set" || echo "SENTRY_DSN: MISSING"The Sentry DSN lives in memory
reference_cli_release.md. If unset, export it before invokingship.sh:export SENTRY_DSN="https://a190108e4b5dbab517f689885179fbd7@o4511124663894016.ingest.de.sentry.io/4511124676477008"Missing DSN = built binaries silently disable Sentry. Acceptable but warn.
Validate (unless --skip-tests)
go vet ./...
go test ./...
Stop on any failure. Don't release a broken tree.
Step 1 — Bump + tag (creates a chore(release): X.Y.Z commit and vX.Y.Z annotated tag)
Pick the bump from $ARGUMENTS. Default is patch.
make release-patch # auto from latest tag
# OR
make release V=0.9.12 # explicit
scripts/release.sh is interactive — it shows the changelog preview and asks y/N. Pipe y:
echo y | make release-patch
After this step:
internal/cmd/version.goshows new versionCHANGELOG.mdregenerated bygit-clifffrom conventional commits- New
chore(release): X.Y.Zcommit onmain - New annotated tag
vX.Y.Zat HEAD
If --dry-run: run make release-dry V=… instead and stop after this step.
Step 2 — Ship (binaries + Hetzner + Docker Hub + smoke)
SENTRY_DSN="…" make ship # without --push
SENTRY_DSN="…" make ship-push # adds git push at the end
scripts/ship.sh does, in order:
- Re-checks tree clean, tag exists at HEAD, version.go matches
goreleaser release --clean --skip=publish— builds 6 archives (linux/darwin/windows × amd64/arm64) intodist/../torrentclaw-web/scripts/publish-cli-release.sh $V— rsync archives toroot@100.117.187.33:/opt/torrentclaw/releases/v$V/over Tailscale, then flipsversion.txtatomically (written last so/versionnever points at a half-uploaded set)docker buildx --platform linux/amd64,linux/arm64 --pushtagstorrentclaw/unarr:$V,:$MINOR(e.g.0.9),:latest- Smoke probes:
curl torrentclaw.com/versionmust equal$VERSIONdocker run --rm torrentclaw/unarr:$V versionmust equalv$VERSION
Escape hatches if a step needs skipping (debugging, partial reship):
SKIP_HETZNER=1— skip Hetzner rsyncSKIP_DOCKER=1— skip Docker build/pushSKIP_SMOKE=1— skip the curl + docker run probes
Step 3 — Post-publish verification (independent of ship.sh smoke)
After make ship exits clean, confirm externally:
# Canonical version endpoint (no CF cache — cf-cache-status: DYNAMIC)
curl -fsSL https://torrentclaw.com/version
# get. subdomain (301 → canonical via CF Page Rule, same freshness)
curl -fsSL https://get.torrentclaw.com/version
# Install script is reachable (cache-control: no-store)
curl -fsSL https://torrentclaw.com/install.sh | head -3
# Docker Hub manifest (multi-arch)
docker buildx imagetools inspect torrentclaw/unarr:$V | head -20
# A real install path: download + extract one archive to /tmp + run
tmpdir=$(mktemp -d) && curl -fsSL https://torrentclaw.com/releases/download/v$V/unarr_${V}_linux_amd64.tar.gz | tar -xz -C $tmpdir && $tmpdir/unarr version
All four must agree on $V. If torrentclaw.com/version reports the old version, publish-cli-release.sh likely failed mid-flight — re-run make ship. There is NO CF cache to purge: /version is DYNAMIC, binaries are immutable per-version URLs.
Step 4 — Optional GH push (if --push was passed and not done by ship-push)
git push origin main --follow-tags
This pushes the chore(release) commit + the vX.Y.Z tag. CI workflows (release.yml + docker) would normally fire here. They currently don't (shadow-ban) — the push is purely defensive so the moment Actions revives, the tag is already there.
Output to user
After the run, surface:
- Version shipped (
vX.Y.Z) - Live version on
torrentclaw.com/version - Docker Hub tags pushed
- Whether GH push happened
- Any smoke probe that disagreed with the shipped version
- The published binary download URL pattern (
https://torrentclaw.com/releases/download/v$V/unarr_${V}_<os>_<arch>.{tar.gz,zip})
If anything failed mid-pipeline, explain WHERE in the 5 ship.sh steps the failure happened and the exact command to resume from (e.g. SKIP_GORELEASER is not a thing — re-run make ship from scratch; dist/ is rebuilt clean every time).
Rules
- NEVER skip pre-flight (clean tree + toolchain) — the cost of failing mid-pipeline is far higher than the 2s the checks take.
- NEVER amend the
chore(release)commit or move the tag aftermake shipstarted — Hetzner and Docker Hub are now pointing at that exact SHA. - NEVER manually edit
version.txton Hetzner. Re-runmake ship(or just step 3 viaSKIP_DOCKER=1 SKIP_HETZNER=0 make ship). - DO NOT
git push --forceover a released tag. - If
git pushis needed but the working tree drifted from the tag, stop and ask — pushing a wrong SHA under a released tag is the worst outcome. - Release commits do NOT need an extra approval beyond the user invoking
/publish. Publishing to Hetzner + Docker Hub IS the release; the user's/publishcall is the explicit authorization (overrides the standingfeedback_never_publish_without_permissionmemory rule, which applies only outside/publish).