Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to ignore certain files from the Git repo change detection #94

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.github.danielflower.mavenplugins</groupId>
<artifactId>multi-module-maven-release-plugin</artifactId>
<version>3.2-SNAPSHOT</version> <!-- When changing also update scaffolding.TestProject.PLUGIN_VERSION_FOR_TESTS and add to src/site/markdown/changelog.md -->
<version>3.4-SNAPSHOT</version> <!-- When changing also update scaffolding.TestProject.PLUGIN_VERSION_FOR_TESTS and add to src/site/markdown/changelog.md -->

<name>The Multi Module Maven Release Plugin</name>
<description>A maven release plugin built for multi-maven-module git repositories allowing continuous deployment
Expand Down Expand Up @@ -123,6 +121,15 @@
<artifactId>maven-invoker</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<!--
The maven-dependency-plugin wants this to be listed explicitly as it comes as a transitive dependency
of maven-model.
-->
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ private AnnotatedTag(Ref ref, String name, JSONObject message) {
this.message = message;
}

public static AnnotatedTag create(String name, String version, long buildNumber) {
public static AnnotatedTag create(String name, String version, String buildNumber) {
JSONObject message = new JSONObject();
message.put(VERSION, version);
message.put(BUILD_NUMBER, String.valueOf(buildNumber));
message.put(BUILD_NUMBER, buildNumber);
return new AnnotatedTag(null, name, message);
}

Expand Down Expand Up @@ -67,8 +67,8 @@ public String version() {
return String.valueOf(message.get(VERSION));
}

public long buildNumber() {
return Long.parseLong(String.valueOf(message.get(BUILD_NUMBER)));
public String buildNumber() {
return String.valueOf(message.get(BUILD_NUMBER));
}

public Ref saveAtHEAD(Git git) throws GitAPIException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,12 @@ boolean isPotentiallySameVersionIgnoringBuildNumber(String versionWithoutBuildNu
return buildNumberOf(versionWithoutBuildNumber, refName) != null;
}

Long buildNumberOf(String versionWithoutBuildNumber, String refName) {
String buildNumberOf(String versionWithoutBuildNumber, String refName) {
String tagName = AnnotatedTag.stripRefPrefix(refName);
String prefix = versionWithoutBuildNumber + versionNamer.getDelimiter();
if (tagName.startsWith(prefix)) {
String end = tagName.substring(prefix.length());
try {
return Long.parseLong(end);
} catch (NumberFormatException e) {
return null;
}
return tagName.substring(prefix.length());
}
return null;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.danielflower.mavenplugins.release;

import org.apache.commons.lang3.StringUtils;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolver;
Expand All @@ -17,15 +18,17 @@
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;

import java.util.List;
import java.util.Set;

import static java.lang.String.format;
import static java.util.Arrays.asList;

/**
* @author Roland Hauser [email protected]
*
*/
public abstract class BaseMojo extends AbstractMojo {
private PluginConfiguration pluginConfiguration;

/**
* The Maven Project.
*/
Expand All @@ -43,16 +46,37 @@ public abstract class BaseMojo extends AbstractMojo {
* </p>
* <p>
* By default, the plugin will automatically find a suitable build number.
* It will start at version 0 and increment this with each release.
* It will start at 0 and increment this with each release.
* </p>
* <p>
* This can be specified using a command line parameter ("-DbuildNumber=2")
* or in this plugin's configuration.
* This can be specified using a command line parameter (e.g.
* <code>-DbuildNumber=2</code>) or in this plugin's configuration.
* </p>
* <p>
* <strong>null vs. ""</strong>: if you do not define the build number it
* is treated as <code>null</code> and the plugin will start at 0. If you
* pass an empty string both the build number and the delimiter that
* precedes it will be omitted.<br>To define an empty string on the CLI use
* <code>-DbuildNumber=''</code>. For the same effect in the POM you can
* use <code>&lt;buildNumber&gt;""&lt;/buildNumber&gt;</code> as Maven does
* not support empty strings for configuration properties. The plugin will
* convert this accordingly.
* </p>
*/
// Maven has historically never supported empty strings in XML plugin configuration (see
// http://mail-archives.apache.org/mod_mbox/maven-users/200708.mbox/%[email protected]%3E
// from 2007). Hence, if a project defines <buildNumber></buildNumber> the property here will be null. However,
// Maven does support -DbuildNumber='' on the CLI.
@Parameter(property = "buildNumber")
protected Long buildNumber;
protected String buildNumber;

public void setBuildNumber(String buildNumber) {
if ("\"\"".equals(buildNumber)) {
this.buildNumber = StringUtils.EMPTY;
} else {
this.buildNumber = buildNumber;
}
}

/**
* <p>
Expand Down Expand Up @@ -162,6 +186,23 @@ public abstract class BaseMojo extends AbstractMojo {
@Parameter(property = "arguments")
public String arguments;

/**
* <p>List of relative file system paths to ignore when detecting changes in the project(s).</p>
* <p>The primary purpose is to skip creating new releases if only "infrastructure" files such as
* <code>.gitignore</code>, <code>.editorconfig</code> and the like changed. Very basic wild cards are supported as
* follows:
* <ul>
* <li><code>foo.txt</code> - matches <code>foo.txt</code> in the root of the top-level project</li>
* <li><code>bar/foo.txt</code> - matches <code>foo.txt</code> in the root of the <code>bar</code> directory</li>
* <li><code>bar</code> - matches the <code>foo</code> directory and ignores everything below</li>
* <li><code>**.txt</code> - matches all paths ending in <code>.txt</code> (suffix match)</li>
* <li><code>**.editorconfig</code> - matches all <code>.editorconfig</code> files in all (sub)directories; a special case of suffix matching</li>
* <ul/>
* <p/>
*/
@Parameter(property = "ignoredPaths")
Set<String> ignoredPaths;

final void setSettings(final Settings settings) {
this.settings = settings;
}
Expand Down Expand Up @@ -253,4 +294,53 @@ protected static String getRemoteUrlOrNullIfNoneSet(Scm originalScm, Scm actualS
return GitHelper.scmUrlToRemote(remote);
}

PluginConfiguration getPluginConfiguration() {
if (pluginConfiguration == null) {
pluginConfiguration = new PluginConfiguration(project, projects, buildNumber, versionNamer,
modulesToRelease, modulesToForceRelease, noChangesAction, factory, artifactResolver, remoteRepositories,
localRepository, settings, pullTags, arguments, ignoredPaths);
}
return pluginConfiguration;
}

static class PluginConfiguration {
final MavenProject rootProject;
final List<MavenProject> projects;
final String buildNumber;
final VersionNamer versionNamer;
final List<String> modulesToRelease;
final List<String> modulesToForceRelease;
final NoChangesAction noChangesAction;
final ArtifactFactory factory;
final ArtifactResolver artifactResolver;
final List remoteRepositories;
final ArtifactRepository localRepository;
final Settings settings;
final boolean pullTags;
final String arguments;
final Set<String> ignoredPaths;

PluginConfiguration(MavenProject rootProject, List<MavenProject> projects, String buildNumber,
VersionNamer versionNamer, List<String> modulesToRelease,
List<String> modulesToForceRelease, NoChangesAction noChangesAction,
ArtifactFactory factory, ArtifactResolver artifactResolver, List remoteRepositories,
ArtifactRepository localRepository, Settings settings, boolean pullTags, String arguments,
Set<String> ignoredPaths) {
this.rootProject = rootProject;
this.projects = projects;
this.buildNumber = buildNumber;
this.versionNamer = versionNamer;
this.modulesToRelease = modulesToRelease;
this.modulesToForceRelease = modulesToForceRelease;
this.noChangesAction = noChangesAction;
this.factory = factory;
this.artifactResolver = artifactResolver;
this.remoteRepositories = remoteRepositories;
this.localRepository = localRepository;
this.settings = settings;
this.pullTags = pullTags;
this.arguments = arguments;
this.ignoredPaths = ignoredPaths;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public void execute() throws MojoExecutionException, MojoFailureException {
project.getModel().getScm()))
.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);
ResolverWrapper resolverWrapper = new ResolverWrapper(getPluginConfiguration());
Reactor reactor = Reactor.fromProjects(repo, getPluginConfiguration(), resolverWrapper, noChangesAction, log);
if (reactor == null) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.danielflower.mavenplugins.release;

import org.apache.commons.lang3.StringUtils;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
Expand Down Expand Up @@ -28,31 +29,32 @@ public List<ReleasableModule> getModulesInBuildOrder() {
return modulesInBuildOrder;
}

public static Reactor fromProjects(Log log, LocalGitRepo gitRepo, MavenProject rootProject, List<MavenProject> projects, Long buildNumber, List<String> modulesToForceRelease, NoChangesAction actionWhenNoChangesDetected, ResolverWrapper resolverWrapper, VersionNamer versionNamer) throws ValidationException, GitAPIException, MojoExecutionException {
DiffDetector detector = new TreeWalkingDiffDetector(gitRepo.git.getRepository());
List<ReleasableModule> modules = new ArrayList<ReleasableModule>();
static Reactor fromProjects(LocalGitRepo gitRepo, BaseMojo.PluginConfiguration pluginConfiguration, ResolverWrapper resolverWrapper, NoChangesAction noChangesAction, Log log) throws ValidationException, GitAPIException, MojoExecutionException {
DiffDetector detector = new TreeWalkingDiffDetector(gitRepo.git.getRepository(), pluginConfiguration.ignoredPaths);
List<ReleasableModule> modules = new ArrayList<>();

resolveVersionsDefinedThroughProperties(projects);
resolveVersionsDefinedThroughProperties(pluginConfiguration.projects);

VersionNamer versionNamer = pluginConfiguration.versionNamer;
AnnotatedTagFinder annotatedTagFinder = new AnnotatedTagFinder(versionNamer);
for (MavenProject project : projects) {
String relativePathToModule = calculateModulePath(rootProject, project);
for (MavenProject project : pluginConfiguration.projects) {
String relativePathToModule = calculateModulePath(pluginConfiguration.rootProject, project);
String artifactId = project.getArtifactId();
String versionWithoutBuildNumber = project.getVersion().replace("-SNAPSHOT", "");
List<AnnotatedTag> previousTagsForThisModule = annotatedTagFinder.tagsForVersion(gitRepo.git, artifactId, versionWithoutBuildNumber);


Collection<Long> previousBuildNumbers = new ArrayList<Long>();
Collection<String> previousBuildNumbers = new ArrayList<>();
if (previousTagsForThisModule != null) {
for (AnnotatedTag previousTag : previousTagsForThisModule) {
previousBuildNumbers.add(previousTag.buildNumber());
}
}

Collection<Long> remoteBuildNumbers = getRemoteBuildNumbers(gitRepo, artifactId, versionWithoutBuildNumber, versionNamer);
Collection<String> remoteBuildNumbers = getRemoteBuildNumbers(gitRepo, artifactId, versionWithoutBuildNumber, versionNamer);
previousBuildNumbers.addAll(remoteBuildNumbers);

VersionName newVersion = versionNamer.name(project.getVersion(), buildNumber, previousBuildNumbers);
VersionName newVersion = versionNamer.name(project.getVersion(), pluginConfiguration.buildNumber, previousBuildNumbers);

boolean oneOfTheDependenciesHasChanged = false;
String changedDependency = null;
Expand Down Expand Up @@ -89,7 +91,7 @@ public static Reactor fromProjects(Log log, LocalGitRepo gitRepo, MavenProject r

String equivalentVersion = null;

if(modulesToForceRelease != null && modulesToForceRelease.contains(artifactId)) {
if(pluginConfiguration.modulesToForceRelease != null && pluginConfiguration.modulesToForceRelease.contains(artifactId)) {
log.info("Releasing " + artifactId + " " + newVersion.releaseVersion() + " as we was asked to forced release.");
} else if (oneOfTheDependenciesHasChanged) {
log.info("Releasing " + artifactId + " " + newVersion.releaseVersion() + " as " + changedDependency + " has changed.");
Expand All @@ -113,15 +115,15 @@ public static Reactor fromProjects(Log log, LocalGitRepo gitRepo, MavenProject r
}

if (!atLeastOneBeingReleased(modules)) {
switch (actionWhenNoChangesDetected) {
switch (noChangesAction) {
case ReleaseNone:
log.warn("No changes have been detected in any modules so will not perform release");
return null;
case FailBuild:
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<ReleasableModule> newList = new ArrayList<ReleasableModule>();
List<ReleasableModule> newList = new ArrayList<>();
for (ReleasableModule module : modules) {
newList.add(module.createReleasableVersion());
}
Expand All @@ -145,14 +147,14 @@ private static boolean hasSameMavenGAByDependencyLocation(ReleasableModule modul
return modelId[0].equals(module.getGroupId()) && modelId[1].equals(module.getArtifactId());
}

private static Collection<Long> getRemoteBuildNumbers(LocalGitRepo gitRepo, String artifactId, String versionWithoutBuildNumber, VersionNamer versionNamer) throws GitAPIException {
private static Collection<String> getRemoteBuildNumbers(LocalGitRepo gitRepo, String artifactId, String versionWithoutBuildNumber, VersionNamer versionNamer) throws GitAPIException {
Collection<Ref> remoteTagRefs = gitRepo.allTags();
Collection<Long> remoteBuildNumbers = new ArrayList<Long>();
Collection<String> remoteBuildNumbers = new ArrayList<>();
String tagWithoutBuildNumber = artifactId + "-" + versionWithoutBuildNumber;
AnnotatedTagFinder annotatedTagFinder = new AnnotatedTagFinder(versionNamer);
for (Ref remoteTagRef : remoteTagRefs) {
String remoteTagName = remoteTagRef.getName();
Long buildNumber = annotatedTagFinder.buildNumberOf(tagWithoutBuildNumber, remoteTagName);
String buildNumber = annotatedTagFinder.buildNumberOf(tagWithoutBuildNumber, remoteTagName);
if (buildNumber != null) {
remoteBuildNumbers.add(buildNumber);
}
Expand Down Expand Up @@ -190,20 +192,25 @@ static AnnotatedTag hasChangedSinceLastRelease(List<AnnotatedTag> previousTagsFo
try {
if (previousTagsForThisModule.size() == 0) return null;
boolean hasChanged = detector.hasChangedSince(relativePathToModule, project.getModel().getModules(), previousTagsForThisModule);
return hasChanged ? null : tagWithHighestBuildNumber(previousTagsForThisModule);
return hasChanged ? null : findTagWithHighestBuildNumber(previousTagsForThisModule);
} catch (Exception e) {
throw new MojoExecutionException("Error while detecting whether or not " + project.getArtifactId() + " has changed since the last release", e);
}
}

private static AnnotatedTag tagWithHighestBuildNumber(List<AnnotatedTag> tags) {
AnnotatedTag cur = null;
// Ignores any tags with non-numeric build numbers and finds the one with the largest build number among the others.
// The tags are guaranteed to be for the same /business version/ i.e. it's likely a small list.
private static AnnotatedTag findTagWithHighestBuildNumber(List<AnnotatedTag> tags) {
AnnotatedTag tagWithHighestBuildNumber = null;
for (AnnotatedTag tag : tags) {
if (cur == null || tag.buildNumber() > cur.buildNumber()) {
cur = tag;
if(StringUtils.isNumeric(tag.buildNumber())) {
if (tagWithHighestBuildNumber == null ||
Long.parseLong(tag.buildNumber()) > Long.parseLong(tagWithHighestBuildNumber.buildNumber())) {
tagWithHighestBuildNumber = tag;
}
}
}
return cur;
return tagWithHighestBuildNumber;
}

public ReleasableModule findByLabel(String label) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public String getVersion() {
return version.businessVersion();
}

public long getBuildNumber() {
public String getBuildNumber() {
return version.buildNumber();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ public void execute() throws MojoExecutionException, MojoFailureException {
.buildFromCurrentDir();
repo.errorIfNotClean();

ResolverWrapper resolverWrapper = new ResolverWrapper(factory, artifactResolver, remoteRepositories, localRepository);
Reactor reactor = Reactor.fromProjects(log, repo, project, projects, buildNumber, modulesToForceRelease, noChangesAction, resolverWrapper, versionNamer);
ResolverWrapper resolverWrapper = new ResolverWrapper(getPluginConfiguration());
Reactor reactor = Reactor.fromProjects(repo, getPluginConfiguration(), resolverWrapper, noChangesAction, log);
if (reactor == null) {
return;
}
Expand Down
Loading