diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..d3e2ce1f --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,27 @@ + + + + +### Expected Behavior + + + +### Current Behavior + + + + + + +### Steps to Reproduce (for bugs only) + + + + +### Environment (for bugs only) + + + + + + diff --git a/.travis.yml b/.travis.yml index 78b6f196..aeabf3b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,6 +27,8 @@ matrix: env: CUSTOM_MVN_VERION="3.3.9" - jdk: oraclejdk9 env: CUSTOM_MVN_VERION="3.5.0" + - jdk: oraclejdk9 + env: CUSTOM_MVN_VERION="3.5.2" - stage: checkstyle jdk: oraclejdk9 script: mvn clean verify -Pcheckstyle -Dcheckstyle.version=8.2 -Dmaven.test.skip=true -B diff --git a/README.md b/README.md index 72c758d9..3e1f81e5 100644 --- a/README.md +++ b/README.md @@ -472,6 +472,7 @@ It's really simple to setup this plugin; below is a sample pom that you may base --> false + + true + + + + HEAD @@ -882,6 +899,7 @@ Optional parameters: *Note*: Depending on your plugin configuration you obviously can choose the 'prefix' of your properties by setting it accordingly in the plugin's configuration. As a result this is therefore only an illustration what the switch means when the 'prefix' is set to it's default value. *Note*: If you set the value to something that's not equal to 'flat' or 'full' (ignoring the case) the plugin will output a warning and will fallback to the default 'flat' mode. +* **evaluateOnCommit** - `(default: HEAD)` *(available since v2.2.4)* Allow to tell the plugin what commit should be used as reference to generate the properties from. By default this property is simply set to `HEAD` which should reference to the latest commit in your repository. In general this property can be set to something generic like `HEAD^1` or point to a branch or tag-name. To support any kind or use-case this configuration can also be set to an entire commit-hash or it's abbreviated version. Please note that for security purposes not all references might be allowed as configuration. If you have a specific use-case that is currently not white listed feel free to file an issue. **gitDescribe**: Worth pointing out is, that git-commit-id tries to be 1-to-1 compatible with git's plain output, even though the describe functionality has been reimplemented manually using JGit (you don't have to have a git executable to use the plugin). So if you're familiar with [git-describe](https://github.com/ktoso/maven-git-commit-id-plugin#git-describe---short-intro-to-an-awesome-command), you probably can skip this section, as it just explains the same options that git provides. diff --git a/pom.xml b/pom.xml index 0ff881e6..5491b1fa 100644 --- a/pom.xml +++ b/pom.xml @@ -163,6 +163,13 @@ test + + com.github.stefanbirkner + system-rules + 1.16.0 + test + + org.slf4j diff --git a/src/main/java/pl/project13/jgit/DescribeCommand.java b/src/main/java/pl/project13/jgit/DescribeCommand.java index 4583dae6..effb5638 100644 --- a/src/main/java/pl/project13/jgit/DescribeCommand.java +++ b/src/main/java/pl/project13/jgit/DescribeCommand.java @@ -27,16 +27,12 @@ import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevWalk; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import pl.project13.jgit.dummy.DatedRevTag; import pl.project13.maven.git.GitDescribeConfig; import pl.project13.maven.git.log.LoggerBridge; import pl.project13.maven.git.util.Pair; - -import java.io.IOException; import java.util.*; /** @@ -46,6 +42,7 @@ public class DescribeCommand extends GitCommand { private LoggerBridge log; private JGitCommon jGitCommon; + private String evaluateOnCommit; // TODO not yet implemented options: // private boolean containsFlag = false; @@ -86,8 +83,8 @@ public class DescribeCommand extends GitCommand { * @param log logger bridge to direct logs to */ @NotNull - public static DescribeCommand on(Repository repo, LoggerBridge log) { - return new DescribeCommand(repo, log); + public static DescribeCommand on(String evaluateOnCommit, Repository repo, LoggerBridge log) { + return new DescribeCommand(evaluateOnCommit, repo, log); } /** @@ -95,8 +92,9 @@ public static DescribeCommand on(Repository repo, LoggerBridge log) { * * @param repo the {@link org.eclipse.jgit.lib.Repository} this command should interact with */ - private DescribeCommand(Repository repo, @NotNull LoggerBridge log) { + private DescribeCommand(@NotNull String evaluateOnCommit, @NotNull Repository repo, @NotNull LoggerBridge log) { super(repo); + this.evaluateOnCommit = evaluateOnCommit; this.jGitCommon = new JGitCommon(log); this.log = log; } @@ -259,14 +257,14 @@ public DescribeResult call() throws GitAPIException { Map> tagObjectIdToName = jGitCommon.findTagObjectIds(repo, tagsFlag, matchPattern); // get current commit - RevCommit headCommit = findHeadObjectId(repo); - ObjectId headCommitId = headCommit.getId(); + RevCommit evalCommit = findEvalCommitObjectId(evaluateOnCommit, repo); + ObjectId evalCommitId = evalCommit.getId(); // check if dirty boolean dirty = findDirtyState(repo); - if (hasTags(headCommit, tagObjectIdToName) && !forceLongFormat) { - String tagName = tagObjectIdToName.get(headCommit).iterator().next(); + if (hasTags(evalCommit, tagObjectIdToName) && !forceLongFormat) { + String tagName = tagObjectIdToName.get(evalCommit).iterator().next(); log.info("The commit we're on is a Tag ([{}]) and forceLongFormat == false, returning.", tagName); return new DescribeResult(tagName, dirty, dirtyOption); @@ -275,7 +273,7 @@ public DescribeResult call() throws GitAPIException { // get commits, up until the nearest tag List commits; try { - commits = jGitCommon.findCommitsUntilSomeTag(repo, headCommit, tagObjectIdToName); + commits = jGitCommon.findCommitsUntilSomeTag(repo, evalCommit, tagObjectIdToName); } catch (Exception e) { if (alwaysFlag) { // Show uniquely abbreviated commit object as fallback @@ -287,18 +285,18 @@ public DescribeResult call() throws GitAPIException { // if there is no tags or any tag is not on that branch then return generic describe if (foundZeroTags(tagObjectIdToName) || commits.isEmpty()) { - return new DescribeResult(objectReader, headCommitId, dirty, dirtyOption) + return new DescribeResult(objectReader, evalCommitId, dirty, dirtyOption) .withCommitIdAbbrev(abbrev); } // check how far away from a tag we are - int distance = jGitCommon.distanceBetween(repo, headCommit, commits.get(0)); + int distance = jGitCommon.distanceBetween(repo, evalCommit, commits.get(0)); String tagName = tagObjectIdToName.get(commits.get(0)).iterator().next(); Pair howFarFromWhichTag = Pair.of(distance, tagName); // if it's null, no tag's were found etc, so let's return just the commit-id - return createDescribeResult(objectReader, headCommitId, dirty, howFarFromWhichTag); + return createDescribeResult(objectReader, evalCommitId, dirty, howFarFromWhichTag); } /** @@ -344,8 +342,8 @@ static boolean hasTags(ObjectId headCommit, @NotNull Map> return tagObjectIdToName.containsKey(headCommit); } - RevCommit findHeadObjectId(@NotNull Repository repo) throws RuntimeException { - return jGitCommon.findHeadObjectId(repo); + RevCommit findEvalCommitObjectId(@NotNull String evaluateOnCommit, @NotNull Repository repo) throws RuntimeException { + return jGitCommon.findEvalCommitObjectId(evaluateOnCommit, repo); } private String createMatchPattern() { diff --git a/src/main/java/pl/project13/jgit/JGitCommon.java b/src/main/java/pl/project13/jgit/JGitCommon.java index fcbd9550..62e91768 100644 --- a/src/main/java/pl/project13/jgit/JGitCommon.java +++ b/src/main/java/pl/project13/jgit/JGitCommon.java @@ -25,7 +25,6 @@ import org.eclipse.jgit.api.Status; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; @@ -53,27 +52,31 @@ public JGitCommon(LoggerBridge log) { this.log = log; } - public Collection getTags(Repository repo, final ObjectId headId) throws GitAPIException { + public Collection getTags(Repository repo, final ObjectId objectId) throws GitAPIException { try (Git git = Git.wrap(repo)) { try (RevWalk walk = new RevWalk(repo)) { - Collection tags = getTags(git, headId, walk); + Collection tags = getTags(git, objectId, walk); walk.dispose(); return tags; } } } - private Collection getTags(final Git git, final ObjectId headId, final RevWalk finalWalk) throws GitAPIException { + private Collection getTags(final Git git, final ObjectId objectId, final RevWalk finalWalk) throws GitAPIException { List tagRefs = git.tagList().call(); Collection tagsForHeadCommit = Collections2.filter(tagRefs, new Predicate() { - @Override public boolean apply(Ref tagRef) { - boolean lightweightTag = tagRef.getObjectId().equals(headId); + @Override + public boolean apply(Ref tagRef) { try { - // TODO make this configurable (most users shouldn't really care too much what kind of tag it is though) - return lightweightTag || finalWalk.parseTag(tagRef.getObjectId()).getObject().getId().equals(headId); // or normal tag - } catch (IOException e) { - return false; + final RevCommit tagCommit = finalWalk.parseCommit(tagRef.getObjectId()); + final RevCommit objectCommit = finalWalk.parseCommit(objectId); + if (finalWalk.isMergedInto(objectCommit, tagCommit)) { + return true; + } + } catch (Exception ignored) { + log.debug("Failed while getTags [{}] -- ", tagRef, ignored); } + return false; } }); Collection tags = Collections2.transform(tagsForHeadCommit, new Function() { @@ -84,16 +87,16 @@ private Collection getTags(final Git git, final ObjectId headId, final R return tags; } - public String getClosestTagName(@NotNull Repository repo, GitDescribeConfig gitDescribe) { + public String getClosestTagName(@NotNull String evaluateOnCommit, @NotNull Repository repo, GitDescribeConfig gitDescribe) { // TODO: Why does some tests fail when it gets headCommit from JGitprovider? - RevCommit headCommit = findHeadObjectId(repo); + RevCommit headCommit = findEvalCommitObjectId(evaluateOnCommit, repo); Pair pair = getClosestRevCommit(repo, headCommit, gitDescribe); return pair.second; } - public String getClosestTagCommitCount(@NotNull Repository repo, GitDescribeConfig gitDescribe) { + public String getClosestTagCommitCount(@NotNull String evaluateOnCommit, @NotNull Repository repo, GitDescribeConfig gitDescribe) { // TODO: Why does some tests fail when it gets headCommit from JGitprovider? - RevCommit headCommit = findHeadObjectId(repo); + RevCommit headCommit = findEvalCommitObjectId(evaluateOnCommit, repo); Pair pair = getClosestRevCommit(repo, headCommit, gitDescribe); RevCommit revCommit = pair.first; int distance = distanceBetween(repo, headCommit, revCommit); @@ -135,19 +138,19 @@ protected Map> findTagObjectIds(@NotNull Repository repo, return commitIdsToTagNames; } - protected RevCommit findHeadObjectId(@NotNull Repository repo) throws RuntimeException { + protected RevCommit findEvalCommitObjectId(@NotNull String evaluateOnCommit, @NotNull Repository repo) throws RuntimeException { try { - ObjectId headId = repo.resolve(Constants.HEAD); + ObjectId evalCommitId = repo.resolve(evaluateOnCommit); try (RevWalk walk = new RevWalk(repo)) { - RevCommit headCommit = walk.lookupCommit(headId); + RevCommit evalCommit = walk.parseCommit(evalCommitId); walk.dispose(); - log.info("HEAD is [{}]", headCommit.getName()); - return headCommit; + log.info("evalCommit is [{}]", evalCommit.getName()); + return evalCommit; } } catch (IOException ex) { - throw new RuntimeException("Unable to obtain HEAD commit!", ex); + throw new RuntimeException("Unable to obtain " + evaluateOnCommit + " commit!", ex); } } diff --git a/src/main/java/pl/project13/maven/git/GitCommitIdMojo.java b/src/main/java/pl/project13/maven/git/GitCommitIdMojo.java index 6e48de32..c0e51fd5 100644 --- a/src/main/java/pl/project13/maven/git/GitCommitIdMojo.java +++ b/src/main/java/pl/project13/maven/git/GitCommitIdMojo.java @@ -36,6 +36,7 @@ import java.util.Map; import java.util.Properties; import java.util.TimeZone; +import java.util.regex.Pattern; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.AbstractMojo; @@ -304,6 +305,23 @@ public class GitCommitIdMojo extends AbstractMojo { @Parameter @VisibleForTesting List replacementProperties; + /** + * Allow to tell the plugin what commit should be used as reference to generate the properties from. + * By default this property is simply set to

HEAD

which should reference to the latest commit in your repository. + * + * In general this property can be set to something generic like

HEAD^1

or point to a branch or tag-name. + * To support any kind or use-case this configuration can also be set to an entire commit-hash or it's abbreviated version. + * + * A use-case for this feature can be found in https://github.com/ktoso/maven-git-commit-id-plugin/issues/338. + * + * Please note that for security purposes not all references might be allowed as configuration. + * If you have a specific use-case that is currently not white listed feel free to file an issue. + * @since 2.2.4 + */ + @Parameter(defaultValue = "HEAD") + private String evaluateOnCommit; + protected static final Pattern allowedCharactersForEvaluateOnCommit = Pattern.compile("[a-zA-Z0-9\\_\\-\\^\\/\\.]+"); + /** * The properties we store our data in and then expose them. */ @@ -369,6 +387,11 @@ public void execute() throws MojoExecutionException { return; } + if ((evaluateOnCommit == null) || !allowedCharactersForEvaluateOnCommit.matcher(evaluateOnCommit).matches()) { + log.error("suspicious argument for evaluateOnCommit, aborting execution!"); + return; + } + try { try { commitIdGenerationModeEnum = CommitIdGenerationMode.valueOf(commitIdGenerationMode.toUpperCase()); @@ -515,7 +538,7 @@ void loadGitDataWithNativeGit(@NotNull Properties properties) throws GitCommitId .setGitDescribe(gitDescribe) .setCommitIdGenerationMode(commitIdGenerationModeEnum); - nativeGitProvider.loadGitData(properties); + nativeGitProvider.loadGitData(evaluateOnCommit, properties); } catch (IOException e) { throw new GitCommitIdExecutionException(e); } @@ -531,7 +554,7 @@ void loadGitDataWithJGit(@NotNull Properties properties) throws GitCommitIdExecu .setGitDescribe(gitDescribe) .setCommitIdGenerationMode(commitIdGenerationModeEnum); - jGitProvider.loadGitData(properties); + jGitProvider.loadGitData(evaluateOnCommit, properties); } void maybeGeneratePropertiesFile(@NotNull Properties localProperties, File base, String propertiesFilename) throws GitCommitIdExecutionException { @@ -787,4 +810,12 @@ static class CannotReadFileException extends Exception { @VisibleForTesting void setFailOnUnableToExtractRepoInfo(boolean failOnUnableToExtractRepoInfo) { this.failOnUnableToExtractRepoInfo = failOnUnableToExtractRepoInfo; } + + @VisibleForTesting String getEvaluateOnCommit() { + return evaluateOnCommit; + } + + @VisibleForTesting void setEvaluateOnCommit(String evaluateOnCommit) { + this.evaluateOnCommit = evaluateOnCommit; + } } diff --git a/src/main/java/pl/project13/maven/git/GitDataProvider.java b/src/main/java/pl/project13/maven/git/GitDataProvider.java index ebd2a0d2..ec34eb14 100644 --- a/src/main/java/pl/project13/maven/git/GitDataProvider.java +++ b/src/main/java/pl/project13/maven/git/GitDataProvider.java @@ -49,6 +49,8 @@ public abstract class GitDataProvider implements GitProvider { protected CommitIdGenerationMode commitIdGenerationMode; + protected String evaluateOnCommit; + public GitDataProvider(@NotNull LoggerBridge log) { this.log = log; } @@ -83,7 +85,8 @@ public GitDataProvider setDateFormatTimeZone(String dateFormatTimeZone) { return this; } - public void loadGitData(@NotNull Properties properties) throws GitCommitIdExecutionException { + public void loadGitData(@NotNull String evaluateOnCommit, @NotNull Properties properties) throws GitCommitIdExecutionException { + this.evaluateOnCommit = evaluateOnCommit; init(); // git.user.name put(properties, GitCommitPropertyConstant.BUILD_AUTHOR_NAME, getBuildAuthorName()); diff --git a/src/main/java/pl/project13/maven/git/JGitProvider.java b/src/main/java/pl/project13/maven/git/JGitProvider.java index c9e302d0..adc84994 100644 --- a/src/main/java/pl/project13/maven/git/JGitProvider.java +++ b/src/main/java/pl/project13/maven/git/JGitProvider.java @@ -23,7 +23,6 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.AbbreviatedObjectId; -import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Ref; @@ -51,7 +50,7 @@ public class JGitProvider extends GitDataProvider { private Repository git; private ObjectReader objectReader; private RevWalk revWalk; - private RevCommit headCommit; + private RevCommit evalCommit; private JGitCommon jGitCommon; @NotNull @@ -87,17 +86,25 @@ public String getBuildAuthorEmail() throws GitCommitIdExecutionException { public void prepareGitToExtractMoreDetailedRepoInformation() throws GitCommitIdExecutionException { try { // more details parsed out bellow - Ref head = git.findRef(Constants.HEAD); - if (head == null) { - throw new GitCommitIdExecutionException("Could not get HEAD Ref, are you sure you have set the dotGitDirectory property of this plugin to a valid path?"); + Ref evaluateOnCommitReference = git.findRef(evaluateOnCommit); + ObjectId evaluateOnCommitResolvedObjectId = git.resolve(evaluateOnCommit); + + if ((evaluateOnCommitReference == null) && (evaluateOnCommitResolvedObjectId == null)) { + throw new GitCommitIdExecutionException("Could not get " + evaluateOnCommit + " Ref, are you sure you have set the dotGitDirectory property of this plugin to a valid path?"); } revWalk = new RevWalk(git); - ObjectId headObjectId = head.getObjectId(); + ObjectId headObjectId = null; + if (evaluateOnCommitReference != null) { + headObjectId = evaluateOnCommitReference.getObjectId(); + } else { + headObjectId = evaluateOnCommitResolvedObjectId; + } + if (headObjectId == null) { - throw new GitCommitIdExecutionException("Could not get HEAD Ref, are you sure you have some commits in the dotGitDirectory?"); + throw new GitCommitIdExecutionException("Could not get " + evaluateOnCommit + " Ref, are you sure you have some commits in the dotGitDirectory?"); } - headCommit = revWalk.parseCommit(headObjectId); - revWalk.markStart(headCommit); + evalCommit = revWalk.parseCommit(headObjectId); + revWalk.markStart(evalCommit); } catch (Exception e) { throw new GitCommitIdExecutionException("Error", e); } @@ -119,12 +126,12 @@ public String getGitDescribe() throws GitCommitIdExecutionException { @Override public String getCommitId() throws GitCommitIdExecutionException { - return headCommit.getName(); + return evalCommit.getName(); } @Override public String getAbbrevCommitId() throws GitCommitIdExecutionException { - return getAbbrevCommitId(objectReader, headCommit, abbrevLength); + return getAbbrevCommitId(objectReader, evalCommit, abbrevLength); } @Override @@ -138,27 +145,27 @@ public boolean isDirty() throws GitCommitIdExecutionException { @Override public String getCommitAuthorName() throws GitCommitIdExecutionException { - return headCommit.getAuthorIdent().getName(); + return evalCommit.getAuthorIdent().getName(); } @Override public String getCommitAuthorEmail() throws GitCommitIdExecutionException { - return headCommit.getAuthorIdent().getEmailAddress(); + return evalCommit.getAuthorIdent().getEmailAddress(); } @Override public String getCommitMessageFull() throws GitCommitIdExecutionException { - return headCommit.getFullMessage().trim(); + return evalCommit.getFullMessage().trim(); } @Override public String getCommitMessageShort() throws GitCommitIdExecutionException { - return headCommit.getShortMessage().trim(); + return evalCommit.getShortMessage().trim(); } @Override public String getCommitTime() throws GitCommitIdExecutionException { - long timeSinceEpoch = headCommit.getCommitTime(); + long timeSinceEpoch = evalCommit.getCommitTime(); Date commitDate = new Date(timeSinceEpoch * 1000); // git is "by sec" and java is "by ms" SimpleDateFormat smf = getSimpleDateFormatWithTimeZone(); return smf.format(commitDate); @@ -174,11 +181,11 @@ public String getRemoteOriginUrl() throws GitCommitIdExecutionException { public String getTags() throws GitCommitIdExecutionException { try { Repository repo = getGitRepository(); - ObjectId headId = headCommit.toObjectId(); - Collection tags = jGitCommon.getTags(repo,headId); + ObjectId headId = evalCommit.toObjectId(); + Collection tags = jGitCommon.getTags(repo, headId); return Joiner.on(",").join(tags); } catch (GitAPIException e) { - log.error("Unable to extract tags from commit: {} ({})", headCommit.getName(), e.getClass().getName()); + log.error("Unable to extract tags from commit: {} ({})", evalCommit.getName(), e.getClass().getName()); return ""; } } @@ -187,7 +194,7 @@ public String getTags() throws GitCommitIdExecutionException { public String getClosestTagName() throws GitCommitIdExecutionException { Repository repo = getGitRepository(); try { - return jGitCommon.getClosestTagName(repo, gitDescribe); + return jGitCommon.getClosestTagName(evaluateOnCommit, repo, gitDescribe); } catch (Throwable t) { // could not find any tags to describe } @@ -198,7 +205,7 @@ public String getClosestTagName() throws GitCommitIdExecutionException { public String getClosestTagCommitCount() throws GitCommitIdExecutionException { Repository repo = getGitRepository(); try { - return jGitCommon.getClosestTagCommitCount(repo, gitDescribe); + return jGitCommon.getClosestTagCommitCount(evaluateOnCommit, repo, gitDescribe); } catch (Throwable t) { // could not find any tags to describe } @@ -225,7 +232,7 @@ public void finalCleanUp() { @VisibleForTesting String getGitDescribe(@NotNull Repository repository) throws GitCommitIdExecutionException { try { DescribeResult describeResult = DescribeCommand - .on(repository, log) + .on(evaluateOnCommit, repository, log) .apply(super.gitDescribe) .call(); diff --git a/src/main/java/pl/project13/maven/git/NativeGitProvider.java b/src/main/java/pl/project13/maven/git/NativeGitProvider.java index ab959d50..5a80ff4e 100644 --- a/src/main/java/pl/project13/maven/git/NativeGitProvider.java +++ b/src/main/java/pl/project13/maven/git/NativeGitProvider.java @@ -92,15 +92,21 @@ public String getBranchName() throws GitCommitIdExecutionException { private String getBranch(File canonical) throws GitCommitIdExecutionException { String branch; try { - branch = runGitCommand(canonical, "symbolic-ref HEAD"); + branch = runGitCommand(canonical, "symbolic-ref " + evaluateOnCommit); if (branch != null) { branch = branch.replace("refs/heads/", ""); } } catch (NativeCommandException e) { // it seems that git repo is in 'DETACHED HEAD'-State, using Commit-Id as Branch String err = e.getStderr(); - if (err != null && err.contains("ref HEAD is not a symbolic ref")) { - branch = getCommitId(); + if (err != null) { + boolean noSymbolicRef = err.contains("ref " + evaluateOnCommit + " is not a symbolic ref"); + boolean noSuchRef = err.contains("No such ref: " + evaluateOnCommit); + if (noSymbolicRef || noSuchRef) { + branch = getCommitId(); + } else { + throw Throwables.propagate(e); + } } else { throw Throwables.propagate(e); } @@ -120,14 +126,23 @@ private String getArgumentsForGitDescribe(GitDescribeConfig describeConfig) { } StringBuilder argumentsForGitDescribe = new StringBuilder(); + boolean hasCommitish = (evaluateOnCommit != null) && !evaluateOnCommit.equals("HEAD"); + if (hasCommitish) { + argumentsForGitDescribe.append(" " + evaluateOnCommit); + } if (describeConfig.isAlways()) { argumentsForGitDescribe.append(" --always"); } final String dirtyMark = describeConfig.getDirty(); - if (dirtyMark != null && !dirtyMark.isEmpty()) { - argumentsForGitDescribe.append(" --dirty=").append(dirtyMark); + if ((dirtyMark != null) && !dirtyMark.isEmpty()) { + // we can either have evaluateOnCommit or --dirty flag set + if (hasCommitish) { + log.warn("You might use strange arguments since it's unfortunately not supported to have evaluateOnCommit and the --dirty flag for the describe command set at the same time"); + } else { + argumentsForGitDescribe.append(" --dirty=").append(dirtyMark); + } } final String matchOption = describeConfig.getMatch(); @@ -149,7 +164,17 @@ private String getArgumentsForGitDescribe(GitDescribeConfig describeConfig) { @Override public String getCommitId() throws GitCommitIdExecutionException { - return runQuietGitCommand(canonical, "rev-parse HEAD"); + boolean evaluateOnCommitIsSet = (evaluateOnCommit != null) && !evaluateOnCommit.equals("HEAD"); + if (evaluateOnCommitIsSet) { + // if evaluateOnCommit represents a tag we need to perform the rev-parse on the actual commit reference + // in case evaluateOnCommit is not a reference rev-list will just return the argument given + // and thus it's always safe(r) to unwrap it + // however when evaluateOnCommit is not set we don't want to waste calls to the native binary + String actualCommitId = runQuietGitCommand(canonical, "rev-list -n 1 " + evaluateOnCommit); + return runQuietGitCommand(canonical, "rev-parse " + actualCommitId); + } else { + return runQuietGitCommand(canonical, "rev-parse HEAD"); + } } @Override @@ -173,34 +198,34 @@ public boolean isDirty() throws GitCommitIdExecutionException { @Override public String getCommitAuthorName() throws GitCommitIdExecutionException { - return runQuietGitCommand(canonical, "log -1 --pretty=format:%an"); + return runQuietGitCommand(canonical, "log -1 --pretty=format:%an " + evaluateOnCommit); } @Override public String getCommitAuthorEmail() throws GitCommitIdExecutionException { - return runQuietGitCommand(canonical, "log -1 --pretty=format:%ae"); + return runQuietGitCommand(canonical, "log -1 --pretty=format:%ae " + evaluateOnCommit); } @Override public String getCommitMessageFull() throws GitCommitIdExecutionException { - return runQuietGitCommand(canonical, "log -1 --pretty=format:%B"); + return runQuietGitCommand(canonical, "log -1 --pretty=format:%B " + evaluateOnCommit); } @Override public String getCommitMessageShort() throws GitCommitIdExecutionException { - return runQuietGitCommand(canonical, "log -1 --pretty=format:%s"); + return runQuietGitCommand(canonical, "log -1 --pretty=format:%s " + evaluateOnCommit); } @Override public String getCommitTime() throws GitCommitIdExecutionException { - String value = runQuietGitCommand(canonical, "log -1 --pretty=format:%ct"); + String value = runQuietGitCommand(canonical, "log -1 --pretty=format:%ct " + evaluateOnCommit); SimpleDateFormat smf = getSimpleDateFormatWithTimeZone(); return smf.format(Long.parseLong(value) * 1000L); } @Override public String getTags() throws GitCommitIdExecutionException { - final String result = runQuietGitCommand(canonical, "tag --contains"); + final String result = runQuietGitCommand(canonical, "tag --contains " + evaluateOnCommit); return result.replace('\n', ','); } @@ -213,7 +238,7 @@ public String getRemoteOriginUrl() throws GitCommitIdExecutionException { public String getClosestTagName() throws GitCommitIdExecutionException { try { StringBuilder argumentsForGitDescribe = new StringBuilder(); - argumentsForGitDescribe.append("describe --abbrev=0"); + argumentsForGitDescribe.append("describe " + evaluateOnCommit + " --abbrev=0"); if (gitDescribe != null) { if (gitDescribe.getTags()) { argumentsForGitDescribe.append(" --tags"); @@ -235,7 +260,7 @@ public String getClosestTagName() throws GitCommitIdExecutionException { public String getClosestTagCommitCount() throws GitCommitIdExecutionException { String closestTagName = getClosestTagName(); if (closestTagName != null && !closestTagName.trim().isEmpty()) { - return runQuietGitCommand(canonical, "rev-list " + closestTagName + "..HEAD --count"); + return runQuietGitCommand(canonical, "rev-list " + closestTagName + ".." + evaluateOnCommit + " --count"); } return ""; } diff --git a/src/test/java/pl/project13/jgit/DescribeCommandAbbrevIntegrationTest.java b/src/test/java/pl/project13/jgit/DescribeCommandAbbrevIntegrationTest.java index eaa3ad1d..4f75e753 100644 --- a/src/test/java/pl/project13/jgit/DescribeCommandAbbrevIntegrationTest.java +++ b/src/test/java/pl/project13/jgit/DescribeCommandAbbrevIntegrationTest.java @@ -69,7 +69,7 @@ public void shouldGiveTheCommitIdAndDirtyMarkerWhenNothingElseCanBeFound() throw try (final Git git = git(); final Repository repo = git.getRepository()) { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .abbrev(2) // 2 is enough to be unique in this small repo .call(); @@ -93,7 +93,7 @@ public void onGitCommitIdsRepo_shouldNoticeThat2CharsIsTooLittleToBeUniqueAndUse try (final Git git = git(); final Repository repo = git.getRepository()) { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .abbrev(2) // way too small to be unique in git-commit-id's repo! .call(); diff --git a/src/test/java/pl/project13/jgit/DescribeCommandIntegrationTest.java b/src/test/java/pl/project13/jgit/DescribeCommandIntegrationTest.java index 1f0c2c61..5004c608 100644 --- a/src/test/java/pl/project13/jgit/DescribeCommandIntegrationTest.java +++ b/src/test/java/pl/project13/jgit/DescribeCommandIntegrationTest.java @@ -59,7 +59,7 @@ public void shouldGiveTheCommitIdAndDirtyMarkerWhenNothingElseCanBeFound() throw try (final Git git = git(); final Repository repo = git.getRepository()) { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .call(); // then @@ -81,7 +81,7 @@ public void shouldGiveTheCommitIdWhenNothingElseCanBeFound() throws Exception { try (final Git git = git(); final Repository repo = git.getRepository()) { // when - DescribeCommand command = spy(DescribeCommand.on(repo, new StdOutLoggerBridge(true))); + DescribeCommand command = spy(DescribeCommand.on(evaluateOnCommit, repo, new StdOutLoggerBridge(true))); doReturn(false).when(command).findDirtyState(any(Repository.class)); DescribeResult res = command.call(); @@ -105,7 +105,7 @@ public void shouldGiveTheCommitIdWhenTagIsOnOtherBranch() throws Exception { try (final Git git = git(); final Repository repo = git.getRepository()) { // when - DescribeCommand command = spy(DescribeCommand.on(repo, new StdOutLoggerBridge(true))); + DescribeCommand command = spy(DescribeCommand.on(evaluateOnCommit, repo, new StdOutLoggerBridge(true))); doReturn(false).when(command).findDirtyState(any(Repository.class)); DescribeResult res = command.call(); @@ -130,7 +130,7 @@ public void shouldGiveTheCommitIdWhenNothingElseCanBeFoundAndUseAbbrevVersionOfI int abbrevLength = 10; try (final Git git = git(); final Repository repo = git.getRepository()) { // when - DescribeCommand command = spy(DescribeCommand.on(repo, new StdOutLoggerBridge(true))); + DescribeCommand command = spy(DescribeCommand.on(evaluateOnCommit, repo, new StdOutLoggerBridge(true))); doReturn(false).when(command).findDirtyState(any(Repository.class)); command @@ -156,7 +156,7 @@ public void shouldGiveTagWithDistanceToCurrentCommitAndItsIdAndDirtyMarker() thr try (final Git git = git(); final Repository repo = git.getRepository()) { // when - DescribeCommand command = DescribeCommand.on(repo, new StdOutLoggerBridge(true)); + DescribeCommand command = DescribeCommand.on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)); command.dirty(DIRTY_SUFFIX); DescribeResult res = command.call(); @@ -181,7 +181,7 @@ public void shouldGiveTagWithDistanceToCurrentCommitAndItsIdAndCustomDirtyMarker try (final Git git = git(); final Repository repo = git.getRepository()) { // when DescribeCommand command = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .dirty(customDirtySuffix); DescribeResult res = command.call(); @@ -207,7 +207,7 @@ public void shouldGiveTagWithDistanceToCurrentCommitAndItsId() throws Exception } // when - DescribeCommand command = DescribeCommand.on(repo, new StdOutLoggerBridge(true)); + DescribeCommand command = DescribeCommand.on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)); DescribeResult res = command.call(); // then @@ -231,7 +231,7 @@ public void shouldGiveTag() throws Exception { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .call(); @@ -256,7 +256,7 @@ public void shouldNotGiveDirtyMarkerWhenOnATagAndDirtyButNoDirtyOptionConfigured // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .call(); @@ -283,7 +283,7 @@ public void shouldGiveTagWithCustomDirtyMarker() throws Exception { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .dirty(customDirtySuffix) .call(); @@ -307,7 +307,7 @@ public void shouldNotGiveDirtyTagByDefault() throws Exception { try (final Git git = git(); final Repository repo = git.getRepository()) { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .call(); @@ -328,7 +328,7 @@ public void shouldGiveAnnotatedTagWithDirtyMarker() throws Exception { try (final Git git = git(); final Repository repo = git.getRepository()) { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .dirty(DIRTY_SUFFIX) .abbrev(0) .call(); @@ -356,7 +356,7 @@ public void shouldGiveLightweightTagWithDirtyMarker() throws Exception { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .call(); @@ -416,7 +416,7 @@ public void shouldReturnJustTheNearestTagWhenAbbrevIsZero() throws Exception { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .abbrev(zeroAbbrev) .call(); diff --git a/src/test/java/pl/project13/jgit/DescribeCommandOptionsTest.java b/src/test/java/pl/project13/jgit/DescribeCommandOptionsTest.java index dd34a825..d4eced53 100644 --- a/src/test/java/pl/project13/jgit/DescribeCommandOptionsTest.java +++ b/src/test/java/pl/project13/jgit/DescribeCommandOptionsTest.java @@ -26,7 +26,7 @@ import static org.mockito.Mockito.*; public class DescribeCommandOptionsTest { - + private static final String evaluateOnCommit = "HEAD"; @Test(expected = IllegalArgumentException.class) public void abbrev_shouldVerifyLengthContract_failOn41() throws Exception { @@ -34,7 +34,7 @@ public void abbrev_shouldVerifyLengthContract_failOn41() throws Exception { final Repository repo = mock(Repository.class); final int length = 41; - DescribeCommand.on(repo, new StdOutLoggerBridge(true)).abbrev(length); + DescribeCommand.on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)).abbrev(length); } @Test(expected = IllegalArgumentException.class) @@ -43,7 +43,7 @@ public void abbrev_shouldVerifyLengthContract_failOnMinus12() throws Exception { final Repository repo = mock(Repository.class); final int length = -12; - DescribeCommand.on(repo, new StdOutLoggerBridge(true)).abbrev(length); + DescribeCommand.on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)).abbrev(length); } @Test @@ -56,7 +56,7 @@ public void apply_shouldDelegateToAllOptions() throws Exception { GitDescribeConfig config = new GitDescribeConfig(true, devel, match, abbrev, true, true); Repository repo = mock(Repository.class); - DescribeCommand command = DescribeCommand.on(repo, new StdOutLoggerBridge(true)); + DescribeCommand command = DescribeCommand.on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)); DescribeCommand spiedCommand = spy(command); // when diff --git a/src/test/java/pl/project13/jgit/DescribeCommandTagsIntegrationTest.java b/src/test/java/pl/project13/jgit/DescribeCommandTagsIntegrationTest.java index 436fe0b3..ab32519f 100644 --- a/src/test/java/pl/project13/jgit/DescribeCommandTagsIntegrationTest.java +++ b/src/test/java/pl/project13/jgit/DescribeCommandTagsIntegrationTest.java @@ -63,7 +63,7 @@ public void shouldFindAnnotatedTagWithTagsOptionNotGiven() throws Exception { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .call(); // then @@ -86,7 +86,7 @@ public void shouldFindLightweightTagWithTagsOptionGiven() throws Exception { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .call(); @@ -110,7 +110,7 @@ public void shouldFindAnnotatedTagWithMatchOptionGiven() throws Exception { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .match("annotated*") .call(); @@ -146,7 +146,7 @@ public void shouldFindNewerTagWhenACommitHasTwoOrMoreTags() throws Exception { // when DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .call(); @@ -179,7 +179,7 @@ public void shouldUseTheNewestTagOnACommitIfItHasMoreThanOneTags() throws Except wrap.tag().setName(latestTag).call(); DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .call(); @@ -211,7 +211,7 @@ public void shouldUseTheNewestTagOnACommitIfItHasMoreThanOneTagsReversedCase() t } DescribeResult res = DescribeCommand - .on(repo, new StdOutLoggerBridge(true)) + .on(evaluateOnCommit, repo, new StdOutLoggerBridge(true)) .tags() .call(); diff --git a/src/test/java/pl/project13/maven/git/AvailableGitTestRepo.java b/src/test/java/pl/project13/maven/git/AvailableGitTestRepo.java index 849b85bb..f514794d 100644 --- a/src/test/java/pl/project13/maven/git/AvailableGitTestRepo.java +++ b/src/test/java/pl/project13/maven/git/AvailableGitTestRepo.java @@ -57,6 +57,14 @@ public enum AvailableGitTestRepo { * */ WITH_LIGHTWEIGHT_TAG_BEFORE_ANNOTATED_TAG("src/test/resources/_git_lightweight_tag_before_annotated_tag"), + /** + *
+   * * 9cb810e - Change in tag - Fri, 29 Nov 2013 10:39:31 +0100 (tag: test_tag, branch: test)
+   * | * 2343428 - Moved master - Fri, 29 Nov 2013 10:38:34 +0100 (HEAD, branch: master)
+   * |/
+   * * e3d159d - Added readme - Fri, 29 Nov 2013 10:38:02 +0100
+   * 
+ */ WITH_TAG_ON_DIFFERENT_BRANCH("src/test/resources/_git_with_tag_on_different_branch"), WITH_ONE_COMMIT_WITH_SPECIAL_CHARACTERS("src/test/resources/_git_one_commit_with_umlaut"), /** diff --git a/src/test/java/pl/project13/maven/git/GitCommitIdMojoIntegrationTest.java b/src/test/java/pl/project13/maven/git/GitCommitIdMojoIntegrationTest.java index bf669de8..828938a8 100644 --- a/src/test/java/pl/project13/maven/git/GitCommitIdMojoIntegrationTest.java +++ b/src/test/java/pl/project13/maven/git/GitCommitIdMojoIntegrationTest.java @@ -19,7 +19,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; import com.google.common.io.Files; + import junitparams.JUnitParamsRunner; import junitparams.Parameters; import org.apache.maven.plugin.MojoExecutionException; @@ -27,7 +30,10 @@ import org.codehaus.plexus.util.FileUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ResetCommand; +import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; +import org.junit.contrib.java.lang.system.EnvironmentVariables; import org.junit.runner.RunWith; import java.io.File; @@ -42,6 +48,9 @@ @RunWith(JUnitParamsRunner.class) public class GitCommitIdMojoIntegrationTest extends GitIntegrationTest { + @Rule + public final EnvironmentVariables environmentVariablesMock = new EnvironmentVariables(); + static final boolean UseJGit = false; static final boolean UseNativeGit = true; @@ -53,11 +62,292 @@ public static Collection useDirty() { return asList(true, false); } + @Test + @Parameters(method = "useNativeGit") + public void shouldIncludeExpectedProperties(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + mojo.setUseNativeGit(useNativeGit); + + // when + mojo.execute(); + + // then + Properties properties = targetProject.getProperties(); + + assertThat(properties).satisfies(new ContainsKeyCondition("git.branch")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.dirty")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.full")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.abbrev")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.name")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.email")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.name")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.email")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.message.full")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.message.short")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.time")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.remote.origin.url")); + } + + @Test + @Parameters(method = "useNativeGit") + public void shouldExcludeAsConfiguredProperties(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + mojo.setUseNativeGit(useNativeGit); + mojo.setExcludeProperties(ImmutableList.of("git.remote.origin.url", ".*.user.*")); + + // when + mojo.execute(); + + // then + Properties properties = targetProject.getProperties(); + + // explicitly excluded + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.remote.origin.url")); + + // glob excluded + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.build.user.name")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.build.user.email")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.user.name")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.user.email")); + + // these stay + assertThat(properties).satisfies(new ContainsKeyCondition("git.branch")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.full")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.abbrev")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.message.full")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.message.short")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.time")); + } + + @Test + @Parameters(method = "useNativeGit") + public void shouldIncludeOnlyAsConfiguredProperties(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + mojo.setUseNativeGit(useNativeGit); + mojo.setIncludeOnlyProperties(ImmutableList.of("git.remote.origin.url", ".*.user.*", "^git.commit.id.full$")); + + // when + mojo.execute(); + + // then + Properties properties = targetProject.getProperties(); + + // explicitly included + assertThat(properties).satisfies(new ContainsKeyCondition("git.remote.origin.url")); + + // glob included + assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.name")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.email")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.full")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.name")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.email")); + + // these excluded + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.branch")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.id.abbrev")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.message.full")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.message.short")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.time")); + } + + @Test + @Parameters(method = "useNativeGit") + public void shouldExcludeAndIncludeAsConfiguredProperties(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + mojo.setUseNativeGit(useNativeGit); + mojo.setIncludeOnlyProperties(ImmutableList.of("git.remote.origin.url", ".*.user.*")); + mojo.setExcludeProperties(ImmutableList.of("git.build.user.email")); + + // when + mojo.execute(); + + // then + Properties properties = targetProject.getProperties(); + + // explicitly included + assertThat(properties).satisfies(new ContainsKeyCondition("git.remote.origin.url")); + + // explicitly excluded -> overrules include only properties + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.build.user.email")); + + // glob included + assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.name")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.name")); + assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.email")); + + // these excluded + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.branch")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.id.full")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.id.abbrev")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.message.full")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.message.short")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.time")); + } + + @Test + @Parameters(method = "useNativeGit") + public void shouldHaveNoPrefixWhenConfiguredPrefixIsEmptyStringAsConfiguredProperties(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + mojo.setUseNativeGit(useNativeGit); + mojo.setPrefix(""); + + // when + mojo.execute(); + + // then + Properties properties = targetProject.getProperties(); + + // explicitly excluded + assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.remote.origin.url")); + assertThat(properties).satisfies(new DoesNotContainKeyCondition(".remote.origin.url")); + assertThat(properties).satisfies(new ContainsKeyCondition("remote.origin.url")); + } + + @Test + @Parameters(method = "useNativeGit") + public void shouldSkipDescribeWhenConfiguredToDoSo(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + + GitDescribeConfig config = new GitDescribeConfig(); + config.setSkip(true); + + // when + mojo.setGitDescribe(config); + mojo.execute(); + + // then + assertThat(targetProject.getProperties()).satisfies(new DoesNotContainKeyCondition("git.commit.id.describe")); + } + + @Test + @Parameters(method = "useNativeGit") + public void shouldUseJenkinsBranchInfoWhenAvailable(boolean useNativeGit) throws Exception { + // given + Map env = Maps.newHashMap(); + + String detachedHeadSha1 = "b6a73ed747dd8dc98642d731ddbf09824efb9d48"; + String ciUrl = "http://myciserver.com"; + + // when + // in a detached head state, getBranch() will return the SHA1...standard behavior + shouldUseJenkinsBranchInfoWhenAvailableHelperAndAssertBranch(useNativeGit, env, detachedHeadSha1); + + // again, SHA1 will be returned if we're in jenkins, but GIT_BRANCH is not set + env.put("JENKINS_URL", ciUrl); + shouldUseJenkinsBranchInfoWhenAvailableHelperAndAssertBranch(useNativeGit, env, detachedHeadSha1); + + // now set GIT_BRANCH too and see that the branch name from env var is returned + env.clear(); + env.put("JENKINS_URL", ciUrl); + env.put("GIT_BRANCH", "mybranch"); + shouldUseJenkinsBranchInfoWhenAvailableHelperAndAssertBranch(useNativeGit, env, "mybranch"); + + // same, but for hudson + env.clear(); + env.put("HUDSON_URL", ciUrl); + env.put("GIT_BRANCH", "mybranch"); + shouldUseJenkinsBranchInfoWhenAvailableHelperAndAssertBranch(useNativeGit, env, "mybranch"); + + // now set GIT_LOCAL_BRANCH too and see that the branch name from env var is returned + env.clear(); + env.put("JENKINS_URL", ciUrl); + env.put("GIT_BRANCH", "mybranch"); + env.put("GIT_LOCAL_BRANCH", "mylocalbranch"); + shouldUseJenkinsBranchInfoWhenAvailableHelperAndAssertBranch(useNativeGit, env, "mylocalbranch"); + + // same, but for hudson + env.clear(); + env.put("HUDSON_URL", ciUrl); + env.put("GIT_BRANCH", "mybranch"); + env.put("GIT_LOCAL_BRANCH", "mylocalbranch"); + shouldUseJenkinsBranchInfoWhenAvailableHelperAndAssertBranch(useNativeGit, env, "mylocalbranch"); + + // GIT_BRANCH but no HUDSON_URL or JENKINS_URL + env.clear(); + env.put("GIT_BRANCH", "mybranch"); + env.put("GIT_LOCAL_BRANCH", "mylocalbranch"); + shouldUseJenkinsBranchInfoWhenAvailableHelperAndAssertBranch(useNativeGit, env, detachedHeadSha1); + } + + private void shouldUseJenkinsBranchInfoWhenAvailableHelperAndAssertBranch(boolean useNativeGit, Map env, String expectedBranchName) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_COMMIT_THAT_HAS_TWO_TAGS) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + + // remove all keys from System.getenv() + List keySet = new ArrayList<>(System.getenv().keySet()); + for (String key: keySet) { + environmentVariablesMock.set(key, null); + } + // set System.getenv() to be equal to given parameter env + for (Map.Entry entry: env.entrySet()) { + environmentVariablesMock.set(entry.getKey(), entry.getValue()); + } + + // verify that System.getenv() is actually equal + Assert.assertEquals(env, System.getenv()); + + // reset repo and force detached HEAD + try (final Git git = git("my-jar-project")) { + git.reset().setMode(ResetCommand.ResetType.HARD).setRef("b6a73ed").call(); + git.checkout().setName("b6a73ed").setForce(true).call(); + } + + // when + mojo.execute(); + + // then + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.branch", expectedBranchName); + } + @Test @Parameters(method = "useNativeGit") public void shouldResolvePropertiesOnDefaultSettingsForNonPomProject(boolean useNativeGit) throws Exception { // given - mavenSandbox.withParentProject("my-jar-project", "jar").withNoChildProject().withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT).create(); + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); mojo.setUseNativeGit(useNativeGit); @@ -73,7 +363,10 @@ public void shouldResolvePropertiesOnDefaultSettingsForNonPomProject(boolean use @Parameters(method = "useNativeGit") public void shouldNotRunWhenSkipIsSet(boolean useNativeGit) throws Exception { // given - mavenSandbox.withParentProject("my-skip-project", "jar").withNoChildProject().withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT).create(); + mavenSandbox.withParentProject("my-skip-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); mojo.setSkip(true); @@ -90,7 +383,10 @@ public void shouldNotRunWhenSkipIsSet(boolean useNativeGit) throws Exception { @Parameters(method = "useNativeGit") public void shouldNotRunWhenPackagingPomAndDefaultSettingsApply(boolean useNativeGit) throws Exception { // given - mavenSandbox.withParentProject("my-pom-project", "pom").withNoChildProject().withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT).create(); + mavenSandbox.withParentProject("my-pom-project", "pom") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); mojo.setUseNativeGit(useNativeGit); @@ -106,7 +402,10 @@ public void shouldNotRunWhenPackagingPomAndDefaultSettingsApply(boolean useNativ @Parameters(method = "useNativeGit") public void shouldRunWhenPackagingPomAndSkipPomsFalse(boolean useNativeGit) throws Exception { // given - mavenSandbox.withParentProject("my-pom-project", "pom").withNoChildProject().withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT).create(); + mavenSandbox.withParentProject("my-pom-project", "pom") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); mojo.setSkipPoms(false); @@ -123,7 +422,10 @@ public void shouldRunWhenPackagingPomAndSkipPomsFalse(boolean useNativeGit) thro @Parameters(method = "useNativeGit") public void shouldUseParentProjectRepoWhenInvokedFromChild(boolean useNativeGit) throws Exception { // given - mavenSandbox.withParentProject("my-pom-project", "pom").withChildProject("my-jar-module", "jar").withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT).create(); + mavenSandbox.withParentProject("my-pom-project", "pom") + .withChildProject("my-jar-module", "jar") + .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); mojo.setSkipPoms(false); @@ -140,7 +442,10 @@ public void shouldUseParentProjectRepoWhenInvokedFromChild(boolean useNativeGit) @Parameters(method = "useNativeGit") public void shouldUseChildProjectRepoIfInvokedFromChild(boolean useNativeGit) throws Exception { // given - mavenSandbox.withParentProject("my-pom-project", "pom").withChildProject("my-jar-module", "jar").withGitRepoInChild(AvailableGitTestRepo.WITH_ONE_COMMIT).create(); + mavenSandbox.withParentProject("my-pom-project", "pom") + .withChildProject("my-jar-module", "jar") + .withGitRepoInChild(AvailableGitTestRepo.WITH_ONE_COMMIT) + .create(); MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); mojo.setSkipPoms(false); @@ -161,7 +466,6 @@ public void shouldFailWithExceptionWhenNoGitRepoFound(boolean useNativeGit) thro .withChildProject("my-jar-module", "jar") .withNoGitRepoAvailable() .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); mojo.setSkipPoms(false); @@ -178,7 +482,6 @@ public void shouldGenerateCustomPropertiesFileProperties(boolean useNativeGit) t .withChildProject("my-jar-module", "jar") .withGitRepoInChild(AvailableGitTestRepo.WITH_ONE_COMMIT_WITH_SPECIAL_CHARACTERS) .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); String targetFilePath = "target/classes/custom-git.properties"; @@ -208,7 +511,6 @@ public void shouldGenerateCustomPropertiesFileJson(boolean useNativeGit) throws .withChildProject("my-jar-module", "jar") .withGitRepoInChild(AvailableGitTestRepo.WITH_ONE_COMMIT_WITH_SPECIAL_CHARACTERS) .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); String targetFilePath = "target/classes/custom-git.properties"; @@ -243,7 +545,6 @@ public void shouldSkipWithoutFailOnNoGitDirectoryWhenNoGitRepoFound(boolean useN .withNoChildProject() .withNoGitRepoAvailable() .create(); - MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); mojo.setFailOnNoGitDirectory(false); @@ -264,7 +565,6 @@ public void shouldNotSkipWithoutFailOnNoGitDirectoryWhenNoGitRepoIsPresent(boole .withNoChildProject() .withGitRepoInParent(AvailableGitTestRepo.WITH_ONE_COMMIT) .create(); - MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); mojo.setFailOnNoGitDirectory(false); @@ -285,7 +585,6 @@ public void shouldGenerateDescribeWithTagOnlyWhenForceLongFormatIsFalse(boolean .withChildProject("my-jar-module", "jar") .withGitRepoInChild(AvailableGitTestRepo.ON_A_TAG) .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); @@ -310,7 +609,6 @@ public void shouldGenerateDescribeWithTagOnlyWhenForceLongFormatIsFalseAndAbbrev .withChildProject("my-jar-module", "jar") .withGitRepoInChild(AvailableGitTestRepo.ON_A_TAG) .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); @@ -335,7 +633,6 @@ public void shouldGenerateDescribeWithTagAndZeroAndCommitIdWhenForceLongFormatIs .withChildProject("my-jar-module", "jar") .withGitRepoInChild(AvailableGitTestRepo.ON_A_TAG) .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); @@ -358,7 +655,6 @@ public void shouldGenerateDescribeWithTagAndZeroAndCommitIdWhenForceLongFormatIs .withChildProject("my-jar-module", "jar") .withGitRepoInChild(AvailableGitTestRepo.ON_A_TAG) .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); @@ -383,7 +679,6 @@ public void shouldGenerateCommitIdAbbrevWithDefaultLength(boolean useNativeGit) .withChildProject("my-jar-module", "jar") .withGitRepoInChild(AvailableGitTestRepo.ON_A_TAG) .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); @@ -405,7 +700,6 @@ public void shouldGenerateCommitIdAbbrevWithNonDefaultLength(boolean useNativeGi .withChildProject("my-jar-module", "jar") .withGitRepoInChild(AvailableGitTestRepo.ON_A_TAG) .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); @@ -567,12 +861,10 @@ public void shouldWorkWithNullGitDescribe(boolean useNativeGit) throws Exception @Parameters(method = "useNativeGit") public void shouldExtractTagsOnGivenCommit(boolean useNativeGit) throws Exception { // given - mavenSandbox - .withParentProject("my-jar-project", "jar") - .withNoChildProject() - .withGitRepoInParent(AvailableGitTestRepo.WITH_COMMIT_THAT_HAS_TWO_TAGS) - .create(); - + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_COMMIT_THAT_HAS_TWO_TAGS) + .create(); try (final Git git = git("my-jar-project")) { git.reset().setMode(ResetCommand.ResetType.HARD).setRef("d37a598").call(); @@ -598,6 +890,68 @@ public void shouldExtractTagsOnGivenCommit(boolean useNativeGit) throws Exceptio .containsOnly("lightweight-tag", "newest-tag"); } + @Test + @Parameters(method = "useNativeGit") + public void shouldExtractTagsOnGivenCommitWithOldestCommit(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_COMMIT_THAT_HAS_TWO_TAGS) + .create(); + + try (final Git git = git("my-jar-project")) { + git.reset().setMode(ResetCommand.ResetType.HARD).setRef("9597545").call(); + } + + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + + mojo.setGitDescribe(null); + mojo.setUseNativeGit(useNativeGit); + + // when + mojo.execute(); + + // then + Properties properties = targetProject.getProperties(); + assertGitPropertiesPresentInProject(properties); + + assertThat(properties).satisfies(new ContainsKeyCondition("git.tags")); + assertThat(properties.get("git.tags").toString()).doesNotContain("refs/tags/"); + + assertThat(Splitter.on(",").split(properties.get("git.tags").toString())) + .containsOnly("annotated-tag", "lightweight-tag", "newest-tag"); + } + + @Test + @Parameters(method = "useNativeGit") + public void shouldExtractTagsOnHead(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.ON_A_TAG) + .create(); + + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + + mojo.setGitDescribe(null); + mojo.setUseNativeGit(useNativeGit); + + // when + mojo.execute(); + + // then + Properties properties = targetProject.getProperties(); + assertGitPropertiesPresentInProject(properties); + + assertThat(properties).satisfies(new ContainsKeyCondition("git.tags")); + assertThat(properties.get("git.tags").toString()).doesNotContain("refs/tags/"); + + assertThat(Splitter.on(",").split(properties.get("git.tags").toString())) + .containsOnly("v1.0.0"); + } + @Test @Parameters(method = "useNativeGit") public void runGitDescribeWithMatchOption(boolean useNativeGit) throws Exception { @@ -647,7 +1001,6 @@ public void shouldGenerateClosestTagInformationWhenOnATag(boolean useNativeGit) .withChildProject("my-jar-module", "jar") .withGitRepoInChild(AvailableGitTestRepo.ON_A_TAG) .create(); - MavenProject targetProject = mavenSandbox.getChildProject(); setProjectToExecuteMojoIn(targetProject); @@ -698,11 +1051,10 @@ public void shouldGenerateClosestTagInformationWhenOnATagAndDirty(boolean useNat @Parameters(method = "useNativeGit") public void shouldGenerateClosestTagInformationWhenCommitHasTwoTags(boolean useNativeGit) throws Exception { // given - mavenSandbox - .withParentProject("my-jar-project", "jar") - .withNoChildProject() - .withGitRepoInParent(AvailableGitTestRepo.WITH_COMMIT_THAT_HAS_TWO_TAGS) - .create(); + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_COMMIT_THAT_HAS_TWO_TAGS) + .create(); try (final Git git = git("my-jar-project")) { git.reset().setMode(ResetCommand.ResetType.HARD).setRef("d37a598").call(); @@ -852,12 +1204,10 @@ public void testDetectDirtyWorkingDirectory(boolean useNativeGit) throws Excepti @Parameters(method = "useNativeGit") public void shouldGenerateClosestTagInformationWithExcludeLightweightTagsForClosestTag(boolean useNativeGit) throws Exception { // given - mavenSandbox - .withParentProject("my-jar-project", "jar") + mavenSandbox.withParentProject("my-jar-project", "jar") .withNoChildProject() .withGitRepoInParent(AvailableGitTestRepo.WITH_LIGHTWEIGHT_TAG_BEFORE_ANNOTATED_TAG) .create(); - MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); @@ -885,12 +1235,10 @@ public void shouldGenerateClosestTagInformationWithExcludeLightweightTagsForClos @Parameters(method = "useNativeGit") public void shouldGenerateClosestTagInformationWithIncludeLightweightTagsForClosestTag(boolean useNativeGit) throws Exception { // given - mavenSandbox - .withParentProject("my-jar-project", "jar") + mavenSandbox.withParentProject("my-jar-project", "jar") .withNoChildProject() .withGitRepoInParent(AvailableGitTestRepo.WITH_LIGHTWEIGHT_TAG_BEFORE_ANNOTATED_TAG) .create(); - MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); @@ -918,12 +1266,10 @@ public void shouldGenerateClosestTagInformationWithIncludeLightweightTagsForClos @Parameters(method = "useNativeGit") public void shouldGenerateClosestTagInformationWithIncludeLightweightTagsForClosestTagAndPreferAnnotatedTags(boolean useNativeGit) throws Exception { // given - mavenSandbox - .withParentProject("my-jar-project", "jar") + mavenSandbox.withParentProject("my-jar-project", "jar") .withNoChildProject() .withGitRepoInParent(AvailableGitTestRepo.WITH_COMMIT_THAT_HAS_TWO_TAGS) .create(); - MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); @@ -951,12 +1297,10 @@ public void shouldGenerateClosestTagInformationWithIncludeLightweightTagsForClos @Parameters(method = "useNativeGit") public void shouldGenerateClosestTagInformationWithIncludeLightweightTagsForClosestTagAndFilter(boolean useNativeGit) throws Exception { // given - mavenSandbox - .withParentProject("my-jar-project", "jar") + mavenSandbox.withParentProject("my-jar-project", "jar") .withNoChildProject() .withGitRepoInParent(AvailableGitTestRepo.WITH_COMMIT_THAT_HAS_TWO_TAGS) .create(); - MavenProject targetProject = mavenSandbox.getParentProject(); setProjectToExecuteMojoIn(targetProject); @@ -981,6 +1325,132 @@ public void shouldGenerateClosestTagInformationWithIncludeLightweightTagsForClos assertPropertyPresentAndEqual(targetProject.getProperties(), "git.closest.tag.commit.count", "1"); } + @Test + @Parameters(method = "useNativeGit") + public void verifyEvalOnDifferentCommitWithParentOfHead(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_TAG_ON_DIFFERENT_BRANCH) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + + GitDescribeConfig gitDescribe = createGitDescribeConfig(true, 9); + gitDescribe.setDirty(null); + + mojo.setGitDescribe(gitDescribe); + mojo.setUseNativeGit(useNativeGit); + mojo.setEvaluateOnCommit("HEAD^1"); + + // when + mojo.execute(); + + // then + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.commit.id.abbrev", "e3d159d"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.commit.id.describe", "e3d159dd7"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.tags", "test_tag"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.dirty", "true"); + } + + @Test + @Parameters(method = "useNativeGit") + public void verifyEvalOnDifferentCommitWithBranchName(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_TAG_ON_DIFFERENT_BRANCH) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + + GitDescribeConfig gitDescribe = createGitDescribeConfig(true, 9); + gitDescribe.setDirty(null); + + mojo.setGitDescribe(gitDescribe); + mojo.setUseNativeGit(useNativeGit); + mojo.setEvaluateOnCommit("test"); + + // when + mojo.execute(); + + // then + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.commit.id.abbrev", "9cb810e"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.commit.id.describe", "test_tag-0-g9cb810e57"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.tags", "test_tag"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.dirty", "true"); + } + + @Test + @Parameters(method = "useNativeGit") + public void verifyEvalOnDifferentCommitWithTagName(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_TAG_ON_DIFFERENT_BRANCH) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + + GitDescribeConfig gitDescribe = createGitDescribeConfig(true, 9); + gitDescribe.setDirty(null); + + mojo.setGitDescribe(gitDescribe); + mojo.setUseNativeGit(useNativeGit); + mojo.setEvaluateOnCommit("test_tag"); + + // when + mojo.execute(); + + // then + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.commit.id.abbrev", "9cb810e"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.commit.id.describe", "test_tag-0-g9cb810e57"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.tags", "test_tag"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.dirty", "true"); + } + + @Test + @Parameters(method = "useNativeGit") + public void verifyEvalOnDifferentCommitWithCommitHash(boolean useNativeGit) throws Exception { + // given + mavenSandbox.withParentProject("my-jar-project", "jar") + .withNoChildProject() + .withGitRepoInParent(AvailableGitTestRepo.WITH_TAG_ON_DIFFERENT_BRANCH) + .create(); + MavenProject targetProject = mavenSandbox.getParentProject(); + setProjectToExecuteMojoIn(targetProject); + + GitDescribeConfig gitDescribe = createGitDescribeConfig(true, 9); + gitDescribe.setDirty(null); + + mojo.setGitDescribe(gitDescribe); + mojo.setUseNativeGit(useNativeGit); + mojo.setEvaluateOnCommit("9cb810e"); + + // when + mojo.execute(); + + // then + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.commit.id.abbrev", "9cb810e"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.commit.id.describe", "test_tag-0-g9cb810e57"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.tags", "test_tag"); + + assertPropertyPresentAndEqual(targetProject.getProperties(), "git.dirty", "true"); + } + + // TODO: Test that fails when trying to pass invalid data to evaluateOnCommit + private GitDescribeConfig createGitDescribeConfig(boolean forceLongFormat, int abbrev) { GitDescribeConfig gitDescribeConfig = new GitDescribeConfig(); gitDescribeConfig.setTags(true); diff --git a/src/test/java/pl/project13/maven/git/GitCommitIdMojoTest.java b/src/test/java/pl/project13/maven/git/GitCommitIdMojoTest.java index 84b695e5..dc0fb571 100644 --- a/src/test/java/pl/project13/maven/git/GitCommitIdMojoTest.java +++ b/src/test/java/pl/project13/maven/git/GitCommitIdMojoTest.java @@ -17,260 +17,21 @@ package pl.project13.maven.git; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.project.MavenProject; -import org.eclipse.jgit.lib.Repository; -import org.junit.Before; import org.junit.Test; -import pl.project13.maven.git.log.StdOutLoggerBridge; import java.io.File; import java.io.IOException; -import java.util.List; -import java.util.Map; + import java.util.Properties; +import java.util.regex.Pattern; import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -/** - * I'm not a big fan of this test - let's move to integration test from now on. - * - */ -// todo remove this test in favor of complete integration tests public class GitCommitIdMojoTest { - GitCommitIdMojo mojo; - JGitProvider jGitProvider; - - @Before - public void setUp() throws Exception { - File dotGitDirectory = AvailableGitTestRepo.GIT_COMMIT_ID.getDir(); - GitDescribeConfig gitDescribeConfig = new GitDescribeConfig(); - gitDescribeConfig.setSkip(false); - - String prefix = "git"; - int abbrevLength = 7; - String dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"; - - mojo = new GitCommitIdMojo(); - mojo.setDotGitDirectory(dotGitDirectory); - mojo.setPrefix(prefix); - mojo.setAbbrevLength(abbrevLength); - mojo.setDateFormat(dateFormat); - mojo.setVerbose(true); - mojo.setUseNativeGit(false); - mojo.setGitDescribe(gitDescribeConfig); - mojo.setCommitIdGenerationMode("full"); - - - mojo.project = mock(MavenProject.class, RETURNS_MOCKS); - Properties props = new Properties(); - when(mojo.project.getProperties()).thenReturn(props); - when(mojo.project.getPackaging()).thenReturn("jar"); - when(mojo.project.getVersion()).thenReturn("3.3-SNAPSHOT"); - - jGitProvider = JGitProvider.on(mojo.lookupGitDirectory(), new StdOutLoggerBridge(true)); - } - - @Test - @SuppressWarnings("") - public void shouldIncludeExpectedProperties() throws Exception { - mojo.execute(); - - Properties properties = mojo.getProperties(); - - assertThat(properties).satisfies(new ContainsKeyCondition("git.branch")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.dirty")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.full")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.abbrev")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.name")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.email")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.name")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.email")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.message.full")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.message.short")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.time")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.remote.origin.url")); - } - - @Test - @SuppressWarnings("") - public void shouldExcludeAsConfiguredProperties() throws Exception { - // given - mojo.setExcludeProperties(ImmutableList.of("git.remote.origin.url", ".*.user.*")); - - // when - mojo.execute(); - - // then - Properties properties = mojo.getProperties(); - - // explicitly excluded - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.remote.origin.url")); - - // glob excluded - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.build.user.name")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.build.user.email")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.user.name")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.user.email")); - - // these stay - assertThat(properties).satisfies(new ContainsKeyCondition("git.branch")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.full")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.abbrev")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.message.full")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.message.short")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.time")); - } - - @Test - public void shouldIncludeOnlyAsConfiguredProperties() throws Exception { - // given - mojo.setIncludeOnlyProperties(ImmutableList.of("git.remote.origin.url", ".*.user.*", "^git.commit.id.full$")); - - // when - mojo.execute(); - - // then - Properties properties = mojo.getProperties(); - - // explicitly included - assertThat(properties).satisfies(new ContainsKeyCondition("git.remote.origin.url")); - - // glob included - assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.name")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.email")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.id.full")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.name")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.email")); - - // these excluded - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.branch")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.id.abbrev")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.message.full")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.message.short")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.time")); - } - - @Test - public void shouldExcludeAndIncludeAsConfiguredProperties() throws Exception { - // given - mojo.setIncludeOnlyProperties(ImmutableList.of("git.remote.origin.url", ".*.user.*")); - mojo.setExcludeProperties(ImmutableList.of("git.build.user.email")); - - // when - mojo.execute(); - - // then - Properties properties = mojo.getProperties(); - - // explicitly included - assertThat(properties).satisfies(new ContainsKeyCondition("git.remote.origin.url")); - - // explicitly excluded -> overrules include only properties - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.build.user.email")); - - // glob included - assertThat(properties).satisfies(new ContainsKeyCondition("git.build.user.name")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.name")); - assertThat(properties).satisfies(new ContainsKeyCondition("git.commit.user.email")); - - // these excluded - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.branch")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.id.full")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.id.abbrev")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.message.full")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.message.short")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.commit.time")); - } - - @Test - @SuppressWarnings("") - public void shouldHaveNoPrefixWhenConfiguredPrefixIsEmptyStringAsConfiguredProperties() throws Exception { - // given - mojo.setPrefix(""); - - // when - mojo.execute(); - - // then - Properties properties = mojo.getProperties(); - - // explicitly excluded - assertThat(properties).satisfies(new DoesNotContainKeyCondition("git.remote.origin.url")); - assertThat(properties).satisfies(new DoesNotContainKeyCondition(".remote.origin.url")); - assertThat(properties).satisfies(new ContainsKeyCondition("remote.origin.url")); - } - - @Test - public void shouldSkipDescribeWhenConfiguredToDoSo() throws Exception { - // given - GitDescribeConfig config = new GitDescribeConfig(); - config.setSkip(true); - - // when - mojo.setGitDescribe(config); - mojo.execute(); - - // then - assertThat(mojo.getProperties()).satisfies(new DoesNotContainKeyCondition("git.commit.id.describe")); - } - - @Test - public void shouldUseJenkinsBranchInfoWhenAvailable() throws GitCommitIdExecutionException, IOException { - // given - Repository git = mock(Repository.class); - Map env = Maps.newHashMap(); - - String detachedHeadSha1 = "16bb801934e652f5e291a003db05e364d83fba25"; - String ciUrl = "http://myciserver.com"; - - when(git.getBranch()).thenReturn(detachedHeadSha1); - jGitProvider.setRepository(git); - // when - // in a detached head state, getBranch() will return the SHA1...standard behavior - assertThat(detachedHeadSha1).isEqualTo(jGitProvider.determineBranchName(env)); - - // again, SHA1 will be returned if we're in jenkins, but GIT_BRANCH is not set - env.put("JENKINS_URL", "http://myjenkinsserver.com"); - assertThat(detachedHeadSha1).isEqualTo(jGitProvider.determineBranchName(env)); - - // now set GIT_BRANCH too and see that the branch name from env var is returned - env.clear(); - env.put("JENKINS_URL", ciUrl); - env.put("GIT_BRANCH", "mybranch"); - assertThat("mybranch").isEqualTo(jGitProvider.determineBranchName(env)); - - // same, but for hudson - env.clear(); - env.put("GIT_BRANCH", "mybranch"); - env.put("HUDSON_URL", ciUrl); - assertThat("mybranch").isEqualTo(jGitProvider.determineBranchName(env)); - - // now set GIT_LOCAL_BRANCH too and see that the branch name from env var is returned - env.clear(); - env.put("JENKINS_URL", ciUrl); - env.put("GIT_BRANCH", "mybranch"); - env.put("GIT_LOCAL_BRANCH", "mylocalbranch"); - assertThat("mylocalbranch").isEqualTo(jGitProvider.determineBranchName(env)); - - // same, but for hudson - env.clear(); - env.put("GIT_BRANCH", "mybranch"); - env.put("GIT_LOCAL_BRANCH", "mylocalbranch"); - env.put("HUDSON_URL", ciUrl); - assertThat("mylocalbranch").isEqualTo(jGitProvider.determineBranchName(env)); - - // GIT_BRANCH but no HUDSON_URL or JENKINS_URL - env.clear(); - env.put("GIT_BRANCH", "mybranch"); - env.put("GIT_BRANCH", "mylocalbranch"); - assertThat(detachedHeadSha1).isEqualTo(jGitProvider.determineBranchName(env)); - } - @Test public void loadShortDescribe() { assertShortDescribe("1.0.2-12-g19471", "1.0.2-12"); @@ -317,13 +78,17 @@ public void testCraftPropertiesOutputFileWithFullPath() throws IOException { } @Test - public void shouldPerformReplacements() throws MojoExecutionException { - mojo.propertiesReplacer = mock(PropertiesReplacer.class); - mojo.replacementProperties = mock(List.class); - - mojo.execute(); - - verify(mojo.propertiesReplacer).performReplacement(any(Properties.class), eq(mojo.replacementProperties)); + public void verifyAllowedCharactersForEvaluateOnCommit() throws MojoExecutionException { + Pattern p = GitCommitIdMojo.allowedCharactersForEvaluateOnCommit; + assertTrue(p.matcher("5957e419d").matches()); + assertTrue(p.matcher("my_tag").matches()); + assertTrue(p.matcher("my-tag").matches()); + assertTrue(p.matcher("my.tag").matches()); + assertTrue(p.matcher("HEAD^1").matches()); + assertTrue(p.matcher("feature/branch").matches()); + + assertFalse(p.matcher("; CODE INJECTION").matches()); + assertFalse(p.matcher("|exit").matches()); + assertFalse(p.matcher("&&cat /etc/passwd").matches()); } - } diff --git a/src/test/java/pl/project13/maven/git/GitIntegrationTest.java b/src/test/java/pl/project13/maven/git/GitIntegrationTest.java index 0348d2d5..4a0227e9 100644 --- a/src/test/java/pl/project13/maven/git/GitIntegrationTest.java +++ b/src/test/java/pl/project13/maven/git/GitIntegrationTest.java @@ -32,6 +32,7 @@ public abstract class GitIntegrationTest { private static final String SANDBOX_DIR = "target" + File.separator + "sandbox" + File.separator; + protected static final String evaluateOnCommit = "HEAD"; /** * Sandbox directory with unique name for current test. @@ -105,6 +106,7 @@ public static void initializeMojoWithDefaults(GitCommitIdMojo mojo) { mojo.setFailOnNoGitDirectory(true); mojo.setUseNativeGit(false); mojo.setCommitIdGenerationMode("full"); + mojo.setEvaluateOnCommit(evaluateOnCommit); } public void setProjectToExecuteMojoIn(@NotNull MavenProject project) {