Skip to content

Commit

Permalink
add BranchError and BranchErrorReason
Browse files Browse the repository at this point in the history
  • Loading branch information
sergiolms committed Sep 27, 2024
1 parent c16510e commit fb0d9ac
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 1 deletion.
33 changes: 32 additions & 1 deletion src/env/node/git/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ const textDecoder = new TextDecoder('utf8');
const rootSha = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';

export const GitErrors = {
noRemoteReference: /unable to delete '.+?': remote ref does not exist/i,
invalidBranchName: /fatal: '.+?' is not a valid branch name/i,
branchAlreadyExists: /fatal: A branch named '.+?' already exists/i,
branchNotFullyMerged: /error: The branch '.+?' is not fully merged/i,
badRevision: /bad revision '(.*?)'/i,
cantLockRef: /cannot lock ref|unable to update local ref/i,
changesWouldBeOverwritten: /Your local changes to the following files would be overwritten/i,
Expand Down Expand Up @@ -509,7 +513,34 @@ export class Git {
}

async branch(repoPath: string, ...args: string[]): Promise<void> {
return this.git<string>({ cwd: repoPath }, 'branch', ...args);
try {
await this.git<string>({ cwd: repoPath }, 'branch', ...args);
} catch (ex) {
const msg: string = ex?.toString() ?? '';
let reason: BranchErrorReason = BranchErrorReason.Other;
switch (true) {
case GitErrors.noRemoteReference.test(msg) || GitErrors.noRemoteReference.test(ex.stderr ?? ''):
reason = BranchErrorReason.NoRemoteReference;
break;
case GitErrors.invalidBranchName.test(msg) || GitErrors.invalidBranchName.test(ex.stderr ?? ''):
reason = BranchErrorReason.InvalidBranchName;
break;
case GitErrors.branchAlreadyExists.test(msg) || GitErrors.branchAlreadyExists.test(ex.stderr ?? ''):
reason = BranchErrorReason.BranchAlreadyExists;
break;
case GitErrors.branchNotFullyMerged.test(msg) || GitErrors.branchNotFullyMerged.test(ex.stderr ?? ''):
reason = BranchErrorReason.BranchNotFullyMerged;
break;
case GitErrors.branchNotYetBorn.test(msg) || GitErrors.branchNotYetBorn.test(ex.stderr ?? ''):
reason = BranchErrorReason.BranchNotYetBorn;
break;
case GitErrors.branchFastForwardRejected.test(msg) ||
GitErrors.branchFastForwardRejected.test(ex.stderr ?? ''):
reason = BranchErrorReason.BranchFastForwardRejected;
break;
}
throw new BranchError(reason, ex);
}
}

branch__set_upstream(repoPath: string, branch: string, remote: string, remoteBranch: string) {
Expand Down
54 changes: 54 additions & 0 deletions src/git/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,60 @@ export class PushError extends Error {
}
}

export const enum BranchErrorReason {
BranchAlreadyExists,
BranchNotFullyMerged,
NoRemoteReference,
InvalidBranchName,
Other,
}

export class BranchError extends Error {
static is(ex: unknown, reason?: BranchErrorReason): ex is BranchError {
return ex instanceof BranchError && (reason == null || ex.reason === reason);
}

readonly original?: Error;
readonly reason: BranchErrorReason | undefined;

constructor(reason?: BranchErrorReason, original?: Error, branch?: string);
constructor(message?: string, original?: Error);
constructor(messageOrReason: string | BranchErrorReason | undefined, original?: Error, branch?: string) {
let message;
const baseMessage = `Unable to perform action on branch${branch ? ` '${branch}'` : ''}`;
let reason: BranchErrorReason | undefined;
if (messageOrReason == null) {
message = baseMessage;
} else if (typeof messageOrReason === 'string') {
message = messageOrReason;
reason = undefined;
} else {
reason = messageOrReason;
switch (reason) {
case BranchErrorReason.BranchAlreadyExists:
message = `${baseMessage} because it already exists.`;
break;
case BranchErrorReason.BranchNotFullyMerged:
message = `${baseMessage} because it is not fully merged.`;
break;
case BranchErrorReason.NoRemoteReference:
message = `${baseMessage} because the remote reference does not exist.`;
break;
case BranchErrorReason.InvalidBranchName:
message = `${baseMessage} because the branch name is invalid.`;
break;
default:
message = baseMessage;
}
}
super(message);

this.original = original;
this.reason = reason;
Error.captureStackTrace?.(this, BranchError);
}
}

export const enum PullErrorReason {
Conflict,
GitIdentity,
Expand Down

0 comments on commit fb0d9ac

Please sign in to comment.