Skip to content

ci: cut releases from a tag push or a manual run, through xraph/workflows - #2

Merged
juicycleff merged 3 commits into
mainfrom
feat/release-workflow
Oct 20, 2026
Merged

juicycleff merged 3 commits into
mainfrom
feat/release-workflow

Conversation

@juicycleff

@juicycleff juicycleff commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Releases now work like octopus: push a tag, or run the Release workflow by hand.

git push origin v1.2.3                                         # tag on main, publishes everything
gh workflow run release.yml --ref main -f version=v1.2.3       # same, without a local tag
gh workflow run release.yml -f version=v1.2.3 -f target=docker -f skip-tests=true

A manual run with target: all tags the commit you started it from, creates the release and publishes everything in that one run. Because nothing waits on a second tag-push run, you don't need a PAT. cli or docker re-publishes only that part of a release that already exists, from its tag, which is what you want when one leg fails and the version is fine.

How it fits together

release.yml starts with a plan job. It checks the version format, that the commit is on main, and that the tag and GitHub release are in the state the target needs, then decides what runs. After that come the existing release checks (lint, unit and integration tests against Postgres) and three publish legs:

job what it uses what it publishes
release xraph/workflows go-release.yml the tag (on a manual run) and the GitHub release
cli xraph/workflows go-binary-release.yml loomctl, the loomplane_* server archives, Homebrew and Scoop
docker ./.github/workflows/publish-docker.yml smoke-tested AMD64 and ARM64 images, the deployment bundle

publish-docker.yml is the old image, smoke test and bundle logic moved unchanged into a reusable workflow. A tag pushed for a release someone already made on the Releases page publishes into that release rather than failing on a duplicate.

The shared workflow

The cli job uses go-binary-release.yml from xraph/workflows v1.20.0, pinned to its commit 4cfa392 the way ci.yml pins v1.19.0. That release came from xraph/workflows#10, which adds the Node and pnpm setup the dashboard build needs. It's merged and tagged, so nothing blocks this one now.

The GitHub release notes now come from go-release.yml, so they open with a go get install line and the commit list since the last tag. That's fine for now. If you'd rather lead with the image and loomctl install lines, that's a separate change.

.goreleaser.yaml reads HOMEBREW_TAP_TOKEN and SCOOP_BUCKET_TOKEN now, the names the shared workflow passes. The repository secret stays HOMEBREW_TAP_GITHUB_TOKEN, and release.yml maps it to both.

Verification

  • actionlint passes on every workflow, including the local reusable call.
  • goreleaser check passes.
  • The plan job's script ran against a scratch repository with a stubbed gh across ten cases: a new version, an existing tag, a bad version, a commit off main, docker with and without a release, cli for a missing tag, a pushed tag with and without a release, and a prerelease tag off main. All ten behaved as intended.
  • No real release has run through it yet.

A release used to push only its exact tag. Now v1.2.3 publishes v1.2.3
and 1.2.3, and moves 1.2, 1 and latest while it's the newest release in
each of those lines. Patching or rerunning an older release can't drag
latest backwards, a prerelease moves nothing, and 0.x skips the major
tag. scripts/release-image-tags.sh makes the choice, so you can check
what a tag would publish before you cut it. With the DOCKERHUB_USERNAME
and DOCKERHUB_TOKEN secrets set, every tag is mirrored to Docker Hub as
well, the same as the main builds.

Verified: the script picks the right tags for first releases, 0.x minor
bumps, a patch to an older minor, 1.0, a patch under a newer major,
1.10 after 1.9, and a prerelease, and rejects a tag without the v.
actionlint and shellcheck pass. It hasn't run in Actions yet.
…lows

You can release two ways now. Push a vX.Y.Z tag that's on main, or run
Release from the Actions tab with a version. A manual run with target
all tags the commit you started it from and publishes everything in the
same run, so it needs no PAT. Target cli or docker re-publishes only that
part of a release that already exists.

The tag and the GitHub release come from xraph/workflows go-release.yml.
GoReleaser runs through go-binary-release.yml for loomctl, the server
archives, Homebrew and Scoop. The image build, smoke test and deployment
bundle moved unchanged into publish-docker.yml, a reusable workflow like
the one octopus has.

.goreleaser.yaml reads HOMEBREW_TAP_TOKEN and SCOOP_BUCKET_TOKEN, the
names the shared workflow passes. The repository secret is still
HOMEBREW_TAP_GITHUB_TOKEN, and release.yml maps it to both.

The cli job pins go-binary-release.yml@v1.20.0, which needs
xraph/workflows#10 merged and tagged. Until then a release run fails at
startup.
xraph/workflows#10 is merged and tagged, so the cli job can run now. The pin is the commit SHA, the way ci.yml pins v1.19.0.
@juicycleff
juicycleff merged commit 6de3785 into main Oct 20, 2026
13 checks passed
@juicycleff
juicycleff deleted the feat/release-workflow branch October 20, 2026 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant