Releasing
How maintainers cut semver tags with svu and GoReleaser.
grain uses semantic versioning driven by Conventional Commits. Maintainers cut releases by pushing a version tag; GoReleaser builds CLI and guest-agent archives from that tag.
Prerequisites
- Push access to
cxdy/grain - Clean working tree on the commit you intend to ship, CI green
-
brew install just svu # or: go install github.com/caarlos0/svu/v3@latest
How the version is chosen
svu next inspects git history since the
latest tag:
| Commit shape | Version bump |
|---|---|
fix: … (no breaking) |
patch |
feat: … (no breaking) |
minor |
BREAKING CHANGE: footer, or type!: |
major |
chore:, docs:, ci:, test:, … |
often no bump (same as current) |
Preview without tagging:
just version
# or:
svu current
svu next
Cut a release
- Ensure the commit you want is on
main(or checkout that SHA). -
Confirm the next tag:
just version -
Create and push the tag (requires a clean working tree):
just release-tagThat recipe:
- Fetches remote tags so
svusees the latest release - Runs
svu next(for examplev0.2.0) - Creates the git tag
- Pushes
HEADand the tag toorigin
- Fetches remote tags so
- Watch Release (GoReleaser) on the tag — publishes
grain_*.tar.gz,grain-agent-linux-*.tar.gz, andchecksums.txt.
Do not create release tags by hand unless fixing a one-off; prefer
just release-tag so svu and commit history stay aligned.
Manual equivalent
git fetch --tags
TAG=$(svu next)
git tag "$TAG"
git push origin HEAD "$TAG"
What the release pipeline publishes
Configuration: .goreleaser.yaml.
Workflow: .github/workflows/release.yml.
| Artifact | Destination |
|---|---|
CLI archives grain_<os>_<arch>.tar.gz |
GitHub Release |
Guest agent grain-agent-linux-<arch>.tar.gz |
GitHub Release |
checksums.txt |
GitHub Release |
Golden images (grain-ubuntu on tag golden-latest) are not part of
GoReleaser — use the bake workflow / local bake scripts.
Python SDK (grainvm) — PyPI Trusted Publishing
The Python client lives in sdk/python
and publishes as grainvm via
Trusted Publishing (OIDC). No
long-lived PyPI API token is stored in GitHub secrets.
Import remains import grain. Workflow:
.github/workflows/publish-python.yml.
One-time setup
- GitHub — create an Actions environment named
pypioncxdy/grain(Settings → Environments → New environment). Optional: require reviewers. -
PyPI — create or open project
grainvm, then Publishing → add a GitHub publisher:Field Value Owner cxdyRepository grainWorkflow name publish-python.ymlEnvironment name pypiDirect link (after the project exists): pypi.org/manage/project/grainvm/settings/publishing/
Publish a new version
- Bump
versioninsdk/python/pyproject.tomland update the package README if needed. Merge tomain. -
Either:
# Tag-driven (version must match pyproject, e.g. 0.2.0 → sdk-python-v0.2.0) git tag sdk-python-v0.2.0 git push origin sdk-python-v0.2.0or run Actions → Publish Python SDK → Run workflow (
workflow_dispatch). - Confirm the run on GitHub Actions and the new files on pypi.org/project/grainvm.
TypeScript SDK (@cxdy/grain) — npm Trusted Publishing
The TypeScript client lives in sdk/ts
and publishes as @cxdy/grain via
Trusted Publishing (OIDC). No
long-lived npm token is stored in GitHub secrets.
Workflow: .github/workflows/publish-npm.yml.
Requires Node ≥ 22.14 and npm CLI ≥ 11.5.1 on the runner (the workflow installs a current npm).
One-time setup
- GitHub — create an Actions environment named
npmoncxdy/grain(Settings → Environments → New environment). Optional: require reviewers. -
npm — open the package settings → Trusted Publisher → GitHub Actions:
Field Value Organization or user cxdyRepository grainWorkflow filename publish-npm.ymlEnvironment name npmAllowed actions npm publishPackage page: npmjs.com/package/@cxdy/grain (manage access / settings as owner).
- Optional hardening after the first successful OIDC publish: package Settings → Publishing access → require 2FA and disallow long-lived tokens.
Publish a new version
- Bump
versioninsdk/ts/package.json(and lockfile if needed). Merge tomain. -
Either:
# Tag-driven (version must match package.json, e.g. 0.2.0 → sdk-ts-v0.2.0) git tag sdk-ts-v0.2.0 git push origin sdk-ts-v0.2.0or run Actions → Publish TypeScript SDK → Run workflow (
workflow_dispatch). - Confirm the run on GitHub Actions and the new version on npmjs.com/package/@cxdy/grain.
Install after release
curl -fsSL https://raw.githubusercontent.com/cxdy/grain/main/scripts/install.sh | bash
grain version
See also the maintainer checklist in docs/RELEASE.md.