Move from Gradle to bld. Close #7

This commit is contained in:
Erik C. Thauvin 2023-08-18 18:12:44 -07:00
parent 4e096b3dad
commit 4858c58978
75 changed files with 1183 additions and 1793 deletions

View file

@ -0,0 +1,147 @@
/*
* SemverBuild.java
*
* Copyright (c) 2016-2023, Erik C. Thauvin (erik@thauvin.net)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of this project nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.thauvin.erik.semver;
import rife.bld.BuildCommand;
import rife.bld.Project;
import rife.bld.extension.JacocoReportOperation;
import rife.bld.extension.PmdOperation;
import rife.bld.extension.TestNgOperation;
import rife.bld.publish.*;
import rife.tools.exceptions.FileUtilsErrorException;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import static rife.bld.dependencies.Repository.*;
import static rife.bld.dependencies.Scope.compile;
import static rife.bld.dependencies.Scope.test;
import static rife.bld.operations.JavadocOptions.DocLinkOption.NO_MISSING;
public class SemverBuild extends Project {
public SemverBuild() {
pkg = "net.thauvin.erik.semver";
name = "SemVer";
version = version(1, 2, 1, "SNAPSHOT");
var description = "Semantic Version Annotation Processor";
var url = "https://github.com/ethauvin/semver";
javaRelease = 17;
downloadSources = true;
repositories = List.of(MAVEN_CENTRAL, SONATYPE_SNAPSHOTS);
scope(compile)
.include(dependency("com.github.spullara.mustache.java", "compiler",
version(0, 9, 10)));
scope(test)
.include(dependency("org.testng", "testng", version(7, 8, 0)));
javadocOperation().javadocOptions()
.tag("created.on", "a", "Created on:")
.windowTitle(name + ' ' + version.toString() + " API")
.docLint(NO_MISSING);
publishOperation()
.repository(version.isSnapshot() ? repository(SONATYPE_SNAPSHOTS_LEGACY.location())
.withCredentials(property("sonatype.user"), property("sonatype.password"))
: repository(SONATYPE_RELEASES.location())
.withCredentials(property("sonatype.user"), property("sonatype.password")))
.repository(MAVEN_LOCAL)
.info(new PublishInfo()
.groupId(pkg)
.artifactId(name.toLowerCase())
.name(name).version(version)
.description(description)
.url(url)
.developer(new PublishDeveloper()
.id("ethauvin")
.name("Erik C. Thauvin")
.email("erik@thauvin.net")
.url("https://erik.thauvin.net/"))
.license(new PublishLicense()
.name("The BSD 3-Clause License")
.url("http://opensource.org/licenses/BSD-3-Clause"))
.scm(new PublishScm()
.connection("scm:git:" + url + ".git")
.developerConnection("scm:git:git@github.com:ethauvin/" + name.toLowerCase() + ".git")
.url(url))
.signKey(property("sign.key"))
.signPassphrase(property("sign.passphrase")));
}
public static void main(String[] args) {
new SemverBuild().start(args);
}
@BuildCommand(summary = "Generates JaCoCo Reports")
public void jacoco() throws IOException {
new JacocoReportOperation().fromProject(this).execute();
}
@BuildCommand(summary = "Runs PMD analysis")
public void pmd() {
new PmdOperation()
.fromProject(this)
.failOnViolation(true)
.ruleSets("config/pmd.xml")
.execute();
}
private void rootPom() throws FileUtilsErrorException {
PomBuilder.generateInto(publishOperation().info(), publishOperation().dependencies(),
Path.of(workDirectory.getPath(), "pom.xml").toFile());
}
@BuildCommand(summary = "Run tests with TestNG")
public void test() throws Exception {
new TestNgOperation()
.fromProject(this)
.packages("net.thauvin.erik.semver")
.execute();
}
@Override
public void publish() throws Exception {
super.publish();
rootPom();
}
@Override
public void publishLocal() throws Exception {
super.publishLocal();
rootPom();
}
}

View file

@ -36,9 +36,10 @@ package net.thauvin.erik.semver;
* The <code>Constants</code> class holds the constant variables used throughout this project.
*
* @author <a href="mailto:erik@thauvin.net" target="_blank">Erik C. Thauvin</a>
* @created 2016-01-13
* @created.on 2016-01-13
* @since 1.0
*/
@SuppressWarnings("PMD.DataClass")
public final class Constants {
/**
* The default metadata prefix.

View file

@ -41,7 +41,7 @@ import java.lang.annotation.Target;
* The <code>Version</code> class implements the annotation interface.
*
* @author <a href="mailto:erik@thauvin.net" target="_blank">Erik C. Thauvin</a>
* @created 2016-01-13
* @created.on 2016-01-13
* @since 1.0
*/
@SuppressWarnings("SameReturnValue")

View file

@ -36,7 +36,7 @@ package net.thauvin.erik.semver;
* The <code>VersionInfo</code> class is used to hold and retrieve the semantic version values.
*
* @author <a href="mailto:erik@thauvin.net" target="_blank">Erik C. Thauvin</a>
* @created 2016-01-16
* @created.on 2016-01-16
* @since 1.0
*/
@SuppressWarnings("PMD.DataClass")
@ -101,15 +101,6 @@ public class VersionInfo {
return buildMeta;
}
/**
* Sets the build meta-data.
*
* @param buildMeta The new build meta-data.
*/
public void setBuildMeta(final String buildMeta) {
this.buildMeta = buildMeta;
}
/**
* Returns the meta-data prefix.
*
@ -119,15 +110,6 @@ public class VersionInfo {
return buildMetaPrefix;
}
/**
* Sets the meta-data prefix.
*
* @param buildMetaPrefix The meta-data prefix.
*/
public void setBuildMetaPrefix(final String buildMetaPrefix) {
this.buildMetaPrefix = buildMetaPrefix;
}
/**
* Returns the class name.
*
@ -137,15 +119,6 @@ public class VersionInfo {
return className;
}
/**
* Sets the class name.
*
* @param className The new class name.
*/
public void setClassName(final String className) {
this.className = className;
}
/**
* Returns the build epoch/Unix timestamp.
*
@ -164,15 +137,6 @@ public class VersionInfo {
return major;
}
/**
* Sets the major version.
*
* @param major The new major version.
*/
public void setMajor(final int major) {
this.major = major;
}
/**
* Returns the major version.
*
@ -182,15 +146,6 @@ public class VersionInfo {
return minor;
}
/**
* Sets the minor version.
*
* @param minor The new minor version.
*/
public void setMinor(final int minor) {
this.minor = minor;
}
/**
* Returns the package name.
*
@ -200,15 +155,6 @@ public class VersionInfo {
return packageName;
}
/**
* Sets the package name.
*
* @param packageName The new package name.
*/
public void setPackageName(final String packageName) {
this.packageName = packageName;
}
/**
* Returns the patch version.
*
@ -218,15 +164,6 @@ public class VersionInfo {
return patch;
}
/**
* Sets the patch version.
*
* @param patch The new patch version.
*/
public void setPatch(final int patch) {
this.patch = patch;
}
/**
* Returns the pre-release version.
*
@ -236,15 +173,6 @@ public class VersionInfo {
return preRelease;
}
/**
* Sets the pre-release version.
*
* @param preRelease The new pre-release version.
*/
public void setPreRelease(final String preRelease) {
this.preRelease = preRelease;
}
/**
* Returns the pre-release prefix.
*
@ -254,15 +182,6 @@ public class VersionInfo {
return preReleasePrefix;
}
/**
* Sets the pre-release prefix.
*
* @param preReleasePrefix The new pre-release prefix.
*/
public void setPreReleasePrefix(final String preReleasePrefix) {
this.preReleasePrefix = preReleasePrefix;
}
/**
* Returns the project name.
*
@ -272,15 +191,6 @@ public class VersionInfo {
return project;
}
/**
* Sets the project name.
*
* @param project The new project name.
*/
public void setProject(final String project) {
this.project = project;
}
/**
* Sames as {@link #getVersion()}.
*
@ -299,15 +209,6 @@ public class VersionInfo {
return separator;
}
/**
* Sets the version separator.
*
* @param separator The new version separator.
*/
public void setSeparator(final String separator) {
this.separator = separator;
}
/**
* Returns the full version string.
*
@ -334,7 +235,106 @@ public class VersionInfo {
+ minor
+ separator
+ patch
+ (preRelease.length() > 0 ? preReleasePrefix + preRelease : "")
+ (buildMeta.length() > 0 ? buildMetaPrefix + buildMeta : "");
+ (!preRelease.isEmpty() ? preReleasePrefix + preRelease : "")
+ (!buildMeta.isEmpty() ? buildMetaPrefix + buildMeta : "");
}
/**
* Sets the build meta-data.
*
* @param buildMeta The new build meta-data.
*/
public void setBuildMeta(final String buildMeta) {
this.buildMeta = buildMeta;
}
/**
* Sets the meta-data prefix.
*
* @param buildMetaPrefix The meta-data prefix.
*/
public void setBuildMetaPrefix(final String buildMetaPrefix) {
this.buildMetaPrefix = buildMetaPrefix;
}
/**
* Sets the class name.
*
* @param className The new class name.
*/
public void setClassName(final String className) {
this.className = className;
}
/**
* Sets the major version.
*
* @param major The new major version.
*/
public void setMajor(final int major) {
this.major = major;
}
/**
* Sets the minor version.
*
* @param minor The new minor version.
*/
public void setMinor(final int minor) {
this.minor = minor;
}
/**
* Sets the package name.
*
* @param packageName The new package name.
*/
public void setPackageName(final String packageName) {
this.packageName = packageName;
}
/**
* Sets the patch version.
*
* @param patch The new patch version.
*/
public void setPatch(final int patch) {
this.patch = patch;
}
/**
* Sets the pre-release version.
*
* @param preRelease The new pre-release version.
*/
public void setPreRelease(final String preRelease) {
this.preRelease = preRelease;
}
/**
* Sets the pre-release prefix.
*
* @param preReleasePrefix The new pre-release prefix.
*/
public void setPreReleasePrefix(final String preReleasePrefix) {
this.preReleasePrefix = preReleasePrefix;
}
/**
* Sets the project name.
*
* @param project The new project name.
*/
public void setProject(final String project) {
this.project = project;
}
/**
* Sets the version separator.
*
* @param separator The new version separator.
*/
public void setSeparator(final String separator) {
this.separator = separator;
}
}

View file

@ -56,7 +56,7 @@ import java.util.Set;
* The <code>VersionProcessor</code> class implements a semantic version annotation processor.
*
* @author <a href="mailto:erik@thauvin.net" target="_blank">Erik C. Thauvin</a>
* @created 2016-01-13
* @created.on 2016-01-13
* @since 1.0
*/
@SuppressWarnings({"PMD.GuardLogStatement", "PMD.BeanMembersShouldSerialize"})
@ -66,10 +66,24 @@ public class VersionProcessor extends AbstractProcessor {
private Messager messager;
private static String getTemplate(final boolean isLocalTemplate, final Version version) {
final String template;
if (isLocalTemplate && Constants.DEFAULT_JAVA_TEMPLATE.equals(version.template())) {
template = Constants.DEFAULT_TEMPLATE_NAME;
} else if (Constants.DEFAULT_JAVA_TEMPLATE.equals(version.template()) && Constants.KOTLIN_TYPE
.equals(version.type())) {
template = Constants.DEFAULT_KOTLIN_TEMPLATE;
} else {
template = version.template();
}
return template;
}
private void error(final String s) {
log(Diagnostic.Kind.ERROR, s);
}
@SuppressWarnings("PMD.UnusedPrivateMethod")
private void error(final String s, final Throwable t) {
log(Diagnostic.Kind.ERROR, t != null ? t.toString() : s);
}
@ -77,7 +91,7 @@ public class VersionProcessor extends AbstractProcessor {
private VersionInfo findValues(final Version version) throws IOException {
final VersionInfo versionInfo = new VersionInfo(version);
if (version.properties().length() > 0) {
if (!version.properties().isEmpty()) {
final File propsFile = getLocalFile(version.properties());
if (propsFile.isFile() && propsFile.canRead()) {
note("Found properties: " + propsFile.getName() + " (" + propsFile.getAbsoluteFile().getParent() + ')');
@ -180,15 +194,7 @@ public class VersionProcessor extends AbstractProcessor {
versionInfo.setPackageName(packageElement.getQualifiedName().toString());
}
note("Found version: " + versionInfo.getVersion());
final String template;
if (isLocalTemplate && Constants.DEFAULT_JAVA_TEMPLATE.equals(version.template())) {
template = Constants.DEFAULT_TEMPLATE_NAME;
} else if (Constants.DEFAULT_JAVA_TEMPLATE.equals(version.template()) && Constants.KOTLIN_TYPE
.equals(version.type())) {
template = Constants.DEFAULT_KOTLIN_TEMPLATE;
} else {
template = version.template();
}
final String template = getTemplate(isLocalTemplate, version);
writeTemplate(version.type(), versionInfo, template);
} catch (IOException | MustacheNotFoundException e) {

View file

@ -1,35 +1,3 @@
<!--
~ package.html
~
~ Copyright (c) 2016-2022, Erik C. Thauvin (erik@thauvin.net)
~ All rights reserved.
~
~ Redistribution and use in source and binary forms, with or without
~ modification, are permitted provided that the following conditions are met:
~
~ Redistributions of source code must retain the above copyright notice, this
~ list of conditions and the following disclaimer.
~
~ Redistributions in binary form must reproduce the above copyright notice,
~ this list of conditions and the following disclaimer in the documentation
~ and/or other materials provided with the distribution.
~
~ Neither the name of this project nor the names of its contributors may be
~ used to endorse or promote products derived from this software without
~ specific prior written permission.
~
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
~ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
~ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
~ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
~ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
~ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
~ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
~ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
~ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
~ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html lang="en">
<head>

View file

@ -1 +1,33 @@
#
# javax.annotation.processing.Processor
#
# Copyright (c) 2016-2023, Erik C. Thauvin (erik@thauvin.net)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of this project nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
net.thauvin.erik.semver.VersionProcessor

View file

@ -1,38 +1,38 @@
/*
* This file is automatically generated.
* Do not modify! -- ALL CHANGES WILL BE ERASED!
*/
* This file is automatically generated.
* Do not modify! -- ALL CHANGES WILL BE ERASED!
*/
package {{packageName}}
import java.util.Date
/**
* Provides semantic version information.
*
* @author <a href="https://github.com/ethauvin/semver">Semantic Version Annotation Processor</a>
*/
* Provides semantic version information.
*
* @author <a href="https://github.com/ethauvin/semver">Semantic Version Annotation Processor</a>
*/
object {{className}} {
@JvmField
val PROJECT = "{{project}}"
@JvmField
val BUILDDATE = Date({{epoch}}L)
@JvmField
val MAJOR = {{major}}
@JvmField
val MINOR = {{minor}}
@JvmField
val PATCH = {{patch}}
@JvmField
val PRERELEASE = "{{preRelease}}"
@JvmField
val PRERELEASE_PREFIX = "{{preReleasePrefix}}"
@JvmField
val BUILDMETA = "{{buildMeta}}"
@JvmField
val BUILDMEATA_PREFIX = "{{buildMetaPrefix}}"
@JvmField
val SEPARATOR = "{{separator}}"
@JvmField
val VERSION = "{{version}}"
@JvmField
val PROJECT = "{{project}}"
@JvmField
val BUILDDATE = Date({{epoch}}L)
@JvmField
val MAJOR = {{major}}
@JvmField
val MINOR = {{minor}}
@JvmField
val PATCH = {{patch}}
@JvmField
val PRERELEASE = "{{preRelease}}"
@JvmField
val PRERELEASE_PREFIX = "{{preReleasePrefix}}"
@JvmField
val BUILDMETA = "{{buildMeta}}"
@JvmField
val BUILDMEATA_PREFIX = "{{buildMetaPrefix}}"
@JvmField
val SEPARATOR = "{{separator}}"
@JvmField
val VERSION = "{{version}}"
}

View file

@ -1,34 +1,34 @@
/*
* This file is automatically generated.
* Do not modify! -- ALL CHANGES WILL BE ERASED!
*/
* This file is automatically generated.
* Do not modify! -- ALL CHANGES WILL BE ERASED!
*/
package {{packageName}};
import java.util.Date;
/**
* Provides semantic version information.
*
* @author <a href="https://github.com/ethauvin/semver">Semantic Version Annotation Processor</a>
*/
* Provides semantic version information.
*
* @author <a href="https://github.com/ethauvin/semver">Semantic Version Annotation Processor</a>
*/
public final class {{className}} {
public static final String PROJECT = "{{project}}";
public static final Date BUILDDATE = new Date({{epoch}}L);
public static final int MAJOR = {{major}};
public static final int MINOR = {{minor}};
public static final int PATCH = {{patch}};
public static final String PRERELEASE = "{{preRelease}}";
public static final String PRERELEASE_PREFIX = "{{preReleasePrefix}}";
public static final String BUILDMETA = "{{buildMeta}}";
public static final String BUILDMETA_PREFIX = "{{buildMetaPrefix}}";
public static final String SEPARATOR = "{{separator}}";
public static final String VERSION = "{{version}}";
public static final String PROJECT = "{{project}}";
public static final Date BUILDDATE = new Date({{epoch}}L);
public static final int MAJOR = {{major}};
public static final int MINOR = {{minor}};
public static final int PATCH = {{patch}};
public static final String PRERELEASE = "{{preRelease}}";
public static final String PRERELEASE_PREFIX = "{{preReleasePrefix}}";
public static final String BUILDMETA = "{{buildMeta}}";
public static final String BUILDMETA_PREFIX = "{{buildMetaPrefix}}";
public static final String SEPARATOR = "{{separator}}";
public static final String VERSION = "{{version}}";
/**
* Disables the default constructor.
*/
private {{className}}() {
throw new UnsupportedOperationException("Illegal constructor call.");
}
/**
* Disables the default constructor.
*/
private {{className}}() {
throw new UnsupportedOperationException("Illegal constructor call.");
}
}

View file

@ -38,13 +38,13 @@ import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.List;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertEquals; // NOPMD
/**
* The <code>ConstantsTest</code> class.
*
* @author <a href="https://erik.thauvin.net/" target="_blank">Erik C. Thauvin</a>
* @created 2019-04-14
* @created.on 2019-04-14
* @since 1.0
*/
public class ConstantsTest {

View file

@ -37,13 +37,13 @@ import org.testng.annotations.Test;
import java.util.Date;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertEquals; // NOPMD
/**
* The <code>VersionInfoTest</code> class.
*
* @author <a href="mailto:erik@thauvin.net">Erik C. Thauvin</a>
* @created 2016-02-03
* @created.on 2016-02-03
* @since 1.0
*/
public class VersionInfoTest {

View file

@ -38,13 +38,13 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertEquals; // NOPMD
/**
* The <code>VersionProcessorTest</code> class.
*
* @author <a href="https://erik.thauvin.net/" target="_blank">Erik C. Thauvin</a>
* @created 2019-04-02
* @created.on 2019-04-02
* @since 1.2.0
*/
public class VersionProcessorTest {

View file

@ -38,7 +38,7 @@ import java.lang.annotation.Annotation;
* The <code>VersionTest</code> class.
*
* @author <a href="https://erik.thauvin.net/" target="_blank">Erik C. Thauvin</a>
* @created 2019-04-02
* @created.on 2019-04-02
* @since 1.2.0
*/
@SuppressWarnings({"ClassExplicitlyAnnotation", "SameReturnValue", "java:S2187", "PMD.TestClassWithoutTestCases"})