Browse Source

Merge branch 'stable-5.6'

* stable-5.6:
  Cleanup CommitAndLogCommandTest
  CLI: Add support for excluding paths from Git log command

Change-Id: I2f48e16640ab1b13f0c32779422add3162260c50
Signed-off-by: David Pursehouse <david.pursehouse@gmail.com>
stable-5.7
David Pursehouse 5 years ago
parent
commit
8a633bde8a
  1. 156
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java
  2. 221
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogFilterTest.java
  3. 43
      org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java

156
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitAndLogCommandTest.java

@ -40,6 +40,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -50,14 +51,10 @@ import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoMessageException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@ -76,13 +73,12 @@ import org.junit.Test;
*/
public class CommitAndLogCommandTest extends RepositoryTestCase {
@Test
public void testSomeCommits() throws JGitInternalException, IOException,
GitAPIException {
public void testSomeCommits() throws Exception {
// do 4 commits
try (Git git = new Git(db)) {
git.commit().setMessage("initial commit").call();
git.commit().setMessage("second commit").setCommitter(committer).call();
git.commit().setMessage("second commit").setCommitter(committer)
.call();
git.commit().setMessage("third commit").setAuthor(author).call();
git.commit().setMessage("fourth commit").setAuthor(author)
.setCommitter(committer).call();
@ -90,79 +86,28 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
// check that all commits came in correctly
PersonIdent defaultCommitter = new PersonIdent(db);
PersonIdent expectedAuthors[] = new PersonIdent[] { defaultCommitter,
committer, author, author };
PersonIdent expectedAuthors[] = new PersonIdent[] {
defaultCommitter, committer, author, author };
PersonIdent expectedCommitters[] = new PersonIdent[] {
defaultCommitter, committer, defaultCommitter, committer };
String expectedMessages[] = new String[] { "initial commit",
"second commit", "third commit", "fourth commit" };
int l = expectedAuthors.length - 1;
for (RevCommit c : commits) {
assertEquals(expectedAuthors[l].getName(), c.getAuthorIdent()
.getName());
assertEquals(expectedCommitters[l].getName(), c.getCommitterIdent()
.getName());
assertEquals(expectedAuthors[l].getName(),
c.getAuthorIdent().getName());
assertEquals(expectedCommitters[l].getName(),
c.getCommitterIdent().getName());
assertEquals(c.getFullMessage(), expectedMessages[l]);
l--;
}
assertEquals(l, -1);
ReflogReader reader = db.getReflogReader(Constants.HEAD);
assertTrue(reader.getLastEntry().getComment().startsWith("commit:"));
assertTrue(
reader.getLastEntry().getComment().startsWith("commit:"));
reader = db.getReflogReader(db.getBranch());
assertTrue(reader.getLastEntry().getComment().startsWith("commit:"));
}
}
@Test
public void testLogWithFilter() throws IOException, JGitInternalException,
GitAPIException {
try (Git git = new Git(db)) {
// create first file
File file = new File(db.getWorkTree(), "a.txt");
FileUtils.createNewFile(file);
try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
writer.print("content1");
}
// First commit - a.txt file
git.add().addFilepattern("a.txt").call();
git.commit().setMessage("commit1").setCommitter(committer).call();
// create second file
file = new File(db.getWorkTree(), "b.txt");
FileUtils.createNewFile(file);
try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
writer.print("content2");
}
// Second commit - b.txt file
git.add().addFilepattern("b.txt").call();
git.commit().setMessage("commit2").setCommitter(committer).call();
// First log - a.txt filter
int count = 0;
for (RevCommit c : git.log().addPath("a.txt").call()) {
assertEquals("commit1", c.getFullMessage());
count++;
}
assertEquals(1, count);
// Second log - b.txt filter
count = 0;
for (RevCommit c : git.log().addPath("b.txt").call()) {
assertEquals("commit2", c.getFullMessage());
count++;
}
assertEquals(1, count);
// Third log - without filter
count = 0;
for (RevCommit c : git.log().call()) {
assertEquals(committer, c.getCommitterIdent());
count++;
}
assertEquals(2, count);
assertTrue(
reader.getLastEntry().getComment().startsWith("commit:"));
}
}
@ -204,19 +149,20 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
}
@Test
public void testMergeEmptyBranches() throws IOException,
JGitInternalException, GitAPIException {
public void testMergeEmptyBranches() throws Exception {
try (Git git = new Git(db)) {
git.commit().setMessage("initial commit").call();
RefUpdate r = db.updateRef("refs/heads/side");
r.setNewObjectId(db.resolve(Constants.HEAD));
assertEquals(r.forceUpdate(), RefUpdate.Result.NEW);
RevCommit second = git.commit().setMessage("second commit").setCommitter(committer).call();
RevCommit second = git.commit().setMessage("second commit")
.setCommitter(committer).call();
db.updateRef(Constants.HEAD).link("refs/heads/side");
RevCommit firstSide = git.commit().setMessage("first side commit").setAuthor(author).call();
RevCommit firstSide = git.commit().setMessage("first side commit")
.setAuthor(author).call();
write(new File(db.getDirectory(), Constants.MERGE_HEAD), ObjectId
.toString(db.resolve("refs/heads/master")));
write(new File(db.getDirectory(), Constants.MERGE_HEAD),
ObjectId.toString(db.resolve("refs/heads/master")));
write(new File(db.getDirectory(), Constants.MERGE_MSG), "merging");
RevCommit commit = git.commit().call();
@ -228,8 +174,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
}
@Test
public void testAddUnstagedChanges() throws IOException,
JGitInternalException, GitAPIException {
public void testAddUnstagedChanges() throws Exception {
File file = new File(db.getWorkTree(), "a.txt");
FileUtils.createNewFile(file);
try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
@ -260,7 +205,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
}
@Test
public void testModeChange() throws IOException, GitAPIException {
public void testModeChange() throws Exception {
assumeFalse(System.getProperty("os.name").startsWith("Windows"));// SKIP
try (Git git = new Git(db)) {
// create file
@ -278,7 +223,8 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
FS fs = db.getFS();
fs.setExecute(file, true);
git.add().addFilepattern("a.txt").call();
git.commit().setMessage("mode change").setCommitter(committer).call();
git.commit().setMessage("mode change").setCommitter(committer)
.call();
// pure mode change should be committable with -o option
fs.setExecute(file, false);
@ -289,34 +235,32 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
}
@Test
public void testCommitRange() throws GitAPIException,
JGitInternalException, MissingObjectException,
IncorrectObjectTypeException {
public void testCommitRange() throws Exception {
// do 4 commits and set the range to the second and fourth one
try (Git git = new Git(db)) {
git.commit().setMessage("first commit").call();
RevCommit second = git.commit().setMessage("second commit")
.setCommitter(committer).call();
git.commit().setMessage("third commit").setAuthor(author).call();
RevCommit last = git.commit().setMessage("fourth commit").setAuthor(
author)
.setCommitter(committer).call();
Iterable<RevCommit> commits = git.log().addRange(second.getId(),
last.getId()).call();
RevCommit last = git.commit().setMessage("fourth commit")
.setAuthor(author).setCommitter(committer).call();
Iterable<RevCommit> commits = git.log()
.addRange(second.getId(), last.getId()).call();
// check that we have the third and fourth commit
PersonIdent defaultCommitter = new PersonIdent(db);
PersonIdent expectedAuthors[] = new PersonIdent[] { author, author };
PersonIdent expectedAuthors[] = new PersonIdent[] { author,
author };
PersonIdent expectedCommitters[] = new PersonIdent[] {
defaultCommitter, committer };
String expectedMessages[] = new String[] { "third commit",
"fourth commit" };
int l = expectedAuthors.length - 1;
for (RevCommit c : commits) {
assertEquals(expectedAuthors[l].getName(), c.getAuthorIdent()
.getName());
assertEquals(expectedCommitters[l].getName(), c.getCommitterIdent()
.getName());
assertEquals(expectedAuthors[l].getName(),
c.getAuthorIdent().getName());
assertEquals(expectedCommitters[l].getName(),
c.getCommitterIdent().getName());
assertEquals(c.getFullMessage(), expectedMessages[l]);
l--;
}
@ -325,8 +269,7 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
}
@Test
public void testCommitAmend() throws JGitInternalException, IOException,
GitAPIException {
public void testCommitAmend() throws Exception {
try (Git git = new Git(db)) {
git.commit().setMessage("first comit").call(); // typo
git.commit().setAmend(true).setMessage("first commit").call();
@ -348,15 +291,14 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
}
@Test
public void testInsertChangeId() throws JGitInternalException,
GitAPIException {
public void testInsertChangeId() throws Exception {
try (Git git = new Git(db)) {
String messageHeader = "Some header line\n\nSome detail explanation\n";
String changeIdTemplate = "\nChange-Id: I"
+ ObjectId.zeroId().getName() + "\n";
String messageFooter = "Some foooter lines\nAnother footer line\n";
RevCommit commit = git.commit().setMessage(
messageHeader + messageFooter)
RevCommit commit = git.commit()
.setMessage(messageHeader + messageFooter)
.setInsertChangeId(true).call();
// we should find a real change id (at the end of the file)
byte[] chars = commit.getFullMessage().getBytes(UTF_8);
@ -364,10 +306,11 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
String lastLine = RawParseUtils.decode(chars, lastLineBegin + 1,
chars.length);
assertTrue(lastLine.contains("Change-Id:"));
assertFalse(lastLine.contains(
"Change-Id: I" + ObjectId.zeroId().getName()));
assertFalse(lastLine
.contains("Change-Id: I" + ObjectId.zeroId().getName()));
commit = git.commit().setMessage(
commit = git.commit()
.setMessage(
messageHeader + changeIdTemplate + messageFooter)
.setInsertChangeId(true).call();
// we should find a real change id (in the line as dictated by the
@ -383,10 +326,11 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
String line = RawParseUtils.decode(chars, lineStart, lineEnd);
assertTrue(line.contains("Change-Id:"));
assertFalse(line.contains(
"Change-Id: I" + ObjectId.zeroId().getName()));
assertFalse(line
.contains("Change-Id: I" + ObjectId.zeroId().getName()));
commit = git.commit().setMessage(
commit = git.commit()
.setMessage(
messageHeader + changeIdTemplate + messageFooter)
.setInsertChangeId(false).call();
// we should find the untouched template
@ -400,8 +344,8 @@ public class CommitAndLogCommandTest extends RepositoryTestCase {
line = RawParseUtils.decode(chars, lineStart, lineEnd);
assertTrue(commit.getFullMessage().contains(
"Change-Id: I" + ObjectId.zeroId().getName()));
assertTrue(commit.getFullMessage()
.contains("Change-Id: I" + ObjectId.zeroId().getName()));
}
}
}

221
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LogFilterTest.java

@ -0,0 +1,221 @@
/*
* Copyright (C) 2019, John Tipper <John_Tipper@hotmail.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.PrintWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.util.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Testing the log command with include and exclude filters
*/
public class LogFilterTest extends RepositoryTestCase {
private Git git;
@Before
public void setup() throws Exception {
super.setUp();
git = new Git(db);
// create first file
File file = new File(db.getWorkTree(), "a.txt");
FileUtils.createNewFile(file);
try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
writer.print("content1");
}
// First commit - a.txt file
git.add().addFilepattern("a.txt").call();
git.commit().setMessage("commit1").setCommitter(committer).call();
// create second file
file = new File(db.getWorkTree(), "b.txt");
FileUtils.createNewFile(file);
try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
writer.print("content2");
}
// Second commit - b.txt file
git.add().addFilepattern("b.txt").call();
git.commit().setMessage("commit2").setCommitter(committer).call();
// create third file
Path includeSubdir = Paths.get(db.getWorkTree().toString(),
"subdir-include");
includeSubdir.toFile().mkdirs();
file = Paths.get(includeSubdir.toString(), "c.txt").toFile();
FileUtils.createNewFile(file);
try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
writer.print("content3");
}
// Third commit - c.txt file
git.add().addFilepattern("subdir-include").call();
git.commit().setMessage("commit3").setCommitter(committer).call();
// create fourth file
Path excludeSubdir = Paths.get(db.getWorkTree().toString(),
"subdir-exclude");
excludeSubdir.toFile().mkdirs();
file = Paths.get(excludeSubdir.toString(), "d.txt").toFile();
FileUtils.createNewFile(file);
try (PrintWriter writer = new PrintWriter(file, UTF_8.name())) {
writer.print("content4");
}
// Fourth commit - d.txt file
git.add().addFilepattern("subdir-exclude").call();
git.commit().setMessage("commit4").setCommitter(committer).call();
}
@After
@Override
public void tearDown() throws Exception {
git.close();
super.tearDown();
}
@Test
public void testLogWithFilterCanDistinguishFilesByPath() throws Exception {
int count = 0;
for (RevCommit c : git.log().addPath("a.txt").call()) {
assertEquals("commit1", c.getFullMessage());
count++;
}
assertEquals(1, count);
count = 0;
for (RevCommit c : git.log().addPath("b.txt").call()) {
assertEquals("commit2", c.getFullMessage());
count++;
}
assertEquals(1, count);
}
@Test
public void testLogWithFilterCanIncludeFilesInDirectory() throws Exception {
int count = 0;
for (RevCommit c : git.log().addPath("subdir-include").call()) {
assertEquals("commit3", c.getFullMessage());
count++;
}
assertEquals(1, count);
}
@Test
public void testLogWithFilterCanExcludeFilesInDirectory() throws Exception {
int count = 0;
Iterator it = git.log().excludePath("subdir-exclude").call().iterator();
while (it.hasNext()) {
it.next();
count++;
}
// of all the commits, we expect to filter out only d.txt
assertEquals(3, count);
}
@Test
public void testLogWithoutFilter() throws Exception {
int count = 0;
for (RevCommit c : git.log().call()) {
assertEquals(committer, c.getCommitterIdent());
count++;
}
assertEquals(4, count);
}
@Test
public void testLogWithFilterCanExcludeAndIncludeFilesInDifferentDirectories()
throws Exception {
int count = 0;
Iterator it = git.log().addPath("subdir-include")
.excludePath("subdir-exclude").call().iterator();
while (it.hasNext()) {
it.next();
count++;
}
// we expect to include c.txt
assertEquals(1, count);
}
@Test
public void testLogWithFilterExcludeAndIncludeSameFileIncludesNothing()
throws Exception {
int count = 0;
Iterator it = git.log().addPath("subdir-exclude")
.excludePath("subdir-exclude").call().iterator();
while (it.hasNext()) {
it.next();
count++;
}
// we expect the exclude to trump everything
assertEquals(0, count);
}
@Test
public void testLogWithFilterCanExcludeFileAndDirectory() throws Exception {
int count = 0;
Iterator it = git.log().excludePath("b.txt")
.excludePath("subdir-exclude").call().iterator();
while (it.hasNext()) {
it.next();
count++;
}
// we expect a.txt and c.txt
assertEquals(2, count);
}
}

43
org.eclipse.jgit/src/org/eclipse/jgit/api/LogCommand.java

@ -64,10 +64,7 @@ import org.eclipse.jgit.revwalk.filter.AndRevFilter;
import org.eclipse.jgit.revwalk.filter.MaxCountRevFilter;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.revwalk.filter.SkipRevFilter;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.treewalk.filter.*;
/**
* A class used to execute a {@code Log} command. It has setters for all
@ -105,6 +102,7 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> {
private RevFilter revFilter;
private final List<PathFilter> pathFilters = new ArrayList<>();
private final List<TreeFilter> excludeTreeFilters = new ArrayList<>();
private int maxCount = -1;
@ -133,9 +131,22 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> {
@Override
public Iterable<RevCommit> call() throws GitAPIException, NoHeadException {
checkCallable();
if (!pathFilters.isEmpty())
walk.setTreeFilter(AndTreeFilter.create(
PathFilterGroup.create(pathFilters), TreeFilter.ANY_DIFF));
List<TreeFilter> filters = new ArrayList<>();
if (!pathFilters.isEmpty()) {
filters.add(AndTreeFilter.create(PathFilterGroup.create(pathFilters), TreeFilter.ANY_DIFF));
}
if (!excludeTreeFilters.isEmpty()) {
for (TreeFilter f : excludeTreeFilters) {
filters.add(AndTreeFilter.create(f, TreeFilter.ANY_DIFF));
}
}
if (!filters.isEmpty()) {
if (filters.size() == 1) {
filters.add(TreeFilter.ANY_DIFF);
}
walk.setTreeFilter(AndTreeFilter.create(filters));
}
if (skip > -1 && maxCount > -1)
walk.setRevFilter(AndRevFilter.create(SkipRevFilter.create(skip),
MaxCountRevFilter.create(maxCount)));
@ -309,6 +320,24 @@ public class LogCommand extends GitCommand<Iterable<RevCommit>> {
return this;
}
/**
* Show all commits that are not within any of the specified paths. The path
* must either name a file or a directory exactly and use <code>/</code>
* (slash) as separator. Note that regular expressions or wildcards are not
* yet supported. If a path is both added and excluded from the search, then
* the exclusion wins.
*
* @param path
* a repository-relative path (with <code>/</code> as separator)
* @return {@code this}
* @since 5.6
*/
public LogCommand excludePath(String path) {
checkCallable();
excludeTreeFilters.add(PathFilter.create(path).negate());
return this;
}
/**
* Skip the number of commits before starting to show the commit output.
*

Loading…
Cancel
Save