Skip to content

Commit 517879e

Browse files
committed
fix: guard against invalid semver, extra repo path segments, and lost error cause
- In the custom version prompt validator, check isValidSemver(currentVersion) before calling semver.gt; an invalid current version (e.g. workspace:*) would cause semver.gt to throw a TypeError instead of returning a user-facing validation message - In normalizeReleaseScriptsOptions, require exactly two non-empty segments when splitting the repo string; values like "owner/repo/extra" were silently truncated to "owner/repo" instead of failing fast with a clear error - In packages.list/get, pass the original WorkspaceError as the cause when wrapping in ReleaseError so structured context is preserved for downstream error formatting
1 parent c85639b commit 517879e

File tree

3 files changed

+9
-4
lines changed

3 files changed

+9
-4
lines changed

src/core/prompts.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ export async function selectVersionPrompt(
124124
if (!isValidSemver(custom)) {
125125
return "That's not a valid version number";
126126
}
127+
if (!isValidSemver(currentVersion)) {
128+
return `Current version "${currentVersion}" is not valid semver — cannot compare`;
129+
}
127130
if (!semver.gt(custom, currentVersion)) {
128131
return `Version must be greater than the current version (${currentVersion})`;
129132
}

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,15 @@ export async function createReleaseScripts(options: ReleaseScriptsOptionsInput):
6868
async list(): Promise<WorkspacePackage[]> {
6969
return withErrorBoundary(async () => {
7070
const result = await discoverWorkspacePackages(normalizedOptions.workspaceRoot, normalizedOptions);
71-
if (!result.ok) throw new ReleaseError(result.error.message);
71+
if (!result.ok) throw new ReleaseError(result.error.message, undefined, result.error);
7272
return result.value;
7373
});
7474
},
7575

7676
async get(packageName: string): Promise<WorkspacePackage | undefined> {
7777
return withErrorBoundary(async () => {
7878
const result = await discoverWorkspacePackages(normalizedOptions.workspaceRoot, normalizedOptions);
79-
if (!result.ok) throw new ReleaseError(result.error.message);
79+
if (!result.ok) throw new ReleaseError(result.error.message, undefined, result.error);
8080
return result.value.find((p) => p.name === packageName);
8181
});
8282
},

src/options.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,13 @@ export function normalizeReleaseScriptsOptions(options: ReleaseScriptsOptionsInp
147147
throw new ReleaseError("Repository (repo) is required. Specify in 'owner/repo' format (e.g., 'octocat/hello-world').");
148148
}
149149

150-
const [owner, repo] = fullRepo.split("/");
151-
if (!owner || !repo) {
150+
const repoParts = fullRepo.trim().split("/");
151+
if (repoParts.length !== 2 || !repoParts[0]!.trim() || !repoParts[1]!.trim()) {
152152
throw new ReleaseError(`Invalid repo format: "${fullRepo}". Expected format: "owner/repo" (e.g., "octocat/hello-world").`);
153153
}
154154

155+
const [owner, repo] = repoParts.map((p) => p.trim()) as [string, string];
156+
155157
const normalizedPackages = typeof packages === "object" && !Array.isArray(packages)
156158
? {
157159
exclude: packages.exclude ?? [],

0 commit comments

Comments
 (0)