omnixient/modules/dev-env/docs/lnbits-upstream-flow.md
Padreug 346042f1c5 docs(dev-env): aiolabs stack overview and lnbits workflow notes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 09:59:05 +02:00

128 lines
4.7 KiB
Markdown

# `lnbits/lnbits` — Upstream Development Flow
Reference for [`github.com/lnbits/lnbits`](https://github.com/lnbits/lnbits).
Verified against git history on 2026-05-18; bump the date when you
re-verify, and patch this doc if the model has drifted.
## Branch model
Two long-lived branches:
| Branch | Role | How it moves |
|---|---|---|
| `dev` | Integration / staging | One squash-merge commit per PR. Linear. |
| `main` | Release | A non-fast-forward merge of `dev` at each release. |
`main` never receives feature PRs directly. **Every change reaches
`main` through `dev`.**
## PR flow → `dev`
1. Contributor opens a PR targeting `dev` (not `main`).
2. Maintainer squash-merges via the GitHub UI.
3. The resulting commit on `dev` has:
- exactly one parent (linear history),
- subject ending in `(#NNNN)` — the squash-merge signature,
- lowercase conventional-commit prefix: `feat:`, `fix:`, `chore:`,
`chore(deps):`, `docs:`, `ci:`, `test:`, `refactor:`.
4. CI runs on the PR; nothing else is required between merge and the
commit appearing on `dev`.
Example chain on `dev`:
```
c9c68bd8 Fix: Use default reaction on bootstrap (#3965)
810a1372 fix: tighten agents file (#3966)
36d696b2 Fix: wrong use of `in` operator (#3960)
8b426efa test: add pyinstrument profiler (#3955)
```
Each is a single squashed commit. No merge commits inside `dev`.
## Release flow → `main`
When `dev` is ready to ship:
1. A release-candidate version bump lands on `dev` as a normal PR:
`chore: update to version vX.Y.Z-rcN (#NNNN)`.
2. Validation happens against the RC.
3. A final version-bump PR lands on `dev`:
`chore: update to version vX.Y.Z (#NNNN)`.
4. A maintainer runs the release merge locally:
```bash
git checkout main
git pull --ff-only origin main
git merge dev # true (non-FF) merge, default message
git push origin main
git tag vX.Y.Z # tag the merge commit or the bump commit
git push origin vX.Y.Z
```
5. The resulting merge commit on `main` has:
- **two parents** (prior `main` tip + `dev` tip),
- subject exactly `Merge branch 'dev'` (git default when on `main`),
- **not** authored via the GitHub PR-merge UI (that would produce
`Merge pull request #N from …`).
Because `main` typically carries a stray release-bump commit that isn't
on `dev`, the histories have diverged and git is forced into a true
merge. `--no-ff` is not needed for that reason.
## Reading the history
```bash
# Release log (one entry per release):
git log main --first-parent --oneline
# Full changelog leading into the next release:
git log dev --oneline
# Verify a merge is a true non-FF merge:
git log <sha> -1 --format='%P' # two parent hashes = true merge
```
## Diagram
```
(PRs squash-merged one at a time)
dev: ── A ── B ── C ── D ── E ── F (rc1) ── G ── H (v1.5.4)
╲ (true merge)
main: ────────── prev release ─────────────── X ─────────── M
Merge branch 'dev'
tag: v1.5.4
```
## Implications for contributors
- **Base PRs on `dev`.** PRs against `main` will not be accepted.
- **Use lowercase conventional-commit titles.** Verified stable across
the last 25+ merged PRs.
- **Don't expect `main` to move between releases.** It only advances
when a maintainer cuts a release merge.
- **Tagging is on `main`.** Consumers pinning to a tag get the
released state, never a `dev` snapshot.
## Adapting this in your own fork
If you maintain a long-lived fork of `lnbits/lnbits` for production use,
you'll likely want to:
1. Mirror upstream's `dev` / `main` split — easier to track upstream
merges back into your fork.
2. Adopt a version-suffix convention that surfaces fork identity in
tags and the packaged `pyproject.toml` version, e.g.
`v<upstream>-<your-tag>.<N>`. This makes it unambiguous in logs and
deployed-package metadata that you're running fork-modified code.
3. Decide whether you also need pre-release channels (`-rcN`, `-devN`)
on top of upstream's; useful if your fork ships to staging hosts
before promotion.
Specifics depend entirely on your team's needs — this scaffold
deliberately doesn't prescribe a fork-versioning scheme.