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

Allow custom separator for years in license header #199

Merged
merged 1 commit into from
Feb 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ You might be looking for:

### Version 1.10.0-SNAPSHOT - TBD (javadoc [lib](https://diffplug.github.io/spotless/javadoc/spotless-lib/snapshot/) [lib-extra](https://diffplug.github.io/spotless/javadoc/spotless-lib-extra/snapshot/), [snapshot repo](https://oss.sonatype.org/content/repositories/snapshots/com/diffplug/spotless/))

* LicenseHeaderStep now supports customizing the year range separator in copyright notices. ([#199](https://github.com/diffplug/spotless/pull/199))

### Version 1.9.0 - February 5th 2018 (javadoc [lib](https://diffplug.github.io/spotless/javadoc/spotless-lib/1.9.0/) [lib-extra](https://diffplug.github.io/spotless/javadoc/spotless-lib-extra/1.9.0/), artifact [lib]([jcenter](https://bintray.com/diffplug/opensource/spotless-lib), [lib-extra]([jcenter](https://bintray.com/diffplug/opensource/spotless-lib-extra)))

* Updated default ktlint from 0.6.1 to 0.14.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Nullable;

import com.diffplug.spotless.FormatterStep;
import com.diffplug.spotless.LineEnding;

Expand All @@ -33,6 +35,7 @@ public final class LicenseHeaderStep implements Serializable {
private static final long serialVersionUID = 1L;

private static final String NAME = "licenseHeader";
private static final String DEFAULT_YEAR_DELIMITER = "-";

private final String licenseHeader;
private final Pattern delimiterPattern;
Expand All @@ -44,10 +47,15 @@ public final class LicenseHeaderStep implements Serializable {

/** Creates a FormatterStep which forces the start of each file to match a license header. */
public static FormatterStep createFromHeader(String licenseHeader, String delimiter) {
return createFromHeader(licenseHeader, delimiter, null);
}

public static FormatterStep createFromHeader(String licenseHeader, String delimiter,
@Nullable String yearSeparator) {
Objects.requireNonNull(licenseHeader, "licenseHeader");
Objects.requireNonNull(delimiter, "delimiter");
return FormatterStep.create(LicenseHeaderStep.NAME,
new LicenseHeaderStep(licenseHeader, delimiter),
new LicenseHeaderStep(licenseHeader, delimiter, yearSeparator),
step -> step::format);
}

Expand All @@ -56,20 +64,36 @@ public static FormatterStep createFromHeader(String licenseHeader, String delimi
* contained in the given file.
*/
public static FormatterStep createFromFile(File licenseHeaderFile, Charset encoding, String delimiter) {
return createFromFile(licenseHeaderFile, encoding, delimiter, null);
}

/**
* Creates a FormatterStep which forces the start of each file to match the license header
* contained in the given file.
*/
public static FormatterStep createFromFile(File licenseHeaderFile, Charset encoding, String delimiter,
@Nullable String yearSeparator) {
Objects.requireNonNull(licenseHeaderFile, "licenseHeaderFile");
Objects.requireNonNull(encoding, "encoding");
Objects.requireNonNull(delimiter, "delimiter");
return FormatterStep.createLazy(LicenseHeaderStep.NAME,
() -> new LicenseHeaderStep(licenseHeaderFile, encoding, delimiter),
() -> new LicenseHeaderStep(licenseHeaderFile, encoding, delimiter, yearSeparator),
step -> step::format);
}

public static String name() {
return NAME;
}

public static String defaultYearDelimiter() {
return DEFAULT_YEAR_DELIMITER;
}

/** The license that we'd like enforced. */
private LicenseHeaderStep(String licenseHeader, String delimiter) {
private LicenseHeaderStep(String licenseHeader, String delimiter, @Nullable String yearSeparator) {
if (yearSeparator == null) {
yearSeparator = defaultYearDelimiter();
}
if (delimiter.contains("\n")) {
throw new IllegalArgumentException("The delimiter must not contain any newlines.");
}
Expand All @@ -86,13 +110,13 @@ private LicenseHeaderStep(String licenseHeader, String delimiter) {
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}(-[0-9]{4})?");
this.yearMatcherPattern = Pattern.compile("[0-9]{4}(" + Pattern.quote(yearSeparator) + "[0-9]{4})?");
}
}

/** Reads the license file from the given file. */
private LicenseHeaderStep(File licenseFile, Charset encoding, String delimiter) throws IOException {
this(new String(Files.readAllBytes(licenseFile.toPath()), encoding), delimiter);
private LicenseHeaderStep(File licenseFile, Charset encoding, String delimiter, @Nullable String yearSeparator) throws IOException {
this(new String(Files.readAllBytes(licenseFile.toPath()), encoding), delimiter, yearSeparator);
}

/** Formats the given string. */
Expand Down
2 changes: 2 additions & 0 deletions plugin-gradle/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

### Version 3.10.0-SNAPSHOT - TBD ([javadoc](https://diffplug.github.io/spotless/javadoc/snapshot/), [snapshot](https://oss.sonatype.org/content/repositories/snapshots/com/diffplug/spotless/spotless-plugin-gradle/))

* LicenseHeaderStep now supports customizing the year range separator in copyright notices. ([#199](https://github.com/diffplug/spotless/pull/199)

### Version 3.9.0 - February 5th 2018 ([javadoc](https://diffplug.github.io/spotless/javadoc/spotless-plugin-gradle/3.9.0/), [jcenter](https://bintray.com/diffplug/opensource/spotless-plugin-gradle/3.9.0))

* Updated default ktlint from 0.6.1 to 0.14.0
Expand Down
14 changes: 13 additions & 1 deletion plugin-gradle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,22 @@ The `licenseHeader` and `licenseHeaderFile` steps will generate license headers
* A generated license header will _not_ be updated when
* a single year is already present, e.g.
`/* Licensed under Apache-2.0 1990. */`
* a hyphen-separated year range is already present, e.g.
* a year range is already present, e.g.
`/* Licensed under Apache-2.0 1990-2003. */`
* the `$YEAR` token is otherwise missing

The separator for the year range defaults to the hyphen character, e.g `1990-2003`, but can be customized with the `yearSeparator` property.

For instance, the following configuration treats `1990, 2003` as a valid year range.

```gradle
spotless {
format java {
licenseHeader(''Licensed under Apache-2.0 $YEAR').yearSeparator(', ')
}
}
```


<a name="custom"></a>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,26 +345,90 @@ public void indentWithTabs() {
indentWithTabs(4);
}

abstract class LicenseHeaderConfig {

String delimiter;
String yearSeparator;

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

/**
* @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");
replaceStep(createStep());
return this;
}

/**
* @param yearSeparator
* 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");
replaceStep(createStep());
return this;
}

abstract FormatterStep createStep();
}

class LicenseStringHeaderConfig extends LicenseHeaderConfig {

private String header;

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

FormatterStep createStep() {
return LicenseHeaderStep.createFromHeader(header, delimiter, yearSeparator);
}
}

class LicenseFileHeaderConfig extends LicenseHeaderConfig {

private Object headerFile;

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

FormatterStep createStep() {
return LicenseHeaderStep
.createFromFile(getProject().file(headerFile), getEncoding(), delimiter,
yearSeparator);
}
}

/**
* @param licenseHeader
* Content that should be at the top of every file
* Content that should be at the top of every file.
* @param delimiter
* Spotless will look for a line that starts with this to know what the "top" is.
* Spotless will look for a line that starts with this regular expression pattern to know what the "top" is.
*/
public void licenseHeader(String licenseHeader, String delimiter) {
addStep(LicenseHeaderStep.createFromHeader(licenseHeader, delimiter));
public LicenseHeaderConfig licenseHeader(String licenseHeader, String delimiter) {
LicenseHeaderConfig config = new LicenseStringHeaderConfig(delimiter, licenseHeader);
addStep(config.createStep());
return config;
}

/**
* @param licenseHeaderFile
* Content that should be at the top of every file
* Content that should be at the top of every file.
* @param delimiter
* Spotless will look for a line that starts with this to know what the "top" is.
* Spotless will look for a line that starts with this regular expression pattern to know what the "top" is.
*/
public void licenseHeaderFile(Object licenseHeaderFile, String delimiter) {
Objects.requireNonNull(licenseHeaderFile, "licenseHeaderFile");
Objects.requireNonNull(delimiter, "delimiter");
addStep(LicenseHeaderStep.createFromFile(getProject().file(licenseHeaderFile), getEncoding(), delimiter));
public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile, String delimiter) {
LicenseHeaderConfig config = new LicenseFileHeaderConfig(delimiter, licenseHeaderFile);
addStep(config.createStep());
return config;
}

/** Sets up a format task according to the values in this extension. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ public void excludeJava(boolean excludeJava) {
this.excludeJava = excludeJava;
}

public void licenseHeader(String licenseHeader) {
licenseHeader(licenseHeader, JavaExtension.LICENSE_HEADER_DELIMITER);
public LicenseHeaderConfig licenseHeader(String licenseHeader) {
return licenseHeader(licenseHeader, JavaExtension.LICENSE_HEADER_DELIMITER);
}

public void licenseHeaderFile(Object licenseHeaderFile) {
licenseHeaderFile(licenseHeaderFile, JavaExtension.LICENSE_HEADER_DELIMITER);
public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile) {
return licenseHeaderFile(licenseHeaderFile, JavaExtension.LICENSE_HEADER_DELIMITER);
}

/** Method interface has been changed to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ public JavaExtension(SpotlessExtension rootExtension) {
// testlib/src/test/java/com/diffplug/spotless/generic/LicenseHeaderStepTest.java as well
static final String LICENSE_HEADER_DELIMITER = "package ";

public void licenseHeader(String licenseHeader) {
licenseHeader(licenseHeader, LICENSE_HEADER_DELIMITER);
public LicenseHeaderConfig licenseHeader(String licenseHeader) {
return licenseHeader(licenseHeader, LICENSE_HEADER_DELIMITER);
}

public void licenseHeaderFile(Object licenseHeaderFile) {
licenseHeaderFile(licenseHeaderFile, LICENSE_HEADER_DELIMITER);
public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile) {
return licenseHeaderFile(licenseHeaderFile, LICENSE_HEADER_DELIMITER);
}

/** Method interface has been changed to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ public KotlinExtension(SpotlessExtension rootExtension) {
super(rootExtension);
}

public void licenseHeader(String licenseHeader) {
licenseHeader(licenseHeader, LICENSE_HEADER_DELIMITER);
public LicenseHeaderConfig licenseHeader(String licenseHeader) {
return licenseHeader(licenseHeader, LICENSE_HEADER_DELIMITER);
}

public void licenseHeaderFile(Object licenseHeaderFile) {
licenseHeaderFile(licenseHeaderFile, LICENSE_HEADER_DELIMITER);
public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile) {
return licenseHeaderFile(licenseHeaderFile, LICENSE_HEADER_DELIMITER);
}

/** Adds the specified version of [ktlint](https://github.com/shyiko/ktlint). */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@

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

import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Test;

public class KotlinExtensionTest extends GradleIntegrationTest {
private static final String HEADER = "// License Header";
private static final String HEADER_WITH_YEAR = "// License Header $YEAR";

@Test
public void integration() throws IOException {
Expand Down Expand Up @@ -72,4 +74,66 @@ public void testWithHeader() throws IOException {
// Make sure that no additional stuff got added to the file.
.contains(HEADER + '\n' + original);
}

@Test
public void testWithCustomHeaderSeparator() throws IOException {
write("build.gradle",
"plugins {",
" id 'nebula.kotlin' version '1.0.6'",
" id 'com.diffplug.gradle.spotless'",
"}",
"repositories { mavenCentral() }",
"spotless {",
" kotlin {",
" licenseHeader ('" + HEADER + "', '@file')",
" ktlint()",
" }",
"}");
final File testFile = write("src/main/kotlin/test.kt", getTestResource("kotlin/licenseheader/KotlinCodeWithoutHeader.test"));
final String original = read(testFile.toPath());
gradleRunner().withArguments("spotlessApply").build();
final String result = read(testFile.toPath());
Assertions
.assertThat(result)
// Make sure the header gets added.
.startsWith(HEADER)
// Make sure that the rest of the file is still there with nothing removed.
.endsWith(original)
// Make sure that no additional stuff got added to the file.
.contains(HEADER + '\n' + original);
}

@Test
public void testWithNonStandardYearSeparator() throws IOException {
write("build.gradle",
"plugins {",
" id 'nebula.kotlin' version '1.0.6'",
" id 'com.diffplug.gradle.spotless'",
"}",
"repositories { mavenCentral() }",
"spotless {",
" kotlin {",
" licenseHeader('" + HEADER_WITH_YEAR + "').yearSeparator(', ')",
" ktlint()",
" }",
"}");

final File testFile = write("src/main/kotlin/test.kt", getTestResource("kotlin/licenseheader/KotlinCodeWithMultiYearHeader.test"));
final String original = read(testFile.toPath());
final File testFile2 = write("src/main/kotlin/test2.kt", getTestResource("kotlin/licenseheader/KotlinCodeWithMultiYearHeader2.test"));
final String original2 = read(testFile.toPath());
gradleRunner().withArguments("spotlessApply").build();
final String result = read(testFile.toPath());
final String result2 = read(testFile2.toPath());

Assertions
.assertThat(result)
// Make sure the a "valid" header isn't changed
.contains("// License Header 2012, 2014");

Assertions
.assertThat(result2)
// Make sure that an "invalid" header is rewritten
.startsWith(HEADER_WITH_YEAR.replace("$YEAR", String.valueOf(YearMonth.now().getYear())));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// License Header 2012, 2014
@file:JvmName("SomeFileName")
package my.test

object AnObject
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// License Header 2012-2014
@file:JvmName("SomeFileName")
package my.test

object AnObject
Loading