-
Notifications
You must be signed in to change notification settings - Fork 522
add a $YEAR as a supported variable in license #179
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
| import java.io.Serializable; | ||
| import java.nio.charset.Charset; | ||
| import java.nio.file.Files; | ||
| import java.time.YearMonth; | ||
| import java.util.Objects; | ||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
|
|
@@ -35,6 +36,11 @@ public final class LicenseHeaderStep implements Serializable { | |
|
|
||
| private final String licenseHeader; | ||
| private final Pattern delimiterPattern; | ||
| private Pattern yearMatcherPattern; | ||
| private boolean hasYearToken; | ||
| private String licenseHeaderBeforeYEARToken; | ||
| private String licenseHeaderAfterYEARToken; | ||
| private 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) { | ||
|
|
@@ -74,6 +80,14 @@ private LicenseHeaderStep(String licenseHeader, String delimiter) { | |
| } | ||
| this.licenseHeader = licenseHeader; | ||
| this.delimiterPattern = Pattern.compile('^' + delimiter, Pattern.UNIX_LINES | Pattern.MULTILINE); | ||
| hasYearToken = licenseHeader.contains("$YEAR"); | ||
| if (hasYearToken) { | ||
| int yearTokenIndex = licenseHeader.indexOf("$YEAR"); | ||
| licenseHeaderBeforeYEARToken = licenseHeader.substring(0, yearTokenIndex); | ||
| licenseHeaderAfterYEARToken = licenseHeader.substring(yearTokenIndex + 5, licenseHeader.length()); | ||
| licenseHeaderWithYEARTokenReplaced = licenseHeader.replace("$YEAR", String.valueOf(YearMonth.now().getYear())); | ||
| this.yearMatcherPattern = Pattern.compile("[0-9]{4}(-[0-9]{4})?"); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor niggle: I believe it would read a bit better if all field usages in this constructor were prepended with For example, |
||
| } | ||
| } | ||
|
|
||
| /** Reads the license file from the given file. */ | ||
|
|
@@ -87,7 +101,14 @@ public String format(String raw) { | |
| if (!matcher.find()) { | ||
| throw new IllegalArgumentException("Unable to find delimiter regex " + delimiterPattern); | ||
| } else { | ||
| if (matcher.start() == licenseHeader.length() && raw.startsWith(licenseHeader)) { | ||
| if (hasYearToken) { | ||
| if (matchesLicenseWithYearToken(raw, matcher)) { | ||
| //that means we have the license like `licenseHeaderBeforeYEARToken 1990-2015 licenseHeaderAfterYEARToken` | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor niggle: There should ideally be a space in between |
||
| return raw; | ||
| } else { | ||
| return licenseHeaderWithYEARTokenReplaced + raw.substring(matcher.start()); | ||
| } | ||
| } else if (matcher.start() == licenseHeader.length() && raw.startsWith(licenseHeader)) { | ||
| // if no change is required, return the raw string without | ||
| // creating any other new strings for maximum performance | ||
| return raw; | ||
|
|
@@ -97,4 +118,10 @@ public String format(String raw) { | |
| } | ||
| } | ||
| } | ||
|
|
||
| private boolean matchesLicenseWithYearToken(String raw, Matcher matcher) { | ||
| int startOfTheSecondPart = raw.indexOf(licenseHeaderAfterYEARToken); | ||
| return (raw.startsWith(licenseHeaderBeforeYEARToken) && startOfTheSecondPart + licenseHeaderAfterYEARToken.length() == matcher.start()) | ||
| && yearMatcherPattern.matcher(raw.substring(licenseHeaderBeforeYEARToken.length(), startOfTheSecondPart)).matches(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again to clarify, usages of |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -273,6 +273,32 @@ spotless { | |
| } | ||
| ``` | ||
|
|
||
| <a name="license-header"></a> | ||
|
|
||
| ## License header options | ||
|
|
||
| The license header can contains a `$YEAR` variable that will be replaced by the current year. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if this sentence would read better as something like the following:
|
||
|
|
||
| For example: | ||
| ``` | ||
| /* Licensed under Apache-2.0 $YEAR. */ | ||
| ``` | ||
| will produce | ||
| ``` | ||
| /* Licensed under Apache-2.0 2017. */ | ||
| ``` | ||
| if build is launched in 2017 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if this would read better as:
|
||
|
|
||
|
|
||
| The step will change the license according to the following rules | ||
| * It replace the license using the current year when | ||
| * The license is missing | ||
| * The license is not formatted correctly | ||
| * It will *not* replace the license when | ||
| * The year variable is already present and is a single year, e.g. `/* Licensed under Apache-2.0 1990. */` | ||
| * The year variable is already present and is a year span, e.g. `/* Licensed under Apache-2.0 1990-2003. */` | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if these rules would read better as: @baptistemesta Is my understanding correct that no year substitution will happen if |
||
|
|
||
|
|
||
| <a name="custom"></a> | ||
|
|
||
| ## Custom rules | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,19 +16,27 @@ | |
| package com.diffplug.spotless.generic; | ||
|
|
||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.time.YearMonth; | ||
|
|
||
| import org.junit.Assert; | ||
| import org.junit.Test; | ||
|
|
||
| import com.diffplug.spotless.FormatterStep; | ||
| import com.diffplug.spotless.ResourceHarness; | ||
| import com.diffplug.spotless.SerializableEqualityTester; | ||
| import com.diffplug.spotless.StepHarness; | ||
|
|
||
| public class LicenseHeaderStepTest extends ResourceHarness { | ||
| private static final String KEY_LICENSE = "license/TestLicense"; | ||
| private static final String KEY_FILE_NOTAPPLIED = "license/MissingLicense.test"; | ||
| private static final String KEY_FILE_APPLIED = "license/HasLicense.test"; | ||
| private static final String KEY_LICENSE_WITH_YEAR = "license/TestLicencseWithYear"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/TestLicencseWithYear/LicenseWithYear/ ? |
||
| private static final String KEY_FILE_WITHOUT_LICENSE = "license/MissLicenseWithYear.test"; | ||
| private static final String KEY_FILE_WITH_PREVIOUS_YEAR = "license/LicenseWithPreviousYear.test"; | ||
| private static final String KEY_FILE_WITH_PREVIOUS_YEARS = "license/LicenseWithPreviousYears.test"; | ||
| private static final String KEY_FILE_WITH_CURRENT_YEAR = "license/LicenseWithYear.test"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe that
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch |
||
|
|
||
| // If this constant changes, don't forget to change the similarly-named one in | ||
| // plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java as well | ||
|
|
@@ -46,6 +54,26 @@ public void fromFile() throws Throwable { | |
| assertOnResources(step, KEY_FILE_NOTAPPLIED, KEY_FILE_APPLIED); | ||
| } | ||
|
|
||
| @Test | ||
| public void should_apply_license_containing_YEAR_variable() throws Throwable { | ||
| FormatterStep step = LicenseHeaderStep.createFromFile(createTestFile(KEY_LICENSE_WITH_YEAR), StandardCharsets.UTF_8, LICENSE_HEADER_DELIMITER); | ||
|
|
||
| StepHarness.forStep(step) | ||
| .test(getTestResource(KEY_FILE_WITHOUT_LICENSE), getFileContentWithYEAR(currentYear())) | ||
| .testUnaffected(getFileContentWithYEAR(currentYear())) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From a reproducibility standpoint, using the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this token is not something configurable, Spotless will always replace the license with
with that, we could set the configuration in test to fixed values instead of a |
||
| .testUnaffected(getFileContentWithYEAR("2003")) | ||
| .testUnaffected(getFileContentWithYEAR("1990-2015")) | ||
| .test(getFileContentWithYEAR("not a year"), getFileContentWithYEAR(currentYear())); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unless I've misunderstood something, I think that this line should be like the following code snippet, so that we test that Spotless replaces .test(getFileContentWithYEAR("$YEAR"), getFileContentWithYEAR(currentYear()));If
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We want to check here that the regex |
||
| } | ||
|
|
||
| private String getFileContentWithYEAR(String year) throws IOException { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it makes more sense for the "YEAR" in this method name to be replaced with "YearToken", to be consistent with
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. renamed. but its more really the content of the |
||
| return getTestResource(KEY_FILE_WITH_CURRENT_YEAR).replace("__YEAR_to_replace_in_tests__", year); | ||
| } | ||
|
|
||
| private String currentYear() { | ||
| return String.valueOf(YearMonth.now().getYear()); | ||
| } | ||
|
|
||
| @Test | ||
| public void efficient() throws Throwable { | ||
| FormatterStep step = LicenseHeaderStep.createFromHeader("LicenseHeader\n", "contentstart"); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| /* | ||
| * Copyright (C) __YEAR_to_replace_in_tests__. ACME corp. | ||
| * This library is free software; you can redistribute it and/or modify it under the terms | ||
| * of the GNU Lesser General Public License as published by the Free Software Foundation | ||
| * version 2.1 of the License. | ||
| * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | ||
| * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| * See the GNU Lesser General Public License for more details. | ||
| * You should have received a copy of the GNU Lesser General Public License along with this | ||
| * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth | ||
| * Floor, Boston, MA 02110-1301, USA. | ||
| **/ | ||
| package com.acme; | ||
|
|
||
| import java.util.function.Function; | ||
|
|
||
|
|
||
| public class Java8Test { | ||
| public void doStuff() throws Exception { | ||
| Function<String, Integer> example = Integer::parseInt; | ||
| example.andThen(val -> { | ||
| return val + 2; | ||
| } ); | ||
| SimpleEnum val = SimpleEnum.A; | ||
| switch (val) { | ||
| case A: | ||
| break; | ||
| case B: | ||
| break; | ||
| case C: | ||
| break; | ||
| default: | ||
| throw new Exception(); | ||
| } | ||
| } | ||
|
|
||
| public enum SimpleEnum { | ||
| A, B, C; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package com.acme; | ||
|
|
||
| import java.util.function.Function; | ||
|
|
||
|
|
||
| public class Java8Test { | ||
| public void doStuff() throws Exception { | ||
| Function<String, Integer> example = Integer::parseInt; | ||
| example.andThen(val -> { | ||
| return val + 2; | ||
| } ); | ||
| SimpleEnum val = SimpleEnum.A; | ||
| switch (val) { | ||
| case A: | ||
| break; | ||
| case B: | ||
| break; | ||
| case C: | ||
| break; | ||
| default: | ||
| throw new Exception(); | ||
| } | ||
| } | ||
|
|
||
| public enum SimpleEnum { | ||
| A, B, C; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| /* | ||
| * Copyright (C) $YEAR. ACME corp. | ||
| * This library is free software; you can redistribute it and/or modify it under the terms | ||
| * of the GNU Lesser General Public License as published by the Free Software Foundation | ||
| * version 2.1 of the License. | ||
| * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | ||
| * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| * See the GNU Lesser General Public License for more details. | ||
| * You should have received a copy of the GNU Lesser General Public License along with this | ||
| * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth | ||
| * Floor, Boston, MA 02110-1301, USA. | ||
| **/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor niggle: I'd ideally like to see instances of
YEARin field names turned intoYear, to be consistent with the rest of the code.Just to clarify, there's no need to change strings like
$YEARstarting with a dollar sign to$Year- just field names. :)