chore: prepare the 2.2.0 release (#660)

Bumps every version surface to 2.2.0, fixes a latent version-coupling bug in the
OCR runtime tests, and stops an absent GPU runner from silently stalling a
release.

Version surfaces: scripts/sync-version.sh covers the 11 workspaces, APP_VERSION,
and the docs release commands across all locales. Root package.json plus the
three surfaces the script never reaches are done by hand: the DOCKERHUB.md banner
and tag table, the docker-tags.md pinning table in 21 locales, and the example
runtimeVersion in tools/image/ocr.md in 21 locales. The release-notes archive step
is deliberately not pre-run, so the notes text stays editable until the release.

Latent bug: runtime-state rejects any runtime whose compatibility.snapotterVersion
is not exactly APP_VERSION, and five fixtures pinned the literal 2.1.0. Since
semantic-release rewrites APP_VERSION on every release, the first PR after any
bump would have gone red for a reason nobody would trace to the release. The
fixtures now derive from APP_VERSION.

GPU runner: sign-ocr-index needs verify-ocr-nvidia on self-hosted hardware, and
the gated manifest job needs ai-bundles, so a missing runner queued instead of
failing and produced no image tags. preflight-gpu-runner claims the same labels
with no dependencies, so it is scheduled first and validates the GPU before the
90-minute build. An API preflight is impossible because listing self-hosted
runners needs Administration:read, which GITHUB_TOKEN cannot hold, so RELEASE.md
carries the maintainer-side check.
This commit is contained in:
SnapOtter
2026-07-27 22:09:31 +08:00
committed by GitHub
parent d10d0f544f
commit 5f21588f6c
101 changed files with 279 additions and 212 deletions
+11 -5
View File
@@ -11,6 +11,7 @@ import {
} from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { APP_VERSION } from "@snapotter/shared";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
getOcrRuntimeCapability,
@@ -21,6 +22,11 @@ import {
selectOcrRuntimeTarget,
} from "../../../packages/ai/src/runtime-state.js";
// runtime-state rejects any runtime whose compatibility.snapotterVersion is not
// exactly APP_VERSION, so these fixtures must track the real version. A literal
// here passes only until the next release bump, then fails every assertion that
// resolves a runtime. That is what happened on 2.1.0 -> 2.2.0.
const temporaryDirectories: string[] = [];
const runtimeSigningKey = generateKeyPairSync("ed25519");
@@ -133,7 +139,7 @@ function createRuntimeFixture(): {
family: "ocr",
target: "linux-amd64-cpu-py312",
generation: "generation-test",
version: "2.1.0",
version: APP_VERSION,
platform: "linux",
arch: "amd64",
archive: {
@@ -152,7 +158,7 @@ function createRuntimeFixture(): {
"pp-ocrv6-small": createHash("sha256").update("small").digest("hex"),
"pp-ocrv6-medium": createHash("sha256").update("medium").digest("hex"),
},
compatibility: { protocolVersion: 1, snapotterVersion: "2.1.0" },
compatibility: { protocolVersion: 1, snapotterVersion: APP_VERSION },
capabilities: {
qualities: ["balanced", "best"],
providers: ["CPUExecutionProvider"],
@@ -192,7 +198,7 @@ function createRuntimeFixture(): {
status: "ready",
activatedAt: "2026-07-13T00:00:00.000Z",
artifact: {
version: "2.1.0",
version: APP_VERSION,
target: "linux-amd64-cpu-py312",
platform: "linux",
arch: "amd64",
@@ -242,7 +248,7 @@ function createRuntimeFixture(): {
},
compatibility: {
protocolVersion: 1,
snapotterVersion: "2.1.0",
snapotterVersion: APP_VERSION,
},
capabilities: {
qualities: ["balanced", "best"],
@@ -393,7 +399,7 @@ describe("readActiveRuntime", () => {
},
compatibility: {
protocolVersion: 1,
snapotterVersion: "2.1.0",
snapotterVersion: APP_VERSION,
},
runtime: {
root: fixture.runtimeRoot,