mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-06-18 02:08:46 -04:00
404 lines
13 KiB
Markdown
404 lines
13 KiB
Markdown
# Development
|
|
|
|
This guide covers the branching model, release process, and versioning. For
|
|
how to submit changes, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
|
|
- [Development Model](#development-model)
|
|
- [Feature Branches](#feature-branches)
|
|
- [Develop](#develop)
|
|
- [Stable](#stable)
|
|
- [Hotfixes](#hotfixes)
|
|
- [Versioning](#versioning)
|
|
- [Examples](#examples)
|
|
- [Adding a settings page](#adding-a-settings-page)
|
|
- [Bug found during testing](#bug-found-during-testing)
|
|
- [Fast patch release](#fast-patch-release)
|
|
- [Hotfix while mid-feature](#hotfix-while-mid-feature)
|
|
- [Multiple features in progress](#multiple-features-in-progress)
|
|
- [Reference](#reference)
|
|
|
|
## Development Model
|
|
|
|
Changes flow through three stages:
|
|
|
|
- **Feature branches**: where work gets built
|
|
- **`develop`** (`:develop`): where work gets tested
|
|
- **Stable** (`:latest`): where work gets released
|
|
|
|
```
|
|
feature branches → develop (:develop) → tagged release (:latest)
|
|
```
|
|
|
|
### Feature Branches
|
|
|
|
All new work happens on feature branches created off `develop`. There can be
|
|
multiple in progress at once, both internal and community contributions. Each
|
|
branch is independent and gets deleted after merging.
|
|
|
|
When a feature branch is ready, it gets **squash merged** into `develop` for
|
|
testing. Squash merging collapses all the commits on the branch into a single
|
|
commit on `develop`. This keeps develop's history clean: one feature, one
|
|
commit, regardless of how many "wip" or "fix typo" commits happened on the
|
|
branch. The squashed commit message is the PR title, so develop reads as a list
|
|
of conventional commit entries.
|
|
|
|
The maintainer decides which branches go in and when; if there's contention,
|
|
it's discussed with testers. Smaller batches are preferred to avoid overloading
|
|
beta testers and to keep the gap between `:develop` and `:latest` short.
|
|
|
|
### Develop
|
|
|
|
`develop` is the default branch, but it's not where day-to-day work happens.
|
|
It's the **testing branch**: it always contains the next release being
|
|
evaluated by beta testers. Every push to `develop` builds the `:develop` Docker
|
|
image.
|
|
|
|
`:develop` is not guaranteed to be stable. Expect untested features and minor
|
|
issues. It won't have major breaking changes, but things may not work perfectly.
|
|
Don't run it on a setup you depend on.
|
|
|
|
**Nothing is committed directly to `develop`.** Bug fixes found during testing
|
|
go through the same feature branch → PR → squash merge flow as everything else.
|
|
This ensures all changes run through CI before landing. Active feature branches
|
|
rebase onto `develop` to pick up these fixes.
|
|
|
|
Before merging anything into a free `develop`, define the next release batch:
|
|
target version, included PRs, whether it needs a soak, and what kind of fixes
|
|
are allowed while it soaks. Use a local `.release-plan.md` scratch file if
|
|
useful; it's ignored by git so the plan can change without repo churn.
|
|
|
|
Once the batch is assembled, treat `develop` as that release candidate. Don't
|
|
add unrelated work during the soak; it either fixes the current batch or waits
|
|
for the next one. Small, low-risk bug fixes may be added if they are easy to
|
|
verify and don't change the release risk profile.
|
|
|
|
### Stable
|
|
|
|
What a release needs depends on what's in it. Automated tests must pass either
|
|
way.
|
|
|
|
If the batch contains anything that needs other people to verify it (a new
|
|
feature, anything risky, or anything the author can't confidently confirm
|
|
alone), it **soaks** on `develop` until the maintainer is satisfied it's ready.
|
|
|
|
If the batch is entirely small, low-risk changes the author can verify
|
|
themselves (most bug fixes, docs, dependency bumps, minor tweaks), it can be
|
|
tagged **as soon as CI passes**; no soak needed.
|
|
|
|
This is the same bar as a hotfix, pointed forward: if you can confidently verify
|
|
it yourself, it doesn't need the beta cycle. Once the criteria are met,
|
|
`develop` gets tagged (e.g. `v2.3.0`) which builds the `:latest` and `:v2.3.0`
|
|
Docker images.
|
|
|
|
The soak applies to the batch as a whole. Once a batch is being soaked, don't
|
|
tack new untested work onto it; that resets the testing clock. New features
|
|
wait for the next batch.
|
|
|
|
Then the cycle repeats: the next batch of complete feature branches is merged
|
|
into `develop` for testing.
|
|
|
|
#### Release Communication
|
|
|
|
When a minor or major release starts soaking on `develop`, two things happen:
|
|
|
|
1. **Bulletin announcement**: publish an announcement via the
|
|
[bulletin repo](https://github.com/Dictionarry-Hub/bulletin) targeting the
|
|
current stable version range. This reaches every running instance and lets
|
|
users know a new release is available for testing on `:develop`.
|
|
|
|
2. **GitHub Discussion**: open a discussion in the profilarr repo summarizing
|
|
what's in the batch, what to watch for, and where to report issues. Link
|
|
this discussion from the announcement's `link` field so users go straight
|
|
from the inbox to the feedback thread.
|
|
|
|
Both go out once `:develop` has rebuilt with the full batch merged. Don't
|
|
announce a planned release before there's something to test.
|
|
|
|
Patch releases that skip the soak (bug fixes, deps, docs) don't need either.
|
|
They're tagged as soon as CI passes and show up in the normal release notes.
|
|
|
|
#### Hotfixes
|
|
|
|
If a core feature is broken in a stable release and it can't wait for the next
|
|
minor version, a hotfix is applied against the stable tag. The bar for this is
|
|
high; a core feature must be broken, not a cosmetic issue or minor annoyance.
|
|
Small issues wait for the next minor release.
|
|
|
|
```
|
|
develop: A — B — C — D — E — F — G (HEAD, testing v2.3.0)
|
|
↑
|
|
v2.2.0 (broken)
|
|
```
|
|
|
|
```bash
|
|
# Branch from the stable tag
|
|
git checkout -b hotfix/v2.2.0-sync-crash v2.2.0
|
|
|
|
# Fix the bug, verify locally
|
|
git commit -m "fix: crash when syncing empty profiles"
|
|
|
|
# Tag the patch release
|
|
git tag v2.2.1
|
|
git push origin hotfix/v2.2.0-sync-crash --tags
|
|
```
|
|
|
|
This builds `:latest` from the fix without including any untested work. The
|
|
maintainer tests the fix locally before tagging; hotfixes don't go through the
|
|
full beta testing cycle. If the fix isn't something you can confidently verify
|
|
yourself, it's not a hotfix.
|
|
|
|
Then the fix is brought into `develop`:
|
|
|
|
```bash
|
|
git checkout develop
|
|
git cherry-pick <commit-hash>
|
|
# If the cherry-pick conflicts, resolve and continue:
|
|
# git add <resolved-file>
|
|
# git cherry-pick --continue
|
|
git push
|
|
|
|
# Clean up
|
|
git branch -d hotfix/v2.2.0-sync-crash
|
|
```
|
|
|
|
## Versioning
|
|
|
|
Version bumps are scoped to what the user achieves, not what the developer
|
|
changed. Define each feature by its atomic goal: the smallest user-facing unit
|
|
with a describable purpose. Version against that goal, not against the size of
|
|
the diff or whether the code is "new."
|
|
|
|
**Patch**: the goal stays the same; the how changes.
|
|
|
|
A number input's goal is "increase and decrease an integer." Adding
|
|
hold-to-change with an acceleration curve is a patch. The user still increases
|
|
and decreases an integer; the interaction just got smoother. New code, new
|
|
behavior, but same atomic plane.
|
|
|
|
**Minor**: the goal expands.
|
|
|
|
That same number input gains float support. The user can now do something they
|
|
couldn't before: work with decimal values. The atomic plane grew, even if the
|
|
code diff is small.
|
|
|
|
**Major**: the product-level contract breaks.
|
|
|
|
The PCD format changes and existing databases can't be read without migration.
|
|
The Docker volume layout changes and existing mounts break on upgrade. An entire
|
|
workflow gets removed that users built around. Major means the user's existing
|
|
setup stops working or requires manual intervention to continue. This is about
|
|
the application's contract with its users, not individual components.
|
|
|
|
A release batch takes the version of its highest-impact change. If any change
|
|
in the batch is a minor, the release is a minor. If every change is a patch,
|
|
the release is a patch.
|
|
|
|
## Examples
|
|
|
|
### Adding a settings page
|
|
|
|
You want to add a settings page. There's nothing currently being tested on
|
|
`develop`; the last release was tagged.
|
|
|
|
```bash
|
|
# Start your feature branch
|
|
git checkout develop
|
|
git pull
|
|
git checkout -b feat/settings-page
|
|
```
|
|
|
|
You work on it over a few days. Commits don't matter much since they'll be
|
|
squashed:
|
|
|
|
```bash
|
|
git commit -m "wip: settings page layout"
|
|
git commit -m "feat: wire up settings form"
|
|
git commit -m "fix: form validation"
|
|
git push origin feat/settings-page
|
|
```
|
|
|
|
It's ready. You open a PR on GitHub targeting `develop`. The PR title is your
|
|
commit message:
|
|
|
|
```
|
|
feat: add settings page
|
|
```
|
|
|
|
You squash merge the PR. `develop` now has one clean commit:
|
|
`feat: add settings page`. The `:develop` image rebuilds. Beta testers start
|
|
testing.
|
|
|
|
A week goes by with no issues. Automated tests pass. You tag it:
|
|
|
|
```bash
|
|
git checkout develop
|
|
git pull
|
|
git tag v2.4.0
|
|
git push --tags
|
|
```
|
|
|
|
`:latest` and `:v2.4.0` build. Stable users get the update. You delete the
|
|
feature branch.
|
|
|
|
### Bug found during testing
|
|
|
|
The settings page feature is on `develop`. A beta tester reports that saving
|
|
settings clears the form instead of showing a success message.
|
|
|
|
Create a fix branch, just like any other change:
|
|
|
|
```bash
|
|
git checkout develop
|
|
git pull
|
|
git checkout -b fix/settings-save-message
|
|
```
|
|
|
|
Fix the bug, commit, and push:
|
|
|
|
```bash
|
|
git commit -m "fix: show success message after saving settings"
|
|
git push origin fix/settings-save-message
|
|
```
|
|
|
|
Open a PR targeting `develop` with the title
|
|
`fix: show success message after saving settings`. CI runs. Once it passes,
|
|
squash merge the PR. `:develop` rebuilds. The tester confirms the fix.
|
|
|
|
No other issues come up. Two testers and the maintainer sign off. You tag it:
|
|
|
|
```bash
|
|
git checkout develop
|
|
git pull
|
|
git tag v2.4.0
|
|
git push --tags
|
|
```
|
|
|
|
The bug fix shipped as part of the minor release. No separate patch needed.
|
|
|
|
If you have feature branches in progress, they rebase onto `develop` to pick up
|
|
the fix:
|
|
|
|
```bash
|
|
git checkout feat/notifications
|
|
git fetch origin
|
|
git rebase origin/develop
|
|
git push --force-with-lease
|
|
```
|
|
|
|
### Fast patch release
|
|
|
|
The last minor (`v2.5.0`) is tagged. Since then, three small changes have landed
|
|
on `develop`: a dropdown clipping fix, a typo in an error message, and a
|
|
dependency bump. All three are low-risk and easy to verify yourself.
|
|
|
|
There's no feature in the batch and nothing risky, so it doesn't need a soak.
|
|
Once CI passes, you tag it:
|
|
|
|
```bash
|
|
git checkout develop
|
|
git pull
|
|
git tag v2.5.1
|
|
git push --tags
|
|
```
|
|
|
|
`:latest` and `:v2.5.1` build. It's a patch because the batch is only fixes. If
|
|
a feature had landed in the batch it would be a minor, and anything needing
|
|
verification would soak first.
|
|
|
|
### Hotfix while mid-feature
|
|
|
|
You're halfway through building a notifications system on `feat/notifications`.
|
|
A user reports that syncing crashes on the stable release (`v2.4.0`). It's a
|
|
core feature, so it needs a hotfix.
|
|
|
|
```bash
|
|
# Stash or commit your in-progress work
|
|
git checkout feat/notifications
|
|
git commit -m "wip: notification preferences"
|
|
|
|
# Branch from the stable tag
|
|
git checkout -b hotfix/v2.4.0-sync-crash v2.4.0
|
|
|
|
# Fix the bug, verify locally
|
|
git commit -m "fix: crash when syncing empty profiles"
|
|
|
|
# Tag the patch release
|
|
git tag v2.4.1
|
|
git push origin hotfix/v2.4.0-sync-crash --tags
|
|
```
|
|
|
|
`:latest` rebuilds from the fix. Stable users get `v2.4.1`.
|
|
|
|
Now bring the fix into `develop` and clean up:
|
|
|
|
```bash
|
|
git checkout develop
|
|
git cherry-pick <commit-hash>
|
|
git push
|
|
git branch -d hotfix/v2.4.0-sync-crash
|
|
```
|
|
|
|
Then go back to your feature and rebase to pick up the fix:
|
|
|
|
```bash
|
|
git checkout feat/notifications
|
|
git fetch origin
|
|
git rebase origin/develop
|
|
git push --force-with-lease
|
|
```
|
|
|
|
Your feature branch now includes the sync fix. You continue working where you
|
|
left off.
|
|
|
|
### Multiple features in progress
|
|
|
|
The settings page (`feat/settings-page`) is on `develop` being tested. While
|
|
that happens, you finish a notifications system and start working on a dark mode
|
|
feature.
|
|
|
|
```
|
|
feat/settings-page → merged into develop, being tested
|
|
feat/notifications → complete, waiting in queue
|
|
feat/dark-mode → in progress
|
|
```
|
|
|
|
Testers sign off on the settings page. You tag it:
|
|
|
|
```bash
|
|
git checkout develop
|
|
git pull
|
|
git tag v2.4.0
|
|
git push --tags
|
|
```
|
|
|
|
Now `develop` is free. The notifications feature is next. You open a PR for
|
|
`feat/notifications` targeting `develop`, rebase first:
|
|
|
|
```bash
|
|
git checkout feat/notifications
|
|
git fetch origin
|
|
git rebase origin/develop
|
|
git push --force-with-lease
|
|
```
|
|
|
|
Squash merge the PR. `:develop` rebuilds with the notifications feature. Beta
|
|
testers start testing.
|
|
|
|
Meanwhile, you keep working on dark mode. When a bug fix lands on `develop`
|
|
during notifications testing, you rebase to pick it up:
|
|
|
|
```bash
|
|
git checkout feat/dark-mode
|
|
git fetch origin
|
|
git rebase origin/develop
|
|
git push --force-with-lease
|
|
```
|
|
|
|
When notifications is tagged, dark mode is next in the queue.
|
|
|
|
## Reference
|
|
|
|
- `docs/ARCHITECTURE.md` - full codebase encyclopedia (modules, data flow, PCD)
|
|
- `docs/CONTRIBUTING.md` - how to submit changes, guidelines, conventions
|
|
- `deno task stats` - per-module code stats (TS/JS/Svelte/CSS/SQL/C#)
|