git: rebase: make rebase dialog reuse the existing common rebase process

This fixes: IDEA-81093, IDEA-55479, IDEA-55672, IDEA-76778, IDEA-55672
This commit is contained in:
Kirill Likhodedov
2016-01-21 18:53:16 +03:00
parent 3ee8e8adb5
commit 905fdebb97
13 changed files with 247 additions and 241 deletions
@@ -444,7 +444,7 @@ public class DvcsUtil {
}
@Nullable
private static VirtualFile guessVcsRoot(@NotNull Project project, @Nullable VirtualFile file) {
public static VirtualFile guessVcsRoot(@NotNull Project project, @Nullable VirtualFile file) {
VirtualFile root = null;
if (file != null) {
root = ProjectLevelVcsManager.getInstance(project).getVcsRootFor(file);
@@ -44,7 +44,7 @@ abstract class GitAbstractRebaseAction extends DumbAwareAction {
super.update(e);
Project project = e.getProject();
if (project == null || !hasGitRepositories(project)) {
e.getPresentation().setVisible(false);
e.getPresentation().setEnabledAndVisible(false);
}
else {
e.getPresentation().setEnabledAndVisible(hasRebaseInProgress(project));
@@ -15,38 +15,58 @@
*/
package git4idea.actions;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.commands.GitLineHandler;
import git4idea.i18n.GitBundle;
import com.intellij.util.containers.ContainerUtil;
import git4idea.rebase.GitRebaseDialog;
import git4idea.rebase.GitRebaseUtils;
import git4idea.repo.GitRepository;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* Git rebase action
*/
public class GitRebase extends GitRebaseActionBase {
import static com.intellij.dvcs.DvcsUtil.sortRepositories;
import static git4idea.GitUtil.*;
import static git4idea.rebase.GitRebaseUtils.getRebasingRepositories;
import static java.util.Collections.singletonList;
/**
* {@inheritDoc}
*/
@NotNull
protected String getActionName() {
return GitBundle.getString("rebase.action.name");
public class GitRebase extends DumbAwareAction {
@Override
public void update(@NotNull AnActionEvent e) {
super.update(e);
Project project = e.getProject();
if (project == null || !hasGitRepositories(project)) {
e.getPresentation().setEnabledAndVisible(false);
}
else {
e.getPresentation().setVisible(true);
e.getPresentation().setEnabled(getRebasingRepositories(project).size() < getRepositories(project).size());
}
}
/**
* {@inheritDoc}
*/
@Nullable
protected GitLineHandler createHandler(Project project, List<VirtualFile> gitRoots, VirtualFile defaultRoot) {
GitRebaseDialog dialog = new GitRebaseDialog(project, gitRoots, defaultRoot);
if (!dialog.showAndGet()) {
return null;
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
final Project project = e.getRequiredData(CommonDataKeys.PROJECT);
ArrayList<GitRepository> repositories = ContainerUtil.newArrayList(getRepositories(project));
repositories.removeAll(getRebasingRepositories(project));
List<VirtualFile> roots = ContainerUtil.newArrayList(getRootsFromRepositories(sortRepositories(repositories)));
VirtualFile defaultRoot = DvcsUtil.guessVcsRoot(project, e.getData(CommonDataKeys.VIRTUAL_FILE));
final GitRebaseDialog dialog = new GitRebaseDialog(project, roots, defaultRoot);
if (dialog.showAndGet()) {
ProgressManager.getInstance().run(new Task.Backgroundable(project, "Rebasing...") {
public void run(@NotNull ProgressIndicator indicator) {
GitRebaseUtils.rebase(project, singletonList(dialog.getSelectedRepository()), dialog.getSelectedParams(), indicator);
}
});
}
return dialog.handler();
}
}
@@ -1,154 +0,0 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package git4idea.actions;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsNotifier;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import git4idea.GitUtil;
import git4idea.commands.Git;
import git4idea.commands.GitCommandResult;
import git4idea.commands.GitLineHandler;
import git4idea.i18n.GitBundle;
import git4idea.rebase.GitInteractiveRebaseEditorHandler;
import git4idea.rebase.GitRebaseEditorService;
import git4idea.rebase.GitRebaseLineListener;
import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Set;
/**
* The base class for rebase actions that use editor
*/
public abstract class GitRebaseActionBase extends GitRepositoryAction {
/**
* {@inheritDoc}
*/
protected void perform(@NotNull final Project project,
@NotNull final List<VirtualFile> gitRoots,
@NotNull final VirtualFile defaultRoot,
final Set<VirtualFile> affectedRoots,
final List<VcsException> exceptions) throws VcsException {
final GitLineHandler h = createHandler(project, gitRoots, defaultRoot);
if (h == null) {
return;
}
final VirtualFile root = h.workingDirectoryFile();
GitRebaseEditorService service = GitRebaseEditorService.getInstance();
final GitInteractiveRebaseEditorHandler editor = new GitInteractiveRebaseEditorHandler(service, project, root, h);
final GitRebaseLineListener resultListener = new GitRebaseLineListener();
h.addLineListener(resultListener);
configureEditor(editor);
affectedRoots.add(root);
service.configureHandler(h, editor.getHandlerNo());
new Task.Backgroundable(project, GitBundle.getString("rebasing.title"), true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
AccessToken token = DvcsUtil.workingTreeChangeStarted(project);
try {
GitCommandResult result = ServiceManager.getService(Git.class).runCommand(h);
editor.close();
GitRepositoryManager manager = GitUtil.getRepositoryManager(project);
manager.updateRepository(root);
VfsUtil.markDirtyAndRefresh(false, true, false, root);
notifyAboutResult(result, resultListener, editor.wasNoopSituationDetected(), exceptions, project);
}
finally {
DvcsUtil.workingTreeChangeFinished(project, token);
}
}
}.queue();
}
private static void notifyAboutResult(@NotNull GitCommandResult commandResult,
@NotNull GitRebaseLineListener resultListener,
boolean noopSituation,
@NotNull List<VcsException> exceptions,
@NotNull Project project) {
final GitRebaseLineListener.Result result = resultListener.getResult();
String messageId;
String message = null;
boolean isError = true;
switch (result.status) {
case CONFLICT:
messageId = "rebase.result.conflict";
break;
case ERROR:
messageId = "rebase.result.error";
message = commandResult.getErrorOutputAsHtmlString();
break;
case CANCELLED:
// we do not need to show a message if editing was cancelled.
exceptions.clear();
return;
case EDIT:
isError = false;
messageId = "rebase.result.amend";
break;
case FINISHED:
isError = false;
messageId = "rebase.result.success";
if (noopSituation) {
message = "Current branch was reset to the base branch";
}
break;
default:
throw new IllegalStateException("Unsupported rebase result: " + result.status);
}
String title = GitBundle.message(messageId + ".title");
if (message == null) {
message = GitBundle.message(messageId, result.current, result.total);
}
if (isError) {
VcsNotifier.getInstance(project).notifyError(title, message);
}
else {
VcsNotifier.getInstance(project).notifySuccess(title, message);
}
}
/**
* This method could be overridden to supply additional information to the editor.
*
* @param editor the editor to configure
*/
protected void configureEditor(GitInteractiveRebaseEditorHandler editor) {
}
/**
* Create line handler that represents a git operation
*
* @param project the context project
* @param gitRoots the git roots
* @param defaultRoot the default root
* @return the line handler or null
*/
@Nullable
protected abstract GitLineHandler createHandler(Project project, List<VirtualFile> gitRoots, VirtualFile defaultRoot);
}
@@ -18,31 +18,71 @@ package git4idea.branch;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import static com.intellij.openapi.util.text.StringUtil.nullize;
import static java.util.Arrays.asList;
public class GitRebaseParams {
@NotNull private final String myNewBase;
@Nullable private final String myBranch;
@Nullable private final String myNewBase;
@NotNull private final String myUpstream;
private final boolean myInteractive;
private final boolean myPreserveMerges;
public GitRebaseParams(@NotNull String newBase) {
myNewBase = newBase;
public GitRebaseParams(@NotNull String upstream) {
this(null, null, upstream, false, false);
}
public GitRebaseParams(@Nullable String branch,
@Nullable String newBase,
@NotNull String upstream,
boolean interactive,
boolean preserveMerges) {
myBranch = nullize(branch, true);
myNewBase = nullize(newBase, true);
myUpstream = upstream;
myInteractive = interactive;
myPreserveMerges = preserveMerges;
}
@NotNull
public List<String> asCommandLineArguments() {
List<String> args = ContainerUtil.newArrayList();
args.add(myNewBase);
if (myInteractive) {
args.add("--interactive");
}
if (myPreserveMerges) {
args.add("--preserve-merges");
}
if (myNewBase != null) {
args.addAll(asList("--onto", myNewBase));
}
args.add(myUpstream);
if (myBranch != null) {
args.add(myBranch);
}
return args;
}
@NotNull
@Nullable
public String getNewBase() {
return myNewBase;
}
@NotNull
public String getUpstream() {
return myUpstream;
}
@Override
public String toString() {
return StringUtil.join(asCommandLineArguments(), " ");
}
public boolean isInteractive() {
return myInteractive;
}
}
@@ -15,6 +15,7 @@
*/
package git4idea.commands;
import com.google.common.annotations.VisibleForTesting;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
@@ -567,10 +568,12 @@ public class GitImpl implements Git {
public GitCommandResult rebase(@NotNull GitRepository repository,
@NotNull GitRebaseParams parameters,
@NotNull GitLineHandlerListener... listeners) {
GitLineHandler handler = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.REBASE);
Project project = repository.getProject();
VirtualFile root = repository.getRoot();
GitLineHandler handler = new GitLineHandler(project, root, GitCommand.REBASE);
handler.addParameters(parameters.asCommandLineArguments());
addListeners(handler, listeners);
return run(handler);
return parameters.isInteractive() ? runWithEditor(project, root, handler, true) : run(handler);
}
@NotNull
@@ -595,9 +598,9 @@ public class GitImpl implements Git {
}
@NotNull
private static GitCommandResult rebaseResume(@NotNull GitRepository repository,
@NotNull GitRebaseResumeMode rebaseMode,
@NotNull GitLineHandlerListener[] listeners) {
private GitCommandResult rebaseResume(@NotNull GitRepository repository,
@NotNull GitRebaseResumeMode rebaseMode,
@NotNull GitLineHandlerListener[] listeners) {
Project project = repository.getProject();
VirtualFile root = repository.getRoot();
GitLineHandler handler = new GitLineHandler(project, root, GitCommand.REBASE);
@@ -607,10 +610,10 @@ public class GitImpl implements Git {
}
@NotNull
private static GitCommandResult runWithEditor(@NotNull Project project,
@NotNull VirtualFile root,
@NotNull GitLineHandler handler,
boolean commitListAware) {
private GitCommandResult runWithEditor(@NotNull Project project,
@NotNull VirtualFile root,
@NotNull GitLineHandler handler,
boolean commitListAware) {
GitInteractiveRebaseEditorHandler editor = configureEditor(project, root, handler, commitListAware);
try {
return run(handler);
@@ -620,11 +623,12 @@ public class GitImpl implements Git {
}
}
@VisibleForTesting
@NotNull
private static GitInteractiveRebaseEditorHandler configureEditor(@NotNull Project project,
@NotNull VirtualFile root,
@NotNull GitLineHandler handler,
boolean commitListAware) {
protected GitInteractiveRebaseEditorHandler configureEditor(@NotNull Project project,
@NotNull VirtualFile root,
@NotNull GitLineHandler handler,
boolean commitListAware) {
GitRebaseEditorService service = GitRebaseEditorService.getInstance();
GitInteractiveRebaseEditorHandler editor = new GitInteractiveRebaseEditorHandler(service, project, root, handler);
if (!commitListAware) {
@@ -26,14 +26,14 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.DocumentAdapter;
import git4idea.*;
import git4idea.branch.GitBranchUtil;
import git4idea.commands.GitCommand;
import git4idea.commands.GitLineHandler;
import git4idea.branch.GitRebaseParams;
import git4idea.config.GitConfigUtil;
import git4idea.config.GitRebaseSettings;
import git4idea.i18n.GitBundle;
import git4idea.merge.GitMergeUtil;
import git4idea.repo.GitRemote;
import git4idea.repo.GitRepository;
import git4idea.repo.GitRepositoryManager;
import git4idea.ui.GitReferenceValidator;
import git4idea.util.GitUIUtil;
import org.jetbrains.annotations.NotNull;
@@ -46,6 +46,9 @@ import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import static com.intellij.openapi.util.text.StringUtil.isEmptyOrSpaces;
import static com.intellij.util.ObjectUtils.assertNotNull;
/**
* The dialog that allows initiating git rebase activity
*/
@@ -53,6 +56,8 @@ public class GitRebaseDialog extends DialogWrapper {
private static final Logger LOG = Logger.getInstance(GitRebaseDialog.class);
@NotNull private final GitRepositoryManager myRepositoryManager;
/**
* Git root selector
*/
@@ -151,6 +156,7 @@ public class GitRebaseDialog extends DialogWrapper {
init();
myProject = project;
mySettings = ServiceManager.getService(myProject, GitRebaseSettings.class);
myRepositoryManager = GitUtil.getRepositoryManager(myProject);
final Runnable validateRunnable = new Runnable() {
public void run() {
validateFields();
@@ -210,39 +216,6 @@ public class GitRebaseDialog extends DialogWrapper {
}
}
public GitLineHandler handler() {
GitLineHandler h = new GitLineHandler(myProject, gitRoot(), GitCommand.REBASE);
h.setStdoutSuppressed(false);
if (myInteractiveCheckBox.isSelected() && myInteractiveCheckBox.isEnabled()) {
h.addParameters("-i");
}
h.addParameters("-v");
if (!myDoNotUseMergeCheckBox.isSelected()) {
if (myMergeStrategyComboBox.getSelectedItem().equals(GitMergeUtil.DEFAULT_STRATEGY)) {
h.addParameters("-m");
}
else {
h.addParameters("-s", myMergeStrategyComboBox.getSelectedItem().toString());
}
}
if (myPreserveMergesCheckBox.isSelected()) {
h.addParameters("-p");
}
String from = GitUIUtil.getTextField(myFromComboBox).getText();
String onto = GitUIUtil.getTextField(myOntoComboBox).getText();
if (from.length() == 0) {
h.addParameters(onto);
}
else {
h.addParameters("--onto", onto, from);
}
final String selectedBranch = (String)myBranchComboBox.getSelectedItem();
if (myCurrentBranch != null && !myCurrentBranch.getName().equals(selectedBranch)) {
h.addParameters(selectedBranch);
}
return h;
}
@Override
protected void doOKAction() {
try {
@@ -457,6 +430,31 @@ public class GitRebaseDialog extends DialogWrapper {
return (VirtualFile)myGitRootComboBox.getSelectedItem();
}
@NotNull
public GitRepository getSelectedRepository() {
return assertNotNull(myRepositoryManager.getRepositoryForRoot(gitRoot()));
}
@NotNull
public GitRebaseParams getSelectedParams() {
String selectedBranch = (String)myBranchComboBox.getSelectedItem();
String branch = myCurrentBranch != null && !myCurrentBranch.getName().equals(selectedBranch) ? selectedBranch : null;
String from = GitUIUtil.getTextField(myFromComboBox).getText();
String onto = GitUIUtil.getTextField(myOntoComboBox).getText();
String upstream;
String newBase;
if (isEmptyOrSpaces(from)) {
upstream = onto;
newBase = null;
}
else {
upstream = from;
newBase = onto;
}
return new GitRebaseParams(branch, newBase, upstream, myInteractiveCheckBox.isSelected(), myPreserveMergesCheckBox.isSelected());
}
/**
* {@inheritDoc}
@@ -42,10 +42,12 @@ public class GitRebaseProblemDetector extends GitLineHandlerAdapter {
"you have unstaged changes",
"your index contains uncommitted changes"
};
private static final String STOPPED_FOR_EDITING = "You can amend the commit now";
private volatile boolean myMergeConflict;
private volatile boolean myNoChangeError;
private volatile boolean myDirtyTree;
private volatile boolean myStoppedForEditing;
public boolean isNoChangeError() {
return myNoChangeError;
@@ -59,6 +61,10 @@ public class GitRebaseProblemDetector extends GitLineHandlerAdapter {
return myDirtyTree;
}
public boolean hasStoppedForEditing() {
return myStoppedForEditing;
}
@Override
public void onLineAvailable(String line, Key outputType) {
for (String conflictIndicator : REBASE_CONFLICT_INDICATORS) {
@@ -79,5 +85,9 @@ public class GitRebaseProblemDetector extends GitLineHandlerAdapter {
return;
}
}
if (StringUtil.containsIgnoreCase(line, STOPPED_FOR_EDITING)) {
myStoppedForEditing = true;
}
}
}
@@ -200,6 +200,10 @@ public class GitRebaseProcess {
boolean somethingRebased = customMode != null || progressListener.getResult().current > 1;
if (result.success()) {
if (rebaseDetector.hasStoppedForEditing()) {
showStoppedForEditingMessage(repository);
return new GitRebaseStatus(GitRebaseStatus.Type.SUSPENDED, skippedCommits);
}
LOG.debug("Successfully rebased " + repoName);
return GitSuccessfulRebase.parseFromOutput(result.getOutput(), skippedCommits);
}
@@ -346,7 +350,7 @@ public class GitRebaseProcess {
});
SuccessType commonType = getItemIfAllTheSame(successTypes, SuccessType.REBASED);
GitRebaseParams params = myRebaseSpec.getParams();
String message = commonType.formatMessage(rebasedBranch, params == null ? null : params.getNewBase());
String message = commonType.formatMessage(rebasedBranch, params == null ? null : notNull(params.getNewBase(), params.getUpstream()));
message += mentionSkippedCommits(skippedCommits);
myNotifier.notifyMinorInfo("Rebase Successful", message, new NotificationListener.Adapter() {
@Override
@@ -391,6 +395,12 @@ public class GitRebaseProcess {
return ResolveConflictResult.UNRESOLVED_REMAIN;
}
private void showStoppedForEditingMessage(@NotNull GitRepository repository) {
String description = "Once you are satisfied with your changes you may <a href='continue'>continue</a>";
myNotifier.notifyImportantInfo("Rebase Stopped for Editing", description,
new RebaseNotificationListener(repository, MultiMap.<GitRepository, GitRebaseUtils.CommitInfo>empty()));
}
private void showFatalError(@NotNull final String error,
@NotNull final GitRepository currentRepository,
boolean somethingWasRebased,
@@ -507,10 +517,10 @@ public class GitRebaseProcess {
private class RebaseNotificationListener extends NotificationListener.Adapter {
@NotNull private final GitRepository myCurrentRepository;
private final MultiMap<GitRepository, GitRebaseUtils.CommitInfo> mySkippedCommits;
@NotNull private final MultiMap<GitRepository, GitRebaseUtils.CommitInfo> mySkippedCommits;
RebaseNotificationListener(@NotNull GitRepository currentRepository,
MultiMap<GitRepository, GitRebaseUtils.CommitInfo> skippedCommits) {
@NotNull MultiMap<GitRepository, GitRebaseUtils.CommitInfo> skippedCommits) {
myCurrentRepository = currentRepository;
mySkippedCommits = skippedCommits;
}
@@ -29,7 +29,7 @@ class GitRebaseStatus {
SUCCESS,
/**
* Rebase started, and some commits were already applied,
* but then rebase stopped because of conflicts, or because of an error.<br/>
* but then rebase stopped because of conflicts, or to edit during interactive rebase, or because of an error.<br/>
* Such rebase can be retried/continued by calling `git rebase --continue/--skip`, or
* it can be aborted by calling `git rebase --abort`.
*/
@@ -18,6 +18,7 @@ package git4idea.rebase
import com.intellij.dvcs.DvcsUtil
import com.intellij.openapi.progress.EmptyProgressIndicator
import com.intellij.openapi.ui.Messages
import com.intellij.util.LineSeparator
import git4idea.branch.GitRebaseParams
import git4idea.repo.GitRepository
import git4idea.test.GitExecutor.file
@@ -174,7 +175,7 @@ class GitSingleRepoRebaseTest : GitRebaseBaseTest() {
myRepo.`diverge feature and master`()
val localChange = LocalChange(myRepo, "new.txt").generate()
object : GitTestingRebaseProcess(myProject, GitRebaseParams("master"), myRepo) {
object : GitTestingRebaseProcess(myProject, simpleParams("master"), myRepo) {
override fun getDirtyRoots(repositories: Collection<GitRepository>): Collection<GitRepository> {
return listOf(myRepo)
}
@@ -190,7 +191,7 @@ class GitSingleRepoRebaseTest : GitRebaseBaseTest() {
myRepo.`diverge feature and master`()
val localChange = LocalChange(myRepo, "new.txt").generate()
object : GitTestingRebaseProcess(myProject, GitRebaseParams("master"), myRepo) {
object : GitTestingRebaseProcess(myProject, simpleParams("master"), myRepo) {
override fun getDirtyRoots(repositories: Collection<GitRepository>): Collection<GitRepository> {
return emptyList()
}
@@ -392,12 +393,48 @@ class GitSingleRepoRebaseTest : GitRebaseBaseTest() {
""")
}
fun `test interactive rebase stopped for editing`() {
build {
master {
0()
1()
}
feature(1) {
2()
3()
}
}
myGit.setInteractiveRebaseEditor {
it.lines().mapIndexed { i, s ->
if (i != 0) s
else s.replace("pick", "edit")
}.joinToString(LineSeparator.getSystemLineSeparator().separatorString)
}
GitTestingRebaseProcess(myProject, GitRebaseParams(null, null, "master", true, false), myRepo).rebase()
assertSuccessfulNotification("Rebase Stopped for Editing", "Once you are satisfied with your changes you may <a href='continue'>continue</a>")
assertEquals("The repository must be in the 'SUSPENDED' state", myRepo, myGitRepositoryManager.ongoingRebaseSpec!!.ongoingRebase)
GitRebaseUtils.continueRebase(myProject)
assertSuccessfulNotification("Rebased feature on master")
myRepo.`assert feature rebased on master`()
assertNoRebaseInProgress(myRepo)
}
private fun build(f: RepoBuilder.() -> Unit) {
build(myRepo, f)
}
private fun rebaseOnMaster() {
GitTestingRebaseProcess(myProject, GitRebaseParams("master"), myRepo).rebase()
GitTestingRebaseProcess(myProject, simpleParams("master"), myRepo).rebase()
}
private fun simpleParams(newBase: String): GitRebaseParams {
return GitRebaseParams(newBase)
}
}
@@ -216,8 +216,12 @@ abstract class GitPlatformTest : PlatformTestCase() {
hookFile.setExecutable(true, false)
}
protected fun assertSuccessfulNotification(title: String, message: String) {
GitTestUtil.assertNotification(NotificationType.INFORMATION, title, message, myVcsNotifier.lastNotification)
}
protected fun assertSuccessfulNotification(message: String) {
GitTestUtil.assertNotification(NotificationType.INFORMATION, "Rebase Successful", message, myVcsNotifier.lastNotification)
assertSuccessfulNotification("Rebase Successful", message)
}
protected fun assertWarningNotification(title: String, message: String) {
@@ -15,12 +15,20 @@
*/
package git4idea.test
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.VirtualFile
import git4idea.branch.GitRebaseParams
import git4idea.commands.GitCommandResult
import git4idea.commands.GitImpl
import git4idea.commands.GitLineHandler
import git4idea.commands.GitLineHandlerListener
import git4idea.rebase.GitInteractiveRebaseEditorHandler
import git4idea.rebase.GitRebaseEditorService
import git4idea.repo.GitRemote
import git4idea.repo.GitRepository
import java.io.File
/**
* Any unknown error that could be returned by Git.
@@ -28,9 +36,11 @@ import git4idea.repo.GitRepository
val UNKNOWN_ERROR_TEXT: String = "unknown error"
class TestGitImpl : GitImpl() {
private val LOG = Logger.getInstance(TestGitImpl::class.java)
private var myRebaseShouldFail: (GitRepository) -> Boolean = { false }
private var myPushHandler: (GitRepository) -> GitCommandResult? = { null }
@Volatile private var myRebaseShouldFail: (GitRepository) -> Boolean = { false }
@Volatile private var myPushHandler: (GitRepository) -> GitCommandResult? = { null }
@Volatile private var myInteractiveRebaseEditor: ((String) -> String)? = null
override fun push(repository: GitRepository,
remote: GitRemote,
@@ -67,6 +77,28 @@ class TestGitImpl : GitImpl() {
}
}
override fun configureEditor(project: Project, root: VirtualFile, handler: GitLineHandler,
commitListAware: Boolean): GitInteractiveRebaseEditorHandler {
if (myInteractiveRebaseEditor == null) return super.configureEditor(project, root, handler, commitListAware)
val service = GitRebaseEditorService.getInstance()
val editor = object: GitInteractiveRebaseEditorHandler(service, project, root, handler) {
override fun editCommits(path: String?): Int {
try {
val file = File(path)
FileUtil.writeToFile(file, myInteractiveRebaseEditor!!(FileUtil.loadFile(file)))
}
catch(e: Exception) {
LOG.error(e)
return 1
}
return 0
}
}
service.configureHandler(handler, editor.handlerNo)
return editor
}
fun setShouldRebaseFail(shouldFail: (GitRepository) -> Boolean) {
myRebaseShouldFail = shouldFail
}
@@ -75,9 +107,14 @@ class TestGitImpl : GitImpl() {
myPushHandler = pushHandler;
}
fun setInteractiveRebaseEditor(editor: (String) -> String) {
myInteractiveRebaseEditor = editor
}
fun reset() {
myRebaseShouldFail = { false }
myPushHandler = { null }
myInteractiveRebaseEditor = null
}
private fun failOrCall(repository: GitRepository, delegate: () -> GitCommandResult): GitCommandResult {