Refuse a 0.x minor mismatch, and republish the overview from the named release's tree
CI / full-gate (push) Successful in 2m50s
CI / full-gate (push) Successful in 2m50s
This commit is contained in:
@@ -5,7 +5,7 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
overview_version:
|
||||
description: 'Version the overview should tell adopters to pull (e.g. 0.1.0)'
|
||||
description: 'Released version to republish the overview for, without the leading v (e.g. 0.1.0)'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
@@ -72,7 +72,11 @@ jobs:
|
||||
needs: [retag-image]
|
||||
runs-on: docker-host
|
||||
steps:
|
||||
# Publish the named release's own tree, so the page never pairs one Plainpages tag with another
|
||||
# release's sidecar pins. A version that was never released fails here.
|
||||
- uses: actions/checkout@v7.0.1
|
||||
with:
|
||||
ref: ${{ inputs.overview_version && format('refs/tags/v{0}', inputs.overview_version) || github.ref }}
|
||||
- name: Publish the Docker Hub overview
|
||||
env:
|
||||
DOCKERHUB_OVERVIEW_TOKEN: ${{ secrets.DOCKERHUB_OVERVIEW_TOKEN }}
|
||||
|
||||
@@ -607,17 +607,20 @@ provider/consumer semantics in `checkApiVersion`:
|
||||
| --- | --- | --- |
|
||||
| same major, same minor (patch ignored) | `ok` | load |
|
||||
| same major, plugin minor **<** host minor | `warn` | load, log — built against an older release; check that release's notes |
|
||||
| **major `0`**, any minor mismatch | `refuse` | **abort boot** — pre-1.0 the minor is the breaking slot |
|
||||
| same major, plugin minor **>** host minor | `refuse` | **abort boot** — plugin needs a newer host |
|
||||
| different major | `refuse` | **abort boot** — incompatible contract |
|
||||
| missing / not a valid semver | `refuse` | **abort boot** — must be declared |
|
||||
|
||||
The plugin pins one exact version (no ranges, per the project's pinning rules); the *host* supplies
|
||||
the caret-style compatibility. One digit carries the whole release, so a **minor** means either the
|
||||
plugin contract changed or a dependency moved far enough to warrant one. A `warn` therefore says
|
||||
"built against an older release" rather than promising new plugin features; check that release's
|
||||
notes before assuming there is anything to adopt. While Plainpages is `0.x` every release shares major `0`, so a plugin
|
||||
built against `0.1.0` still loads on a `0.9.0` host with a `warn`; reaching `1.0.0` refuses everything
|
||||
built against `0.x`, which is the point of that milestone.
|
||||
the compatibility. One digit carries the whole release, so a **minor** means either the plugin
|
||||
contract changed or a dependency moved far enough to warrant one.
|
||||
|
||||
While Plainpages is `0.x` the major stays `0`, which leaves the minor as the only slot a breaking
|
||||
change can use — so a minor mismatch is refused rather than warned: a plugin declaring `0.1.0` will
|
||||
not boot on a `0.2.0` host until it is rebuilt against it. Once `1.0.0` lands the minor becomes
|
||||
additive and the `warn` row applies, saying "built against an older release" rather than promising
|
||||
new features.
|
||||
|
||||
### Conflict rules
|
||||
|
||||
|
||||
@@ -86,6 +86,9 @@ test("checkApiVersion: semver compat — equal/patch ok, older minor warns, newe
|
||||
assert.equal(checkApiVersion("1.3.0", "1.2.0").level, "refuse"); // needs features a newer host has
|
||||
assert.equal(checkApiVersion("2.0.0", "1.5.0").level, "refuse"); // incompatible major (newer)
|
||||
assert.equal(checkApiVersion("1.0.0", "2.0.0").level, "refuse"); // incompatible major (older)
|
||||
assert.equal(checkApiVersion("0.1.0", "0.1.9").level, "ok"); // pre-1.0 patch is still ignored
|
||||
assert.equal(checkApiVersion("0.1.0", "0.2.0").level, "refuse"); // pre-1.0 the minor IS the breaking slot
|
||||
assert.equal(checkApiVersion("0.2.0", "0.1.0").level, "refuse");
|
||||
for (const bad of ["1", "1.2", "v1.2.3", "01.2.3", "1.2.x", "", 1, undefined, null]) {
|
||||
assert.equal(checkApiVersion(bad).level, "refuse", `${String(bad)} must refuse`);
|
||||
}
|
||||
|
||||
@@ -156,6 +156,12 @@ export function checkApiVersion(pluginVersion: unknown, hostVersion: string = HO
|
||||
if (plugin.major !== host.major) {
|
||||
return { level: "refuse", message: `plugin targets apiVersion ${pluginVersion}; host is ${hostVersion} — incompatible major` };
|
||||
}
|
||||
// Pre-1.0 the major is pinned at 0 until the 1.0.0 milestone, so a breaking change can only land
|
||||
// as a minor (release-tooling/next-version.ts shifts every level down). Treating that as additive
|
||||
// would let a stale plugin boot and fail at runtime instead of at discovery.
|
||||
if (host.major === 0 && plugin.minor !== host.minor) {
|
||||
return { level: "refuse", message: `plugin targets apiVersion ${pluginVersion}; host is ${hostVersion} — pre-1.0 a minor is a contract break, rebuild against ${hostVersion}` };
|
||||
}
|
||||
if (plugin.minor > host.minor) {
|
||||
return { level: "refuse", message: `plugin targets apiVersion ${pluginVersion} but host is ${hostVersion}; upgrade the host` };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user