Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,13 @@ These hold across the whole codebase; the skills explain the mechanisms.
image tag, so `just version::check` (a CI stage) fails where these disagree.
The frontend reads `VERSION` at build time (`vite.config.ts` → `$lib/version`
→ the footer) and displays it.
- **`main` is the only long-lived branch, and merging to it deploys to dev.**
One focused pull request per change, each carrying its manually added
`CHANGELOG.md` entry. Both clusters install the same chart from the GitOps
setup in `sdsc-ordes/cloud-infra` and differ only in image overrides: **dev**
runs `temporary/*:latest` with `pullPolicy: Always`, so every push to `main`
- **`main` is where development happens, and merging to it deploys to dev.** One
focused pull request per change, each carrying its manually added
`CHANGELOG.md` entry. Each released minor line has a `release/X.Y` branch that
takes hotfixes only, released from its own tags and cherry-picked back to
`main`. Both clusters install the same chart from the GitOps setup in
`sdsc-ordes/cloud-infra` and differ only in image overrides: **dev** runs
`temporary/*:latest` with `pullPolicy: Always`, so every push to `main`
reaches it on the next container restart; **prod** takes the chart defaults,
`release/*` at `appVersion`, so nothing merged can reach it until someone
bumps `appVersion` and installs the new chart version. See `RELEASING.md`.
Expand Down
120 changes: 102 additions & 18 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,37 @@ them.

## Branches

`main` is the only long-lived branch. Work happens on a short-lived branch —
`feat/…`, `fix/…`, `docs/…`, `chore/…` — and merges into `main` through a pull
request, with its changelog entry in the same pull request.

There is no integration branch. One focused pull request per change, reviewed
and merged on its own, is what keeps the history readable and the changelog
honest.
```
main ──●──●──●──●──●──●──●──●──●──► development; dev follows it
│
v0.12.1 + its chart bump
│
└── release/0.12 ──●── v0.12.2 ──●── v0.12.3 hotfixes only; prod runs these tags
▲
hotfix/… PRs
```

A pull request runs the full CI suite: codegen drift, lint, version consistency,
chart lint, build, tests, and an image build. That is the only gate in front of
`main` which matters for the reason below.
`main` is where development happens. Work happens on a short-lived branch —
`feat/…`, `fix/…`, `docs/…`, `chore/…` — and merges into `main` through a pull
request, with its changelog entry in the same pull request. One focused pull
request per change, reviewed and merged on its own, is what keeps the history
readable and the changelog honest.

`release/X.Y` is one branch per released minor line, created when that line is
released ([Making an app release](#making-an-app-release)). It never receives
features, only the fixes that prod cannot wait for — see
[Making a hotfix](#making-a-hotfix). Its tags (`v0.12.2`, `v0.12.3`, …) are what
prod runs. Once the next minor line is released, the old branch simply stops
being used and can be deleted once the new release has been deployed to
production.

So `main` can keep moving during a hackathon while prod stays on the release it
was installed with, and a hotfix for prod can be done on `release/X.Y`.

A pull request runs the full CI suite, whichever branch it targets: codegen
drift, lint, version consistency, chart lint, build, tests, and an image build.
That is the only gate in front of `main` and `release/*`. A push to `release/*`
itself builds nothing; only its tags do.

## Deployment

Expand Down Expand Up @@ -74,6 +94,9 @@ that exists because a `v*` tag built it.
Nothing merged to `main` can reach prod. It changes only when someone bumps
`appVersion`, publishes the chart, and installs that chart version.

While a hackathon is running on prod, install nothing there except hotfixes in
case the event needs them.

## Three version numbers

Two of them are the app, one is the chart, and they move independently. Read
Expand Down Expand Up @@ -111,7 +134,7 @@ Concurrent pull requests both appending under `[Unreleased]` will conflict on
those lines. The conflict is trivial to resolve — keep both entries — and is the
price of a file anyone can read without tooling.

## Cutting an app release
## Making an app release

From an up-to-date, clean `main`:

Expand All @@ -134,6 +157,17 @@ Pushing the tag builds and pushes `release/backend-service:0.9.0` and
`release/frontend-service:0.9.0`. A release image is never overwritten, so a
botched tag is fixed by bumping again, not by re-tagging.

Then [make the release deployable](#making-a-release-deployable). Once that
chart pull request is merged, create the release branch from its merge commit —
not from the tag, which does not have the chart bump yet. `main` may have moved
on in the meantime, so name the commit:

```bash
git fetch origin
git switch -c release/0.9 <merge commit of the chart pull request>
git push -u origin release/0.9
```

### If you bumped the wrong way

`bump` commits and tags locally and pushes nothing, so a release you have not
Expand All @@ -144,15 +178,59 @@ git reset --hard origin/main
git tag -d v0.9.0
```

If `main` has moved past something you cannot ship and a released version needs
a fix, branch from the tag rather than from `main`:
## Making a hotfix

```bash
git switch -c hotfix/thing v0.8.0
```
A hotfix goes on the release branch prod runs, never through `main`. Take
`release/0.12` and a fix that becomes `v0.12.2`:

1. **Branch from the release branch**, not from `main`:

```bash
git fetch origin
git switch -c hotfix/thing origin/release/0.12
```

2. **Fix it, in one pull request into `release/0.12`** — set that as the base;
GitHub suggests `main`. The pull request carries:
- the fix itself,
- its line under `[Unreleased]` → `### Fixed` in `CHANGELOG.md`,
- the chart bump for the release it will become: `Chart.yaml` `version` up
one patch, `appVersion: "0.12.2"`.

The chart bump belongs here, not in a pull request afterwards: CI publishes
charts only for pushes to `main` and for tags, so on a release branch the
chart has to be in the commit that gets tagged.

3. **Release it from the release branch**, once the pull request is merged:

Open the pull request against `main` if the fix belongs there too. Create such a
branch when a fix actually needs one — not in advance.
```bash
git switch release/0.12 && git pull
just version::bump patch
git show # read the release commit before it leaves
git push && git push origin v0.12.2
```

The tag builds `release/*:0.12.2`, then publishes the chart from the tagged
commit. Installing that chart version on prod is what ships the fix. A wrong
bump is undone as [above](#if-you-bumped-the-wrong-way), resetting to
`origin/release/0.12` instead of `origin/main`.

4. **Bring the fix to `main`**, or the next minor release brings the bug back.
Cherry-pick the fix commit onto a new branch and open a pull request into
`main`:

```bash
git switch -c fix/thing origin/main
git cherry-pick --no-commit <fix commit>
git restore --source=origin/main --staged --worktree helm-chart/Chart.yaml
git commit
```

Pick only the fix. The hotfix commit also carries the release's chart bump,
which is why `Chart.yaml` is put back to `main`'s before committing; merging
the release branch into `main` would bring its release commits and changelog
headings as well. `CHANGELOG.md` will conflict: keep the entry, under
`main`'s own `[Unreleased]`.

## Making a release deployable

Expand All @@ -173,6 +251,12 @@ no images yet.
Publishing a chart is not deploying it. Once a real deployment exists,
installing that chart version is the step that changes what runs.

`main` and a release branch both publish charts, so they must never pick the
same number. A release line keeps the chart patch versions of its release —
`release/0.12` started at chart `0.8.1` and goes on with `0.8.2`, `0.8.3`. On
`main`, the first chart change after cutting a release branch moves the chart to
the next minor (`0.9.0`).

## A first release checklist

Worth knowing once, then never again:
Expand Down
Loading