Skip to content

Commit

Permalink
Add feature to ignore git commits by id
Browse files Browse the repository at this point in the history
  • Loading branch information
philippn authored and mathieucarbou committed Mar 30, 2022
1 parent 93a3c0a commit 6f6a551
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 14 deletions.
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Basically, when you are developing a project either in open source or in a compa
* [@stain](https://github.com/stain)
* [@vromero](https://github.com/vromero)
* [@yoosiba](https://github.com/yoosiba)
* [@philippn](https://github.com/philippn)

Please let me know if your name is missing!

Expand Down
2 changes: 2 additions & 0 deletions license-maven-plugin-git/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Which properties is license-maven-plugin-git adding?

The full git history for a file is required for accurate determination of the first commit (for the creation author name/email, creation year, or existence years). The plugin will warn if it detects a shallow git repository. If you are certain your shallow depth will still permit determination of these values you may suppress the warning by setting the parameter `license.warnIfShallow` to false.

It is possible to filter out specific commits by adding one or more (comma-separated) SHA-1 hashes to the property `license.git.commitsToIgnore`. This property will only affect the computation of the last change year, not of the creation year.

If you are using properties requiring the year of the last commit of a file but not using the "creation" properties requiring the first commit, you can improve performance by limiting the git history for each file using the property `license.git.maxCommitsLookup`. A value of 1 would provide the best performance but could be impacted if the last commit year is earlier than the year of previous commits.

How to use license-maven-plugin-git
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.stream.Collectors;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.DiffConfig;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.FollowFilter;
Expand All @@ -57,6 +62,7 @@ public class GitLookup implements Closeable {
private static final String COPYRIGHT_LAST_YEAR_MAX_COMMITS_LOOKUP_KEY = "license.git.copyrightLastYearMaxCommitsLookup";
public static final String COPYRIGHT_LAST_YEAR_SOURCE_KEY = "license.git.copyrightLastYearSource";
public static final String COPYRIGHT_LAST_YEAR_TIME_ZONE_KEY = "license.git.copyrightLastYearTimeZone";
public static final String COMMITS_TO_IGNORE_KEY = "license.git.commitsToIgnore";

public enum DateSource {
AUTHOR, COMMITER
Expand All @@ -68,6 +74,7 @@ public enum DateSource {
private final Repository repository;
private final TimeZone timeZone;
private final boolean shallow;
private final Set<ObjectId> commitsToIgnore;

/**
* Lazily initializes #gitLookup assuming that all subsequent calls to this method will be related
Expand All @@ -81,7 +88,7 @@ public static GitLookup create(File file, Map<String, String> props) {
GitLookup.DateSource dateSource = GitLookup.DateSource.valueOf(
dateSourceString.toUpperCase(Locale.US));
String checkCommitsCountString = props.get(MAX_COMMITS_LOOKUP_KEY);
// Backwads compatibility
// Backwards compatibility
if (checkCommitsCountString == null) {
checkCommitsCountString = props.get(COPYRIGHT_LAST_YEAR_MAX_COMMITS_LOOKUP_KEY);
}
Expand All @@ -90,6 +97,15 @@ public static GitLookup create(File file, Map<String, String> props) {
checkCommitsCountString = checkCommitsCountString.trim();
checkCommitsCount = Integer.parseInt(checkCommitsCountString);
}
String commitsToIgnoreString = props.get(COMMITS_TO_IGNORE_KEY);
Set<ObjectId> commitsToIgnore = Collections.emptySet();
if (commitsToIgnoreString != null) {
commitsToIgnoreString = commitsToIgnoreString.trim();
commitsToIgnore = Arrays.stream(commitsToIgnoreString.split(","))
.map(String::trim)
.map(ObjectId::fromString)
.collect(Collectors.toSet());
}
final TimeZone timeZone;
String tzString = props.get(COPYRIGHT_LAST_YEAR_TIME_ZONE_KEY);
switch (dateSource) {
Expand All @@ -108,7 +124,7 @@ public static GitLookup create(File file, Map<String, String> props) {
throw new IllegalStateException(
"Unexpected " + GitLookup.DateSource.class.getName() + " " + dateSource);
}
return new GitLookup(file, dateSource, timeZone, checkCommitsCount);
return new GitLookup(file, dateSource, timeZone, checkCommitsCount, commitsToIgnore);
}

/**
Expand All @@ -122,10 +138,11 @@ public static GitLookup create(File file, Map<String, String> props) {
* @param dateSource where to read the commit dates from - committer date or author date
* @param timeZone the time zone if {@code dateSource} is {@link DateSource#COMMITER};
* otherwise must be {@code null}.
* @param checkCommitsCount
* @param checkCommitsCount the number of historical commits, per file, to check
* @param commitsToIgnore the commits to ignore while inspecting the history for {@code anyFile}
* @throws IOException
*/
private GitLookup(File anyFile, DateSource dateSource, TimeZone timeZone, int checkCommitsCount) {
private GitLookup(File anyFile, DateSource dateSource, TimeZone timeZone, int checkCommitsCount, Set<ObjectId> commitsToIgnore) {
try {
this.repository = new FileRepositoryBuilder().findGitDir(anyFile).build();
/* A workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=457961 */
Expand Down Expand Up @@ -155,6 +172,7 @@ private GitLookup(File anyFile, DateSource dateSource, TimeZone timeZone, int ch
"Unexpected " + DateSource.class.getName() + " " + dateSource);
}
this.checkCommitsCount = checkCommitsCount;
this.commitsToIgnore = commitsToIgnore;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Expand All @@ -165,7 +183,7 @@ private GitLookup(File anyFile, DateSource dateSource, TimeZone timeZone, int ch
* year is taken either from the committer date or from the author identity depending on how {@link #dateSource} was
* initialized.
* <p>
* See also the note on time zones in {@link #GitLookup(File, DateSource, TimeZone, int)}.
* See also the note on time zones in {@link #GitLookup(File, DateSource, TimeZone, int, Set)}.
*
* @param file for which the year should be retrieved
* @return year of last modification of the file
Expand All @@ -182,6 +200,9 @@ int getYearOfLastChange(File file) throws GitAPIException, IOException {
int commitYear = 0;
RevWalk walk = getGitRevWalk(repoRelativePath, false);
for (RevCommit commit : walk) {
if (commitsToIgnore.contains(commit.getId())) {
continue;
}
int y = getYearFromCommit(commit);
if (y > commitYear) {
commitYear = y;
Expand Down Expand Up @@ -314,4 +335,4 @@ private String getAuthorEmailFromCommit(RevCommit commit) {
public void close() {
repository.close();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ void reuseProvider() throws GitAPIException, IOException {
@Test
void timezone() throws GitAPIException, IOException {
try {
GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.AUTHOR, "GMT", "10"));
GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.AUTHOR, "GMT", "10", null));
Assertions.fail("RuntimeException expected");
} catch (RuntimeException e) {
if (e.getMessage().contains(
Expand All @@ -170,25 +170,25 @@ void timezone() throws GitAPIException, IOException {

/* null is GMT */
GitLookup nullTzLookup = GitLookup.create(gitRepoRoot.toFile(),
buildProps(DateSource.COMMITER, null, "10"));
buildProps(DateSource.COMMITER, null, "10", null));
assertLastChange(nullTzLookup, "dir1/file3.txt", 2010);

/* explicit GMT */
GitLookup gmtLookup = GitLookup.create(gitRepoRoot.toFile(),
buildProps(DateSource.COMMITER, "GMT", "10"));
buildProps(DateSource.COMMITER, "GMT", "10", null));
assertLastChange(gmtLookup, "dir1/file3.txt", 2010);

/*
* explicit non-GMT zome. Note that the relevant commit's (GMT) time stamp is 2010-12-31T23:30:00 which yealds
* 2011 in the CET (+01:00) time zone
*/
GitLookup cetLookup = GitLookup.create(gitRepoRoot.toFile(),
buildProps(DateSource.COMMITER, "CET", "10"));
buildProps(DateSource.COMMITER, "CET", "10", null));
assertLastChange(cetLookup, "dir1/file3.txt", 2011);

}

private Map<String, String> buildProps(DateSource ds, String tz, String history) {
private Map<String, String> buildProps(DateSource ds, String tz, String history, String commitsToIgnoreCSV) {
Map<String, String> props = new HashMap<>();
if (history != null) {
props.put(GitLookup.MAX_COMMITS_LOOKUP_KEY, history);
Expand All @@ -199,15 +199,40 @@ private Map<String, String> buildProps(DateSource ds, String tz, String history)
if (ds != null) {
props.put(GitLookup.COPYRIGHT_LAST_YEAR_SOURCE_KEY, ds.name());
}
if (commitsToIgnoreCSV != null) {
props.put(GitLookup.COMMITS_TO_IGNORE_KEY, commitsToIgnoreCSV);
}
return props;
}

private GitLookup newAuthorLookup() {
return GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.AUTHOR, null, "10"));
return GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.AUTHOR, null, "10", null));
}

private GitLookup newCommitterLookup() {
return GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.COMMITER, null, "10"));
return GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.COMMITER, null, "10", null));
}

@Test
public void ignoreCommitsInLastChange() throws GitAPIException, IOException {
assertLastChange(newAuthorLookup("95d52919cbe340dc271cf1f5ec68cf36705bd3a3"), "dir1/file1.txt", 2004);
assertLastChange(newCommitterLookup("95d52919cbe340dc271cf1f5ec68cf36705bd3a3"), "dir1/file1.txt", 2004);
}

@Test
public void doNotIgnoreCommitsInCreation() throws GitAPIException, IOException {
assertCreation(newAuthorLookup("53b44baedc5a378f9b665da12f298e1003793219"), "dir1/file1.txt", 2000);
assertCreation(newCommitterLookup("53b44baedc5a378f9b665da12f298e1003793219"), "dir1/file1.txt", 2000);
}

private GitLookup newAuthorLookup(String... commitsToIgnore) throws IOException {
String commitsToIgnoreCSV = String.join(",", commitsToIgnore);
return GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.AUTHOR, null, "10", commitsToIgnoreCSV));
}

private GitLookup newCommitterLookup(String... commitsToIgnore) throws IOException {
String commitsToIgnoreCSV = String.join(",", commitsToIgnore);
return GitLookup.create(gitRepoRoot.toFile(), buildProps(DateSource.COMMITER, null, "10", commitsToIgnoreCSV));
}

private void assertLastChange(GitLookup provider, String relativePath, int expected) throws
Expand All @@ -224,4 +249,4 @@ private void assertCreation(GitLookup provider, String relativePath, int expecte
Assertions.assertEquals(expected, actual);
}

}
}

0 comments on commit 6f6a551

Please sign in to comment.