|
| 1 | +# Multirepo Development (cozystack + cozystack-ui) |
| 2 | + |
| 3 | +Cozystack spans two repositories that ship as one product: |
| 4 | + |
| 5 | +| Repo | Role | |
| 6 | +|------|------| |
| 7 | +| [`cozystack/cozystack`](https://github.com/cozystack/cozystack) | monorepo — Helm charts, Go controllers, CRDs, the release pipeline | |
| 8 | +| [`cozystack/cozystack-ui`](https://github.com/cozystack/cozystack-ui) | the dashboard frontend, built into the dashboard image | |
| 9 | + |
| 10 | +Both repos use the same branching model — `main` for development, `release-X.Y` for maintenance — and the two `release-X.Y` lines are kept in lockstep so a patch release never ships unreleased UI work. This guide explains how the two repos move together. For the release pipeline itself, see [`release.md`](./release.md). |
| 11 | + |
| 12 | +## The seam: how the UI gets into a build |
| 13 | + |
| 14 | +The dashboard image is built by `packages/system/dashboard/Makefile`, which clones **one** branch of `cozystack-ui` at build time, selected by `CONSOLE_BRANCH`. That single variable is what ties a cozystack release line to a cozystack-ui release line. |
| 15 | + |
| 16 | +`CONSOLE_BRANCH` is resolved automatically — there is no per-branch value to maintain by hand: |
| 17 | + |
| 18 | +| Build context | How it's resolved | Result | |
| 19 | +|---------------|-------------------|--------| |
| 20 | +| `cozystack/main`, feature branches (CI or local) | Makefile derives from git branch | `cozystack-ui@main` | |
| 21 | +| `cozystack/release-X.Y` checkout (local) | Makefile derives from git branch | `cozystack-ui@release-X.Y` | |
| 22 | +| Release build (`tags.yaml`, detached HEAD on a tag) | workflow passes the tag's base branch explicitly | `main` for `vX.Y.0`, `release-X.Y` for patch tags | |
| 23 | + |
| 24 | +The release build must supply the value explicitly because a tag checkout is a detached `HEAD` where the branch name is unavailable. Local builds derive it from the checked-out branch, so a `release-X.Y` checkout always builds the matching UI without any extra flags. |
| 25 | + |
| 26 | +## Developing a feature |
| 27 | + |
| 28 | +Everything new lands on `main` first — in **both** repos, always. |
| 29 | + |
| 30 | +- **Backend / chart / CRD change** → PR to `cozystack/main`. |
| 31 | +- **UI change** → PR to `cozystack-ui/main`. The repo's `test` job (type-check + build) gates the PR. |
| 32 | + |
| 33 | +Because a `cozystack/main` build clones `cozystack-ui@main`, the development branch always integrates the latest UI. No coordination commit is needed between the repos for day-to-day feature work. |
| 34 | + |
| 35 | +## Cutting a new minor (`vX.Y.0`) |
| 36 | + |
| 37 | +This is automatic. When the regular-release PR merges, `pull-requests-release.yaml` finalize: |
| 38 | + |
| 39 | +1. Creates `cozystack/release-X.Y` (the cozystack maintenance branch). |
| 40 | +2. Creates `cozystack-ui/release-X.Y` from `cozystack-ui/main` HEAD. |
| 41 | + |
| 42 | +The new `cozystack/release-X.Y` inherits the branch-deriving Makefile, so it is wired to `cozystack-ui/release-X.Y` from the moment it exists. Nothing to pin, nothing to remember. |
| 43 | + |
| 44 | +> Prerequisite: the `cozystack-ci` GitHub App must be installed on `cozystack-ui` with `contents:write`, so finalize can create the branch cross-repo. |
| 45 | +
|
| 46 | +## Backporting a fix to a patch release (`vX.Y.Z`) |
| 47 | + |
| 48 | +This is the one step that needs human judgment, and it is symmetric across both repos — the same discipline as any backend backport: |
| 49 | + |
| 50 | +- **Backend fix**: land on `cozystack/main` → cherry-pick to `cozystack/release-X.Y`. |
| 51 | +- **UI fix**: land on `cozystack-ui/main` → cherry-pick to `cozystack-ui/release-X.Y`. |
| 52 | + |
| 53 | +`auto-release.yaml` (nightly) notices commits ahead of the latest tag on `cozystack/release-X.Y`, cuts `vX.Y.Z`, and the build clones `cozystack-ui@release-X.Y` automatically. A UI-only fix therefore needs **no** cozystack-side commit — the next patch build picks it up on its own. |
| 54 | + |
| 55 | +Features are never cherry-picked. Only fixes to functionality that already shipped in `vX.Y.0` belong on a release branch. |
| 56 | + |
| 57 | +## Mental model |
| 58 | + |
| 59 | +A change is "in" a release line only when it has been cherry-picked to that line in **both** repos. Everything else lives on `main`. |
| 60 | + |
| 61 | +The minor cut and the build wiring are automatic. The cherry-pick triage — deciding what is a safe backport versus an unreleased feature — is the human's job, identical on both sides of the seam. |
| 62 | + |
| 63 | +## See also |
| 64 | + |
| 65 | +- [`release.md`](./release.md) — the full release pipeline, including the "UI release branch (dashboard)" section. |
| 66 | +- [`agents/contributing.md`](./agents/contributing.md) — commit/PR conventions and backport label semantics. |
| 67 | +- [`../packages/system/dashboard/Makefile`](../packages/system/dashboard/Makefile) — `CONSOLE_BRANCH` resolution. |
0 commit comments