diff --git a/pom.xml b/pom.xml index 7a01cc3a..e0c27dd1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,8 +6,8 @@ com.github.danielflower.mavenplugins multi-module-maven-release-plugin - 3.6-SNAPSHOT - + 3.7-SNAPSHOT + The Multi Module Maven Release Plugin A maven release plugin built for multi-maven-module git repositories allowing continuous deployment diff --git a/src/main/java/com/github/danielflower/mavenplugins/release/BaseMojo.java b/src/main/java/com/github/danielflower/mavenplugins/release/BaseMojo.java index ca53fcf8..253e43d8 100644 --- a/src/main/java/com/github/danielflower/mavenplugins/release/BaseMojo.java +++ b/src/main/java/com/github/danielflower/mavenplugins/release/BaseMojo.java @@ -1,5 +1,10 @@ package com.github.danielflower.mavenplugins.release; +import static java.lang.String.format; + +import java.util.List; +import java.util.Set; + import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.resolver.ArtifactResolver; @@ -16,41 +21,38 @@ import org.eclipse.jgit.transport.JschConfigSessionFactory; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; -import java.util.List; - -import static java.lang.String.format; - /** * @author Roland Hauser sourcepond@gmail.com * */ public abstract class BaseMojo extends AbstractMojo { - /** - * The Maven Project. - */ - @Parameter(property = "project", required = true, readonly = true, defaultValue = "${project}") - protected MavenProject project; - - @Parameter(property = "projects", required = true, readonly = true, defaultValue = "${reactorProjects}") - protected List projects; - - /** - *

- * The build number to use in the release version. Given a snapshot version - * of "1.0-SNAPSHOT" and a buildNumber value of "2", the actual released - * version will be "1.0.2". - *

- *

- * By default, the plugin will automatically find a suitable build number. - * It will start at version 0 and increment this with each release. - *

- *

- * This can be specified using a command line parameter ("-DbuildNumber=2") - * or in this plugin's configuration. - *

- */ - @Parameter(property = "buildNumber") - protected Long buildNumber; + + /** + * The Maven Project. + */ + @Parameter(property = "project", required = true, readonly = true, defaultValue = "${project}") + protected MavenProject project; + + @Parameter(property = "projects", required = true, readonly = true, defaultValue = "${reactorProjects}") + protected List projects; + + /** + *

+ * The build number to use in the release version. Given a snapshot version + * of "1.0-SNAPSHOT" and a buildNumber value of "2", the actual released + * version will be "1.0.2". + *

+ *

+ * By default, the plugin will automatically find a suitable build number. + * It will start at version 0 and increment this with each release. + *

+ *

+ * This can be specified using a command line parameter ("-DbuildNumber=2") + * or in this plugin's configuration. + *

+ */ + @Parameter(property = "buildNumber") + protected Long buildNumber; /** @@ -61,20 +63,20 @@ public abstract class BaseMojo extends AbstractMojo { @Parameter(property = "versionNamer") protected VersionNamer versionNamer = new VersionNamer("."); - /** - * The modules to release, or no value to to release the project from the - * root pom, which is the default. The selected module plus any other - * modules it needs will be built and released also. When run from the - * command line, this can be a comma-separated list of module names. - */ - @Parameter(alias = "modulesToRelease", property = "modulesToRelease") - protected List modulesToRelease; - - /** - * A module to force release on, even if no changes has been detected. - */ - @Parameter(alias = "forceRelease", property = "forceRelease") - protected List modulesToForceRelease; + /** + * The modules to release, or no value to to release the project from the + * root pom, which is the default. The selected module plus any other + * modules it needs will be built and released also. When run from the + * command line, this can be a comma-separated list of module names. + */ + @Parameter(alias = "modulesToRelease", property = "modulesToRelease") + protected List modulesToRelease; + + /** + * A module to force release on, even if no changes has been detected. + */ + @Parameter(alias = "forceRelease", property = "forceRelease") + protected List modulesToForceRelease; /** * Determines the action to take when no module changes are detected. Possible values: @@ -108,40 +110,40 @@ public abstract class BaseMojo extends AbstractMojo { @Parameter(property = "localRepository", required = true, readonly = true, defaultValue = "${localRepository}") protected ArtifactRepository localRepository; - @Parameter(property = "disableSshAgent") - private boolean disableSshAgent; + @Parameter(property = "disableSshAgent") + private boolean disableSshAgent; - @Parameter(defaultValue = "${settings}", readonly = true, required = true) - private Settings settings; + @Parameter(defaultValue = "${settings}", readonly = true, required = true) + private Settings settings; - /** - *

If set, the identityFile and passphrase will be read from the Maven settings file.

+ /** + *

If set, the identityFile and passphrase will be read from the Maven settings file.

*

See https://maven.apache.org/guides/mini/guide-deployment-security-settings.html * for more information on configuring servers in Maven.

- */ - @Parameter(property = "serverId") - private String serverId; - - /** - * If set, this file will be used to specify the known_hosts. This will - * override any default value. - */ - @Parameter(property = "knownHosts") - private String knownHosts; - - /** - * Specifies the private key to be used for SSH URLs. By default it will use ~/.ssh/id_rsa - */ - @Parameter(property = "privateKey") - private String privateKey; - - /** - *

Specifies the passphrase to be used with the identityFile specified for SSH where the private key requires a pass phrase.

+ */ + @Parameter(property = "serverId") + private String serverId; + + /** + * If set, this file will be used to specify the known_hosts. This will + * override any default value. + */ + @Parameter(property = "knownHosts") + private String knownHosts; + + /** + * Specifies the private key to be used for SSH URLs. By default it will use ~/.ssh/id_rsa + */ + @Parameter(property = "privateKey") + private String privateKey; + + /** + *

Specifies the passphrase to be used with the identityFile specified for SSH where the private key requires a pass phrase.

*

To avoid specifying a passphrase in your pom, you could instead specify a server in your * maven settings file and then set the serverId property.

- */ - @Parameter(property = "passphrase") - private String passphrase; + */ + @Parameter(property = "passphrase") + private String passphrase; /** * Fetch tags from remote repository to determine the next build number. If @@ -161,35 +163,52 @@ public abstract class BaseMojo extends AbstractMojo { @Parameter(property = "arguments") public String arguments; + /** + *

List of relative file system paths to ignore when detecting changes in the project(s).

+ *

The primary purpose is to skip creating new releases if only "infrastructure" files such as + * .gitignore, .editorconfig and the like changed. Very basic wild cards are supported as + * follows: + *

    + *
  • foo.txt - matches foo.txt in the root of the top-level project
  • + *
  • bar/foo.txt - matches foo.txt in the root of the bar directory
  • + *
  • bar - matches the foo directory and ignores everything below
  • + *
  • **.txt - matches all paths ending in .txt (suffix match)
  • + *
  • **.editorconfig - matches all .editorconfig files in all (sub)directories; a special case of suffix matching
  • + *
      + *

      + */ + @Parameter(property = "ignoredPaths") + Set ignoredPaths; + final void setSettings(final Settings settings) { - this.settings = settings; - } + this.settings = settings; + } final Settings getSettings() { return settings; } - final void setServerId(final String serverId) { - this.serverId = serverId; - } + final void setServerId(final String serverId) { + this.serverId = serverId; + } - final void setKnownHosts(final String knownHosts) { - this.knownHosts = knownHosts; - } + final void setKnownHosts(final String knownHosts) { + this.knownHosts = knownHosts; + } - final void setPrivateKey(final String privateKey) { - this.privateKey = privateKey; - } + final void setPrivateKey(final String privateKey) { + this.privateKey = privateKey; + } - final void setPassphrase(final String passphrase) { - this.passphrase = passphrase; - } + final void setPassphrase(final String passphrase) { + this.passphrase = passphrase; + } - final void disableSshAgent() { - disableSshAgent = true; - } + final void disableSshAgent() { + disableSshAgent = true; + } - protected CredentialsProvider getCredentialsProvider(final Log log) throws ValidationException { + protected CredentialsProvider getCredentialsProvider(final Log log) throws ValidationException { if (serverId != null) { Server server = settings.getServer(serverId); if (server == null) { @@ -204,21 +223,21 @@ protected CredentialsProvider getCredentialsProvider(final Log log) throws Valid return null; } - protected final void configureJsch(final Log log) { - if (!disableSshAgent) { - if (serverId != null) { - final Server server = settings.getServer(serverId); - if (server != null) { - privateKey = privateKey == null ? server.getPrivateKey() : privateKey; - passphrase = passphrase == null ? server.getPassphrase() : passphrase; - } else { - log.warn(format("No server configuration in Maven settings found with id %s", serverId)); - } - } - - JschConfigSessionFactory.setInstance(new SshAgentSessionFactory(log, knownHosts, privateKey, passphrase)); - } - } + protected final void configureJsch(final Log log) { + if (!disableSshAgent) { + if (serverId != null) { + final Server server = settings.getServer(serverId); + if (server != null) { + privateKey = privateKey == null ? server.getPrivateKey() : privateKey; + passphrase = passphrase == null ? server.getPassphrase() : passphrase; + } else { + log.warn(format("No server configuration in Maven settings found with id %s", serverId)); + } + } + + JschConfigSessionFactory.setInstance(new SshAgentSessionFactory(log, knownHosts, privateKey, passphrase)); + } + } static void printBigErrorMessageAndThrow(Log log, String terseMessage, List linesToLog) throws MojoExecutionException { log.error(""); diff --git a/src/main/java/com/github/danielflower/mavenplugins/release/NextMojo.java b/src/main/java/com/github/danielflower/mavenplugins/release/NextMojo.java index de41f73f..a1cc705d 100644 --- a/src/main/java/com/github/danielflower/mavenplugins/release/NextMojo.java +++ b/src/main/java/com/github/danielflower/mavenplugins/release/NextMojo.java @@ -46,7 +46,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { .credentialsProvider(getCredentialsProvider(log)) .buildFromCurrentDir(); ResolverWrapper resolverWrapper = new ResolverWrapper(factory, artifactResolver, remoteRepositories, localRepository); - Reactor reactor = Reactor.fromProjects(log, repo, project, projects, buildNumber, modulesToForceRelease, noChangesAction, resolverWrapper, versionNamer); + Reactor reactor = Reactor.fromProjects(log, repo, project, projects, buildNumber, modulesToForceRelease, noChangesAction, resolverWrapper, versionNamer, ignoredPaths); if (reactor == null) { return; } diff --git a/src/main/java/com/github/danielflower/mavenplugins/release/Reactor.java b/src/main/java/com/github/danielflower/mavenplugins/release/Reactor.java index 3ef17308..0049e0d6 100644 --- a/src/main/java/com/github/danielflower/mavenplugins/release/Reactor.java +++ b/src/main/java/com/github/danielflower/mavenplugins/release/Reactor.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Set; import static com.github.danielflower.mavenplugins.release.MavenVersionResolver.resolveVersionsDefinedThroughProperties; @@ -28,8 +29,8 @@ public List getModulesInBuildOrder() { return modulesInBuildOrder; } - public static Reactor fromProjects(Log log, LocalGitRepo gitRepo, MavenProject rootProject, List projects, Long buildNumber, List modulesToForceRelease, NoChangesAction actionWhenNoChangesDetected, ResolverWrapper resolverWrapper, VersionNamer versionNamer) throws ValidationException, GitAPIException, MojoExecutionException { - DiffDetector detector = new TreeWalkingDiffDetector(gitRepo.git.getRepository()); + public static Reactor fromProjects(Log log, LocalGitRepo gitRepo, MavenProject rootProject, List projects, Long buildNumber, List modulesToForceRelease, NoChangesAction actionWhenNoChangesDetected, ResolverWrapper resolverWrapper, VersionNamer versionNamer, Set ignoredPaths) throws ValidationException, GitAPIException, MojoExecutionException { + DiffDetector detector = new TreeWalkingDiffDetector(gitRepo.git.getRepository(), ignoredPaths); List modules = new ArrayList(); resolveVersionsDefinedThroughProperties(projects); @@ -121,7 +122,7 @@ public static Reactor fromProjects(Log log, LocalGitRepo gitRepo, MavenProject r throw new MojoExecutionException("No module changes have been detected"); default: log.warn("No changes have been detected in any modules so will re-release them all"); - List newList = new ArrayList(); + List newList = new ArrayList<>(); for (ReleasableModule module : modules) { newList.add(module.createReleasableVersion()); } diff --git a/src/main/java/com/github/danielflower/mavenplugins/release/ReleaseMojo.java b/src/main/java/com/github/danielflower/mavenplugins/release/ReleaseMojo.java index 2cc6da85..f7829b1a 100644 --- a/src/main/java/com/github/danielflower/mavenplugins/release/ReleaseMojo.java +++ b/src/main/java/com/github/danielflower/mavenplugins/release/ReleaseMojo.java @@ -69,27 +69,27 @@ public class ReleaseMojo extends BaseMojo { */ @Parameter(alias = "skipTests", defaultValue = "false", property = "skipTests") private boolean skipTests; - - /** - * Specifies a custom, user specific Maven settings file to be used during the release build. + + /** + * Specifies a custom, user specific Maven settings file to be used during the release build. * * @deprecated In versions prior to 2.1, if the plugin was run with custom user settings the settings were ignored * during the release phase. Now that custom settings are inherited, setting this value is no longer needed. * Please use the '-s' command line parameter to set custom user settings. - */ - @Parameter(alias = "userSettings") - private File userSettings; + */ + @Parameter(alias = "userSettings") + private File userSettings; - /** - * Specifies a custom, global Maven settings file to be used during the release build. + /** + * Specifies a custom, global Maven settings file to be used during the release build. * * @deprecated In versions prior to 2.1, if the plugin was run with custom global settings the settings were ignored * during the release phase. Now that custom settings are inherited, setting this value is no longer needed. * Please use the '-gs' command line parameter to set custom global settings. */ - @Parameter(alias = "globalSettings") - private File globalSettings; - + @Parameter(alias = "globalSettings") + private File globalSettings; + /** * Push tags to remote repository as they are created. */ @@ -159,7 +159,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { repo.errorIfNotClean(ignoredUntrackedPaths); ResolverWrapper resolverWrapper = new ResolverWrapper(factory, artifactResolver, remoteRepositories, localRepository); - Reactor reactor = Reactor.fromProjects(log, repo, project, projects, buildNumber, modulesToForceRelease, noChangesAction, resolverWrapper, versionNamer); + Reactor reactor = Reactor.fromProjects(log, repo, project, projects, buildNumber, modulesToForceRelease, noChangesAction, resolverWrapper, versionNamer, ignoredPaths); if (reactor == null) { return; } @@ -180,8 +180,8 @@ public void execute() throws MojoExecutionException, MojoFailureException { tagAndPushRepo(log, repo, proposedTags); try { - final ReleaseInvoker invoker = new ReleaseInvoker(getLog(), project); - invoker.setGlobalSettings(globalSettings); + final ReleaseInvoker invoker = new ReleaseInvoker(getLog(), project); + invoker.setGlobalSettings(globalSettings); if (userSettings != null) { invoker.setUserSettings(userSettings); } else if (getSettings() != null) { @@ -190,11 +190,11 @@ public void execute() throws MojoExecutionException, MojoFailureException { new DefaultSettingsWriter().write(settingsFile, null, getSettings()); invoker.setUserSettings(settingsFile); } - invoker.setGoals(goals); - invoker.setModulesToRelease(modulesToRelease); - invoker.setReleaseProfiles(releaseProfiles); - invoker.setSkipTests(skipTests); - invoker.setArguments(arguments); + invoker.setGoals(goals); + invoker.setModulesToRelease(modulesToRelease); + invoker.setReleaseProfiles(releaseProfiles); + invoker.setSkipTests(skipTests); + invoker.setArguments(arguments); invoker.runMavenBuild(reactor); revertChanges(log, repo, changedFiles, true); // throw if you can't revert as that is the root problem diff --git a/src/main/java/com/github/danielflower/mavenplugins/release/TreeWalkingDiffDetector.java b/src/main/java/com/github/danielflower/mavenplugins/release/TreeWalkingDiffDetector.java index 81fd260c..ba1e6c67 100644 --- a/src/main/java/com/github/danielflower/mavenplugins/release/TreeWalkingDiffDetector.java +++ b/src/main/java/com/github/danielflower/mavenplugins/release/TreeWalkingDiffDetector.java @@ -6,34 +6,70 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.filter.AndTreeFilter; import org.eclipse.jgit.treewalk.filter.PathFilter; +import org.eclipse.jgit.treewalk.filter.PathSuffixFilter; import org.eclipse.jgit.treewalk.filter.TreeFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; public class TreeWalkingDiffDetector implements DiffDetector { private final Repository repo; + private final Set ignoredPaths; - public TreeWalkingDiffDetector(Repository repo) { + TreeWalkingDiffDetector(Repository repo, Set ignoredPaths) { this.repo = repo; + this.ignoredPaths = ignoredPaths; } - public boolean hasChangedSince(String modulePath, java.util.List childModules, Collection tags) throws IOException { + TreeWalkingDiffDetector(Repository repository) { + this(repository, Collections.emptySet()); + } + + public boolean hasChangedSince(String modulePath, List childModules, Collection tags) throws IOException { RevWalk walk = new RevWalk(repo); try { walk.setRetainBody(false); walk.markStart(walk.parseCommit(repo.getRefDatabase().findRef("HEAD").getObjectId())); - filterOutOtherModulesChanges(modulePath, childModules, walk); + + List treeFilters = createTreeFiltersForOtherModulesChanges(modulePath, childModules); + treeFilters.addAll(createTreeFiltersForIgnoredPaths()); + walk.setTreeFilter(treeFilters.size() == 1 ? treeFilters.get(0) : AndTreeFilter.create(treeFilters)); stopWalkingWhenTheTagsAreHit(tags, walk); + return walk.iterator().hasNext(); } finally { walk.dispose(); } } + private Collection createTreeFiltersForIgnoredPaths() { + List treeFilters = new ArrayList<>(); + if (ignoredPaths != null) { + treeFilters.addAll( + ignoredPaths.stream() + // To differentiate path suffix filters from path filters in the configuration there is the special + // "**" prefix. + // foo.txt -> path filter that matches foo.txt in the root of the top-level project + // bar/foo.txt -> path filter that matches foo.txt in the root of the bar directory + // bar -> path filter that matches everything in/under the bar directory + // **.txt -> path suffix filter that matches all paths ending in .txt (suffix match) + // **.editorconfig -> path suffix filter that matches all .editorconfig files in all (sub)directories; a special case of suffix matching + .map(p -> p.startsWith("**") ? PathSuffixFilter.create(p.substring(2)): PathFilter.create(p)) + // tree filters define what to include, yet the users define what to IGNORE -> negate the filter + .map(TreeFilter::negate) + .collect(Collectors.toList()) + ); + } + return treeFilters; + } + private static void stopWalkingWhenTheTagsAreHit(Collection tags, RevWalk walk) throws IOException { for (AnnotatedTag tag : tags) { ObjectId commitId = tag.ref().getTarget().getObjectId(); @@ -42,7 +78,7 @@ private static void stopWalkingWhenTheTagsAreHit(Collection tags, } } - private void filterOutOtherModulesChanges(String modulePath, List childModules, RevWalk walk) { + private List createTreeFiltersForOtherModulesChanges(String modulePath, List childModules) { boolean isRootModule = ".".equals(modulePath); boolean isMultiModuleProject = !isRootModule || !childModules.isEmpty(); List treeFilters = new ArrayList<>(); @@ -60,7 +96,6 @@ private void filterOutOtherModulesChanges(String modulePath, List childM } } - TreeFilter treeFilter = treeFilters.size() == 1 ? treeFilters.get(0) : AndTreeFilter.create(treeFilters); - walk.setTreeFilter(treeFilter); + return treeFilters; } } diff --git a/src/site/markdown/changelog.md b/src/site/markdown/changelog.md index 2cb828ec..4c11c852 100644 --- a/src/site/markdown/changelog.md +++ b/src/site/markdown/changelog.md @@ -1,6 +1,10 @@ Changelog --------- +### 3.7.0 + +* Allow to define paths which should be ignored when detecting changes (`.gitignore` et.al.), #77 + ### 3.6.0 * Latest tagged version from current branch is used for unchanged modules [issue #118 for details](https://github.com/danielflower/multi-module-maven-release-plugin/issues/118) @@ -9,7 +13,7 @@ Changelog * Added support for processing version properties e.g. `${foo.version}` * Added support for processing dependencies in `` sections e.g. for BOMs -* Fix bugs with custom delimiters (joins build number to version) +* Fix bugs with custom delimiters (joins build number to version) ### 3.1.2 @@ -91,7 +95,7 @@ Warning: inadvertently requires java 8 (rather than java 7). Use 2.0.11 for java #### 1.3.4 * Fixed bug where a partial build failure where a single commit has multiple tags could result in subsequent releases -failing due to the plugin picking the older tag to use when it is detected that the module hadn't changed. +failing due to the plugin picking the older tag to use when it is detected that the module hadn't changed. ### 1.3.0 @@ -112,9 +116,9 @@ should force all children to be updated. ### 1.1.0 -* Bug fix: tags are now pushed before building so that in the event of failure, the next build will use an incremented build number. -This is needed for cases where part of the build succeeded and some module(s) were uploaded to Nexus - re-uploading would cause an -error if the build number is not incremented. +* Bug fix: tags are now pushed before building so that in the event of failure, the next build will use an incremented build number. +This is needed for cases where part of the build succeeded and some module(s) were uploaded to Nexus - re-uploading would cause an +error if the build number is not incremented. #### 1.0.2 diff --git a/src/test/java/com/github/danielflower/mavenplugins/release/IgnorePathsTest.java b/src/test/java/com/github/danielflower/mavenplugins/release/IgnorePathsTest.java new file mode 100644 index 00000000..5793c556 --- /dev/null +++ b/src/test/java/com/github/danielflower/mavenplugins/release/IgnorePathsTest.java @@ -0,0 +1,85 @@ +package com.github.danielflower.mavenplugins.release; + +import static com.github.danielflower.mavenplugins.release.AnnotatedTagFinderTest.saveFileInModuleAndTag; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + +import org.eclipse.jgit.api.errors.GitAPIException; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.collect.Sets; + +import scaffolding.TestProject; + +@RunWith(Parameterized.class) +public class IgnorePathsTest { + private static TestProject project; + private static AnnotatedTag tag; + + @Parameter + public String ignoredPathsPattern; + + @Parameter(1) + public boolean changeExpected; + + @BeforeClass + public static void setup() throws IOException, GitAPIException { + project = TestProject.nestedProject(); + // create & commit a random file, then create a tag at that revision + tag = saveFileInModuleAndTag(project, "server-modules", "1.0", 0); + // create & commit three more files but do NOT create a tag at that revision + // -> changes in the project (-> signal for the plugin to release those) + project.commitFile("server-modules", "paul.txt"); + project.commitFile("core-utils", "muller.txt"); + project.commitFile("core-utils", "dave.txt"); + project.commitFile("core-utils", "john.txt"); + project.commitFile("parent-module", "muller.txt"); + project.commitFile("parent-module", "dave.txt"); + project.commitFile("parent-module", "john.txt"); + project.commitFile(".", "4711.txt"); + } + + @Parameters(name = "{0} -> has changes: {1}") + public static Collection data() { + return Arrays.asList( + new Object[]{"**.txt", false}, // all .txt are ignored -> no (other) changes + new Object[]{"core-utils", true}, // only 1 directory ignored -> there are (other) changes + new Object[]{"core-utils/muller.txt", true}, // only 1 file in 1 directory ignored -> there are (other) changes + new Object[]{"4711.txt", true}, // only 1 file ignored -> there are (other) changes + new Object[]{null, true}, // no file ignored -> there are (other) changes + new Object[]{"server-modules/paul.txt,core-utils/,parent-module/,4711.txt", false}, // all file ignored -> no (other) changes + new Object[]{"server-modules/paul.txt,core-utils/muller.txt,core-utils/dave.txt,core-utils/john.txt,parent-module/muller.txt,parent-module/dave.txt,parent-module/john.txt,4711.txt", false} // all file ignored -> no (other) changes + ); + } + + @Test + public void shouldConsiderIgnoredPathsWhenDetectingChanges() throws IOException { + // given the test project in setup() @BeforeClass + Set ignoredPaths = Objects.isNull(ignoredPathsPattern) ? null : Sets.newHashSet(ignoredPathsPattern.split(",|;")); + DiffDetector detector = new TreeWalkingDiffDetector(project.local.getRepository(), ignoredPaths); + + // when + boolean hasChangedSince = detector.hasChangedSince(".", Collections.emptyList(), singletonListOf(tag)); + + // then + assertThat(hasChangedSince, is(changeExpected)); + } + + private static Collection singletonListOf(AnnotatedTag tag) { + return Collections.singletonList(tag); + } + + +} diff --git a/src/test/java/scaffolding/TestProject.java b/src/test/java/scaffolding/TestProject.java index e89f6fe7..804b270b 100644 --- a/src/test/java/scaffolding/TestProject.java +++ b/src/test/java/scaffolding/TestProject.java @@ -4,7 +4,15 @@ import org.apache.commons.io.filefilter.FileFilterUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.InitCommand; +import org.eclipse.jgit.api.errors.AbortedByHookException; +import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.api.errors.NoFilepatternException; +import org.eclipse.jgit.api.errors.NoHeadException; +import org.eclipse.jgit.api.errors.NoMessageException; +import org.eclipse.jgit.api.errors.ServiceUnavailableException; +import org.eclipse.jgit.api.errors.UnmergedPathsException; +import org.eclipse.jgit.api.errors.WrongRepositoryStateException; import java.io.File; import java.io.FileFilter; @@ -19,7 +27,7 @@ public class TestProject { private static final MvnRunner defaultRunner = new MvnRunner(null); - private static final String PLUGIN_VERSION_FOR_TESTS = "3.6-SNAPSHOT"; + private static final String PLUGIN_VERSION_FOR_TESTS = "3.7-SNAPSHOT"; public final File originDir; public final Git origin; @@ -63,11 +71,18 @@ public List mvnReleaserNext(String buildNumber, String...arguments) thro } public TestProject commitRandomFile(String module) throws IOException, GitAPIException { + String filenameAndPostfix = UUID.randomUUID() + ".txt"; + return commitFile(module, filenameAndPostfix); + } + + public TestProject commitFile(String module, String filenameAndPostfix) throws IOException, GitAPIException, + NoFilepatternException, AbortedByHookException, ConcurrentRefUpdateException, NoHeadException, + NoMessageException, ServiceUnavailableException, UnmergedPathsException, WrongRepositoryStateException { File moduleDir = new File(localDir, module); if (!moduleDir.isDirectory()) { throw new RuntimeException("Could not find " + moduleDir.getCanonicalPath()); } - File random = new File(moduleDir, UUID.randomUUID() + ".txt"); + File random = new File(moduleDir, filenameAndPostfix); random.createNewFile(); String modulePath = module.equals(".") ? "" : module + "/"; local.add().addFilepattern(modulePath + random.getName()).call(); @@ -186,7 +201,7 @@ public static TestProject dependencyManagementProject() { } public static TestProject dependencyManagementUsingParentModuleVersionPropertyProject() { - return project("dependencymanagement-using-parent-module-version-property"); + return project("dependencymanagement-using-parent-module-version-property"); } public static TestProject moduleWithTestFailure() {