Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3530 Change revert terminal-run commands into normal commands w/ proper error handling #3789

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

sergiolms
Copy link
Contributor

@sergiolms sergiolms commented Nov 21, 2024

Description

This task creates the git revert commands to move away from runTerminalCommand

Solves #3530

Checklist

  • I have followed the guidelines in the Contributing document
  • My changes follow the coding style of this project
  • My changes build without any errors or warnings
  • My changes have been formatted and linted
  • My changes include any required corresponding changes to the documentation (including CHANGELOG.md and README.md)
  • My changes have been rebased and squashed to the minimal number (typically 1) of relevant commits
  • My changes have a descriptive commit message with a short title, including a Fixes $XXX - or Closes #XXX - prefix to auto-close the issue that your PR addresses

@sergiolms sergiolms self-assigned this Nov 21, 2024
@sergiolms sergiolms marked this pull request as draft November 21, 2024 14:05
@gitkraken gitkraken deleted a comment from Ppeepost4489 Nov 22, 2024
@sergiolms sergiolms force-pushed the feature/#3530_change_git-revert_command_to_normal_cmd branch from b3280b6 to 5d90ed8 Compare November 27, 2024 14:17
@sergiolms sergiolms requested a review from eamodio November 27, 2024 14:17
@sergiolms sergiolms marked this pull request as ready for review November 27, 2024 14:17
@sergiolms sergiolms force-pushed the feature/#3530_change_git-revert_command_to_normal_cmd branch 2 times, most recently from bf93067 to 87b29d1 Compare December 3, 2024 15:26
Comment on lines 1338 to 1343
async revert(repoPath: string | Uri, ref: string, flags: string[] | undefined = []): Promise<void> {
const { provider, path } = this.getProvider(repoPath);
if (provider.revert == null) throw new ProviderNotSupportedError(provider.descriptor.name);

const options: { edit?: boolean } = {};
for (const flag of flags) {
switch (flag) {
case '--edit':
options.edit = true;
break;
case '--no-edit':
options.edit = false;
break;
default:
break;
}
}

return provider.revert(path, ref, options);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is a pattern in other places or not but, why at the git provider service level should the caller provide flags instead of just passing in options? Flags feel like low-level terminal args that should be abstracted down to the git.ts level and anything coming in from above should really only be dealing with a list of options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we could parse that in src/commands/git/* directly. Since currently this method is only being called from commands I didn't have preference on where to perform that conversion, but we can absolutely do that before and send the options directly to the method. Even better, maybe we can have an alternative

createFlagsQuickPickItem<Flags>(state.flags, ['--no-edit'], {
	label: this.title,
	description: '--no-edit',
	detail: `Will revert ${getReferenceLabel(state.references)}`,
}),

That accepts and returns an option set so we don't have to parse the flags every time. Let me think this through

Comment on lines +1601 to +1616
async revert(repoPath: string, ...args: string[]) {
try {
await this.git<string>({ cwd: repoPath }, 'revert', ...args);
} catch (ex) {
const msg: string = ex?.toString() ?? '';
for (const [error, reason] of revertErrorAndReason) {
if (error.test(msg) || error.test(ex.stderr ?? '')) {
throw new RevertError(reason, ex);
}
}

throw new RevertError(RevertErrorReason.Other, ex);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should take constrained options, generate the flags and params necessary off of those options, and then run the command with the args it generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is being performed at localGitProvider. From my understanding, localGitProvider is an abstraction from GitLens that uses the local implementation for git (the git binary in our case). As such, it should receive the options (business logic) and make the proper adaptations to call the local git implementation (the git methods).
The current implementation keeps the methods in git as atomic as possible and separated from our business logic (we could even move the error parsing to localGitProvider if necessary).

If you think it would be clearer to perform that here, I could move that logic here and leave the revert at localGitProvider with just the git call. Is this what you mean?

// localGitProvider.ts 
export class LocalGitProvider implements GitProvider, Disposable {
	// ...

	revert(repoPath: string, ref: string, options?: { edit?: boolean }): Promise<void> {
		return this.git.revert(repoPath, ref, options);
	}
}


// git.ts
export class Git {
	// ...
	
	async revert(repoPath: string, ref: string, options?: { edit?: boolean }) {
		const args = [];
		if (options.edit !== undefined) {
			args.push(options.edit ? '--edit' : '--no-edit');
		}
		
		args.push(ref);

		try {
			await this.git<string>({ cwd: repoPath }, 'revert', ...args);
		} catch (ex) {
			const msg: string = ex?.toString() ?? '';
			for (const [error, reason] of revertErrorAndReason) {
				if (error.test(msg) || error.test(ex.stderr ?? '')) {
					throw new RevertError(reason, ex, ref);
				}
			}

			throw new RevertError(RevertErrorReason.Other, ex, ref);
		}
	}
}

Comment on lines 80 to 102
for (const ref of state.references.reverse()) {
try {
await state.repo.git.revert(ref.ref, state.flags);
} catch (ex) {
if (ex instanceof RevertError) {
let shouldRetry = false;
if (ex.reason === RevertErrorReason.LocalChangesWouldBeOverwritten) {
const response = await showShouldCommitOrStashPrompt();
if (response === 'Stash') {
await executeCommand(Commands.GitCommandsStashPush);
shouldRetry = true;
} else if (response === 'Commit') {
await executeCoreCommand('workbench.view.scm');
shouldRetry = true;
} else {
continue;
}
}

if (shouldRetry) {
try {
await state.repo.git.revert(ref.ref, state.flags);
} catch (ex) {
Logger.error(ex, this.title);
void showGenericErrorMessage(ex.message);
}
}

continue;
}

Logger.error(ex, this.title);
void showGenericErrorMessage(ex.message);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably going to result in me receiving a crash course on git revert flows, but for my own education, can you explain what this is doing?

Copy link
Contributor Author

@sergiolms sergiolms Dec 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The revert command could return a "changes would be overwritten" error when the user had WIP while reverting. With this piece of code, we would catch that, let the user know they have WIP they should either commit or stash, and ask them what to do. Then, depending on the option they chose, we run & wait for the command and retry the revert action (unless they cancelled).

EDIT: Just tried it, and autostash is only available for rebase. I've seen some inconsistencies with the retry, since it fires before the other command finishes. Removing it now.

@sergiolms sergiolms force-pushed the feature/#3530_change_git-revert_command_to_normal_cmd branch from 87b29d1 to 4f921f8 Compare December 5, 2024 15:13
@sergiolms sergiolms force-pushed the feature/#3530_change_git-revert_command_to_normal_cmd branch from 4f921f8 to 028b32d Compare December 12, 2024 10:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants