The release process is mostly automated via GitHub Actions. A maintainer triggers the Start Release workflow, and the pipeline handles branch preparation, version bumping, CI builds, smoke testing, release notes generation, GitHub release publishing, Homebrew formula update, and latest-release branch update. The one manual step is creating a PR to merge the release branch back into main.
Start Release workflow (triggered by maintainer)
│
├─ Resets latest-release → main
├─ Runs release.ts (version bump, changelog, tag push)
│
▼
CircleCI tags workflow (triggered by tag push)
│
├─ Builds binaries (macOS, Linux, Windows, Alpine)
├─ Signs Windows binary
├─ Creates draft GitHub release with artifacts
├─ Triggers post-release workflow via repository_dispatch
│
▼
Post-release workflow (triggered by CircleCI)
│
├─ Downloads binary, runs smoke test
├─ Generates release notes from changelog
├─ Publishes the release (draft → published)
├─ Triggers downstream workflows via repository_dispatch
│
▼
Publish release workflow Post-release branch update
│ │
├─ Creates and merges ├─ Updates latest-release branch
│ Homebrew PR │ (used for docs)
│ │
▼ ▼
Done Done
┌──────────────────────────┐
│ MANUAL STEP │
│ Create PR to merge │
│ release branch → main │
│ (see instructions below)│
└──────────────────────────┘
- Go to the Start Release workflow in GitHub Actions.
- Click Run workflow.
- Select the release type (
patch,minor, etc.) and base branch (default:main). - Click Run workflow and wait for the full pipeline to complete.
That's it. The changelog-based release notes, Homebrew update, and latest-release branch update are all handled automatically.
- After the pipeline completes, create a PR to merge the release branch back into
main:This PR only contains version bumps, changelog updates, and lock file changes. If flaky tests block merging, merge manually — the release branch does not introduce new code, so test failures are unrelated to the release.gh pr create --base main --head release-<version> \ --title "chore(release): merge release <version> into main"
After the release is published, you can edit the release notes on the Releases page if any manual adjustments are needed (e.g. adding a summary, highlighting key changes).
The automated pipeline generates release notes from the changelog. To replace or supplement them with a hand-written summary (e.g. for a feature-heavy release), find the release here https://github.com/garden-io/garden/releases and edit the release notes.
If the automated flow fails or you need more control, you can still release manually. The post-release automation detects manual releases (by checking the commit author) and skips auto-publishing, so you can safely edit the draft before publishing.
- Checkout to the
latest-releasebranch. - Reset
latest-releasetomainwithgit reset --hard origin/main - Run
git logto make sure the latest commit is the expected one. - Run
./scripts/release.ts patch(orminor, etc.). - Wait for the CI build job to get the binaries from the GitHub Releases page.
- Run the
devcommand inexamples/demo-projectand verify that no errors come up immediately. - Go to the Releases page and edit the draft release.
- Run
./scripts/draft-release-notes.ts <previous-tag> <current-tag>to generate release notes.- Add
--manualto get TODO placeholders to help with manual editing. - Without
--manual, the notes are publish-ready with a default description.
- Add
- Click Publish release.
Once you publish, the following automation kicks in automatically:
- Homebrew PR is created and merged
latest-releasebranch is updated to the released tag
You still need to manually create the release PR (see step 5 in "One-click release" above).
We have dedicated release branches, latest-release and latest-release-0.13. These are the base branches for our releases. The latest-release branch is also used for deploying our documentation, so it must always point to the latest stable release.
On every merge to main we publish an unstable release with the version edge-cedar that is always flagged as a pre-release.
For 0.13, use the 0.13 branch as the base branch in the Start Release workflow. This will use the latest-release-0.13 branch.
On every merge to the 0.13 branch, we publish an unstable release with the version edge-bonsai.
The release script has the following signature:
./scripts/release.ts <minor | patch | preminor | prepatch | prerelease> [--force] [--dry-run] [--yes]Flags:
--force: Override existing tags--dry-run: Perform all steps except pushing tags/branches--yes/-y: Skip the interactive confirmation prompt (used by CI)
The script:
- Checks out a branch named
release-<version>. - Updates
package.jsonversions andCHANGELOG.md. - Commits the changes, tags the commit, and pushes the tag and branch.
- Pushing the tag triggers CircleCI to build artifacts and create a draft GitHub release.
Release notes are generated automatically by scripts/draft-release-notes.ts:
./scripts/draft-release-notes.ts <previous-tag> <current-tag> [--output-stdout] [--manual]Features:
- Auto-detects external contributors via the GitHub API
- Extracts fixed issues from commit messages (
fixes #123,closes #123) --output-stdout: Print notes to stdout instead of writing a file--manual: Include TODO placeholders for hand-editing (legacy behavior)
The following secrets are used by the release workflows:
| Secret | Purpose |
|---|---|
GITHUB_TOKEN |
Default token for GitHub API operations |
COMMITTER_TOKEN |
PAT (gordon-garden-bot) for Homebrew repo operations |
- Branch protection on homebrew-garden must allow the
COMMITTER_TOKENbot to merge without review approvals.
The release-homebrew job triggered on a new release (see publish-release.yaml) creates and directly merges a PR on the Homebrew repository. The token used is stored as a secret under the name COMMITTER_TOKEN, owned by the gordon-garden-bot account.
Pre-releases are supported by the Start Release workflow (select prerelease, preminor, or prepatch as the release type). For pre-releases, CircleCI publishes the release directly (not as a draft), so the post-release automation (smoke test, release notes, Homebrew, release PR) is skipped — which is the desired behavior.
To test the full post-release pipeline (smoke test → release notes → publish → Homebrew → release PR) without doing a real stable release, you can manually trigger the post-release.yml workflow:
- Create a pre-release using the Start Release workflow
- Manually convert it to a draft on the GitHub Releases page (Edit → check "Set as a pre-release", uncheck, then check "Set as draft")
- Go to the Post-release automation workflow and trigger it manually with the tag name
Alternatively, the post-release.yml workflow can be triggered via workflow_dispatch at any time against an existing draft release for recovery or testing purposes.
On every merge to main, CircleCI builds and publishes an edge release tagged edge-cedar. This is always marked as a pre-release and is useful for testing the latest changes before a stable release.