Skip to content

Commit b72edf3

Browse files
authored
Improved support for multi-module maven projects (#210)
* Improved support for multi-module maven projects Some steps in the maven plugin require paths to configuration files. For example eclipse formatter and scalafmt. In multi-module maven projects it is desirable to specify paths only once and not duplicate configs in multiple modules. Each sub-project should not assume anything about the general project structure and should not refer to files in parent modules using relative paths. It is recommended to create a separate module with configuration files and depend on it in the plugin. This approach is taken by the Checkstyle and PMD plugins: http://maven.apache.org/plugins/maven-checkstyle-plugin/examples/multi-module-config.html https://maven.apache.org/plugins/maven-pmd-plugin/examples/multi-module-config.html Such approach means configuration files no longer live within the project and might be inside a JAR. Thus specified value of `<file>` require special resolution. Both Checkstyle and PMD use builtin plexus `ResourceManager` which is able to locate files from regular file system, URL or JAR. Located file is then copied to the output directory (usually `./target/`) and used as a regular file. This commit makes spotless plugin also use `ResourceManager` in order to support multi-module configuration with config files in a dedicated module. Every step that contains `<file>` is updated to perform the resolution. It is also possible to specify configuration file URLs, though this feature is not tested. * Updated CHANGES.md for the maven plugin * Removed `<relativePath>` from multi-module test POMs It's default value is `..` so no need to be explicit about it.
1 parent 2dd2157 commit b72edf3

19 files changed

+465
-22
lines changed

gradle.properties

+1
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@ VER_MOCKITO=2.13.0
3838
VER_MAVEN_API=3.0
3939
VER_ECLIPSE_AETHER=1.1.0
4040
VER_MUSTACHE=0.9.5
41+
VER_PLEXUS_RESOURCES=1.0.1

plugin-maven/CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
### Version 1.10.0-SNAPSHOT - TBD ([javadoc](https://diffplug.github.io/spotless/javadoc/spotless-maven-plugin/snapshot/), [snapshot](https://oss.sonatype.org/content/repositories/snapshots/com/diffplug/spotless/spotless-maven-plugin/))
44

5+
* Improved support for multi-module Maven projects ([#210](https://github.com/diffplug/spotless/pull/210)).
6+
57
### Version 1.0.0.BETA2 - February 15th 2018 ([javadoc](https://diffplug.github.io/spotless/javadoc/spotless-maven-plugin/1.0.0.BETA2/), [jcenter](https://bintray.com/diffplug/opensource/spotless-maven-plugin/1.0.0.BETA2))
68

79
* Fix build to ensure that published versions never have snapshot deps ([#205](https://github.com/diffplug/spotless/pull/205)).

plugin-maven/build.gradle

+4-1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ dependencies {
6767
compileOnly "org.apache.maven.plugin-tools:maven-plugin-annotations:${VER_MAVEN_API}"
6868
compileOnly "org.eclipse.aether:aether-api:${VER_ECLIPSE_AETHER}"
6969
compileOnly "org.eclipse.aether:aether-util:${VER_ECLIPSE_AETHER}"
70+
compileOnly "org.codehaus.plexus:plexus-resources:${VER_PLEXUS_RESOURCES}"
7071

7172
testCompile project(":testlib")
7273
testCompile "junit:junit:${VER_JUNIT}"
@@ -76,6 +77,7 @@ dependencies {
7677
testCompile "com.github.spullara.mustache.java:compiler:${VER_MUSTACHE}"
7778
testCompile "org.apache.maven:maven-plugin-api:${VER_MAVEN_API}"
7879
testCompile "org.eclipse.aether:aether-api:${VER_ECLIPSE_AETHER}"
80+
testCompile "org.codehaus.plexus:plexus-resources:${VER_PLEXUS_RESOURCES}"
7981
}
8082

8183
task cleanMavenProjectDir(type: Delete) { delete MAVEN_PROJECT_DIR }
@@ -141,6 +143,7 @@ task createPomXml(dependsOn: installLocalDependencies) {
141143
mavenApiVersion : VER_MAVEN_API,
142144
eclipseAetherVersion : VER_ECLIPSE_AETHER,
143145
spotlessLibVersion : project.versionLib,
146+
plexusResourcesVersion : VER_PLEXUS_RESOURCES,
144147
additionalDependencies : additionalDependencies
145148
]
146149

@@ -182,6 +185,6 @@ test.dependsOn(jar)
182185
test {
183186
testLogging { exceptionFormat = 'full' }
184187
// pass location of the local maven repository and plugin version to junit tests
185-
systemProperty "localMavenRepositoryDir", "${LOCAL_MAVEN_REPO_DIR}"
188+
systemProperty "localMavenRepositoryDir", LOCAL_MAVEN_REPO_DIR
186189
systemProperty "spotlessMavenPluginVersion", project.versionMaven
187190
}

plugin-maven/src/main/java/com/diffplug/spotless/maven/AbstractSpotlessMojo.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import org.apache.maven.plugin.MojoExecutionException;
3030
import org.apache.maven.plugins.annotations.Component;
3131
import org.apache.maven.plugins.annotations.Parameter;
32+
import org.codehaus.plexus.resource.ResourceManager;
33+
import org.codehaus.plexus.resource.loader.FileResourceLoader;
3234
import org.codehaus.plexus.util.FileUtils;
3335
import org.eclipse.aether.RepositorySystem;
3436
import org.eclipse.aether.RepositorySystemSession;
@@ -50,6 +52,9 @@ public abstract class AbstractSpotlessMojo extends AbstractMojo {
5052
@Component
5153
private RepositorySystem repositorySystem;
5254

55+
@Component
56+
private ResourceManager resourceManager;
57+
5358
@Parameter(defaultValue = "${repositorySystemSession}", required = true, readonly = true)
5459
private RepositorySystemSession repositorySystemSession;
5560

@@ -126,7 +131,15 @@ private FormatterConfig getFormatterConfig() {
126131
ArtifactResolver resolver = new ArtifactResolver(repositorySystem, repositorySystemSession, repositories, getLog());
127132
Provisioner provisioner = MavenProvisioner.create(resolver);
128133
List<FormatterStepFactory> formatterStepFactories = getFormatterStepFactories();
129-
return new FormatterConfig(baseDir, encoding, lineEndings, provisioner, formatterStepFactories);
134+
FileLocator fileLocator = getFileLocator();
135+
return new FormatterConfig(baseDir, encoding, lineEndings, provisioner, fileLocator, formatterStepFactories);
136+
}
137+
138+
private FileLocator getFileLocator() {
139+
resourceManager.addSearchPath(FileResourceLoader.ID, baseDir.getAbsolutePath());
140+
resourceManager.addSearchPath("url", "");
141+
resourceManager.setOutputDirectory(targetDir);
142+
return new FileLocator(resourceManager);
130143
}
131144

132145
private List<FormatterFactory> getFormatterFactories() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2016 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.maven;
17+
18+
import static com.diffplug.common.base.Strings.*;
19+
20+
import java.io.File;
21+
22+
import org.codehaus.plexus.resource.ResourceManager;
23+
import org.codehaus.plexus.resource.loader.FileResourceCreationException;
24+
import org.codehaus.plexus.resource.loader.ResourceNotFoundException;
25+
import org.codehaus.plexus.util.FileUtils;
26+
27+
public class FileLocator {
28+
29+
private final ResourceManager resourceManager;
30+
31+
public FileLocator(ResourceManager resourceManager) {
32+
this.resourceManager = resourceManager;
33+
}
34+
35+
public File locateFile(String path) {
36+
if (isNullOrEmpty(path)) {
37+
return null;
38+
}
39+
40+
String outputFile = tmpOutputFileName(path);
41+
try {
42+
return resourceManager.getResourceAsFile(path, outputFile);
43+
} catch (ResourceNotFoundException e) {
44+
throw new RuntimeException("Unable to locate file with path: " + path, e);
45+
} catch (FileResourceCreationException e) {
46+
throw new RuntimeException("Unable to create temporaty file '" + outputFile + "' in the output directory", e);
47+
}
48+
}
49+
50+
private static String tmpOutputFileName(String path) {
51+
String nameWithExtension = FileUtils.filename(path);
52+
String extension = FileUtils.extension(path);
53+
String name = nameWithExtension.replace('.' + extension, "");
54+
return name + '-' + System.currentTimeMillis() + '.' + extension;
55+
}
56+
}

plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterConfig.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ public class FormatterConfig {
2929
private final String encoding;
3030
private final LineEnding lineEndings;
3131
private final Provisioner provisioner;
32+
private final FileLocator fileLocator;
3233
private final List<FormatterStepFactory> globalStepFactories;
3334

3435
public FormatterConfig(File baseDir, String encoding, LineEnding lineEndings, Provisioner provisioner,
35-
List<FormatterStepFactory> globalStepFactories) {
36+
FileLocator fileLocator, List<FormatterStepFactory> globalStepFactories) {
3637
this.baseDir = baseDir;
3738
this.encoding = encoding;
3839
this.lineEndings = lineEndings;
3940
this.provisioner = provisioner;
41+
this.fileLocator = fileLocator;
4042
this.globalStepFactories = globalStepFactories;
4143
}
4244

@@ -59,4 +61,8 @@ public Provisioner getProvisioner() {
5961
public List<FormatterStepFactory> getGlobalStepFactories() {
6062
return unmodifiableList(globalStepFactories);
6163
}
64+
65+
public FileLocator getFileLocator() {
66+
return fileLocator;
67+
}
6268
}

plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ private LineEnding lineEndings(FormatterConfig config) {
101101
}
102102

103103
private FormatterStepConfig stepConfig(Charset encoding, FormatterConfig config) {
104-
return new FormatterStepConfig(encoding, licenseHeaderDelimiter(), config.getProvisioner());
104+
return new FormatterStepConfig(encoding, licenseHeaderDelimiter(), config.getProvisioner(), config.getFileLocator());
105105
}
106106

107107
private static List<FormatterStepFactory> gatherStepFactories(List<FormatterStepFactory> allGlobal, List<FormatterStepFactory> allConfigured) {

plugin-maven/src/main/java/com/diffplug/spotless/maven/FormatterStepConfig.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ public class FormatterStepConfig {
2424
private final Charset encoding;
2525
private final String licenseHeaderDelimiter;
2626
private final Provisioner provisioner;
27+
private final FileLocator fileLocator;
2728

28-
public FormatterStepConfig(Charset encoding, String licenseHeaderDelimiter, Provisioner provisioner) {
29+
public FormatterStepConfig(Charset encoding, String licenseHeaderDelimiter, Provisioner provisioner, FileLocator fileLocator) {
2930
this.encoding = encoding;
3031
this.licenseHeaderDelimiter = licenseHeaderDelimiter;
3132
this.provisioner = provisioner;
33+
this.fileLocator = fileLocator;
3234
}
3335

3436
public Charset getEncoding() {
@@ -42,4 +44,8 @@ public String getLicenseHeaderDelimiter() {
4244
public Provisioner getProvisioner() {
4345
return provisioner;
4446
}
47+
48+
public FileLocator getFileLocator() {
49+
return fileLocator;
50+
}
4551
}

plugin-maven/src/main/java/com/diffplug/spotless/maven/generic/LicenseHeader.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
public class LicenseHeader implements FormatterStepFactory {
2828
@Parameter
29-
private File file;
29+
private String file;
3030

3131
@Parameter
3232
private String content;
@@ -43,7 +43,8 @@ public final FormatterStep newFormatterStep(FormatterStepConfig config) {
4343

4444
if (file != null ^ content != null) {
4545
if (file != null) {
46-
return LicenseHeaderStep.createFromFile(file, config.getEncoding(), delimiterString);
46+
File licenseHeaderFile = config.getFileLocator().locateFile(file);
47+
return LicenseHeaderStep.createFromFile(licenseHeaderFile, config.getEncoding(), delimiterString);
4748
} else {
4849
return LicenseHeaderStep.createFromHeader(content, delimiterString);
4950
}

plugin-maven/src/main/java/com/diffplug/spotless/maven/java/Eclipse.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import static java.util.Collections.singleton;
2020

2121
import java.io.File;
22-
import java.util.Set;
2322

2423
import org.apache.maven.plugins.annotations.Parameter;
2524

@@ -31,15 +30,15 @@
3130
public class Eclipse implements FormatterStepFactory {
3231

3332
@Parameter(required = true)
34-
private File file;
33+
private String file;
3534

3635
@Parameter
3736
private String version;
3837

3938
@Override
4039
public FormatterStep newFormatterStep(FormatterStepConfig config) {
4140
String formatterVersion = version == null ? defaultVersion() : version;
42-
Set<File> settingsFiles = singleton(file);
43-
return EclipseFormatterStep.create(formatterVersion, settingsFiles, config.getProvisioner());
41+
File settingsFile = config.getFileLocator().locateFile(file);
42+
return EclipseFormatterStep.create(formatterVersion, singleton(settingsFile), config.getProvisioner());
4443
}
4544
}

plugin-maven/src/main/java/com/diffplug/spotless/maven/java/ImportOrder.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
public class ImportOrder implements FormatterStepFactory {
2828
@Parameter
29-
private File file;
29+
private String file;
3030

3131
@Parameter
3232
private String order;
@@ -35,7 +35,8 @@ public class ImportOrder implements FormatterStepFactory {
3535
public FormatterStep newFormatterStep(FormatterStepConfig config) {
3636
if (file != null ^ order != null) {
3737
if (file != null) {
38-
return ImportOrderStep.createFromFile(file);
38+
File importsFile = config.getFileLocator().locateFile(file);
39+
return ImportOrderStep.createFromFile(importsFile);
3940
} else {
4041
return ImportOrderStep.createFromOrder(order.split(","));
4142
}

plugin-maven/src/main/java/com/diffplug/spotless/maven/scala/Scalafmt.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@
2727
public class Scalafmt implements FormatterStepFactory {
2828

2929
@Parameter
30-
private File file;
30+
private String file;
3131

3232
@Parameter
3333
private String version;
3434

3535
@Override
3636
public FormatterStep newFormatterStep(FormatterStepConfig config) {
3737
String scalafmtVersion = version != null ? version : ScalaFmtStep.defaultVersion();
38-
return ScalaFmtStep.create(scalafmtVersion, config.getProvisioner(), file);
38+
File configFile = config.getFileLocator().locateFile(file);
39+
return ScalaFmtStep.create(scalafmtVersion, config.getProvisioner(), configFile);
3940
}
4041
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2016 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.maven;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertNull;
21+
import static org.mockito.ArgumentMatchers.any;
22+
import static org.mockito.ArgumentMatchers.eq;
23+
import static org.mockito.Mockito.*;
24+
25+
import java.io.File;
26+
27+
import org.codehaus.plexus.resource.ResourceManager;
28+
import org.junit.Test;
29+
import org.mockito.ArgumentCaptor;
30+
31+
public class FileLocatorTest {
32+
33+
private final ResourceManager resourceManager = mock(ResourceManager.class);
34+
private final FileLocator fileLocator = new FileLocator(resourceManager);
35+
36+
@Test
37+
public void locateEmptyString() {
38+
assertNull(fileLocator.locateFile(""));
39+
}
40+
41+
@Test
42+
public void locateNull() {
43+
assertNull(fileLocator.locateFile(null));
44+
}
45+
46+
@Test
47+
public void locateValidFile() throws Exception {
48+
File file = new File("test-config.xml");
49+
when(resourceManager.getResourceAsFile(any(), any())).thenReturn(file);
50+
51+
File locatedFile = fileLocator.locateFile("/tmp/configs/my-config.xml");
52+
53+
assertEquals(file, locatedFile);
54+
55+
ArgumentCaptor<String> argCaptor = ArgumentCaptor.forClass(String.class);
56+
verify(resourceManager).getResourceAsFile(eq("/tmp/configs/my-config.xml"), argCaptor.capture());
57+
assertThat(argCaptor.getValue()).startsWith("my-config").endsWith(".xml");
58+
}
59+
}

0 commit comments

Comments
 (0)