diff --git a/CHANGES.md b/CHANGES.md index fd8f864f9b..72ef499ec0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 +* Enable IntelliJ-compatible token `$today.year` for specifying the year in license header files. ([#542](https://github.com/diffplug/spotless/pull/542)) ### Build * All `CHANGES.md` are now in keepachangelog format. ([#507](https://github.com/diffplug/spotless/pull/507)) * We now use [javadoc.io](https://javadoc.io/) instead of github pages. ([#508](https://github.com/diffplug/spotless/pull/508)) diff --git a/lib/src/main/java/com/diffplug/spotless/generic/LicenseHeaderStep.java b/lib/src/main/java/com/diffplug/spotless/generic/LicenseHeaderStep.java index 590701a816..384738af84 100644 --- a/lib/src/main/java/com/diffplug/spotless/generic/LicenseHeaderStep.java +++ b/lib/src/main/java/com/diffplug/spotless/generic/LicenseHeaderStep.java @@ -21,7 +21,10 @@ import java.nio.charset.Charset; import java.nio.file.Files; import java.time.YearMonth; +import java.util.Arrays; +import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,17 +38,18 @@ public final class LicenseHeaderStep implements Serializable { private static final String NAME = "licenseHeader"; private static final String DEFAULT_YEAR_DELIMITER = "-"; + private static final List YEAR_TOKENS = Arrays.asList("$YEAR", "$today.year"); private static final SerializableFileFilter UNSUPPORTED_JVM_FILES_FILTER = SerializableFileFilter.skipFilesNamed( "package-info.java", "package-info.groovy", "module-info.java"); private final String licenseHeader; + private final boolean hasYearToken; private final Pattern delimiterPattern; - private Pattern yearMatcherPattern; - private boolean hasYearToken; - private String licenseHeaderBeforeYearToken; - private String licenseHeaderAfterYearToken; - private String licenseHeaderWithYearTokenReplaced; + private final Pattern yearMatcherPattern; + private final String licenseHeaderBeforeYearToken; + private final String licenseHeaderAfterYearToken; + private final String licenseHeaderWithYearTokenReplaced; /** Creates a FormatterStep which forces the start of each file to match a license header. */ public static FormatterStep createFromHeader(String licenseHeader, String delimiter) { @@ -107,16 +111,34 @@ private LicenseHeaderStep(String licenseHeader, String delimiter, String yearSep } this.licenseHeader = licenseHeader; this.delimiterPattern = Pattern.compile('^' + delimiter, Pattern.UNIX_LINES | Pattern.MULTILINE); - this.hasYearToken = licenseHeader.contains("$YEAR"); - if (this.hasYearToken) { - int yearTokenIndex = licenseHeader.indexOf("$YEAR"); - this.licenseHeaderBeforeYearToken = licenseHeader.substring(0, yearTokenIndex); - this.licenseHeaderAfterYearToken = licenseHeader.substring(yearTokenIndex + 5, licenseHeader.length()); - this.licenseHeaderWithYearTokenReplaced = licenseHeader.replace("$YEAR", String.valueOf(YearMonth.now().getYear())); - this.yearMatcherPattern = Pattern.compile("[0-9]{4}(" + Pattern.quote(yearSeparator) + "[0-9]{4})?"); + + Optional yearToken = getYearToken(licenseHeader); + this.hasYearToken = yearToken.isPresent(); + if (hasYearToken) { + int yearTokenIndex = licenseHeader.indexOf(yearToken.get()); + licenseHeaderBeforeYearToken = licenseHeader.substring(0, yearTokenIndex); + licenseHeaderAfterYearToken = licenseHeader.substring(yearTokenIndex + 5); + licenseHeaderWithYearTokenReplaced = licenseHeader.replace(yearToken.get(), String.valueOf(YearMonth.now().getYear())); + yearMatcherPattern = Pattern.compile("[0-9]{4}(" + Pattern.quote(yearSeparator) + "[0-9]{4})?"); + } else { + licenseHeaderBeforeYearToken = null; + licenseHeaderAfterYearToken = null; + licenseHeaderWithYearTokenReplaced = null; + yearMatcherPattern = null; } } + /** + * Get the first place holder token being used in the + * license header for specifying the year + * + * @param licenseHeader String representation of the license header + * @return Matching value from YEAR_TOKENS or null if none exist + */ + private static Optional getYearToken(String licenseHeader) { + return YEAR_TOKENS.stream().filter(licenseHeader::contains).findFirst(); + } + /** Reads the license file from the given file. */ private LicenseHeaderStep(File licenseFile, Charset encoding, String delimiter, String yearSeparator) throws IOException { this(new String(Files.readAllBytes(licenseFile.toPath()), encoding), delimiter, yearSeparator); diff --git a/plugin-gradle/CHANGES.md b/plugin-gradle/CHANGES.md index 09eda48b82..739ec3ef6d 100644 --- a/plugin-gradle/CHANGES.md +++ b/plugin-gradle/CHANGES.md @@ -3,10 +3,13 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `3.27.0`). ## [Unreleased] +### Added +* Enable IntelliJ-compatible token `$today.year` for specifying the year in license header files. ([#542](https://github.com/diffplug/spotless/pull/542)) ### Fixed * Eclipse-WTP formatter (web tools platform, not java) could encounter errors in parallel multiproject builds [#492](https://github.com/diffplug/spotless/issues/492). Fixed for Eclipse-WTP formatter Eclipse version 4.13.0 (default version). ## [3.27.2] - 2020-03-05 +### Fixed * Add tests to `SpecificFilesTest` to fix [#529](https://github.com/diffplug/spotless/issues/529) * If you applied spotless to a subproject, but not to the root project, then on Gradle 6+ you would get the deprecation warning `Using method Project#afterEvaluate(Action) when the project is already evaluated has been deprecated.` This has now been fixed. ([#506](https://github.com/diffplug/spotless/issues/506)) diff --git a/plugin-gradle/README.md b/plugin-gradle/README.md index 3436e32f9e..245f7f4220 100644 --- a/plugin-gradle/README.md +++ b/plugin-gradle/README.md @@ -523,9 +523,7 @@ to true. ## License header options -If the string contents of a licenseHeader step or the file contents of a licenseHeaderFile step contains a $YEAR token, -then in the end-result generated license headers which use this license header as a template, $YEAR will be replaced with the current year. - +If the license header (specified with `licenseHeader` or `licenseHeaderFile`) contains `$YEAR` or `$today.year`, then that token will be replaced with the current 4-digit year. For example: ``` diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 089e86e638..1998acb1a6 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -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 +* Enable IntelliJ-compatible token `$today.year` for specifying the year in license header files. ([#542](https://github.com/diffplug/spotless/pull/542)) ### Fixed * Fix scala and kotlin maven config documentation. * Eclipse-WTP formatter (web tools platform, not java) could encounter errors in parallel multiproject builds [#492](https://github.com/diffplug/spotless/issues/492). Fixed for Eclipse-WTP formatter Eclipse version 4.13.0 (default version). diff --git a/testlib/src/test/java/com/diffplug/spotless/generic/LicenseHeaderStepTest.java b/testlib/src/test/java/com/diffplug/spotless/generic/LicenseHeaderStepTest.java index 5d82767954..96b05ba5f9 100644 --- a/testlib/src/test/java/com/diffplug/spotless/generic/LicenseHeaderStepTest.java +++ b/testlib/src/test/java/com/diffplug/spotless/generic/LicenseHeaderStepTest.java @@ -39,6 +39,8 @@ public class LicenseHeaderStepTest extends ResourceHarness { private static final String KEY_FILE_WITH_LICENSE_AND_PLACEHOLDER = "license/FileWithLicenseHeaderAndPlaceholder.test"; // Licenses to test $YEAR token replacement private static final String LICENSE_HEADER_YEAR = "This is a fake license, $YEAR. ACME corp."; + // License to test $today.year token replacement + private static final String LICENSE_HEADER_YEAR_INTELLIJ_TOKEN = "This is a fake license, $today.year. ACME corp."; // Special case where the characters immediately before and after the year token are the same, // start position of the second part might overlap the end position of the first part. private static final String LICENSE_HEADER_YEAR_VARIANT = "This is a fake license. Copyright $YEAR ACME corp."; @@ -82,6 +84,12 @@ public void should_apply_license_containing_YEAR_token() throws Throwable { .test(fileWithLicenseContaining(" ACME corp."), fileWithLicenseContaining(LICENSE_HEADER_YEAR_VARIANT, currentYear())) .test(fileWithLicenseContaining("This is a fake license. Copyright ACME corp."), fileWithLicenseContaining(LICENSE_HEADER_YEAR_VARIANT, currentYear())) .test(fileWithLicenseContaining("This is a fake license. CopyrightACME corp."), fileWithLicenseContaining(LICENSE_HEADER_YEAR_VARIANT, currentYear())); + + //Check when token is of the format $today.year + step = LicenseHeaderStep.createFromFile(createLicenseWith(LICENSE_HEADER_YEAR_INTELLIJ_TOKEN), StandardCharsets.UTF_8, LICENSE_HEADER_DELIMITER); + + StepHarness.forStep(step) + .test(fileWithLicenseContaining(LICENSE_HEADER_YEAR_INTELLIJ_TOKEN), fileWithLicenseContaining(LICENSE_HEADER_YEAR_INTELLIJ_TOKEN, currentYear(), "$today.year")); } @Test @@ -126,6 +134,10 @@ private String fileWithLicenseContaining(String license, String yearContent) thr return getTestResource(KEY_FILE_WITH_LICENSE_AND_PLACEHOLDER).replace("__LICENSE_PLACEHOLDER__", license).replace("$YEAR", yearContent); } + private String fileWithLicenseContaining(String license, String yearContent, String token) throws IOException { + return getTestResource(KEY_FILE_WITH_LICENSE_AND_PLACEHOLDER).replace("__LICENSE_PLACEHOLDER__", license).replace(token, yearContent); + } + private String currentYear() { return String.valueOf(YearMonth.now().getYear()); }