Versioning
Two audiences want different things from a version number, so a distribution gives them different ones.
Dates for end users
End users want to know their copy is current. 2023.12.01 against a latest of
2024.12.01 says a year has passed, immediately. 1.1.1 against 1.2.1 says
nothing about time, and secure software needs regular updates — so bumping
should be obviously overdue when it is.
A distribution is therefore versioned by the date it was released.
Semver for developers
Developers consuming a module want to know how much work an upgrade is. 1.2.3
to 1.2.4 is nothing; 2.0.0 is a morning. So modules are versioned by semver
and tagged in their own repositories.
Tags go on the module, not the distribution. A monorepo that tags every package fills its history with noise; here each module has its own repository, so its tags are its own.
Where a version comes from
The submodule commit is the pin. The version is whatever the package.json
inside that checkout says. Nothing in the distribution repository restates it.
pnpm links the checkout into the workspace, so that is also the version
everything resolves against — an app depending on a package gets the checkout,
not a published copy. Modules are depended on with workspace:*, which names no
version at all.
A repository that also wrote "@acme/design": "1.4.0" somewhere would be
carrying a second copy of the same fact, free to drift from the first.
fg-dist sync reports the version it reads out of each
checkout:
apps/widget v1.2.0 -> v1.3.0 (minor)
packages/design v1.4.0 up to date
Published distributions
A published distribution has no submodules, so its manifest carries the versions it shipped. That is what an extension is compared against, and the only place versions are written down.
Maintenance branches
A mature distribution has users slow to take major upgrades, which is what an LTS branch is for. How often to cut one is a trade between the cost of maintaining branches and the cost of forcing upgrades — once or twice a year, or every two, depending on how often you break things.
Yearly
lts-2023 is created in 2023 and maintained until 2025, tagged 2023.01-lts,
2023.02-lts and so on. lts-2024 is created in 2024 and maintained until
2026, tagged 2024.01-lts onwards.
Quarterly
lts-2023-q2 is created in Q2 2023 and maintained until Q2 2024, tagged
2023.04.01-lts, 2023.04.02-lts and so on. lts-2023-q4 runs Q4 2023 to Q4
2024 with 2023.10.01-lts onwards, and lts-2024-q2 runs Q2 2024 to Q2 2025
with 2024.04.01-lts onwards.
Modules do not get LTS
A module that changes often enough gets maintenance branches by patch version instead:
@fairgarden/id
1.2.3 the latest version
1.2.x main, until it is branched off when 1.3.0 is released
1.1.x the previous maintenance branch
So @fairgarden/core:2023.04.01 depends on 1.1.x and
@fairgarden/core:2023.10.01 on 1.2.x.
These are only needed when a distribution is using LTS. A module carried in an LTS distribution is one that is probably dependable enough to use on its own too.