Skip to content

Commit 8756832

Browse files
committedFeb 9, 2018
Allow custom separator for years in license header
1 parent 115aa61 commit 8756832

File tree

12 files changed

+237
-29
lines changed

12 files changed

+237
-29
lines changed
 

‎CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ You might be looking for:
77

88
### 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/))
99

10+
* LicenseHeaderStep now supports customizing the year range separator in copyright notices. ([#199](https://github.com/diffplug/spotless/pull/199))
11+
1012
### 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)))
1113

1214
* Updated default ktlint from 0.6.1 to 0.14.0

‎lib/src/main/java/com/diffplug/spotless/generic/LicenseHeaderStep.java

+30-6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
import java.util.regex.Matcher;
2626
import java.util.regex.Pattern;
2727

28+
import javax.annotation.Nullable;
29+
2830
import com.diffplug.spotless.FormatterStep;
2931
import com.diffplug.spotless.LineEnding;
3032

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

3537
private static final String NAME = "licenseHeader";
38+
private static final String DEFAULT_YEAR_DELIMITER = "-";
3639

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

4548
/** Creates a FormatterStep which forces the start of each file to match a license header. */
4649
public static FormatterStep createFromHeader(String licenseHeader, String delimiter) {
50+
return createFromHeader(licenseHeader, delimiter, null);
51+
}
52+
53+
public static FormatterStep createFromHeader(String licenseHeader, String delimiter,
54+
@Nullable String yearSeparator) {
4755
Objects.requireNonNull(licenseHeader, "licenseHeader");
4856
Objects.requireNonNull(delimiter, "delimiter");
4957
return FormatterStep.create(LicenseHeaderStep.NAME,
50-
new LicenseHeaderStep(licenseHeader, delimiter),
58+
new LicenseHeaderStep(licenseHeader, delimiter, yearSeparator),
5159
step -> step::format);
5260
}
5361

@@ -56,20 +64,36 @@ public static FormatterStep createFromHeader(String licenseHeader, String delimi
5664
* contained in the given file.
5765
*/
5866
public static FormatterStep createFromFile(File licenseHeaderFile, Charset encoding, String delimiter) {
67+
return createFromFile(licenseHeaderFile, encoding, delimiter, null);
68+
}
69+
70+
/**
71+
* Creates a FormatterStep which forces the start of each file to match the license header
72+
* contained in the given file.
73+
*/
74+
public static FormatterStep createFromFile(File licenseHeaderFile, Charset encoding, String delimiter,
75+
@Nullable String yearSeparator) {
5976
Objects.requireNonNull(licenseHeaderFile, "licenseHeaderFile");
6077
Objects.requireNonNull(encoding, "encoding");
6178
Objects.requireNonNull(delimiter, "delimiter");
6279
return FormatterStep.createLazy(LicenseHeaderStep.NAME,
63-
() -> new LicenseHeaderStep(licenseHeaderFile, encoding, delimiter),
80+
() -> new LicenseHeaderStep(licenseHeaderFile, encoding, delimiter, yearSeparator),
6481
step -> step::format);
6582
}
6683

6784
public static String name() {
6885
return NAME;
6986
}
7087

88+
public static String defaultYearDelimiter() {
89+
return DEFAULT_YEAR_DELIMITER;
90+
}
91+
7192
/** The license that we'd like enforced. */
72-
private LicenseHeaderStep(String licenseHeader, String delimiter) {
93+
private LicenseHeaderStep(String licenseHeader, String delimiter, @Nullable String yearSeparator) {
94+
if (yearSeparator == null) {
95+
yearSeparator = defaultYearDelimiter();
96+
}
7397
if (delimiter.contains("\n")) {
7498
throw new IllegalArgumentException("The delimiter must not contain any newlines.");
7599
}
@@ -86,13 +110,13 @@ private LicenseHeaderStep(String licenseHeader, String delimiter) {
86110
this.licenseHeaderBeforeYearToken = licenseHeader.substring(0, yearTokenIndex);
87111
this.licenseHeaderAfterYearToken = licenseHeader.substring(yearTokenIndex + 5, licenseHeader.length());
88112
this.licenseHeaderWithYearTokenReplaced = licenseHeader.replace("$YEAR", String.valueOf(YearMonth.now().getYear()));
89-
this.yearMatcherPattern = Pattern.compile("[0-9]{4}(-[0-9]{4})?");
113+
this.yearMatcherPattern = Pattern.compile("[0-9]{4}(" + Pattern.quote(yearSeparator) + "[0-9]{4})?");
90114
}
91115
}
92116

93117
/** Reads the license file from the given file. */
94-
private LicenseHeaderStep(File licenseFile, Charset encoding, String delimiter) throws IOException {
95-
this(new String(Files.readAllBytes(licenseFile.toPath()), encoding), delimiter);
118+
private LicenseHeaderStep(File licenseFile, Charset encoding, String delimiter, @Nullable String yearSeparator) throws IOException {
119+
this(new String(Files.readAllBytes(licenseFile.toPath()), encoding), delimiter, yearSeparator);
96120
}
97121

98122
/** Formats the given string. */

‎plugin-gradle/CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
### 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/))
44

5+
* LicenseHeaderStep now supports customizing the year range separator in copyright notices. ([#199](https://github.com/diffplug/spotless/pull/199)
6+
57
### 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))
68

79
* Updated default ktlint from 0.6.1 to 0.14.0

‎plugin-gradle/README.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,22 @@ The `licenseHeader` and `licenseHeaderFile` steps will generate license headers
307307
* A generated license header will _not_ be updated when
308308
* a single year is already present, e.g.
309309
`/* Licensed under Apache-2.0 1990. */`
310-
* a hyphen-separated year range is already present, e.g.
310+
* a year range is already present, e.g.
311311
`/* Licensed under Apache-2.0 1990-2003. */`
312312
* the `$YEAR` token is otherwise missing
313313

314+
The separator for the year range defaults to the hyphen character, e.g `1990-2003`, but can be customized with the `yearSeparator` property.
315+
316+
For instance, the following configuration treats `1990, 2003` as a valid year range.
317+
318+
```gradle
319+
spotless {
320+
format java {
321+
licenseHeader(''Licensed under Apache-2.0 $YEAR').yearSeparator(', ')
322+
}
323+
}
324+
```
325+
314326

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

‎plugin-gradle/src/main/java/com/diffplug/gradle/spotless/FormatExtension.java

+74-10
Original file line numberDiff line numberDiff line change
@@ -345,26 +345,90 @@ public void indentWithTabs() {
345345
indentWithTabs(4);
346346
}
347347

348+
abstract class LicenseHeaderConfig {
349+
350+
String delimiter;
351+
String yearSeparator;
352+
353+
public LicenseHeaderConfig(String delimiter) {
354+
this.delimiter = Objects.requireNonNull(delimiter, "delimiter");
355+
}
356+
357+
/**
358+
* @param delimiter
359+
* Spotless will look for a line that starts with this regular expression pattern to know what the "top" is.
360+
*/
361+
public LicenseHeaderConfig delimiter(String delimiter) {
362+
this.delimiter = Objects.requireNonNull(delimiter, "delimiter");
363+
replaceStep(createStep());
364+
return this;
365+
}
366+
367+
/**
368+
* @param yearSeparator
369+
* The characters used to separate the first and last years in multi years patterns.
370+
*/
371+
public LicenseHeaderConfig yearSeparator(String yearSeparator) {
372+
this.yearSeparator = Objects.requireNonNull(yearSeparator, "yearSeparator");
373+
replaceStep(createStep());
374+
return this;
375+
}
376+
377+
abstract FormatterStep createStep();
378+
}
379+
380+
class LicenseStringHeaderConfig extends LicenseHeaderConfig {
381+
382+
private String header;
383+
384+
LicenseStringHeaderConfig(String delimiter, String header) {
385+
super(delimiter);
386+
this.header = Objects.requireNonNull(header, "header");
387+
}
388+
389+
FormatterStep createStep() {
390+
return LicenseHeaderStep.createFromHeader(header, delimiter, yearSeparator);
391+
}
392+
}
393+
394+
class LicenseFileHeaderConfig extends LicenseHeaderConfig {
395+
396+
private Object headerFile;
397+
398+
LicenseFileHeaderConfig(String delimiter, Object headerFile) {
399+
super(delimiter);
400+
this.headerFile = Objects.requireNonNull(headerFile, "headerFile");
401+
}
402+
403+
FormatterStep createStep() {
404+
return LicenseHeaderStep
405+
.createFromFile(getProject().file(headerFile), getEncoding(), delimiter,
406+
yearSeparator);
407+
}
408+
}
409+
348410
/**
349411
* @param licenseHeader
350-
* Content that should be at the top of every file
412+
* Content that should be at the top of every file.
351413
* @param delimiter
352-
* Spotless will look for a line that starts with this to know what the "top" is.
414+
* Spotless will look for a line that starts with this regular expression pattern to know what the "top" is.
353415
*/
354-
public void licenseHeader(String licenseHeader, String delimiter) {
355-
addStep(LicenseHeaderStep.createFromHeader(licenseHeader, delimiter));
416+
public LicenseHeaderConfig licenseHeader(String licenseHeader, String delimiter) {
417+
LicenseHeaderConfig config = new LicenseStringHeaderConfig(delimiter, licenseHeader);
418+
addStep(config.createStep());
419+
return config;
356420
}
357421

358422
/**
359423
* @param licenseHeaderFile
360-
* Content that should be at the top of every file
424+
* Content that should be at the top of every file.
361425
* @param delimiter
362-
* Spotless will look for a line that starts with this to know what the "top" is.
426+
* Spotless will look for a line that starts with this regular expression pattern to know what the "top" is.
363427
*/
364-
public void licenseHeaderFile(Object licenseHeaderFile, String delimiter) {
365-
Objects.requireNonNull(licenseHeaderFile, "licenseHeaderFile");
366-
Objects.requireNonNull(delimiter, "delimiter");
367-
addStep(LicenseHeaderStep.createFromFile(getProject().file(licenseHeaderFile), getEncoding(), delimiter));
428+
public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile, String delimiter) {
429+
LicenseHeaderConfig config = new LicenseFileHeaderConfig(delimiter, licenseHeaderFile);
430+
addStep(config.createStep());
431+
return config;
368432
}
369433

370434
/** Sets up a format task according to the values in this extension. */

‎plugin-gradle/src/main/java/com/diffplug/gradle/spotless/GroovyExtension.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ public void excludeJava(boolean excludeJava) {
5555
this.excludeJava = excludeJava;
5656
}
5757

58-
public void licenseHeader(String licenseHeader) {
59-
licenseHeader(licenseHeader, JavaExtension.LICENSE_HEADER_DELIMITER);
58+
public LicenseHeaderConfig licenseHeader(String licenseHeader) {
59+
return licenseHeader(licenseHeader, JavaExtension.LICENSE_HEADER_DELIMITER);
6060
}
6161

62-
public void licenseHeaderFile(Object licenseHeaderFile) {
63-
licenseHeaderFile(licenseHeaderFile, JavaExtension.LICENSE_HEADER_DELIMITER);
62+
public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile) {
63+
return licenseHeaderFile(licenseHeaderFile, JavaExtension.LICENSE_HEADER_DELIMITER);
6464
}
6565

6666
/** Method interface has been changed to

‎plugin-gradle/src/main/java/com/diffplug/gradle/spotless/JavaExtension.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ public JavaExtension(SpotlessExtension rootExtension) {
4646
// testlib/src/test/java/com/diffplug/spotless/generic/LicenseHeaderStepTest.java as well
4747
static final String LICENSE_HEADER_DELIMITER = "package ";
4848

49-
public void licenseHeader(String licenseHeader) {
50-
licenseHeader(licenseHeader, LICENSE_HEADER_DELIMITER);
49+
public LicenseHeaderConfig licenseHeader(String licenseHeader) {
50+
return licenseHeader(licenseHeader, LICENSE_HEADER_DELIMITER);
5151
}
5252

53-
public void licenseHeaderFile(Object licenseHeaderFile) {
54-
licenseHeaderFile(licenseHeaderFile, LICENSE_HEADER_DELIMITER);
53+
public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile) {
54+
return licenseHeaderFile(licenseHeaderFile, LICENSE_HEADER_DELIMITER);
5555
}
5656

5757
/** Method interface has been changed to

‎plugin-gradle/src/main/java/com/diffplug/gradle/spotless/KotlinExtension.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ public KotlinExtension(SpotlessExtension rootExtension) {
3333
super(rootExtension);
3434
}
3535

36-
public void licenseHeader(String licenseHeader) {
37-
licenseHeader(licenseHeader, LICENSE_HEADER_DELIMITER);
36+
public LicenseHeaderConfig licenseHeader(String licenseHeader) {
37+
return licenseHeader(licenseHeader, LICENSE_HEADER_DELIMITER);
3838
}
3939

40-
public void licenseHeaderFile(Object licenseHeaderFile) {
41-
licenseHeaderFile(licenseHeaderFile, LICENSE_HEADER_DELIMITER);
40+
public LicenseHeaderConfig licenseHeaderFile(Object licenseHeaderFile) {
41+
return licenseHeaderFile(licenseHeaderFile, LICENSE_HEADER_DELIMITER);
4242
}
4343

4444
/** Adds the specified version of [ktlint](https://github.com/shyiko/ktlint). */

‎plugin-gradle/src/test/java/com/diffplug/gradle/spotless/KotlinExtensionTest.java

+64
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717

1818
import java.io.File;
1919
import java.io.IOException;
20+
import java.time.YearMonth;
2021

2122
import org.assertj.core.api.Assertions;
2223
import org.junit.Assert;
2324
import org.junit.Test;
2425

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

2830
@Test
2931
public void integration() throws IOException {
@@ -72,4 +74,66 @@ public void testWithHeader() throws IOException {
7274
// Make sure that no additional stuff got added to the file.
7375
.contains(HEADER + '\n' + original);
7476
}
77+
78+
@Test
79+
public void testWithCustomHeaderSeparator() throws IOException {
80+
write("build.gradle",
81+
"plugins {",
82+
" id 'nebula.kotlin' version '1.0.6'",
83+
" id 'com.diffplug.gradle.spotless'",
84+
"}",
85+
"repositories { mavenCentral() }",
86+
"spotless {",
87+
" kotlin {",
88+
" licenseHeader ('" + HEADER + "', '@file')",
89+
" ktlint()",
90+
" }",
91+
"}");
92+
final File testFile = write("src/main/kotlin/test.kt", getTestResource("kotlin/licenseheader/KotlinCodeWithoutHeader.test"));
93+
final String original = read(testFile.toPath());
94+
gradleRunner().withArguments("spotlessApply").build();
95+
final String result = read(testFile.toPath());
96+
Assertions
97+
.assertThat(result)
98+
// Make sure the header gets added.
99+
.startsWith(HEADER)
100+
// Make sure that the rest of the file is still there with nothing removed.
101+
.endsWith(original)
102+
// Make sure that no additional stuff got added to the file.
103+
.contains(HEADER + '\n' + original);
104+
}
105+
106+
@Test
107+
public void testWithNonStandardYearSeparator() throws IOException {
108+
write("build.gradle",
109+
"plugins {",
110+
" id 'nebula.kotlin' version '1.0.6'",
111+
" id 'com.diffplug.gradle.spotless'",
112+
"}",
113+
"repositories { mavenCentral() }",
114+
"spotless {",
115+
" kotlin {",
116+
" licenseHeader('" + HEADER_WITH_YEAR + "').yearSeparator(', ')",
117+
" ktlint()",
118+
" }",
119+
"}");
120+
121+
final File testFile = write("src/main/kotlin/test.kt", getTestResource("kotlin/licenseheader/KotlinCodeWithMultiYearHeader.test"));
122+
final String original = read(testFile.toPath());
123+
final File testFile2 = write("src/main/kotlin/test2.kt", getTestResource("kotlin/licenseheader/KotlinCodeWithMultiYearHeader2.test"));
124+
final String original2 = read(testFile.toPath());
125+
gradleRunner().withArguments("spotlessApply").build();
126+
final String result = read(testFile.toPath());
127+
final String result2 = read(testFile2.toPath());
128+
129+
Assertions
130+
.assertThat(result)
131+
// Make sure the a "valid" header isn't changed
132+
.contains("// License Header 2012, 2014");
133+
134+
Assertions
135+
.assertThat(result2)
136+
// Make sure that an "invalid" header is rewritten
137+
.startsWith(HEADER_WITH_YEAR.replace("$YEAR", String.valueOf(YearMonth.now().getYear())));
138+
}
75139
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// License Header 2012, 2014
2+
@file:JvmName("SomeFileName")
3+
package my.test
4+
5+
object AnObject
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// License Header 2012-2014
2+
@file:JvmName("SomeFileName")
3+
package my.test
4+
5+
object AnObject

0 commit comments

Comments
 (0)
Please sign in to comment.