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

Enable up-to-date checking in Maven plugin by default #1621

Merged
Merged
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
2 changes: 2 additions & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
@@ -7,6 +7,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
* You can now put the filename into a license header template with `$FILE`. ([#1605](https://github.com/diffplug/spotless/pull/1605) fixes [#1147](https://github.com/diffplug/spotless/issues/1147))
### Fixed
* `licenseHeader` default pattern for Java files is updated to `(package|import|public|class|module) `. ([#1614](https://github.com/diffplug/spotless/pull/1614))
### Changes
* Enable incremental up-to-date checking by default. ([#1621](https://github.com/diffplug/spotless/pull/1621))

## [2.34.0] - 2023-02-27
### Added
2 changes: 1 addition & 1 deletion plugin-maven/README.md
Original file line number Diff line number Diff line change
@@ -1262,7 +1262,7 @@ To define what lines to skip at the beginning of such files, fill the `skipLines

## Incremental up-to-date checking and formatting

**This feature is turned off by default.**
**This feature is enabled by default starting from version 2.35.0.**

Execution of `spotless:check` and `spotless:apply` for large projects can take time.
By default, Spotless Maven plugin needs to read and format each source file.
Original file line number Diff line number Diff line change
@@ -187,7 +187,7 @@ public abstract class AbstractSpotlessMojo extends AbstractMojo {
private String setLicenseHeaderYearsFromGitHistory;

@Parameter
private UpToDateChecking upToDateChecking;
private UpToDateChecking upToDateChecking = UpToDateChecking.enabled();

protected abstract void process(Iterable<File> files, Formatter formatter, UpToDateChecker upToDateChecker) throws MojoExecutionException;

@@ -373,9 +373,9 @@ private UpToDateChecker createUpToDateChecker(Iterable<Formatter> formatters) {
}
final UpToDateChecker checker;
if (upToDateChecking != null && upToDateChecking.isEnabled()) {
getLog().info("Up-to-date checking enabled");
checker = UpToDateChecker.forProject(project, indexFile, formatters, getLog());
} else {
getLog().info("Up-to-date checking disabled");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed logging slightly because disabled up-to-date checking will be an uncommon path that requires explicit configuration. Thus, the plugin should log something on such an uncommon path

checker = UpToDateChecker.noop(project, indexFile, getLog());
}
return UpToDateChecker.wrapWithBuildContext(checker, buildContext);
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
import java.util.Objects;

import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.project.MavenProject;

import com.diffplug.spotless.Formatter;
@@ -43,10 +44,7 @@ private PluginFingerprint(String value) {
}

static PluginFingerprint from(MavenProject project, Iterable<Formatter> formatters) {
Plugin spotlessPlugin = project.getPlugin(SPOTLESS_PLUGIN_KEY);
if (spotlessPlugin == null) {
throw new IllegalArgumentException("Spotless plugin absent from the project: " + project);
}
Plugin spotlessPlugin = findSpotlessPlugin(project);
byte[] digest = digest(spotlessPlugin, formatters);
String value = Base64.getEncoder().encodeToString(digest);
return new PluginFingerprint(value);
@@ -86,6 +84,24 @@ public String toString() {
return "PluginFingerprint[" + value + "]";
}

private static Plugin findSpotlessPlugin(MavenProject project) {
// Try to find the plugin instance from <build><plugins><plugin> XML element
Plugin plugin = project.getPlugin(SPOTLESS_PLUGIN_KEY);
if (plugin == null) {
// Try to find the plugin instance from <build><pluginManagement><plugins><plugin> XML element. Useful when
// the current module is a parent of a multimodule project
PluginManagement pluginManagement = project.getPluginManagement();
if (pluginManagement != null) {
plugin = pluginManagement.getPluginsAsMap().get(SPOTLESS_PLUGIN_KEY);
}
}

if (plugin == null) {
throw new IllegalArgumentException("Spotless plugin absent from the project: " + project);
}
return plugin;
}

private static byte[] digest(Plugin plugin, Iterable<Formatter> formatters) {
try (ObjectDigestOutputStream out = ObjectDigestOutputStream.create()) {
out.writeObject(plugin.getVersion());
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2022 DiffPlug
* Copyright 2021-2023 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,4 +38,10 @@ public boolean isEnabled() {
public Path getIndexFile() {
return indexFile == null ? null : new File(indexFile).toPath();
}

public static UpToDateChecking enabled() {
UpToDateChecking upToDateChecking = new UpToDateChecking();
upToDateChecking.enabled = true;
return upToDateChecking;
}
}
Original file line number Diff line number Diff line change
@@ -32,31 +32,31 @@ class MultiModuleProjectTest extends MavenIntegrationHarness {
@Test
void testConfigurationDependency() throws Exception {
/*
create a multi-module project with the following stucture:
create a multi-module project with the following structure:

/junit-tmp-dir
├── config
   ├── pom.xml
   └── src/main/resources/configs
   ├── eclipse-formatter.xml
   └── scalafmt.conf
├── pom.xml
└── src/main/resources/configs
├── eclipse-formatter.xml
└── scalafmt.conf
├── mvnw
├── mvnw.cmd
├── one
   ├── pom.xml
   └── src
   ├── main/java/test1.java
   └── test/java/test2.java
├── pom.xml
└── src
├── main/java/test1.java
└── test/java/test2.java
├── two
   ├── pom.xml
   └── src
   ├── main/java/test1.java
   └── test/java/test2.java
├── pom.xml
└── src
├── main/java/test1.java
└── test/java/test2.java
├── three
   ├── pom.xml
   └── src
   ├── main/scala/test1.scala
   └── test/scala/test2.scala
├── pom.xml
└── src
├── main/scala/test1.scala
└── test/scala/test2.scala
├── pom.xml
├── .mvn
├── mvnw
Original file line number Diff line number Diff line change
@@ -23,9 +23,12 @@
import java.io.ByteArrayInputStream;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginManagement;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.ReaderFactory;
@@ -106,14 +109,45 @@ void emptyFingerprint() {
}

@Test
void failsWhenProjectDoesNotContainSpotlessPlugin() {
void failsForProjectWithoutSpotlessPlugin() {
MavenProject projectWithoutSpotless = new MavenProject();

assertThatThrownBy(() -> PluginFingerprint.from(projectWithoutSpotless, FORMATTERS))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("Spotless plugin absent from the project");
}

@Test
void buildsFingerprintForProjectWithSpotlessPluginInBuildPlugins() {
MavenProject project = new MavenProject();
Plugin spotlessPlugin = new Plugin();
spotlessPlugin.setGroupId("com.diffplug.spotless");
spotlessPlugin.setArtifactId("spotless-maven-plugin");
spotlessPlugin.setVersion("1.2.3");
project.getBuild().addPlugin(spotlessPlugin);

PluginFingerprint fingerprint = PluginFingerprint.from(project, Collections.emptyList());

assertThat(fingerprint).isNotNull();
}

@Test
void buildsFingerprintForProjectWithSpotlessPluginInPluginManagement() {
MavenProject project = new MavenProject();
Plugin spotlessPlugin = new Plugin();
spotlessPlugin.setGroupId("com.diffplug.spotless");
spotlessPlugin.setArtifactId("spotless-maven-plugin");
spotlessPlugin.setVersion("1.2.3");
project.getBuild().addPlugin(spotlessPlugin);
PluginManagement pluginManagement = new PluginManagement();
pluginManagement.addPlugin(spotlessPlugin);
project.getBuild().setPluginManagement(pluginManagement);

PluginFingerprint fingerprint = PluginFingerprint.from(project, Collections.emptyList());

assertThat(fingerprint).isNotNull();
}

private MavenProject mavenProject(String spotlessVersion) throws Exception {
String xml = createPomXmlContent(spotlessVersion, new String[0], new String[0]);
return new MavenProject(readPom(xml));
Original file line number Diff line number Diff line change
@@ -31,8 +31,10 @@

class UpToDateCheckingTest extends MavenIntegrationHarness {

private static final String DISABLED_MESSAGE = "Up-to-date checking disabled";

@Test
void upToDateCheckingDisabledByDefault() throws Exception {
void upToDateCheckingEnabledByDefault() throws Exception {
writePom(
"<java>",
" <googleJavaFormat/>",
@@ -41,75 +43,53 @@ void upToDateCheckingDisabledByDefault() throws Exception {
List<File> files = writeUnformattedFiles(1);
String output = runSpotlessApply();

assertThat(output).doesNotContain("Up-to-date checking enabled");
assertThat(output).doesNotContain(DISABLED_MESSAGE);
assertFormatted(files);
}

@Test
void enableUpToDateChecking() throws Exception {
void explicitlyEnableUpToDateChecking() throws Exception {
writePomWithUpToDateCheckingEnabled(true);

List<File> files = writeUnformattedFiles(1);
String output = runSpotlessApply();

assertThat(output).contains("Up-to-date checking enabled");
assertThat(output).doesNotContain(DISABLED_MESSAGE);
assertFormatted(files);
}

@Test
void enableUpToDateCheckingWithPluginDependencies() throws Exception {
writePomWithPluginManagementAndDependency();
void explicitlyDisableUpToDateChecking() throws Exception {
writePomWithUpToDateCheckingEnabled(false);

List<File> files = writeUnformattedFiles(1);
String output = runSpotlessApply();

assertThat(output).contains("Up-to-date checking enabled");
assertThat(output).contains(DISABLED_MESSAGE);
assertFormatted(files);
}

@Test
void enableUpToDateCheckingWithPluginDependenciesMaven3_6_3() throws Exception {
void enableUpToDateCheckingWithPluginDependencies() throws Exception {
writePomWithPluginManagementAndDependency();

setFile(".mvn/wrapper/maven-wrapper.properties").toContent("distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip\n");

List<File> files = writeUnformattedFiles(1);
String output = runSpotlessApply();

assertThat(output).contains("Up-to-date checking enabled");
assertThat(output).doesNotContain(DISABLED_MESSAGE);
assertFormatted(files);
}

private void writePomWithPluginManagementAndDependency() throws IOException {
setFile("pom.xml").toContent(createPomXmlContent("/pom-test-management.xml.mustache",
null,
null,
new String[]{
"<java>",
" <googleJavaFormat/>",
"</java>",
"<upToDateChecking>",
" <enabled>true</enabled>",
"</upToDateChecking>"},
new String[]{
"<dependencies>",
" <dependency>",
" <groupId>javax.inject</groupId>",
" <artifactId>javax.inject</artifactId>",
" <version>1</version>",
" </dependency>",
"</dependencies>"},
null));
}

@Test
void disableUpToDateChecking() throws Exception {
writePomWithUpToDateCheckingEnabled(false);
void enableUpToDateCheckingWithPluginDependenciesMaven3_6_3() throws Exception {
writePomWithPluginManagementAndDependency();

setFile(".mvn/wrapper/maven-wrapper.properties").toContent("distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip\n");

List<File> files = writeUnformattedFiles(1);
String output = runSpotlessApply();

assertThat(output).doesNotContain("Up-to-date checking enabled");
assertThat(output).doesNotContain(DISABLED_MESSAGE);
assertFormatted(files);
}

@@ -124,7 +104,7 @@ void enableUpToDateCheckingCustomIndexFile() throws Exception {
List<File> files = writeUnformattedFiles(1);
String output = runSpotlessApply();

assertThat(output).contains("Up-to-date checking enabled");
assertThat(output).doesNotContain(DISABLED_MESSAGE);
assertFormatted(files);
assertThat(indexFile.getParent()).exists();
assertThat(indexFile).exists();
@@ -143,7 +123,7 @@ void disableUpToDateCheckingCustomIndexFile() throws Exception {
List<File> files = writeUnformattedFiles(1);
String output = runSpotlessApply();

assertThat(output).doesNotContain("Up-to-date checking enabled");
assertThat(output).contains(DISABLED_MESSAGE);
assertFormatted(files);
assertThat(indexFile.getParent()).exists();
assertThat(indexFile).doesNotExist();
@@ -215,6 +195,25 @@ void spotlessCheckRecordsUnformattedFiles() throws Exception {
assertSpotlessCheckSkipped(files, checkOutput3);
}

private void writePomWithPluginManagementAndDependency() throws IOException {
setFile("pom.xml").toContent(createPomXmlContent("/pom-test-management.xml.mustache",
null,
null,
new String[]{
"<java>",
" <googleJavaFormat/>",
"</java>"},
new String[]{
"<dependencies>",
" <dependency>",
" <groupId>javax.inject</groupId>",
" <artifactId>javax.inject</artifactId>",
" <version>1</version>",
" </dependency>",
"</dependencies>"},
null));
}

private void writePomWithUpToDateCheckingEnabled(boolean enabled) throws IOException {
writePom(
"<java>",