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

Refactor the public API of LicenseHeaderStep #628

Merged
merged 7 commits into from
Jun 30, 2020
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
* **BREAKING** `FileSignature` can no longer sign folders, only files. Signatures are now based only on filename (not path), size, and a content hash. It throws an error if a signature is attempted on a folder or on multiple files with different paths but the same filename - it never breaks silently. This change does not break any of Spotless' internal logic, so it is unlikely to affect any of Spotless' consumers either. ([#571](https://github.com/diffplug/spotless/pull/571))
* This change allows the maven plugin to cache classloaders across subprojects when loading config resources from the classpath (fixes [#559](https://github.com/diffplug/spotless/issues/559)).
* This change also allows the gradle plugin to work with the remote buildcache (fixes [#280](https://github.com/diffplug/spotless/issues/280)).
* **BREAKING** Heavy refactor of the `LicenseHeaderStep` public API. Doesn't change internal behavior, but makes implementation of the gradle and maven plugins much easier. ([#628](https://github.com/diffplug/spotless/pull/628))

## [1.34.1] - 2020-06-17
### Changed
Expand Down
448 changes: 252 additions & 196 deletions lib/src/main/java/com/diffplug/spotless/generic/LicenseHeaderStep.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import static com.diffplug.gradle.spotless.PluginGradlePreconditions.requireElementsNonNull;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.nio.file.Files;
Expand Down Expand Up @@ -47,6 +46,7 @@
import com.diffplug.spotless.generic.EndWithNewlineStep;
import com.diffplug.spotless.generic.IndentStep;
import com.diffplug.spotless.generic.LicenseHeaderStep;
import com.diffplug.spotless.generic.LicenseHeaderStep.YearMode;
import com.diffplug.spotless.generic.ReplaceRegexStep;
import com.diffplug.spotless.generic.ReplaceStep;
import com.diffplug.spotless.generic.TrimTrailingWhitespaceStep;
Expand Down Expand Up @@ -443,21 +443,20 @@ public void indentWithTabs() {
* For most language-specific formats (e.g. java, scala, etc.) you can omit the second `delimiter` argument, because it is supplied
* automatically ({@link HasBuiltinDelimiterForLicense}).
*/
public abstract class LicenseHeaderConfig {
String delimiter;
String yearSeparator = LicenseHeaderStep.defaultYearDelimiter();
public class LicenseHeaderConfig {
LicenseHeaderStep builder;
Boolean updateYearWithLatest = null;

public LicenseHeaderConfig(String delimiter) {
this.delimiter = Objects.requireNonNull(delimiter, "delimiter");
public LicenseHeaderConfig(LicenseHeaderStep builder) {
this.builder = builder;
}

/**
* @param delimiter
* Spotless will look for a line that starts with this regular expression pattern to know what the "top" is.
*/
public LicenseHeaderConfig delimiter(String delimiter) {
this.delimiter = Objects.requireNonNull(delimiter, "delimiter");
builder = builder.withDelimiter(delimiter);
replaceStep(createStep());
return this;
}
Expand All @@ -467,7 +466,7 @@ public LicenseHeaderConfig delimiter(String delimiter) {
* The characters used to separate the first and last years in multi years patterns.
*/
public LicenseHeaderConfig yearSeparator(String yearSeparator) {
this.yearSeparator = Objects.requireNonNull(yearSeparator, "yearSeparator");
builder = builder.withYearSeparator(yearSeparator);
replaceStep(createStep());
return this;
}
Expand All @@ -483,61 +482,15 @@ public LicenseHeaderConfig updateYearWithLatest(boolean updateYearWithLatest) {
return this;
}

protected abstract String licenseHeader() throws IOException;

FormatterStep createStep() {
if ("true".equals(spotless.project.findProperty(LicenseHeaderStep.FLAG_SET_LICENSE_HEADER_YEARS_FROM_GIT_HISTORY()))) {
return FormatterStep.createNeverUpToDateLazy(LicenseHeaderStep.name(), () -> {
boolean updateYear = false; // doesn't matter
LicenseHeaderStep step = new LicenseHeaderStep(licenseHeader(), delimiter, yearSeparator, updateYear);
return new FormatterFunc() {
@Override
public String apply(String input, File source) throws Exception {
return step.setLicenseHeaderYearsFromGitHistory(input, source);
}

@Override
public String apply(String input) throws Exception {
throw new UnsupportedOperationException();
}
};
});
} else {
return FormatterStep.createLazy(LicenseHeaderStep.name(), () -> {
// by default, we should update the year if the user is using ratchetFrom
return builder.withYearModeLazy(() -> {
if ("true".equals(spotless.project.findProperty(LicenseHeaderStep.FLAG_SET_LICENSE_HEADER_YEARS_FROM_GIT_HISTORY()))) {
return YearMode.SET_FROM_GIT;
} else {
boolean updateYear = updateYearWithLatest == null ? getRatchetFrom() != null : updateYearWithLatest;
return new LicenseHeaderStep(licenseHeader(), delimiter, yearSeparator, updateYear);
}, step -> step::format);
}
}
}

private class LicenseStringHeaderConfig extends LicenseHeaderConfig {
private String header;

LicenseStringHeaderConfig(String delimiter, String header) {
super(delimiter);
this.header = Objects.requireNonNull(header, "header");
}

@Override
protected String licenseHeader() {
return header;
}
}

private class LicenseFileHeaderConfig extends LicenseHeaderConfig {
private Object headerFile;

LicenseFileHeaderConfig(String delimiter, Object headerFile) {
super(delimiter);
this.headerFile = Objects.requireNonNull(headerFile, "headerFile");
}

@Override
protected String licenseHeader() throws IOException {
byte[] content = Files.readAllBytes(getProject().file(headerFile).toPath());
return new String(content, getEncoding());
return updateYear ? YearMode.UPDATE_TO_TODAY : YearMode.PRESERVE;
}
}).build();
}
}

Expand All @@ -548,7 +501,7 @@ protected String licenseHeader() throws IOException {
* Spotless will look for a line that starts with this regular expression pattern to know what the "top" is.
*/
public LicenseHeaderConfig licenseHeader(String licenseHeader, String delimiter) {
LicenseHeaderConfig config = new LicenseStringHeaderConfig(delimiter, licenseHeader);
LicenseHeaderConfig config = new LicenseHeaderConfig(LicenseHeaderStep.headerDelimiter(licenseHeader, delimiter));
addStep(config.createStep());
return config;
}
Expand All @@ -560,7 +513,11 @@ public LicenseHeaderConfig licenseHeader(String licenseHeader, String delimiter)
* Spotless will look for a line that starts with this regular expression pattern to know what the "top" is.
*/
public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile, String delimiter) {
LicenseHeaderConfig config = new LicenseFileHeaderConfig(delimiter, licenseHeaderFile);
LicenseHeaderConfig config = new LicenseHeaderConfig(LicenseHeaderStep.headerDelimiter(() -> {
File file = getProject().file(licenseHeaderFile);
byte[] data = Files.readAllBytes(file.toPath());
return new String(data, getEncoding());
}, delimiter));
addStep(config.createStep());
return config;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ private void assertUnchanged(String year) throws IOException {

private void assertTransform(String yearBefore, String yearAfter) throws IOException {
setFile(TEST_JAVA).toContent("/** " + yearBefore + " */\n" + CONTENT);
gradleRunner().withArguments("spotlessApply", "--stacktrace").build();
gradleRunner().withArguments("spotlessApply", "--stacktrace").forwardOutput().build();
assertFile(TEST_JAVA).hasContent("/** " + yearAfter + " */\n" + CONTENT);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@
*/
package com.diffplug.spotless.maven.generic;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

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

import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.generic.LicenseHeaderStep;
import com.diffplug.spotless.generic.LicenseHeaderStep.YearMode;
import com.diffplug.spotless.maven.FormatterStepConfig;
import com.diffplug.spotless.maven.FormatterStepFactory;

Expand All @@ -45,32 +44,17 @@ public final FormatterStep newFormatterStep(FormatterStepConfig config) {
throw new IllegalArgumentException("You need to specify 'delimiter'.");
}
if (file != null ^ content != null) {
FormatterStep unfiltered;
YearMode yearMode;
if ("true".equals(config.spotlessSetLicenseHeaderYearsFromGitHistory().orElse(""))) {
unfiltered = FormatterStep.createNeverUpToDateLazy(LicenseHeaderStep.name(), () -> {
boolean updateYear = false; // doesn't matter
LicenseHeaderStep step = new LicenseHeaderStep(readFileOrContent(config), delimiterString, LicenseHeaderStep.defaultYearDelimiter(), updateYear);
return new FormatterFunc() {
@Override
public String apply(String input, File source) throws Exception {
return step.setLicenseHeaderYearsFromGitHistory(input, source);
}

@Override
public String apply(String input) throws Exception {
throw new UnsupportedOperationException();
}
};
});
yearMode = YearMode.SET_FROM_GIT;
} else {
unfiltered = FormatterStep.createLazy(LicenseHeaderStep.name(), () -> {
// by default, we should update the year if the user is using ratchetFrom
boolean updateYear = config.getRatchetFrom().isPresent();
String header = readFileOrContent(config);
return new LicenseHeaderStep(header, delimiterString, LicenseHeaderStep.defaultYearDelimiter(), updateYear);
}, step -> step::format);
boolean updateYear = config.getRatchetFrom().isPresent();
yearMode = updateYear ? YearMode.UPDATE_TO_TODAY : YearMode.PRESERVE;
}
return unfiltered.filterByFile(LicenseHeaderStep.unsupportedJvmFilesFilter());
return LicenseHeaderStep.headerDelimiter(() -> readFileOrContent(config), delimiterString)
.withYearMode(yearMode)
.build()
.filterByFile(LicenseHeaderStep.unsupportedJvmFilesFilter());
} else {
throw new IllegalArgumentException("Must specify exactly one of 'file' or 'content'.");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2020 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless.maven.generic;

import java.io.IOException;
import java.time.YearMonth;

import org.eclipse.jgit.api.Git;
import org.junit.Test;

import com.diffplug.spotless.maven.MavenIntegrationHarness;

public class LicenseHeaderRatchetTest extends MavenIntegrationHarness {
private static final String NOW = String.valueOf(YearMonth.now().getYear());

private static final String TEST_JAVA = "src/main/java/pkg/Test.java";
private static final String CONTENT = "package pkg;\npublic class Test {}";

private void setRatchetFrom(String ratchetFrom) throws IOException {
writePomWithJavaSteps(
"<licenseHeader>",
" <content>/** $YEAR */</content>",
"</licenseHeader>",
ratchetFrom);
}

private void assertUnchanged(String year) throws Exception {
assertTransform(year, year);
}

private void assertTransform(String yearBefore, String yearAfter) throws Exception {
setFile(TEST_JAVA).toContent("/** " + yearBefore + " */\n" + CONTENT);
mavenRunner().withArguments("spotless:apply").runNoError();
assertFile(TEST_JAVA).hasContent("/** " + yearAfter + " */\n" + CONTENT);
}

private void testSuiteUpdateWithLatest(boolean update) throws Exception {
if (update) {
assertTransform("2003", "2003-" + NOW);
assertTransform("2003-2005", "2003-" + NOW);
} else {
assertUnchanged("2003");
assertUnchanged("2003-2005");
}
assertUnchanged(NOW);
assertTransform("", NOW);
}

@Test
public void normal() throws Exception {
setRatchetFrom("");
testSuiteUpdateWithLatest(false);
}

@Test
public void ratchetFrom() throws Exception {
try (Git git = Git.init().setDirectory(rootFolder()).call()) {
git.commit().setMessage("First commit").call();
}
setRatchetFrom("<ratchetFrom>HEAD</ratchetFrom>");
testSuiteUpdateWithLatest(true);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 DiffPlug
* Copyright 2016-2020 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 @@ -31,7 +31,7 @@ public class CppDefaultsTest extends ResourceHarness {
@Test
public void testDelimiterExpr() throws Exception {
final String header = "/*My tests header*/";
FormatterStep step = LicenseHeaderStep.createFromHeader(header, CppDefaults.DELIMITER_EXPR);
FormatterStep step = LicenseHeaderStep.headerDelimiter(header, CppDefaults.DELIMITER_EXPR).build();
final File dummyFile = setFile("src/main/cpp/file1.dummy").toContent("");
for (String testSource : Arrays.asList(
"//Accpet multiple spaces between composed term.@using namespace std;",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 DiffPlug
* Copyright 2016-2020 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 @@ -33,7 +33,7 @@ public class CssDefaultsTest extends ResourceHarness {
@Test
public void testDelimiterExpr() throws Exception {
final String header = "/*My tests header*/";
FormatterStep step = LicenseHeaderStep.createFromHeader(header, CssDefaults.DELIMITER_EXPR);
FormatterStep step = LicenseHeaderStep.headerDelimiter(header, CssDefaults.DELIMITER_EXPR).build();
final File dummyFile = setFile("src/main/cpp/file1.dummy").toContent("");
for (String testSource : Arrays.asList(
"/* Starts with element selector */@\np {",
Expand Down
Loading