Skip to content

Commit

Permalink
Support $FILE in license headers (#1605)
Browse files Browse the repository at this point in the history
  • Loading branch information
nedtwigg authored Mar 11, 2023
2 parents ec85679 + 40488be commit 7477651
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ This document is intended for Spotless developers.
We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`).

## [Unreleased]
### Added
* 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))
### Changes
* We are now opting in to Gradle's new stable configuration cache. ([#1591](https://github.com/diffplug/spotless/pull/1591))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public FormatterStep build() {
throw new IllegalStateException(yearMode.toString());
}
return new Runtime(headerLazy.get(), delimiter, yearSeparator, updateYear, skipLinesMatching);
}, step -> step::format);
}, step -> FormatterFunc.needsFile(step::format));
}

if (contentPattern == null) {
Expand Down Expand Up @@ -214,6 +214,9 @@ private static class Runtime implements Serializable {
private final @Nullable String afterYear;
private final boolean updateYearWithLatest;
private final boolean licenseHeaderWithRange;
private final boolean hasFileToken;

private static final Pattern FILENAME_PATTERN = Pattern.compile("\\$FILE");

/** The license that we'd like enforced. */
private Runtime(String licenseHeader, String delimiter, String yearSeparator, boolean updateYearWithLatest, @Nullable String skipLinesMatching) {
Expand All @@ -227,6 +230,7 @@ private Runtime(String licenseHeader, String delimiter, String yearSeparator, bo
}
this.delimiterPattern = Pattern.compile('^' + delimiter, Pattern.UNIX_LINES | Pattern.MULTILINE);
this.skipLinesMatching = skipLinesMatching == null ? null : Pattern.compile(skipLinesMatching);
this.hasFileToken = FILENAME_PATTERN.matcher(licenseHeader).find();

Optional<String> yearToken = getYearToken(licenseHeader);
if (yearToken.isPresent()) {
Expand Down Expand Up @@ -267,9 +271,9 @@ private static Optional<String> getYearToken(String licenseHeader) {
}

/** Formats the given string. */
private String format(String raw) {
private String format(String raw, File file) {
if (skipLinesMatching == null) {
return addOrUpdateLicenseHeader(raw);
return addOrUpdateLicenseHeader(raw, file);
} else {
String[] lines = raw.split("\n");
StringBuilder skippedLinesBuilder = new StringBuilder();
Expand All @@ -288,11 +292,17 @@ private String format(String raw) {
remainingLinesBuilder.append(line).append('\n');
}
}
return skippedLinesBuilder + addOrUpdateLicenseHeader(remainingLinesBuilder.toString());
return skippedLinesBuilder + addOrUpdateLicenseHeader(remainingLinesBuilder.toString(), file);
}
}

private String addOrUpdateLicenseHeader(String raw) {
private String addOrUpdateLicenseHeader(String raw, File file) {
raw = replaceYear(raw);
raw = replaceFileName(raw, file);
return raw;
}

private String replaceYear(String raw) {
Matcher contentMatcher = delimiterPattern.matcher(raw);
if (!contentMatcher.find()) {
throw new IllegalArgumentException("Unable to find delimiter regex " + delimiterPattern);
Expand Down Expand Up @@ -422,6 +432,19 @@ private String setLicenseHeaderYearsFromGitHistory(String raw, File file) throws
return beforeYear + yearRange + afterYear + raw.substring(contentMatcher.start());
}

private String replaceFileName(String raw, File file) {
if (!hasFileToken) {
return raw;
}
Matcher contentMatcher = delimiterPattern.matcher(raw);
if (!contentMatcher.find()) {
throw new IllegalArgumentException("Unable to find delimiter regex " + delimiterPattern);
}
String header = raw.substring(0, contentMatcher.start());
String content = raw.substring(contentMatcher.start());
return FILENAME_PATTERN.matcher(header).replaceAll(file.getName()) + content;
}

private static String parseYear(String cmd, File file) throws IOException {
String fullCmd = cmd + " -- " + file.getAbsolutePath();
ProcessBuilder builder = new ProcessBuilder().directory(file.getParentFile());
Expand Down
2 changes: 2 additions & 0 deletions plugin-gradle/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 `3.27.0`).

## [Unreleased]
### Added
* 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))
* `licenseHeader` default pattern for Java files is updated to `(package|import|public|class|module) `. ([#1614](https://github.com/diffplug/spotless/pull/1614))

## [6.16.0] - 2023-02-27
Expand Down
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]
### Added
* 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))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,16 @@
import com.diffplug.spotless.ResourceHarness;
import com.diffplug.spotless.SerializableEqualityTester;
import com.diffplug.spotless.StepHarness;
import com.diffplug.spotless.StepHarnessWithFile;
import com.diffplug.spotless.generic.LicenseHeaderStep.YearMode;

class LicenseHeaderStepTest extends ResourceHarness {
private static final String FILE_NO_LICENSE = "license/FileWithoutLicenseHeader.test";
private static final String package_ = LicenseHeaderStep.DEFAULT_JAVA_HEADER_DELIMITER;
private static final String HEADER_WITH_$YEAR = "This is a fake license, $YEAR. ACME corp.";
private static final String HEADER_WITH_RANGE_TO_$YEAR = "This is a fake license with range, 2009-$YEAR. ACME corp.";
private static final String HEADER_WITH_$FILE = "This is a fake license, $FILE. ACME corp.";
private static final String HEADER_WITH_$YEAR_$FILE = "This is a fake license, $FILE, $YEAR. ACME corp.";

@Test
void parseExistingYear() throws Exception {
Expand Down Expand Up @@ -163,6 +166,16 @@ private String hasHeaderWithRangeAndWithYearTo(String toYear) throws IOException
return hasHeaderYear(HEADER_WITH_RANGE_TO_$YEAR, toYear);
}

private String hasHeaderFileName(String license, String fileName) throws IOException {
return header(license).replace("$FILE", fileName) + getTestResource(FILE_NO_LICENSE);
}

private String hasHeaderYearFileName(String license, String year, String fileName) throws IOException {
return header(license)
.replace("$YEAR", year)
.replace("$FILE", fileName) + getTestResource(FILE_NO_LICENSE);
}

private static String currentYear() {
return String.valueOf(YearMonth.now().getYear());
}
Expand Down Expand Up @@ -252,6 +265,36 @@ void should_preserve_year_for_license_with_address() throws Throwable {
}

@Test
void should_apply_license_containing_filename_token() throws Exception {
FormatterStep step = LicenseHeaderStep.headerDelimiter(header(HEADER_WITH_$FILE), package_).build();
StepHarnessWithFile.forStep(this, step)
.test(new File("Test.java"), getTestResource(FILE_NO_LICENSE), hasHeaderFileName(HEADER_WITH_$FILE, "Test.java"))
.testUnaffected(new File("Test.java"), hasHeaderFileName(HEADER_WITH_$FILE, "Test.java"));
}

@Test
void should_update_license_containing_filename_token() throws Exception {
FormatterStep step = LicenseHeaderStep.headerDelimiter(header(HEADER_WITH_$FILE), package_).build();
StepHarnessWithFile.forStep(this, step)
.test(
new File("After.java"),
hasHeaderFileName(HEADER_WITH_$FILE, "Before.java"),
hasHeaderFileName(HEADER_WITH_$FILE, "After.java"));
}

@Test
void should_apply_license_containing_YEAR_filename_token() throws Exception {
FormatterStep step = LicenseHeaderStep.headerDelimiter(header(HEADER_WITH_$YEAR_$FILE), package_).build();
StepHarnessWithFile.forStep(this, step)
.test(
new File("Test.java"),
getTestResource(FILE_NO_LICENSE),
hasHeaderYearFileName(HEADER_WITH_$YEAR_$FILE, currentYear(), "Test.java"))
.testUnaffected(
new File("Test.java"),
hasHeaderYearFileName(HEADER_WITH_$YEAR_$FILE, currentYear(), "Test.java"));
}

void noPackage() throws Throwable {
String header = header(getTestResource("license/TestLicense"));
FormatterStep step = LicenseHeaderStep.headerDelimiter(header, package_).build();
Expand Down

0 comments on commit 7477651

Please sign in to comment.