mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-23 04:26:05 +00:00
fix(repository): type expected reference failures (#28880)
This commit is contained in:
parent
4f6eaf859b
commit
aee552c043
3 changed files with 80 additions and 13 deletions
|
|
@ -7,8 +7,11 @@ import {
|
|||
repositoryCachePath,
|
||||
sameRepositoryReference,
|
||||
parseRepositoryReference,
|
||||
parseRemoteRepositoryReference,
|
||||
validateRepositoryBranch,
|
||||
isRemoteRepositoryReference,
|
||||
InvalidRepositoryBranchError,
|
||||
InvalidRepositoryReferenceError,
|
||||
UnsupportedLocalRepositoryError,
|
||||
type RemoteReference,
|
||||
} from "@/util/repository"
|
||||
|
||||
|
|
@ -138,23 +141,26 @@ export function isError(error: unknown): error is Error {
|
|||
}
|
||||
|
||||
export const parseRemoteReference = Effect.fn("RepositoryCache.parseRemoteReference")(function* (repository: string) {
|
||||
const reference = parseRepositoryReference(repository)
|
||||
if (!reference) {
|
||||
try {
|
||||
return parseRemoteRepositoryReference(repository)
|
||||
} catch (error) {
|
||||
if (error instanceof InvalidRepositoryReferenceError || error instanceof UnsupportedLocalRepositoryError) {
|
||||
return yield* new InvalidRepositoryError({ repository: error.repository, message: error.message })
|
||||
}
|
||||
return yield* new InvalidRepositoryError({
|
||||
repository,
|
||||
message: "Repository must be a git URL, host/path reference, or GitHub owner/repo shorthand",
|
||||
message: errorMessage(error),
|
||||
})
|
||||
}
|
||||
if (!isRemoteRepositoryReference(reference)) {
|
||||
return yield* new InvalidRepositoryError({ repository, message: "Local file repositories are not supported" })
|
||||
}
|
||||
return reference
|
||||
})
|
||||
|
||||
export const validateBranch = Effect.fn("RepositoryCache.validateBranch")(function* (branch: string) {
|
||||
try {
|
||||
validateRepositoryBranch(branch)
|
||||
} catch (error) {
|
||||
if (error instanceof InvalidRepositoryBranchError) {
|
||||
return yield* new InvalidBranchError({ branch: error.branch, message: error.message })
|
||||
}
|
||||
return yield* new InvalidBranchError({ branch, message: errorMessage(error) })
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import path from "path"
|
||||
import { fileURLToPath } from "url"
|
||||
import { Schema } from "effect"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
|
||||
type BaseReference = {
|
||||
|
|
@ -23,6 +24,43 @@ export type FileReference = BaseReference & {
|
|||
|
||||
export type Reference = RemoteReference | FileReference
|
||||
|
||||
export class InvalidRepositoryReferenceError extends Schema.TaggedErrorClass<InvalidRepositoryReferenceError>()(
|
||||
"RepositoryInvalidReferenceError",
|
||||
{
|
||||
repository: Schema.String,
|
||||
message: Schema.String,
|
||||
},
|
||||
) {}
|
||||
|
||||
export class UnsupportedLocalRepositoryError extends Schema.TaggedErrorClass<UnsupportedLocalRepositoryError>()(
|
||||
"RepositoryUnsupportedLocalRepositoryError",
|
||||
{
|
||||
repository: Schema.String,
|
||||
message: Schema.String,
|
||||
},
|
||||
) {}
|
||||
|
||||
export class InvalidRepositoryBranchError extends Schema.TaggedErrorClass<InvalidRepositoryBranchError>()(
|
||||
"RepositoryInvalidBranchError",
|
||||
{
|
||||
branch: Schema.String,
|
||||
message: Schema.String,
|
||||
},
|
||||
) {}
|
||||
|
||||
export type RepositoryError =
|
||||
| InvalidRepositoryReferenceError
|
||||
| UnsupportedLocalRepositoryError
|
||||
| InvalidRepositoryBranchError
|
||||
|
||||
export function isRepositoryError(error: unknown): error is RepositoryError {
|
||||
return (
|
||||
error instanceof InvalidRepositoryReferenceError ||
|
||||
error instanceof UnsupportedLocalRepositoryError ||
|
||||
error instanceof InvalidRepositoryBranchError
|
||||
)
|
||||
}
|
||||
|
||||
function normalizeRepositoryInput(input: string) {
|
||||
return input
|
||||
.trim()
|
||||
|
|
@ -147,16 +185,27 @@ export function isRemoteRepositoryReference(reference: Reference): reference is
|
|||
|
||||
export function parseRemoteRepositoryReference(input: string) {
|
||||
const reference = parseRepositoryReference(input)
|
||||
if (!reference) throw new Error("Repository must be a git URL, host/path reference, or GitHub owner/repo shorthand")
|
||||
if (!isRemoteRepositoryReference(reference)) throw new Error("Local file repositories are not supported")
|
||||
if (!reference) {
|
||||
throw new InvalidRepositoryReferenceError({
|
||||
repository: input,
|
||||
message: "Repository must be a git URL, host/path reference, or GitHub owner/repo shorthand",
|
||||
})
|
||||
}
|
||||
if (!isRemoteRepositoryReference(reference)) {
|
||||
throw new UnsupportedLocalRepositoryError({
|
||||
repository: input,
|
||||
message: "Local file repositories are not supported",
|
||||
})
|
||||
}
|
||||
return reference
|
||||
}
|
||||
|
||||
export function validateRepositoryBranch(branch: string) {
|
||||
if (!/^[A-Za-z0-9/_.-]+$/.test(branch) || branch.startsWith("-") || branch.includes("..")) {
|
||||
throw new Error(
|
||||
"Branch must contain only alphanumeric characters, /, _, ., and -, and cannot start with - or contain ..",
|
||||
)
|
||||
throw new InvalidRepositoryBranchError({
|
||||
branch,
|
||||
message: "Branch must contain only alphanumeric characters, /, _, ., and -, and cannot start with - or contain ..",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ import path from "path"
|
|||
import { pathToFileURL } from "url"
|
||||
import { Global } from "@opencode-ai/core/global"
|
||||
import {
|
||||
InvalidRepositoryBranchError,
|
||||
InvalidRepositoryReferenceError,
|
||||
UnsupportedLocalRepositoryError,
|
||||
isFileRepositoryReference,
|
||||
isRemoteRepositoryReference,
|
||||
parseRemoteRepositoryReference,
|
||||
|
|
@ -61,6 +64,14 @@ describe("util.repository", () => {
|
|||
expect(() => parseRemoteRepositoryReference(pathToFileURL(localPath).href)).toThrow(
|
||||
"Local file repositories are not supported",
|
||||
)
|
||||
expect(() => parseRemoteRepositoryReference(pathToFileURL(localPath).href)).toThrow(UnsupportedLocalRepositoryError)
|
||||
})
|
||||
|
||||
test("rejects invalid remote repository references with typed errors", () => {
|
||||
expect(() => parseRemoteRepositoryReference("not-a-repo")).toThrow(InvalidRepositoryReferenceError)
|
||||
expect(() => parseRemoteRepositoryReference("git@github.com:../../../etc/passwd")).toThrow(
|
||||
InvalidRepositoryReferenceError,
|
||||
)
|
||||
})
|
||||
|
||||
test("compares cache identity independent of input spelling", () => {
|
||||
|
|
@ -77,5 +88,6 @@ describe("util.repository", () => {
|
|||
expect(() => validateRepositoryBranch("-bad")).toThrow("Branch must contain only alphanumeric characters")
|
||||
expect(() => validateRepositoryBranch("bad..branch")).toThrow("Branch must contain only alphanumeric characters")
|
||||
expect(() => validateRepositoryBranch("bad branch")).toThrow("Branch must contain only alphanumeric characters")
|
||||
expect(() => validateRepositoryBranch("bad branch")).toThrow(InvalidRepositoryBranchError)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue