blob: 553cf260e268128cd5893032ab692ddcde3d64c8 [file] [log] [blame]
/*
* Copyright 2000-2012 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;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.intellij.mock.MockVirtualFile;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.LocalChangeList;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile;
import com.intellij.testFramework.vcs.MockChangeListManager;
import com.intellij.testFramework.vcs.MockContentRevision;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsFullCommitDetails;
import com.intellij.vcs.log.VcsLogObjectsFactory;
import com.intellij.vcs.log.impl.HashImpl;
import cucumber.annotation.en.And;
import cucumber.annotation.en.Given;
import cucumber.annotation.en.Then;
import cucumber.annotation.en.When;
import git4idea.cherrypick.GitCherryPicker;
import git4idea.config.GitVersionSpecialty;
import git4idea.test.MockVcsHelper;
import java.util.*;
import static com.intellij.openapi.vcs.Executor.echo;
import static git4idea.GitCucumberWorld.*;
import static git4idea.test.GitExecutor.git;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
/**
* @author Kirill Likhodedov
*/
public class GitCherryPickStepdefs {
@Given("^(enabled|disabled) auto-commit in the settings$")
public void auto_commit_in_the_settings(String state) {
boolean enabled = state.equals("enabled");
myPlatformFacade.getSettings(myProject).setAutoCommitOnCherryPick(enabled);
}
@When("^I cherry-pick the commit (\\w+)$")
public void I_cherry_pick_the_commit(String hash) {
cherryPick(hash);
}
@When("^I cherry-pick commits (.+) and (\\w+)$")
public void I_cherry_pick_commits(String severalCommits, String hash2) throws Throwable {
String[] hashes = severalCommits.split(",");
String[] allHashes = new String[hashes.length + 1];
for (int i = 0; i < allHashes.length - 1; i++) {
allHashes[i] = hashes[i].trim();
}
allHashes[allHashes.length - 1] = hash2;
cherryPick(allHashes);
}
@When("^I cherry-pick the commit (\\w+) and( don't)? resolve conflicts$")
public void I_cherry_pick_the_commit_and_resolve_conflicts(String hash, String negation) throws Throwable {
if (negation == null) {
resolveConflictsInFuture();
}
cherryPick(hash);
}
private static void resolveConflictsInFuture() {
myVcsHelper.registerHandler(new MockVcsHelper.MergeHandler() {
@Override
public void showMergeDialog() {
git("add -u .");
}
});
}
private static void commitInFuture(final int times) {
myVcsHelper.registerHandler(new MockVcsHelper.CommitHandler() {
private int myCommitRequests;
@Override
public boolean commit(String commitMessage) {
if (myCommitRequests >= times) {
return false;
}
myCommitRequests++;
git(String.format("commit -am '%s'", commitMessage));
return true;
}
});
}
private static void commitInFuture() {
commitInFuture(Integer.MAX_VALUE);
}
@When("^I cherry-pick the commit (.+), resolve conflicts and( don't)? commit$")
public void I_cherry_pick_the_commit_resolve_conflicts_and_commit(String hash, String negation) throws Throwable {
resolveConflictsInFuture();
if (negation == null) {
commitInFuture();
}
cherryPick(hash);
}
@When("^I cherry-pick the commit (\\w+) and( don't)? commit$")
public void I_cherry_pick_the_commit_hash_and_commit(String hash, String negation) throws Throwable {
if (negation == null) {
commitInFuture();
}
cherryPick(hash);
}
@When("^I cherry-pick commits (.+) and commit both of them$")
public void I_cherry_pick_commits_and_commit_both_of_them(String listOfHashes) throws Throwable {
commitInFuture();
cherryPick(GeneralStepdefs.splitByComma(listOfHashes));
}
@When("^I cherry-pick commits (.+), but commit only the first one$")
public void I_cherry_pick_commits_but_commit_only_the_first_one(String listOfHashes) throws Throwable {
commitInFuture(1);
cherryPick(GeneralStepdefs.splitByComma(listOfHashes));
}
@Then("^the last commit is$")
public void the_last_commit_is(String message) throws Throwable {
git_log_should_return(1, message);
}
@Then("^the last commit is (.+)$")
public void the_last_commit_is_hash(String hash) throws Throwable {
assertEquals("The last commit hash doesn't match", virtualCommits.replaceVirtualHashes(hash), git("log -1 --pretty=%h"));
}
@Then("^`git log -(\\d+)` should return$")
public void git_log_should_return(int commitNum, String messages) throws Throwable {
List<String> expectedMessages = Arrays.asList(messages.split("-----"));
final String RECORD_SEPARATOR = "@";
boolean fullBody = GitVersionSpecialty.STARTED_USING_RAW_BODY_IN_FORMAT.existsIn(myVcs.getVersion());
String data = fullBody ? "%B" : "%s%b";
String output = git("log -%s --pretty=%s%s", String.valueOf(commitNum), data, RECORD_SEPARATOR);
List<String> actualMessages = Arrays.asList(output.split(RECORD_SEPARATOR));
for (int i = 0; i < expectedMessages.size(); i++) {
String expectedMessage = StringUtil.convertLineSeparators(expectedMessages.get(i).trim());
String actualMessage = StringUtil.convertLineSeparators(actualMessages.get(i).trim());
if (!fullBody) {
// the subject (%s) contains both "fix #1" and "cherry-picked from <hash>" in a single line
// so let's compare without taking line breaks and spaces into consideration
expectedMessage = expectedMessage.replace("\n", "").replace(" ", "");
actualMessage = actualMessage.replace("\n", "").replace(" ", "");
}
expectedMessage = virtualCommits.replaceVirtualHashes(expectedMessage);
assertEquals("Commit doesn't match", expectedMessage, trimHash(actualMessage));
}
}
@And("^no new changelists are created$")
public void no_new_changelists_are_created() {
assertOnlyDefaultChangelist();
}
@Given("^(.+) is locally modified:$")
public void is_locally_modified(String filename, String content) {
echo(filename, content);
}
String trimHash(String commitMessage) {
return commitMessage.replaceAll("([a-fA-F0-9]{7})[a-fA-F0-9]{33}", "$1");
}
@Then("^nothing is committed$")
public void nothing_is_committed() throws Throwable {
working_tree_is_dirty();
}
@And("^working tree is dirty$")
public void working_tree_is_dirty() throws Throwable {
assertFalse("Working tree is unexpectedly clean", git("diff").trim().isEmpty() && git("diff --cached").trim().isEmpty());
}
@Then("^merge dialog should be shown$")
public void merge_dialog_should_be_shown() throws Throwable {
assertTrue("Merge dialog was not shown", myVcsHelper.mergeDialogWasShown());
}
@Then("^commit dialog should be shown$")
public void commit_dialog_should_be_shown() throws Throwable {
assertTrue("Commit dialog was not shown", myVcsHelper.commitDialogWasShown());
}
@Then("^active changelist is '(.+)'$")
public void active_changelist_is(String name) throws Throwable {
assertActiveChangeList(virtualCommits.replaceVirtualHashes(name));
}
private static void assertOnlyDefaultChangelist() {
String DEFAULT = MockChangeListManager.DEFAULT_CHANGE_LIST_NAME;
assertChangeLists(Collections.singleton(DEFAULT), DEFAULT);
}
private static void assertChangeLists(Collection<String> changeLists, String activeChangelist) {
List<LocalChangeList> lists = myChangeListManager.getChangeLists();
Collection<String> listNames = Collections2.transform(lists, new Function<LocalChangeList, String>() {
@Override
public String apply(LocalChangeList input) {
return input.getName();
}
});
assertEquals("Change lists are different", new ArrayList<String>(changeLists), new ArrayList<String>(listNames));
assertActiveChangeList(activeChangelist);
}
private static void assertActiveChangeList(String name) {
assertEquals("Wrong active changelist", name, myChangeListManager.getDefaultChangeList().getName());
}
private static void cherryPick(List<String> virtualHashes) {
List<VcsFullCommitDetails> commits = ContainerUtil.newArrayList();
for (String virtualHash : virtualHashes) {
commits.add(createMockCommit(virtualHash));
}
new GitCherryPicker(myProject, myGit, myPlatformFacade, mySettings.isAutoCommitOnCherryPick())
.cherryPick(Collections.singletonMap(myRepository, commits));
}
private static void cherryPick(String... virtualHashes) {
cherryPick(Arrays.asList(virtualHashes));
}
private static VcsFullCommitDetails createMockCommit(String virtualHash) {
CommitDetails realCommit = virtualCommits.getRealCommit(virtualHash);
return mockCommit(realCommit.getHash(), realCommit.getMessage());
}
private static VcsFullCommitDetails mockCommit(String hash, String message) {
final List<Change> changes = new ArrayList<Change>();
changes.add(new Change(null, new MockContentRevision(new FilePathImpl(new MockVirtualFile("name")), VcsRevisionNumber.NULL)));
return ServiceManager.getService(myProject, VcsLogObjectsFactory.class).createFullDetails(
HashImpl.build(hash), Collections.<Hash>emptyList(), 0, NullVirtualFile.INSTANCE, message, "John Smith", "john@mail.com", message,
"John Smith", "john@mail.com", 0, new ThrowableComputable<Collection<Change>, Exception>() {
@Override
public Collection<Change> compute() throws Exception {
return changes;
}
}
);
}
}