chore: generate
This commit is contained in:
@@ -34,7 +34,12 @@ export interface Interface {
|
|||||||
readonly head: (directory: string) => Effect.Effect<string | undefined>
|
readonly head: (directory: string) => Effect.Effect<string | undefined>
|
||||||
readonly branch: (directory: string) => Effect.Effect<string | undefined>
|
readonly branch: (directory: string) => Effect.Effect<string | undefined>
|
||||||
readonly remoteHead: (directory: string) => Effect.Effect<string | undefined>
|
readonly remoteHead: (directory: string) => Effect.Effect<string | undefined>
|
||||||
readonly clone: (input: { remote: string; target: string; branch?: string; depth?: number }) => Effect.Effect<Result, AppProcess.AppProcessError>
|
readonly clone: (input: {
|
||||||
|
remote: string
|
||||||
|
target: string
|
||||||
|
branch?: string
|
||||||
|
depth?: number
|
||||||
|
}) => Effect.Effect<Result, AppProcess.AppProcessError>
|
||||||
readonly fetch: (directory: string) => Effect.Effect<Result, AppProcess.AppProcessError>
|
readonly fetch: (directory: string) => Effect.Effect<Result, AppProcess.AppProcessError>
|
||||||
readonly fetchBranch: (directory: string, branch: string) => Effect.Effect<Result, AppProcess.AppProcessError>
|
readonly fetchBranch: (directory: string, branch: string) => Effect.Effect<Result, AppProcess.AppProcessError>
|
||||||
readonly checkout: (directory: string, branch: string) => Effect.Effect<Result, AppProcess.AppProcessError>
|
readonly checkout: (directory: string, branch: string) => Effect.Effect<Result, AppProcess.AppProcessError>
|
||||||
@@ -109,7 +114,10 @@ export const layer = Layer.effect(
|
|||||||
})
|
})
|
||||||
|
|
||||||
const clone = Effect.fn("Git.clone")((input: { remote: string; target: string; branch?: string; depth?: number }) =>
|
const clone = Effect.fn("Git.clone")((input: { remote: string; target: string; branch?: string; depth?: number }) =>
|
||||||
execute(path.dirname(input.target), proc)([
|
execute(
|
||||||
|
path.dirname(input.target),
|
||||||
|
proc,
|
||||||
|
)([
|
||||||
"clone",
|
"clone",
|
||||||
"--depth",
|
"--depth",
|
||||||
String(input.depth ?? 100),
|
String(input.depth ?? 100),
|
||||||
@@ -134,7 +142,20 @@ export const layer = Layer.effect(
|
|||||||
execute(directory, proc)(["reset", "--hard", target]),
|
execute(directory, proc)(["reset", "--hard", target]),
|
||||||
)
|
)
|
||||||
|
|
||||||
return Service.of({ find, remote, roots, origin, head, branch, remoteHead, clone, fetch, fetchBranch, checkout, reset })
|
return Service.of({
|
||||||
|
find,
|
||||||
|
remote,
|
||||||
|
roots,
|
||||||
|
origin,
|
||||||
|
head,
|
||||||
|
branch,
|
||||||
|
remoteHead,
|
||||||
|
clone,
|
||||||
|
fetch,
|
||||||
|
fetchBranch,
|
||||||
|
checkout,
|
||||||
|
reset,
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -150,7 +171,8 @@ export interface Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function run(cwd: string, proc: AppProcess.Interface) {
|
function run(cwd: string, proc: AppProcess.Interface) {
|
||||||
return (args: string[]) => execute(cwd, proc)(args).pipe(Effect.catch(() => Effect.succeed({ exitCode: 1, text: "", stderr: "" })))
|
return (args: string[]) =>
|
||||||
|
execute(cwd, proc)(args).pipe(Effect.catch(() => Effect.succeed({ exitCode: 1, text: "", stderr: "" })))
|
||||||
}
|
}
|
||||||
|
|
||||||
function execute(cwd: string, proc: AppProcess.Interface) {
|
function execute(cwd: string, proc: AppProcess.Interface) {
|
||||||
@@ -166,7 +188,11 @@ function execute(cwd: string, proc: AppProcess.Interface) {
|
|||||||
.pipe(
|
.pipe(
|
||||||
Effect.map(
|
Effect.map(
|
||||||
(result) =>
|
(result) =>
|
||||||
({ exitCode: result.exitCode, text: result.stdout.toString("utf8"), stderr: result.stderr.toString("utf8") }) satisfies Result,
|
({
|
||||||
|
exitCode: result.exitCode,
|
||||||
|
text: result.stdout.toString("utf8"),
|
||||||
|
stderr: result.stderr.toString("utf8"),
|
||||||
|
}) satisfies Result,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,13 @@ export class InvalidRepositoryError extends Schema.TaggedErrorClass<InvalidRepos
|
|||||||
},
|
},
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
export class InvalidBranchError extends Schema.TaggedErrorClass<InvalidBranchError>()("RepositoryCacheInvalidBranchError", {
|
export class InvalidBranchError extends Schema.TaggedErrorClass<InvalidBranchError>()(
|
||||||
branch: Schema.String,
|
"RepositoryCacheInvalidBranchError",
|
||||||
message: Schema.String,
|
{
|
||||||
}) {}
|
branch: Schema.String,
|
||||||
|
message: Schema.String,
|
||||||
|
},
|
||||||
|
) {}
|
||||||
|
|
||||||
export class CloneFailedError extends Schema.TaggedErrorClass<CloneFailedError>()("RepositoryCacheCloneFailedError", {
|
export class CloneFailedError extends Schema.TaggedErrorClass<CloneFailedError>()("RepositoryCacheCloneFailedError", {
|
||||||
repository: Schema.String,
|
repository: Schema.String,
|
||||||
@@ -64,11 +67,14 @@ export class LockFailedError extends Schema.TaggedErrorClass<LockFailedError>()(
|
|||||||
message: Schema.String,
|
message: Schema.String,
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
export class CacheOperationError extends Schema.TaggedErrorClass<CacheOperationError>()("RepositoryCacheOperationError", {
|
export class CacheOperationError extends Schema.TaggedErrorClass<CacheOperationError>()(
|
||||||
operation: Schema.String,
|
"RepositoryCacheOperationError",
|
||||||
path: Schema.String,
|
{
|
||||||
message: Schema.String,
|
operation: Schema.String,
|
||||||
}) {}
|
path: Schema.String,
|
||||||
|
message: Schema.String,
|
||||||
|
},
|
||||||
|
) {}
|
||||||
|
|
||||||
export type Error =
|
export type Error =
|
||||||
| InvalidRepositoryError
|
| InvalidRepositoryError
|
||||||
@@ -155,27 +161,35 @@ export const layer: Layer.Layer<
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (status === "cloned") {
|
if (status === "cloned") {
|
||||||
const result = yield* git.clone({ remote: input.reference.remote, target: localPath, branch: input.branch }).pipe(
|
const result = yield* git
|
||||||
Effect.mapError((error) => new CloneFailedError({ repository, message: errorMessage(error) })),
|
.clone({ remote: input.reference.remote, target: localPath, branch: input.branch })
|
||||||
)
|
.pipe(Effect.mapError((error) => new CloneFailedError({ repository, message: errorMessage(error) })))
|
||||||
if (result.exitCode !== 0) {
|
if (result.exitCode !== 0) {
|
||||||
return yield* new CloneFailedError({ repository, message: resultMessage(result, `Failed to clone ${repository}`) })
|
return yield* new CloneFailedError({
|
||||||
|
repository,
|
||||||
|
message: resultMessage(result, `Failed to clone ${repository}`),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status === "refreshed") {
|
if (status === "refreshed") {
|
||||||
const fetch = yield* git.fetch(localPath).pipe(
|
const fetch = yield* git
|
||||||
Effect.mapError((error) => new FetchFailedError({ repository, message: errorMessage(error) })),
|
.fetch(localPath)
|
||||||
)
|
.pipe(Effect.mapError((error) => new FetchFailedError({ repository, message: errorMessage(error) })))
|
||||||
if (fetch.exitCode !== 0) {
|
if (fetch.exitCode !== 0) {
|
||||||
return yield* new FetchFailedError({ repository, message: resultMessage(fetch, `Failed to refresh ${repository}`) })
|
return yield* new FetchFailedError({
|
||||||
|
repository,
|
||||||
|
message: resultMessage(fetch, `Failed to refresh ${repository}`),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.branch) {
|
if (input.branch) {
|
||||||
const requestedBranch = input.branch
|
const requestedBranch = input.branch
|
||||||
const fetchBranch = yield* git.fetchBranch(localPath, requestedBranch).pipe(
|
const fetchBranch = yield* git
|
||||||
Effect.mapError((error) => new FetchFailedError({ repository, message: errorMessage(error) })),
|
.fetchBranch(localPath, requestedBranch)
|
||||||
)
|
.pipe(
|
||||||
|
Effect.mapError((error) => new FetchFailedError({ repository, message: errorMessage(error) })),
|
||||||
|
)
|
||||||
if (fetchBranch.exitCode !== 0) {
|
if (fetchBranch.exitCode !== 0) {
|
||||||
return yield* new FetchFailedError({
|
return yield* new FetchFailedError({
|
||||||
repository,
|
repository,
|
||||||
@@ -183,11 +197,18 @@ export const layer: Layer.Layer<
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkout = yield* git.checkout(localPath, requestedBranch).pipe(
|
const checkout = yield* git
|
||||||
Effect.mapError((error) =>
|
.checkout(localPath, requestedBranch)
|
||||||
new CheckoutFailedError({ repository, branch: requestedBranch, message: errorMessage(error) }),
|
.pipe(
|
||||||
),
|
Effect.mapError(
|
||||||
)
|
(error) =>
|
||||||
|
new CheckoutFailedError({
|
||||||
|
repository,
|
||||||
|
branch: requestedBranch,
|
||||||
|
message: errorMessage(error),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
if (checkout.exitCode !== 0) {
|
if (checkout.exitCode !== 0) {
|
||||||
return yield* new CheckoutFailedError({
|
return yield* new CheckoutFailedError({
|
||||||
repository,
|
repository,
|
||||||
@@ -197,11 +218,14 @@ export const layer: Layer.Layer<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const reset = yield* git.reset(localPath, yield* resetTarget(git, localPath, input.branch)).pipe(
|
const reset = yield* git
|
||||||
Effect.mapError((error) => new ResetFailedError({ repository, message: errorMessage(error) })),
|
.reset(localPath, yield* resetTarget(git, localPath, input.branch))
|
||||||
)
|
.pipe(Effect.mapError((error) => new ResetFailedError({ repository, message: errorMessage(error) })))
|
||||||
if (reset.exitCode !== 0) {
|
if (reset.exitCode !== 0) {
|
||||||
return yield* new ResetFailedError({ repository, message: resultMessage(reset, `Failed to reset ${repository}`) })
|
return yield* new ResetFailedError({
|
||||||
|
repository,
|
||||||
|
message: resultMessage(reset, `Failed to reset ${repository}`),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +269,9 @@ function errorMessage(error: unknown) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cacheOperation<A, E, R>(effect: Effect.Effect<A, E, R>, operation: string, target: string) {
|
function cacheOperation<A, E, R>(effect: Effect.Effect<A, E, R>, operation: string, target: string) {
|
||||||
return effect.pipe(Effect.mapError((error) => new CacheOperationError({ operation, path: target, message: errorMessage(error) })))
|
return effect.pipe(
|
||||||
|
Effect.mapError((error) => new CacheOperationError({ operation, path: target, message: errorMessage(error) })),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetTarget = Effect.fnUntraced(function* (git: Git.Interface, cwd: string, requestedBranch?: string) {
|
const resetTarget = Effect.fnUntraced(function* (git: Git.Interface, cwd: string, requestedBranch?: string) {
|
||||||
|
|||||||
@@ -182,7 +182,8 @@ function buildRemote(input: { host: string; segments: string[]; remote?: string;
|
|||||||
segments,
|
segments,
|
||||||
owner: segments.length === 2 ? segments[0] : undefined,
|
owner: segments.length === 2 ? segments[0] : undefined,
|
||||||
repo: segments[segments.length - 1],
|
repo: segments[segments.length - 1],
|
||||||
remote: input.remote ?? (host === "github.com" ? githubRemote(repositoryPath) : `https://${host}/${repositoryPath}.git`),
|
remote:
|
||||||
|
input.remote ?? (host === "github.com" ? githubRemote(repositoryPath) : `https://${host}/${repositoryPath}.git`),
|
||||||
label: host === "github.com" && segments.length === 2 ? repositoryPath : `${host}/${repositoryPath}`,
|
label: host === "github.com" && segments.length === 2 ? repositoryPath : `${host}/${repositoryPath}`,
|
||||||
protocol: input.protocol,
|
protocol: input.protocol,
|
||||||
} satisfies RemoteReference
|
} satisfies RemoteReference
|
||||||
|
|||||||
@@ -116,5 +116,10 @@ function read(file: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function exists(file: string) {
|
function exists(file: string) {
|
||||||
return Effect.promise(() => fs.stat(file).then(() => true, () => false))
|
return Effect.promise(() =>
|
||||||
|
fs.stat(file).then(
|
||||||
|
() => true,
|
||||||
|
() => false,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ describe("Repository", () => {
|
|||||||
expect(reference).toMatchObject({ host: "file", protocol: "file:", label: localPath })
|
expect(reference).toMatchObject({ host: "file", protocol: "file:", label: localPath })
|
||||||
expect(reference && Repository.isFile(reference)).toBe(true)
|
expect(reference && Repository.isFile(reference)).toBe(true)
|
||||||
expect(reference && Repository.isRemote(reference)).toBe(false)
|
expect(reference && Repository.isRemote(reference)).toBe(false)
|
||||||
expect(() => Repository.parseRemote(pathToFileURL(localPath).href)).toThrow(Repository.UnsupportedLocalRepositoryError)
|
expect(() => Repository.parseRemote(pathToFileURL(localPath).href)).toThrow(
|
||||||
|
Repository.UnsupportedLocalRepositoryError,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("rejects unsafe remote references and branches with typed errors", () => {
|
test("rejects unsafe remote references and branches with typed errors", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user