Skip to content

Commit 79bcd96

Browse files
committed
init: new indra-licenser-spotless module
1 parent f606d37 commit 79bcd96

File tree

13 files changed

+558
-10
lines changed

13 files changed

+558
-10
lines changed

indra-common/build.gradle

+1-9
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ dependencies {
3535
compileOnlyApi libs.immutables.builder
3636
compileOnlyApi libs.jetbrainsAnnotations
3737
api project(":indra-git")
38+
api project(":indra-licenser-cadix") // for backwards compat
3839
implementation libs.missingMetadataGuava
39-
implementation libs.cadixLicenser
4040
implementation libs.asm
4141
api libs.mammoth
4242
testImplementation project(":indra-testlib")
@@ -64,14 +64,6 @@ indraPluginPublishing {
6464
["boilerplate", "checkstyle"]
6565
)
6666

67-
plugin(
68-
"indra.license-header",
69-
"net.kyori.indra.IndraLicenseHeaderPlugin",
70-
"Indra License Header",
71-
"License header configuration in line with the Indra file layout",
72-
["boilerplate", "license", "license-header", "licensing"]
73-
)
74-
7567
plugin(
7668
"indra.publishing",
7769
"net.kyori.indra.IndraPublishingPlugin",

indra-licenser-cadix/build.gradle

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
dependencies {
2+
compileOnlyApi libs.jetbrainsAnnotations
3+
implementation libs.cadixLicenser
4+
api libs.mammoth
5+
testImplementation project(':indra-testlib')
6+
}
7+
8+
indraPluginPublishing {
9+
plugin(
10+
"indra.license-header",
11+
"net.kyori.indra.IndraLicenseHeaderPlugin",
12+
"Indra License Header",
13+
"License header configuration in line with the Indra file layout, using the Cadix licenser",
14+
["boilerplate", "license", "license-header", "licensing"]
15+
)
16+
}

indra-common/src/main/java/net/kyori/indra/IndraLicenseHeaderPlugin.java indra-licenser-cadix/src/main/java/net/kyori/indra/IndraLicenseHeaderPlugin.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
*/
2424
package net.kyori.indra;
2525

26+
import java.util.HashSet;
27+
import java.util.Set;
2628
import net.kyori.mammoth.ProjectPlugin;
2729
import org.cadixdev.gradle.licenser.LicenseExtension;
2830
import org.cadixdev.gradle.licenser.Licenser;
@@ -32,7 +34,26 @@
3234
import org.gradle.api.tasks.TaskContainer;
3335
import org.jetbrains.annotations.NotNull;
3436

37+
/**
38+
* A plugin to apply and configure the Cadix licenser plugin.
39+
*
40+
* @deprecated since 2.2.0, for replacement with <a href="https://github.com/diffplug/spotless">Spotless</a>
41+
* @since 1.0.0
42+
*/
43+
@Deprecated
3544
public class IndraLicenseHeaderPlugin implements ProjectPlugin {
45+
// Copied from Indra since this plugin is just temporary anyways
46+
private static final Set<String> SOURCE_FILES = sourceFiles();
47+
48+
private static Set<String> sourceFiles() {
49+
final Set<String> sourceFiles = new HashSet<>();
50+
sourceFiles.add( "**/*.groovy");
51+
sourceFiles.add( "**/*.java");
52+
sourceFiles.add( "**/*.kt");
53+
sourceFiles.add( "**/*.scala");
54+
return sourceFiles;
55+
}
56+
3657
private static final String HEADER_FILE_NAME = "license_header.txt";
3758

3859
@Override
@@ -42,7 +63,7 @@ public void apply(final @NotNull Project project, final @NotNull PluginContainer
4263
// Configure sensible defaults
4364
extensions.configure(LicenseExtension.class, extension -> {
4465
extension.header(project.getRootProject().file(HEADER_FILE_NAME));
45-
extension.include(Indra.SOURCE_FILES);
66+
extension.include(SOURCE_FILES);
4667
extension.getNewLine().set(false);
4768
});
4869
}

indra-licenser-spotless/build.gradle

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
dependencies {
2+
compileOnlyApi libs.jetbrainsAnnotations
3+
api libs.mammoth
4+
api libs.spotless
5+
testImplementation project(":indra-testlib")
6+
}
7+
8+
indraPluginPublishing {
9+
plugin(
10+
"indra.licenser.spotless",
11+
"net.kyori.indra.licenser.spotless.SpotlessLicenserPlugin",
12+
"Indra Spotless License Headers",
13+
"Helper for configuring license header generation in Spotless with template parameters and differing formats",
14+
["indra", "licenser", "license-header", "spotless"]
15+
)
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* This file is part of indra, licensed under the MIT License.
3+
*
4+
* Copyright (c) 2020-2022 KyoriPowered
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package net.kyori.indra.licenser.spotless;
25+
26+
import org.jetbrains.annotations.Nullable;
27+
28+
/**
29+
* A description of a license header format.
30+
*
31+
* @since 2.2.0
32+
*/
33+
public class HeaderFormat {
34+
private final @Nullable String begin;
35+
private final @Nullable String linePrefix;
36+
private final @Nullable String lineSuffix;
37+
private final @Nullable String end;
38+
39+
HeaderFormat(
40+
final @Nullable String begin,
41+
final @Nullable String linePrefix,
42+
final @Nullable String lineSuffix,
43+
final @Nullable String end
44+
) {
45+
this.begin = begin;
46+
this.linePrefix = linePrefix;
47+
this.lineSuffix = lineSuffix;
48+
this.end = end;
49+
}
50+
51+
public static HeaderFormat headerFormat(final @Nullable String begin, final @Nullable String linePrefix, final @Nullable String lineSuffix, final @Nullable String end) {
52+
return new HeaderFormat(begin, linePrefix, lineSuffix, end);
53+
}
54+
55+
public static HeaderFormat starSlash() {
56+
return new HeaderFormat("/* ", " * ", null, " */");
57+
}
58+
59+
public static HeaderFormat doubleSlash() {
60+
return prefix("// ");
61+
}
62+
63+
public static HeaderFormat prefix(final String prefix) {
64+
return new HeaderFormat(null, prefix, null, null);
65+
}
66+
67+
public @Nullable String begin() {
68+
return this.begin;
69+
}
70+
71+
public @Nullable String linePrefix() {
72+
return this.linePrefix;
73+
}
74+
75+
public @Nullable String lineSuffix() {
76+
return this.lineSuffix;
77+
}
78+
79+
public @Nullable String end() {
80+
return this.end;
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* This file is part of indra, licensed under the MIT License.
3+
*
4+
* Copyright (c) 2020-2022 KyoriPowered
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package net.kyori.indra.licenser.spotless;
25+
26+
import com.diffplug.gradle.spotless.FormatExtension;
27+
import groovy.text.SimpleTemplateEngine;
28+
import org.gradle.api.Action;
29+
import org.gradle.api.provider.MapProperty;
30+
import org.gradle.api.provider.Property;
31+
import org.gradle.api.provider.Provider;
32+
import org.gradle.api.resources.TextResource;
33+
import org.jetbrains.annotations.NotNull;
34+
35+
import static java.util.Objects.requireNonNull;
36+
37+
public interface SpotlessLicenserExtension {
38+
39+
@NotNull Property<TextResource> licenseHeaderFile();
40+
41+
void licenseHeaderFile(final @NotNull Object file);
42+
43+
@NotNull Property<HeaderFormat> headerFormat();
44+
45+
/**
46+
* Set the header format to use.
47+
*
48+
* @param format the header format
49+
* @since 2.2.0
50+
*/
51+
default void headerFormat(final @NotNull HeaderFormat format) {
52+
this.headerFormat().set(requireNonNull(format, "format"));
53+
}
54+
55+
@NotNull MapProperty<String, HeaderFormat> languageFormatOverrides();
56+
57+
void languageFormatOverride(final @NotNull String language, final @NotNull HeaderFormat headerFormat);
58+
59+
/**
60+
* Properties to replace within license header contents.
61+
*
62+
* <p>The Groovy {@link SimpleTemplateEngine} is used to pre-process license headers.</p>
63+
*
64+
* @return the properties map
65+
* @since 2.2.0
66+
*/
67+
@NotNull MapProperty<String, Object> properties();
68+
69+
/**
70+
* Add a property to be expanded.
71+
*
72+
* @param key the property key
73+
* @param value the value to resolve to
74+
* @return this extension, for chaining
75+
* @since 2.2.0
76+
*/
77+
default @NotNull SpotlessLicenserExtension property(final @NotNull String key, final @NotNull String value) {
78+
this.properties().put(key, value);
79+
return this;
80+
}
81+
82+
/**
83+
* Add a property to be expanded.
84+
*
85+
* @param key the property key
86+
* @param value the value provider to resolve to
87+
* @return this extension, for chaining
88+
* @since 2.2.0
89+
*/
90+
default @NotNull SpotlessLicenserExtension property(final @NotNull String key, final @NotNull Provider<?> value) {
91+
this.properties().put(key, value);
92+
return this;
93+
}
94+
95+
/**
96+
* Get whether to append an additional newline at the end of files.
97+
*
98+
* @return the newline property
99+
* @since 2.2.0
100+
*/
101+
@NotNull Property<Boolean> newLine();
102+
103+
/**
104+
* Add an extra configure step to modify applied license header configurations.
105+
*
106+
* @param configureStep the extra configuration step
107+
* @since 2.2.0
108+
*/
109+
void extraConfig(final @NotNull Action<FormatExtension.LicenseHeaderConfig> configureStep);
110+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* This file is part of indra, licensed under the MIT License.
3+
*
4+
* Copyright (c) 2020-2022 KyoriPowered
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package net.kyori.indra.licenser.spotless;
25+
26+
import com.diffplug.gradle.spotless.FormatExtension;
27+
import com.diffplug.gradle.spotless.SpotlessExtension;
28+
import com.diffplug.spotless.generic.LicenseHeaderStep;
29+
import com.diffplug.spotless.kotlin.KotlinConstants;
30+
import net.kyori.indra.licenser.spotless.internal.SpotlessLicenserExtensionImpl;
31+
import net.kyori.mammoth.ProjectPlugin;
32+
import org.gradle.api.Action;
33+
import org.gradle.api.Project;
34+
import org.gradle.api.plugins.ExtensionContainer;
35+
import org.gradle.api.plugins.PluginContainer;
36+
import org.gradle.api.tasks.TaskContainer;
37+
import org.jetbrains.annotations.NotNull;
38+
39+
/**
40+
* A plugin to provide user-friendly configuration for the Spotless license header steps.
41+
*
42+
* @since 2.2.0
43+
*/
44+
public class SpotlessLicenserPlugin implements ProjectPlugin {
45+
private static final String JAVA_LICENSE_HEADER_DELIMITER = "package ";
46+
47+
private static final String HEADER_FILE_NAME = "license_header.txt";
48+
49+
@Override
50+
public void apply(
51+
final @NotNull Project project,
52+
final @NotNull PluginContainer plugins,
53+
final @NotNull ExtensionContainer extensions,
54+
final @NotNull TaskContainer tasks
55+
) {
56+
// Register our own extension
57+
final SpotlessLicenserExtensionImpl extension = (SpotlessLicenserExtensionImpl) extensions.create(SpotlessLicenserExtension.class, "indraSpotlessLicenser", SpotlessLicenserExtensionImpl.class);
58+
59+
// Default licenser configuration
60+
extension.licenseHeaderFile().convention(project.getResources().getText().fromFile(project.getRootProject().file(HEADER_FILE_NAME), "UTF-8"));
61+
62+
// Apply spotless
63+
plugins.apply("com.diffplug.spotless");
64+
final SpotlessExtension spotless = extensions.getByType(SpotlessExtension.class);
65+
66+
// Apply license header config to individual languages
67+
plugins.withId("java", $ -> {
68+
spotless.java(java -> {
69+
addStep(project, java, extension, "java", JAVA_LICENSE_HEADER_DELIMITER);
70+
});
71+
});
72+
73+
plugins.withId("org.jetbrains.kotlin.jvm", $ -> {
74+
spotless.kotlin(kotlin -> {
75+
addStep(project, kotlin, extension, "kotlin", KotlinConstants.LICENSE_HEADER_DELIMITER);
76+
});
77+
});
78+
79+
plugins.withId("groovy", $ -> {
80+
spotless.groovy(groovy -> {
81+
addStep(project, groovy, extension, "groovy", JAVA_LICENSE_HEADER_DELIMITER);
82+
});
83+
});
84+
85+
// TODO: scala -- scala doesn't support its own delimiter
86+
}
87+
88+
private static void addStep(final Project project, final FormatExtension format, final SpotlessLicenserExtensionImpl indraExtension, final String name, final String delimiter) {
89+
final LicenseHeaderStep step = LicenseHeaderStep.headerDelimiter(indraExtension.createHeaderSupplier(name), "");
90+
format.addStep(step.withYearMode(LicenseHeaderStep.YearMode.PRESERVE).build()); // add with dummy settings
91+
final FormatExtension.LicenseHeaderConfig config = format.new LicenseHeaderConfig(step);
92+
config.delimiter(delimiter); // replace the step with a properly configured one
93+
94+
// Then apply any extra steps after evaluation
95+
project.afterEvaluate(p -> {
96+
for (final Action<FormatExtension.LicenseHeaderConfig> configStep : indraExtension.extraConfigSteps()) {
97+
configStep.execute(config);
98+
}
99+
});
100+
}
101+
}

0 commit comments

Comments
 (0)