Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
259 lines
6.3 KiB
JavaScript
259 lines
6.3 KiB
JavaScript
import {
|
|
normalizeReleaseTag,
|
|
normalizeReleaseVersion,
|
|
parseReleaseTag
|
|
} from "./releaseConfig.mjs";
|
|
|
|
function parseStableVersion(value) {
|
|
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(value);
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
major: Number(match[1]),
|
|
minor: Number(match[2]),
|
|
patch: Number(match[3])
|
|
};
|
|
}
|
|
|
|
export function parseReleaseVersion(value) {
|
|
const normalized = normalizeReleaseVersion(value);
|
|
const match =
|
|
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(rc|beta)\.(0|[1-9]\d*))?$/.exec(
|
|
normalized
|
|
);
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
|
|
const channel = match[4] ?? null;
|
|
const prereleaseNumber = match[5] === undefined ? null : Number(match[5]);
|
|
return {
|
|
major: Number(match[1]),
|
|
minor: Number(match[2]),
|
|
patch: Number(match[3]),
|
|
beta: channel === "beta" ? prereleaseNumber : null,
|
|
channel,
|
|
prereleaseNumber,
|
|
rc: channel === "rc" ? prereleaseNumber : null
|
|
};
|
|
}
|
|
|
|
export function formatReleaseVersion(version) {
|
|
const stable = `${version.major}.${version.minor}.${version.patch}`;
|
|
const channel =
|
|
version.channel ?? ((version.rc ?? null) !== null ? "rc" : null);
|
|
const prereleaseNumber =
|
|
version.prereleaseNumber ?? (channel === "rc" ? version.rc : version.beta);
|
|
return channel === null ? stable : `${stable}-${channel}.${prereleaseNumber}`;
|
|
}
|
|
|
|
export function isReleaseCandidateVersion(version) {
|
|
return parseReleaseVersion(formatReleaseVersion(version))?.channel === "rc";
|
|
}
|
|
|
|
function toStableVersion(version) {
|
|
return {
|
|
beta: null,
|
|
channel: null,
|
|
major: version.major,
|
|
minor: version.minor,
|
|
patch: version.patch,
|
|
prereleaseNumber: null,
|
|
rc: null
|
|
};
|
|
}
|
|
|
|
function compareStableVersions(left, right) {
|
|
return (
|
|
left.major - right.major ||
|
|
left.minor - right.minor ||
|
|
left.patch - right.patch
|
|
);
|
|
}
|
|
|
|
function bumpStableVersion(currentVersion, strategy) {
|
|
if (
|
|
strategy === "patch" ||
|
|
strategy === "patch_rc" ||
|
|
strategy === "patch_beta"
|
|
) {
|
|
return {
|
|
beta: null,
|
|
channel: null,
|
|
major: currentVersion.major,
|
|
minor: currentVersion.minor,
|
|
patch: currentVersion.patch + 1,
|
|
prereleaseNumber: null,
|
|
rc: null
|
|
};
|
|
}
|
|
if (
|
|
strategy === "minor" ||
|
|
strategy === "minor_rc" ||
|
|
strategy === "minor_beta"
|
|
) {
|
|
return {
|
|
beta: null,
|
|
channel: null,
|
|
major: currentVersion.major,
|
|
minor: currentVersion.minor + 1,
|
|
patch: 0,
|
|
prereleaseNumber: null,
|
|
rc: null
|
|
};
|
|
}
|
|
if (
|
|
strategy === "major" ||
|
|
strategy === "major_rc" ||
|
|
strategy === "major_beta"
|
|
) {
|
|
return {
|
|
beta: null,
|
|
channel: null,
|
|
major: currentVersion.major + 1,
|
|
minor: 0,
|
|
patch: 0,
|
|
prereleaseNumber: null,
|
|
rc: null
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function resolveLatestStableVersion(currentVersion, tags) {
|
|
let latestVersion = toStableVersion(currentVersion);
|
|
|
|
for (const tag of tags) {
|
|
const parsedVersion = parseReleaseVersion(tag);
|
|
if (!parsedVersion || parsedVersion.channel !== null) {
|
|
continue;
|
|
}
|
|
if (compareStableVersions(parsedVersion, latestVersion) > 0) {
|
|
latestVersion = toStableVersion(parsedVersion);
|
|
}
|
|
}
|
|
|
|
return latestVersion;
|
|
}
|
|
|
|
function resolveNextPrereleaseVersion(baseVersion, tags, channel) {
|
|
let highestPrerelease = -1;
|
|
|
|
for (const tag of tags) {
|
|
const parsedVersion = parseReleaseVersion(tag);
|
|
if (
|
|
!parsedVersion ||
|
|
parsedVersion.channel !== channel ||
|
|
compareStableVersions(parsedVersion, baseVersion) !== 0
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
highestPrerelease = Math.max(
|
|
highestPrerelease,
|
|
parsedVersion.prereleaseNumber
|
|
);
|
|
}
|
|
|
|
const prereleaseNumber = highestPrerelease + 1;
|
|
return {
|
|
...baseVersion,
|
|
beta: channel === "beta" ? prereleaseNumber : null,
|
|
channel,
|
|
prereleaseNumber,
|
|
rc: channel === "rc" ? prereleaseNumber : null
|
|
};
|
|
}
|
|
|
|
function resolveNextRcVersion(baseVersion, tags) {
|
|
return resolveNextPrereleaseVersion(baseVersion, tags, "rc");
|
|
}
|
|
|
|
function parseExplicitReleaseTag(tag) {
|
|
const parsedTag = parseReleaseTag(tag);
|
|
return parsedTag ? parseReleaseVersion(parsedTag) : null;
|
|
}
|
|
|
|
export function resolveDesktopRelease({
|
|
currentVersion,
|
|
explicitTag = "",
|
|
explicitVersion = "",
|
|
strategy,
|
|
tags = []
|
|
}) {
|
|
const parsedCurrentVersion = parseReleaseVersion(currentVersion);
|
|
if (!parsedCurrentVersion) {
|
|
throw new Error(
|
|
`Unsupported package.json version: ${currentVersion || "(empty)"}`
|
|
);
|
|
}
|
|
|
|
let releaseVersion;
|
|
if (
|
|
strategy === "patch" ||
|
|
strategy === "minor" ||
|
|
strategy === "major" ||
|
|
strategy === "patch_rc" ||
|
|
strategy === "minor_rc" ||
|
|
strategy === "major_rc" ||
|
|
strategy === "patch_beta" ||
|
|
strategy === "minor_beta" ||
|
|
strategy === "major_beta"
|
|
) {
|
|
const latestStableVersion = resolveLatestStableVersion(
|
|
parsedCurrentVersion,
|
|
tags
|
|
);
|
|
const bumpedVersion = bumpStableVersion(latestStableVersion, strategy);
|
|
if (!bumpedVersion) {
|
|
throw new Error(`Unsupported strategy: ${strategy}`);
|
|
}
|
|
if (strategy.endsWith("_rc")) {
|
|
releaseVersion = resolveNextPrereleaseVersion(bumpedVersion, tags, "rc");
|
|
} else if (strategy.endsWith("_beta")) {
|
|
releaseVersion = resolveNextPrereleaseVersion(
|
|
bumpedVersion,
|
|
tags,
|
|
"beta"
|
|
);
|
|
} else {
|
|
releaseVersion = bumpedVersion;
|
|
}
|
|
} else if (strategy === "explicit_version") {
|
|
releaseVersion = parseReleaseVersion(explicitVersion);
|
|
if (!releaseVersion) {
|
|
throw new Error(
|
|
`Invalid release version: ${explicitVersion || "(empty)"}`
|
|
);
|
|
}
|
|
} else if (strategy === "explicit_tag") {
|
|
releaseVersion = parseExplicitReleaseTag(explicitTag);
|
|
if (!releaseVersion) {
|
|
throw new Error(`Invalid release tag: ${explicitTag || "(empty)"}`);
|
|
}
|
|
} else {
|
|
throw new Error(`Unsupported strategy: ${strategy}`);
|
|
}
|
|
|
|
const version = formatReleaseVersion(releaseVersion);
|
|
const channel = releaseVersion.channel ?? "stable";
|
|
const prerelease = channel !== "stable";
|
|
return {
|
|
channel,
|
|
makeLatest: !prerelease,
|
|
prerelease,
|
|
tag: normalizeReleaseTag(version),
|
|
version
|
|
};
|
|
}
|
|
|
|
export {
|
|
compareStableVersions,
|
|
parseStableVersion,
|
|
resolveLatestStableVersion,
|
|
resolveNextPrereleaseVersion,
|
|
resolveNextRcVersion
|
|
};
|