源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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
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
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { resolveDesktopRelease } from "./resolveDesktopRelease.mjs";
|
||||
|
||||
function isExplicitStrategy(strategy) {
|
||||
return strategy === "explicit_tag" || strategy === "explicit_version";
|
||||
}
|
||||
|
||||
export async function claimDesktopRelease({
|
||||
currentVersion,
|
||||
explicitTag = "",
|
||||
explicitVersion = "",
|
||||
listTags,
|
||||
maxAttempts = 20,
|
||||
reserveTag,
|
||||
strategy
|
||||
}) {
|
||||
if (typeof listTags !== "function") {
|
||||
throw new Error("listTags must be provided");
|
||||
}
|
||||
if (typeof reserveTag !== "function") {
|
||||
throw new Error("reserveTag must be provided");
|
||||
}
|
||||
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
||||
const release = resolveDesktopRelease({
|
||||
currentVersion,
|
||||
explicitTag,
|
||||
explicitVersion,
|
||||
strategy,
|
||||
tags: await listTags()
|
||||
});
|
||||
|
||||
if (await reserveTag(release.tag)) {
|
||||
return release;
|
||||
}
|
||||
|
||||
if (isExplicitStrategy(strategy)) {
|
||||
throw new Error(`Release tag already exists: ${release.tag}`);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Unable to reserve a unique release tag after ${maxAttempts} attempts`
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { parseReleaseTag } from "./releaseConfig.mjs";
|
||||
|
||||
function normalizeSemverLikeVersion(value) {
|
||||
const normalized = value.trim().replace(/^v/u, "");
|
||||
return /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/u.test(normalized)
|
||||
? normalized
|
||||
: null;
|
||||
}
|
||||
|
||||
function normalizePrereleaseIdentifier(value) {
|
||||
return value
|
||||
.trim()
|
||||
.replace(/[^0-9A-Za-z.-]+/gu, "-")
|
||||
.replace(/^[.-]+/u, "")
|
||||
.replace(/[.-]+$/u, "");
|
||||
}
|
||||
|
||||
export function normalizeDesktopGitDescribeVersion(value) {
|
||||
const normalized = typeof value === "string" ? value.trim() : "";
|
||||
if (!normalized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const releaseVersion = parseReleaseTag(normalized);
|
||||
if (releaseVersion) {
|
||||
return releaseVersion;
|
||||
}
|
||||
|
||||
const semverLike = normalizeSemverLikeVersion(normalized);
|
||||
if (semverLike) {
|
||||
return semverLike;
|
||||
}
|
||||
|
||||
const prerelease = normalizePrereleaseIdentifier(normalized);
|
||||
return prerelease ? `0.0.0-${prerelease}` : null;
|
||||
}
|
||||
|
||||
export function resolveDesktopBuildVersion({
|
||||
describeVersion = "",
|
||||
fallbackVersion = "",
|
||||
releaseTag = ""
|
||||
} = {}) {
|
||||
return (
|
||||
normalizeDesktopGitDescribeVersion(releaseTag) ??
|
||||
normalizeDesktopGitDescribeVersion(describeVersion) ??
|
||||
normalizeDesktopGitDescribeVersion(fallbackVersion)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
const GITHUB_RELEASE_BODY_MAX_LENGTH = 125_000;
|
||||
const RELEASE_NOTES_TRUNCATION_NOTICE =
|
||||
"> Additional generated release-note entries were omitted to stay within GitHub's 125,000-character limit.";
|
||||
|
||||
function composeReleaseBody({
|
||||
existingBody,
|
||||
leadingSections,
|
||||
trailingSections,
|
||||
truncated
|
||||
}) {
|
||||
const sections = [
|
||||
...leadingSections,
|
||||
existingBody,
|
||||
...(truncated ? [RELEASE_NOTES_TRUNCATION_NOTICE] : []),
|
||||
...trailingSections
|
||||
]
|
||||
.map((section) => section.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
return `${sections.join("\n\n")}\n`;
|
||||
}
|
||||
|
||||
function truncateAtLineBoundary(body, maxLength) {
|
||||
if (maxLength <= 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const candidate = body.slice(0, maxLength).trimEnd();
|
||||
if (candidate.length === body.trimEnd().length) {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
const lastLineBreak = candidate.lastIndexOf("\n");
|
||||
return lastLineBreak === -1
|
||||
? ""
|
||||
: candidate.slice(0, lastLineBreak).trimEnd();
|
||||
}
|
||||
|
||||
function buildLimitedGithubReleaseBody({
|
||||
existingBody,
|
||||
leadingSections = [],
|
||||
maxLength = GITHUB_RELEASE_BODY_MAX_LENGTH,
|
||||
trailingSections = []
|
||||
}) {
|
||||
const normalizedExistingBody = existingBody.trim();
|
||||
const fullBody = composeReleaseBody({
|
||||
existingBody: normalizedExistingBody,
|
||||
leadingSections,
|
||||
trailingSections,
|
||||
truncated: false
|
||||
});
|
||||
if (fullBody.length <= maxLength) {
|
||||
return fullBody;
|
||||
}
|
||||
|
||||
const fixedBody = composeReleaseBody({
|
||||
existingBody: "",
|
||||
leadingSections,
|
||||
trailingSections,
|
||||
truncated: true
|
||||
});
|
||||
if (fixedBody.length > maxLength) {
|
||||
throw new Error(
|
||||
`Managed GitHub Release sections exceed the ${maxLength}-character limit`
|
||||
);
|
||||
}
|
||||
|
||||
const retainedExistingBody = truncateAtLineBoundary(
|
||||
normalizedExistingBody,
|
||||
maxLength - fixedBody.length - 2
|
||||
);
|
||||
const limitedBody = composeReleaseBody({
|
||||
existingBody: retainedExistingBody,
|
||||
leadingSections,
|
||||
trailingSections,
|
||||
truncated: true
|
||||
});
|
||||
|
||||
if (limitedBody.length > maxLength) {
|
||||
throw new Error(
|
||||
`GitHub Release body exceeds the ${maxLength}-character limit after truncation`
|
||||
);
|
||||
}
|
||||
return limitedBody;
|
||||
}
|
||||
|
||||
export {
|
||||
GITHUB_RELEASE_BODY_MAX_LENGTH,
|
||||
RELEASE_NOTES_TRUNCATION_NOTICE,
|
||||
buildLimitedGithubReleaseBody,
|
||||
truncateAtLineBoundary
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
import { parseReleaseTag } from "./releaseConfig.mjs";
|
||||
|
||||
function normalizeVersion(tag) {
|
||||
return parseReleaseTag(tag) ?? tag.replace(/^v/u, "");
|
||||
}
|
||||
|
||||
function isPrereleaseVersion(version) {
|
||||
return /-[0-9A-Za-z.-]+$/u.test(version);
|
||||
}
|
||||
|
||||
function parseStableCore(version) {
|
||||
const match = /^(?<core>\d+\.\d+\.\d+)(?:-(?:rc|beta)\.\d+)?$/u.exec(version);
|
||||
return match?.groups?.core ?? "";
|
||||
}
|
||||
|
||||
function resolvePreviousReleaseTag({ channel, tag, tags, version }) {
|
||||
const currentTagIndex = tags.indexOf(tag);
|
||||
const candidates =
|
||||
currentTagIndex === -1
|
||||
? tags.filter((candidate) => candidate !== tag)
|
||||
: tags.slice(currentTagIndex + 1);
|
||||
if (channel === "stable") {
|
||||
return (
|
||||
candidates.find(
|
||||
(candidate) => !isPrereleaseVersion(normalizeVersion(candidate))
|
||||
) ?? ""
|
||||
);
|
||||
}
|
||||
|
||||
const stableCore = parseStableCore(version);
|
||||
return (
|
||||
candidates.find((candidate) => {
|
||||
const candidateVersion = normalizeVersion(candidate);
|
||||
return (
|
||||
candidateVersion.startsWith(`${stableCore}-${channel}.`) &&
|
||||
isPrereleaseVersion(candidateVersion)
|
||||
);
|
||||
}) ??
|
||||
candidates.find(
|
||||
(candidate) => !isPrereleaseVersion(normalizeVersion(candidate))
|
||||
) ??
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
isPrereleaseVersion,
|
||||
normalizeVersion,
|
||||
parseStableCore,
|
||||
resolvePreviousReleaseTag
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
const candidateSchemaVersion = "tutti.desktop.release.candidate.v1";
|
||||
|
||||
function sha256(value) {
|
||||
return createHash("sha256").update(value).digest("hex");
|
||||
}
|
||||
|
||||
function requireString(value, label) {
|
||||
const normalized = String(value ?? "").trim();
|
||||
if (!normalized) {
|
||||
throw new Error(`${label} is required`);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function createReleaseCandidateManifest(input) {
|
||||
const tag = requireString(input.tag, "tag");
|
||||
const version = requireString(input.version, "version");
|
||||
const candidateId = requireString(input.candidateId, "candidateId");
|
||||
if (tag !== `v${version}` || !/^v\d+\.\d+\.\d+$/u.test(tag)) {
|
||||
throw new Error("stable candidate tag and version must match");
|
||||
}
|
||||
if (!candidateId.startsWith(`${tag}-`)) {
|
||||
throw new Error("candidateId must start with the planned tag");
|
||||
}
|
||||
|
||||
const targetCommit = requireString(input.targetCommit, "targetCommit");
|
||||
if (!/^[a-f0-9]{40}$/u.test(targetCommit)) {
|
||||
throw new Error("targetCommit must be a full Git commit SHA");
|
||||
}
|
||||
|
||||
return {
|
||||
schemaVersion: candidateSchemaVersion,
|
||||
candidateId,
|
||||
tag,
|
||||
version,
|
||||
channel: "stable",
|
||||
targetCommit,
|
||||
sourceRef: requireString(input.sourceRef, "sourceRef"),
|
||||
createdAt: requireString(input.createdAt, "createdAt"),
|
||||
workflowRunUrl: requireString(input.workflowRunUrl, "workflowRunUrl"),
|
||||
checksumsSha256: sha256(requireString(input.checksums, "checksums")),
|
||||
generatedSummarySha256: sha256(
|
||||
requireString(input.generatedSummary, "generatedSummary")
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
function validateReleaseCandidateManifest(manifest, expected = {}) {
|
||||
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
|
||||
throw new Error("candidate manifest must be an object");
|
||||
}
|
||||
if (manifest.schemaVersion !== candidateSchemaVersion) {
|
||||
throw new Error(`unexpected candidate schema: ${manifest.schemaVersion}`);
|
||||
}
|
||||
const normalized = createReleaseCandidateManifest({
|
||||
...manifest,
|
||||
checksums: expected.checksums,
|
||||
generatedSummary: expected.generatedSummary
|
||||
});
|
||||
for (const [field, expectedValue] of Object.entries(expected)) {
|
||||
if (
|
||||
field !== "checksums" &&
|
||||
field !== "generatedSummary" &&
|
||||
expectedValue &&
|
||||
normalized[field] !== expectedValue
|
||||
) {
|
||||
throw new Error(`candidate manifest ${field} does not match`);
|
||||
}
|
||||
}
|
||||
if (manifest.checksumsSha256 !== normalized.checksumsSha256) {
|
||||
throw new Error("candidate checksums digest does not match");
|
||||
}
|
||||
if (manifest.generatedSummarySha256 !== normalized.generatedSummarySha256) {
|
||||
throw new Error("candidate summary digest does not match");
|
||||
}
|
||||
return manifest;
|
||||
}
|
||||
|
||||
function buildReleaseApprovalDigest(manifest, approvedSummary) {
|
||||
return sha256(
|
||||
JSON.stringify({
|
||||
candidateId: manifest.candidateId,
|
||||
checksumsSha256: manifest.checksumsSha256,
|
||||
generatedSummarySha256: manifest.generatedSummarySha256,
|
||||
tag: manifest.tag,
|
||||
targetCommit: manifest.targetCommit,
|
||||
approvedSummary
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
buildReleaseApprovalDigest,
|
||||
candidateSchemaVersion,
|
||||
createReleaseCandidateManifest,
|
||||
validateReleaseCandidateManifest
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
export const RELEASE_REPO_OWNER = "tutti-os";
|
||||
export const RELEASE_REPO_NAME = "tutti";
|
||||
export const LEGACY_RELEASE_TAG_PREFIX = "tutti-desktop-v";
|
||||
export const RELEASE_TAG_PREFIX = "v";
|
||||
|
||||
export function parseReleaseTag(tag) {
|
||||
const normalized = typeof tag === "string" ? tag.trim() : "";
|
||||
if (
|
||||
normalized.startsWith(LEGACY_RELEASE_TAG_PREFIX) &&
|
||||
normalized.length > LEGACY_RELEASE_TAG_PREFIX.length
|
||||
) {
|
||||
return normalized.slice(LEGACY_RELEASE_TAG_PREFIX.length);
|
||||
}
|
||||
|
||||
if (
|
||||
normalized.startsWith(RELEASE_TAG_PREFIX) &&
|
||||
normalized.length > RELEASE_TAG_PREFIX.length
|
||||
) {
|
||||
return normalized.slice(RELEASE_TAG_PREFIX.length);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function normalizeReleaseVersion(value) {
|
||||
const normalized = typeof value === "string" ? value.trim() : "";
|
||||
const parsed = parseReleaseTag(normalized);
|
||||
if (parsed) {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
return normalized.startsWith("v") ? normalized.slice(1) : normalized;
|
||||
}
|
||||
|
||||
export function normalizeReleaseTag(value) {
|
||||
return `${RELEASE_TAG_PREFIX}${normalizeReleaseVersion(value)}`;
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
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
|
||||
};
|
||||
Reference in New Issue
Block a user