Skip to content

Commit

Permalink
Merge pull request #1461 from lutovich/improve-maven-plugin-fingerprint
Browse files Browse the repository at this point in the history
Reduce spurious invalidations of the up-to-date index in Maven plugin
  • Loading branch information
lutovich authored Jan 8, 2023
2 parents 1b2c449 + 016eecf commit c50503e
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 139 deletions.
2 changes: 2 additions & 0 deletions plugin-maven/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
### Fixed
* Reduce spurious invalidations of the up-to-date index file ([#1461](https://github.com/diffplug/spotless/pull/1461))

## [2.29.0] - 2023-01-02
### Added
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 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.
Expand Down Expand Up @@ -76,7 +76,7 @@ static FileIndex read(FileIndexConfig config, Log log) {
PluginFingerprint computedFingerprint = config.getPluginFingerprint();
PluginFingerprint storedFingerprint = PluginFingerprint.from(firstLine);
if (!computedFingerprint.equals(storedFingerprint)) {
log.info("Fingerprint mismatch in the index file. Fallback to an empty index");
log.info("Index file corresponds to a different configuration of the plugin. Either the plugin version or its configuration has changed. Fallback to an empty index");
return emptyIndexFallback(config);
} else {
Content content = readIndexContent(reader, config.getProjectDir(), log);
Expand Down
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.
Expand All @@ -17,17 +17,21 @@

import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Objects;

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

import com.diffplug.spotless.Formatter;

/**
* Represents a particular Spotless Maven plugin setup using a Base64-encoded serialized form of:
* <ol>
* <li>Plugin version as configured in the POM</li>
* <li>Formatter instances created according to the POM configuration</li>
* </ol>
*/
class PluginFingerprint {

private static final String SPOTLESS_PLUGIN_KEY = "com.diffplug.spotless:spotless-maven-plugin";
Expand Down Expand Up @@ -83,22 +87,15 @@ public String toString() {
}

private static byte[] digest(Plugin plugin, Iterable<Formatter> formatters) {
// dependencies can be an unserializable org.apache.maven.model.merge.ModelMerger$MergingList
// replace it with a serializable ArrayList
List<Dependency> dependencies = plugin.getDependencies();
plugin.setDependencies(new ArrayList<>(dependencies));
try (ObjectDigestOutputStream out = ObjectDigestOutputStream.create()) {
out.writeObject(plugin);
out.writeObject(plugin.getVersion());
for (Formatter formatter : formatters) {
out.writeObject(formatter);
}
out.flush();
return out.digest();
} catch (IOException e) {
throw new UncheckedIOException("Unable to serialize plugin " + plugin, e);
} finally {
// reset the original list
plugin.setDependencies(dependencies);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 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.
Expand Down Expand Up @@ -60,7 +60,7 @@ void readFallsBackToEmptyIndexOnFingerprintMismatch() throws Exception {
FileIndex index = FileIndex.read(config, log);

assertThat(index.size()).isZero();
verify(log).info("Fingerprint mismatch in the index file. Fallback to an empty index");
verify(log).info("Index file corresponds to a different configuration of the plugin. Either the plugin version or its configuration has changed. Fallback to an empty index");
}

@Test
Expand Down
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.
Expand Down Expand Up @@ -43,126 +43,22 @@ class PluginFingerprintTest extends MavenIntegrationHarness {
private static final String VERSION_1 = "1.0.0";
private static final String VERSION_2 = "2.0.0";

private static final String[] EXECUTION_1 = {
"<execution>",
" <id>check</id>",
" <goals>",
" <goal>check</goal>",
" </goals>",
"</execution>"
};
private static final String[] EXECUTION_2 = {};

private static final String[] CONFIGURATION_1 = {
"<googleJavaFormat>",
" <version>1.2</version>",
"</googleJavaFormat>"
};
private static final String[] CONFIGURATION_2 = {
"<googleJavaFormat>",
" <version>1.8</version>",
" <reflowLongStrings>true</reflowLongStrings>",
"</googleJavaFormat>"
};

private static final String[] DEPENDENCIES_1 = {
"<dependencies>",
" <dependency>",
" <groupId>unknown</groupId>",
" <artifactId>unknown</artifactId>",
" <version>1.0</version>",
" </dependency>",
"</dependencies>"
};
private static final String[] DEPENDENCIES_2 = {
"<dependencies>",
" <dependency>",
" <groupId>unknown</groupId>",
" <artifactId>unknown</artifactId>",
" <version>2.0</version>",
" </dependency>",
"</dependencies>"
};

private static final List<Formatter> FORMATTERS = singletonList(formatter(formatterStep("default")));

@Test
void sameFingerprint() throws Exception {
String xml1 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1);
String xml2 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1);
void sameFingerprintWhenVersionAndFormattersAreTheSame() throws Exception {
MavenProject project = mavenProject(VERSION_1);

MavenProject project1 = mavenProject(xml1);
MavenProject project2 = mavenProject(xml2);

PluginFingerprint fingerprint1 = PluginFingerprint.from(project1, FORMATTERS);
PluginFingerprint fingerprint2 = PluginFingerprint.from(project2, FORMATTERS);
PluginFingerprint fingerprint1 = PluginFingerprint.from(project, FORMATTERS);
PluginFingerprint fingerprint2 = PluginFingerprint.from(project, FORMATTERS);

assertThat(fingerprint1).isEqualTo(fingerprint2);
}

@Test
void sameFingerprintWithDependencies() throws Exception {
String xml1 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1, DEPENDENCIES_1);
String xml2 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1, DEPENDENCIES_1);

MavenProject project1 = mavenProject(xml1);
MavenProject project2 = mavenProject(xml2);

PluginFingerprint fingerprint1 = PluginFingerprint.from(project1, FORMATTERS);
PluginFingerprint fingerprint2 = PluginFingerprint.from(project2, FORMATTERS);

assertThat(fingerprint1).isEqualTo(fingerprint2);
}

@Test
void differentFingerprintForDifferentDependencies() throws Exception {
String xml1 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1, DEPENDENCIES_1);
String xml2 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1, DEPENDENCIES_2);

MavenProject project1 = mavenProject(xml1);
MavenProject project2 = mavenProject(xml2);

PluginFingerprint fingerprint1 = PluginFingerprint.from(project1, FORMATTERS);
PluginFingerprint fingerprint2 = PluginFingerprint.from(project2, FORMATTERS);

assertThat(fingerprint1).isNotEqualTo(fingerprint2);
}

@Test
void differentFingerprintForDifferentPluginVersion() throws Exception {
String xml1 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1);
String xml2 = createPomXmlContent(VERSION_2, EXECUTION_1, CONFIGURATION_1);

MavenProject project1 = mavenProject(xml1);
MavenProject project2 = mavenProject(xml2);

PluginFingerprint fingerprint1 = PluginFingerprint.from(project1, FORMATTERS);
PluginFingerprint fingerprint2 = PluginFingerprint.from(project2, FORMATTERS);

assertThat(fingerprint1).isNotEqualTo(fingerprint2);
}

@Test
void differentFingerprintForDifferentExecution() throws Exception {
String xml1 = createPomXmlContent(VERSION_2, EXECUTION_1, CONFIGURATION_1);
String xml2 = createPomXmlContent(VERSION_2, EXECUTION_2, CONFIGURATION_1);

MavenProject project1 = mavenProject(xml1);
MavenProject project2 = mavenProject(xml2);

PluginFingerprint fingerprint1 = PluginFingerprint.from(project1, FORMATTERS);
PluginFingerprint fingerprint2 = PluginFingerprint.from(project2, FORMATTERS);

assertThat(fingerprint1).isNotEqualTo(fingerprint2);
}

@Test
void differentFingerprintForDifferentConfiguration() throws Exception {
String xml1 = createPomXmlContent(VERSION_1, EXECUTION_2, CONFIGURATION_2);
String xml2 = createPomXmlContent(VERSION_1, EXECUTION_2, CONFIGURATION_1);

MavenProject project1 = mavenProject(xml1);
MavenProject project2 = mavenProject(xml2);
void differentFingerprintForDifferentPluginVersions() throws Exception {
MavenProject project1 = mavenProject(VERSION_1);
MavenProject project2 = mavenProject(VERSION_2);

PluginFingerprint fingerprint1 = PluginFingerprint.from(project1, FORMATTERS);
PluginFingerprint fingerprint2 = PluginFingerprint.from(project2, FORMATTERS);
Expand All @@ -172,11 +68,8 @@ void differentFingerprintForDifferentConfiguration() throws Exception {

@Test
void differentFingerprintForFormattersWithDifferentSteps() throws Exception {
String xml1 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1);
String xml2 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1);

MavenProject project1 = mavenProject(xml1);
MavenProject project2 = mavenProject(xml2);
MavenProject project1 = mavenProject(VERSION_1);
MavenProject project2 = mavenProject(VERSION_1);

FormatterStep step1 = formatterStep("step1");
FormatterStep step2 = formatterStep("step2");
Expand All @@ -192,11 +85,8 @@ void differentFingerprintForFormattersWithDifferentSteps() throws Exception {

@Test
void differentFingerprintForFormattersWithDifferentLineEndings() throws Exception {
String xml1 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1);
String xml2 = createPomXmlContent(VERSION_1, EXECUTION_1, CONFIGURATION_1);

MavenProject project1 = mavenProject(xml1);
MavenProject project2 = mavenProject(xml2);
MavenProject project1 = mavenProject(VERSION_1);
MavenProject project2 = mavenProject(VERSION_1);

FormatterStep step = formatterStep("step");
List<Formatter> formatters1 = singletonList(formatter(LineEnding.UNIX, step));
Expand Down Expand Up @@ -224,7 +114,8 @@ void failsWhenProjectDoesNotContainSpotlessPlugin() {
.hasMessageContaining("Spotless plugin absent from the project");
}

private static MavenProject mavenProject(String xml) throws Exception {
private MavenProject mavenProject(String spotlessVersion) throws Exception {
String xml = createPomXmlContent(spotlessVersion, new String[0], new String[0]);
return new MavenProject(readPom(xml));
}

Expand Down

0 comments on commit c50503e

Please sign in to comment.