diff options
author | Andre Bossert <andre.bossert@siemens.com> | 2020-01-19 20:52:56 +0100 |
---|---|---|
committer | Andrey Loskutov <loskutov@gmx.de> | 2022-05-25 13:52:04 +0200 |
commit | 85734356351ec2df4067b2472a37f6d9bcbb7350 (patch) | |
tree | 0596c7e5a59bfdbe37f1fb5456c755ec9a823580 /org.eclipse.jgit.pgm.test/tst/org/eclipse | |
parent | 24171b05f0db8487d0a1dc40072cc313bb6e2087 (diff) | |
download | jgit-85734356351ec2df4067b2472a37f6d9bcbb7350.tar.gz jgit-85734356351ec2df4067b2472a37f6d9bcbb7350.zip |
Add command line support for "git mergetool"
see: https://git-scm.com/docs/git-mergetool
see: https://git-scm.com/docs/git-config
* add command line support for "git mergetool"
* add option handling for "--tool-help", "--tool=<mytool>",
"--[no-]prompt", "--[no-]gui"
* handle prompt
* add MergeTools
* add pre-defined mergetools
* print merge actions --> no execute, will be done later
Bug: 356832
Change-Id: I6e505ffc3d03f75ecf4bba452a25d25dfcf5793f
Signed-off-by: Andre Bossert <andre.bossert@siemens.com>
Diffstat (limited to 'org.eclipse.jgit.pgm.test/tst/org/eclipse')
3 files changed, 287 insertions, 91 deletions
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java index e2ff189276..017a5d994f 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others. + * Copyright (C) 2021-2022, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -14,68 +14,30 @@ import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.eclipse.jgit.api.Git; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.internal.diffmergetool.CommandLineDiffTool; -import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.StoredConfig; -import org.eclipse.jgit.pgm.opt.CmdLineParser; -import org.eclipse.jgit.pgm.opt.SubcommandHandler; import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.treewalk.FileTreeIterator; -import org.eclipse.jgit.treewalk.TreeWalk; import org.junit.Before; import org.junit.Test; -import org.kohsuke.args4j.Argument; /** * Testing the {@code difftool} command. */ -public class DiffToolTest extends CLIRepositoryTestCase { - public static class GitCliJGitWrapperParser { - @Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class) - TextBuiltin subcommand; +public class DiffToolTest extends ExternalToolTestCase { - @Argument(index = 1, metaVar = "metaVar_arg") - List<String> arguments = new ArrayList<>(); - } - - private String[] runAndCaptureUsingInitRaw(String... args) - throws Exception { - CLIGitCommand.Result result = new CLIGitCommand.Result(); - - GitCliJGitWrapperParser bean = new GitCliJGitWrapperParser(); - CmdLineParser clp = new CmdLineParser(bean); - clp.parseArgument(args); - - TextBuiltin cmd = bean.subcommand; - cmd.initRaw(db, null, null, result.out, result.err); - cmd.execute(bean.arguments.toArray(new String[bean.arguments.size()])); - if (cmd.getOutputWriter() != null) { - cmd.getOutputWriter().flush(); - } - if (cmd.getErrorWriter() != null) { - cmd.getErrorWriter().flush(); - } - return result.outLines().toArray(new String[0]); - } - - private static final String TOOL_NAME = "some_tool"; - private Git git; + private static final String DIFF_TOOL = CONFIG_DIFFTOOL_SECTION; @Override @Before public void setUp() throws Exception { super.setUp(); - git = new Git(db); - git.commit().setMessage("initial commit").call(); configureEchoTool(TOOL_NAME); } @@ -83,7 +45,7 @@ public class DiffToolTest extends CLIRepositoryTestCase { public void testNotDefinedTool() throws Exception { createUnstagedChanges(); - runAndCaptureUsingInitRaw("difftool", "--tool", "undefined"); + runAndCaptureUsingInitRaw(DIFF_TOOL, "--tool", "undefined"); fail("Expected exception when trying to run undefined tool"); } @@ -91,7 +53,7 @@ public class DiffToolTest extends CLIRepositoryTestCase { public void testTool() throws Exception { RevCommit commit = createUnstagedChanges(); List<DiffEntry> changes = getRepositoryChanges(commit); - String[] expectedOutput = getExpectedDiffToolOutput(changes); + String[] expectedOutput = getExpectedToolOutput(changes); String[] options = { "--tool", @@ -101,7 +63,7 @@ public class DiffToolTest extends CLIRepositoryTestCase { for (String option : options) { assertArrayOfLinesEquals("Incorrect output for option: " + option, expectedOutput, - runAndCaptureUsingInitRaw("difftool", option, + runAndCaptureUsingInitRaw(DIFF_TOOL, option, TOOL_NAME)); } } @@ -110,13 +72,13 @@ public class DiffToolTest extends CLIRepositoryTestCase { public void testToolTrustExitCode() throws Exception { RevCommit commit = createUnstagedChanges(); List<DiffEntry> changes = getRepositoryChanges(commit); - String[] expectedOutput = getExpectedDiffToolOutput(changes); + String[] expectedOutput = getExpectedToolOutput(changes); String[] options = { "--tool", "-t", }; for (String option : options) { assertArrayOfLinesEquals("Incorrect output for option: " + option, - expectedOutput, runAndCaptureUsingInitRaw("difftool", + expectedOutput, runAndCaptureUsingInitRaw(DIFF_TOOL, "--trust-exit-code", option, TOOL_NAME)); } } @@ -125,13 +87,13 @@ public class DiffToolTest extends CLIRepositoryTestCase { public void testToolNoGuiNoPromptNoTrustExitcode() throws Exception { RevCommit commit = createUnstagedChanges(); List<DiffEntry> changes = getRepositoryChanges(commit); - String[] expectedOutput = getExpectedDiffToolOutput(changes); + String[] expectedOutput = getExpectedToolOutput(changes); String[] options = { "--tool", "-t", }; for (String option : options) { assertArrayOfLinesEquals("Incorrect output for option: " + option, - expectedOutput, runAndCaptureUsingInitRaw("difftool", + expectedOutput, runAndCaptureUsingInitRaw(DIFF_TOOL, "--no-gui", "--no-prompt", "--no-trust-exit-code", option, TOOL_NAME)); } @@ -141,13 +103,13 @@ public class DiffToolTest extends CLIRepositoryTestCase { public void testToolCached() throws Exception { RevCommit commit = createStagedChanges(); List<DiffEntry> changes = getRepositoryChanges(commit); - String[] expectedOutput = getExpectedDiffToolOutput(changes); + String[] expectedOutput = getExpectedToolOutput(changes); String[] options = { "--cached", "--staged", }; for (String option : options) { assertArrayOfLinesEquals("Incorrect output for option: " + option, - expectedOutput, runAndCaptureUsingInitRaw("difftool", + expectedOutput, runAndCaptureUsingInitRaw(DIFF_TOOL, option, "--tool", TOOL_NAME)); } } @@ -174,7 +136,8 @@ public class DiffToolTest extends CLIRepositoryTestCase { String option = "--tool-help"; assertArrayOfLinesEquals("Incorrect output for option: " + option, - expectedOutput.toArray(new String[0]), runAndCaptureUsingInitRaw("difftool", option)); + expectedOutput.toArray(new String[0]), + runAndCaptureUsingInitRaw(DIFF_TOOL, option)); } private void configureEchoTool(String toolName) { @@ -196,33 +159,7 @@ public class DiffToolTest extends CLIRepositoryTestCase { String.valueOf(false)); } - private RevCommit createUnstagedChanges() throws Exception { - writeTrashFile("a", "Hello world a"); - writeTrashFile("b", "Hello world b"); - git.add().addFilepattern(".").call(); - RevCommit commit = git.commit().setMessage("files a & b").call(); - writeTrashFile("a", "New Hello world a"); - writeTrashFile("b", "New Hello world b"); - return commit; - } - - private RevCommit createStagedChanges() throws Exception { - RevCommit commit = createUnstagedChanges(); - git.add().addFilepattern(".").call(); - return commit; - } - - private List<DiffEntry> getRepositoryChanges(RevCommit commit) - throws Exception { - TreeWalk tw = new TreeWalk(db); - tw.addTree(commit.getTree()); - FileTreeIterator modifiedTree = new FileTreeIterator(db); - tw.addTree(modifiedTree); - List<DiffEntry> changes = DiffEntry.scan(tw); - return changes; - } - - private String[] getExpectedDiffToolOutput(List<DiffEntry> changes) { + private String[] getExpectedToolOutput(List<DiffEntry> changes) { String[] expectedToolOutput = new String[changes.size()]; for (int i = 0; i < changes.size(); ++i) { DiffEntry change = changes.get(i); @@ -232,17 +169,4 @@ public class DiffToolTest extends CLIRepositoryTestCase { } return expectedToolOutput; } - - private static void assertArrayOfLinesEquals(String failMessage, - String[] expected, String[] actual) { - assertEquals(failMessage, toString(expected), toString(actual)); - } - - private static String getEchoCommand() { - /* - * use 'MERGED' placeholder, as both 'LOCAL' and 'REMOTE' will be - * replaced with full paths to a temporary file during some of the tests - */ - return "(echo \"$MERGED\")"; - } } diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ExternalToolTestCase.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ExternalToolTestCase.java new file mode 100644 index 0000000000..e10b13efb1 --- /dev/null +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ExternalToolTestCase.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2022, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.pgm; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.api.CherryPickResult; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.lib.CLIRepositoryTestCase; +import org.eclipse.jgit.pgm.opt.CmdLineParser; +import org.eclipse.jgit.pgm.opt.SubcommandHandler; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.treewalk.FileTreeIterator; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.junit.Before; +import org.kohsuke.args4j.Argument; + +/** + * Base test case for the {@code difftool} and {@code mergetool} commands. + */ +public abstract class ExternalToolTestCase extends CLIRepositoryTestCase { + + public static class GitCliJGitWrapperParser { + @Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class) + TextBuiltin subcommand; + + @Argument(index = 1, metaVar = "metaVar_arg") + List<String> arguments = new ArrayList<>(); + } + + protected static final String TOOL_NAME = "some_tool"; + + private static final String TEST_BRANCH_NAME = "test_branch"; + + private Git git; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + git = new Git(db); + git.commit().setMessage("initial commit").call(); + git.branchCreate().setName(TEST_BRANCH_NAME).call(); + } + + protected String[] runAndCaptureUsingInitRaw(String... args) + throws Exception { + CLIGitCommand.Result result = new CLIGitCommand.Result(); + + GitCliJGitWrapperParser bean = new GitCliJGitWrapperParser(); + CmdLineParser clp = new CmdLineParser(bean); + clp.parseArgument(args); + + TextBuiltin cmd = bean.subcommand; + cmd.initRaw(db, null, null, result.out, result.err); + cmd.execute(bean.arguments.toArray(new String[bean.arguments.size()])); + if (cmd.getOutputWriter() != null) { + cmd.getOutputWriter().flush(); + } + if (cmd.getErrorWriter() != null) { + cmd.getErrorWriter().flush(); + } + return result.outLines().toArray(new String[0]); + } + + protected CherryPickResult createMergeConflict() throws Exception { + writeTrashFile("a", "Hello world a"); + writeTrashFile("b", "Hello world b"); + git.add().addFilepattern(".").call(); + git.commit().setMessage("files a & b added").call(); + writeTrashFile("a", "Hello world a 1"); + writeTrashFile("b", "Hello world b 1"); + git.add().addFilepattern(".").call(); + RevCommit commit1 = git.commit().setMessage("files a & b commit 1") + .call(); + git.branchCreate().setName("branch_1").call(); + git.checkout().setName(TEST_BRANCH_NAME).call(); + writeTrashFile("a", "Hello world a 2"); + writeTrashFile("b", "Hello world b 2"); + git.add().addFilepattern(".").call(); + git.commit().setMessage("files a & b commit 2").call(); + git.branchCreate().setName("branch_2").call(); + CherryPickResult result = git.cherryPick().include(commit1).call(); + return result; + } + + protected RevCommit createUnstagedChanges() throws Exception { + writeTrashFile("a", "Hello world a"); + writeTrashFile("b", "Hello world b"); + git.add().addFilepattern(".").call(); + RevCommit commit = git.commit().setMessage("files a & b").call(); + writeTrashFile("a", "New Hello world a"); + writeTrashFile("b", "New Hello world b"); + return commit; + } + + protected RevCommit createStagedChanges() throws Exception { + RevCommit commit = createUnstagedChanges(); + git.add().addFilepattern(".").call(); + return commit; + } + + protected List<DiffEntry> getRepositoryChanges(RevCommit commit) + throws Exception { + TreeWalk tw = new TreeWalk(db); + tw.addTree(commit.getTree()); + FileTreeIterator modifiedTree = new FileTreeIterator(db); + tw.addTree(modifiedTree); + List<DiffEntry> changes = DiffEntry.scan(tw); + return changes; + } + + protected static void assertArrayOfLinesEquals(String failMessage, + String[] expected, String[] actual) { + assertEquals(failMessage, toString(expected), toString(actual)); + } + + protected static String getEchoCommand() { + /* + * use 'MERGED' placeholder, as both 'LOCAL' and 'REMOTE' will be + * replaced with full paths to a temporary file during some of the tests + */ + return "(echo \"$MERGED\")"; + } +} diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java new file mode 100644 index 0000000000..32cd60415e --- /dev/null +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/MergeToolTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2022, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.pgm; + +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGETOOL_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jgit.internal.diffmergetool.CommandLineMergeTool; +import org.eclipse.jgit.lib.StoredConfig; +import org.junit.Before; +import org.junit.Test; + +/** + * Testing the {@code mergetool} command. + */ +public class MergeToolTest extends ExternalToolTestCase { + + private static final String MERGE_TOOL = CONFIG_MERGETOOL_SECTION; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + configureEchoTool(TOOL_NAME); + } + + @Test + public void testTool() throws Exception { + createMergeConflict(); + String[] expectedOutput = getExpectedToolOutput(); + + String[] options = { + "--tool", + "-t", + }; + + for (String option : options) { + assertArrayOfLinesEquals("Incorrect output for option: " + option, + expectedOutput, + runAndCaptureUsingInitRaw(MERGE_TOOL, option, + TOOL_NAME)); + } + } + + @Test + public void testToolNoGuiNoPrompt() throws Exception { + createMergeConflict(); + String[] expectedOutput = getExpectedToolOutput(); + + String[] options = { "--tool", "-t", }; + + for (String option : options) { + assertArrayOfLinesEquals("Incorrect output for option: " + option, + expectedOutput, runAndCaptureUsingInitRaw(MERGE_TOOL, + "--no-gui", "--no-prompt", option, TOOL_NAME)); + } + } + + @Test + public void testToolHelp() throws Exception { + CommandLineMergeTool[] defaultTools = CommandLineMergeTool.values(); + List<String> expectedOutput = new ArrayList<>(); + expectedOutput.add( + "'git mergetool --tool=<tool>' may be set to one of the following:"); + for (CommandLineMergeTool defaultTool : defaultTools) { + String toolName = defaultTool.name(); + expectedOutput.add(toolName); + } + String customToolHelpLine = TOOL_NAME + "." + CONFIG_KEY_CMD + " " + + getEchoCommand(); + expectedOutput.add("user-defined:"); + expectedOutput.add(customToolHelpLine); + String[] userDefinedToolsHelp = { + "The following tools are valid, but not currently available:", + "Some of the tools listed above only work in a windowed", + "environment. If run in a terminal-only session, they will fail.", + }; + expectedOutput.addAll(Arrays.asList(userDefinedToolsHelp)); + + String option = "--tool-help"; + assertArrayOfLinesEquals("Incorrect output for option: " + option, + expectedOutput.toArray(new String[0]), + runAndCaptureUsingInitRaw(MERGE_TOOL, option)); + } + + private void configureEchoTool(String toolName) { + StoredConfig config = db.getConfig(); + // the default merge tool is configured without a subsection + String subsection = null; + config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_TOOL, + toolName); + + String command = getEchoCommand(); + + config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD, + command); + /* + * prevent prompts as we are running in tests and there is no user to + * interact with on the command line + */ + config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_PROMPT, + String.valueOf(false)); + } + + private String[] getExpectedToolOutput() { + String[] mergeConflictFilenames = { "a", "b", }; + List<String> expectedOutput = new ArrayList<>(); + expectedOutput.add("Merging:"); + for (String mergeConflictFilename : mergeConflictFilenames) { + expectedOutput.add(mergeConflictFilename); + } + for (String mergeConflictFilename : mergeConflictFilenames) { + expectedOutput.add("Normal merge conflict for '" + + mergeConflictFilename + "':"); + expectedOutput.add("{local}: modified file"); + expectedOutput.add("{remote}: modified file"); + expectedOutput.add("TODO: Launch mergetool '" + TOOL_NAME + + "' for path '" + mergeConflictFilename + "'..."); + } + return expectedOutput.toArray(new String[0]); + } +} |