From beb99af54563b473cd8f209afa78aca35f813d7b Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 16:06:43 -0800 Subject: [PATCH 01/17] Adopt `de.benediktritter.maven-plugin-development` --- plugin-maven/build.gradle | 169 +++--------------- .../src/test/resources/pom-build.xml.mustache | 96 ---------- 2 files changed, 21 insertions(+), 244 deletions(-) delete mode 100644 plugin-maven/src/test/resources/pom-build.xml.mustache diff --git a/plugin-maven/build.gradle b/plugin-maven/build.gradle index 3ea73e6101..6cf17dd986 100644 --- a/plugin-maven/build.gradle +++ b/plugin-maven/build.gradle @@ -1,42 +1,15 @@ -buildscript { - repositories { mavenCentral() } - dependencies { classpath "com.github.spullara.mustache.java:compiler:${VER_MUSTACHE}" } -} plugins { - id 'cz.malohlava.visteg' version '1.0.5' // https://github.com/mmalohlava/gradle-visteg + // https://www.benediktritter.de/maven-plugin-development/#release-history + id 'de.benediktritter.maven-plugin-development' version '0.4.0' } + repositories { mavenCentral() } apply from: rootProject.file('gradle/changelog.gradle') -apply from: rootProject.file('gradle/spotless-freshmark.gradle') - -// to generate taskGraph.pdf -// - set enabled (below) to true -// - run: ./gradlew :plugin-maven:test -// - run: rm plugin-maven/output.pdf -// - run: dot -Tpdf plugin-maven/build/reports/visteg.dot > plugin-maven/taskGraph.pdf -visteg { - enabled = false - nodeShape = 'box' - startNodeShape = 'box' - endNodeShape = 'box' - colorscheme = 'pastel24' // https://www.graphviz.org/doc/info/colors.html -} - -import com.github.mustachejava.DefaultMustacheFactory - -import java.nio.file.Files - -import static java.nio.charset.StandardCharsets.UTF_8 -import static java.nio.file.StandardOpenOption.CREATE -import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING - ext.artifactId = project.artifactIdMaven version = spotlessChangelog.versionNext -apply from: rootProject.file("gradle/java-setup.gradle") -apply from: rootProject.file("gradle/java-publish.gradle") -final MAVEN_PROJECT_DIR = project.layout.buildDirectory.dir("mavenProject").get() -final LOCAL_MAVEN_REPO_DIR = project.layout.buildDirectory.dir("localMavenRepository").get() +apply from: rootProject.file("gradle/java-setup.gradle") +apply from: rootProject.file('gradle/spotless-freshmark.gradle') def mvnw(String args) { boolean isWin = System.getProperty('os.name').toLowerCase().contains('win') @@ -55,17 +28,15 @@ def mvnw(String args) { } } -String libVersion = version.endsWith('-SNAPSHOT') ? - rootProject.spotlessChangelog.versionNext : - rootProject.spotlessChangelog.versionLast +apply plugin: 'de.benediktritter.maven-plugin-development' +mavenPlugin { + name = 'Spotless Maven Plugin' + artifactId = project.artifactIdMaven + description = project.description +} dependencies { - if (version.endsWith('-SNAPSHOT') || (rootProject.spotlessChangelog.versionNext == rootProject.spotlessChangelog.versionLast)) { - implementation project(':lib') - implementation project(':lib-extra') - } else { - implementation "com.diffplug.spotless:spotless-lib:${libVersion}" - implementation "com.diffplug.spotless:spotless-lib-extra:${libVersion}" - } + implementation project(':lib') + implementation project(':lib-extra') compileOnly "org.apache.maven:maven-plugin-api:${VER_MAVEN_API}" compileOnly "org.apache.maven.plugin-tools:maven-plugin-annotations:${VER_MAVEN_API}" @@ -90,112 +61,14 @@ dependencies { testImplementation "org.apache.maven:maven-core:${VER_MAVEN_API}" } -task copySourceFiles(type: Sync) { - from "src/main/java" - into MAVEN_PROJECT_DIR.dir("src/main/java") -} - -task copyMvnw(type: Copy, dependsOn: copySourceFiles) { - from 'src/test/resources' - include 'mvnw' - include 'mvnw.cmd' - include '.mvn/**' - into MAVEN_PROJECT_DIR -} - -task installLocalDependencies -def libs = [ - 'lib', - 'lib-extra', - 'testlib' -] -libs.each { - def groupId = 'com.diffplug.spotless' - def artifactId = "spotless-${it}" - def jarTask = tasks.getByPath(":${it}:jar") - def file = jarTask.archivePath - - def installDependency = task "install_${artifactId}"(type: Exec) { - workingDir MAVEN_PROJECT_DIR - - inputs.file(file) - outputs.dir(LOCAL_MAVEN_REPO_DIR.file(groupId.replace('.', '/') + "/" + artifactId + "/" + version)) - commandLine mvnw("org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file " + - "-Dfile=${file} " + - "-DgroupId=${groupId} " + - "-DartifactId=${artifactId} " + - "-Dversion=${libVersion} " + - "-Dpackaging=jar " + - "-DlocalRepositoryPath=${LOCAL_MAVEN_REPO_DIR}") - } - installDependency.dependsOn(jarTask) - - installLocalDependencies.dependsOn installDependency -} - -task createPomXml(dependsOn: installLocalDependencies) { - def newPomXml = MAVEN_PROJECT_DIR.file("pom.xml").asFile.toPath() - - outputs.file(newPomXml) - doLast { - def additionalDependencies = project.configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts.findAll { - return !libs.contains(it.moduleVersion.id.name) - }.collect { - return " \n" + - " ${it.moduleVersion.id.group}\n" + - " ${it.moduleVersion.id.name}\n" + - " ${it.moduleVersion.id.version}\n" + - " \n" - }.join() - - def versions = [ - spotlessMavenPluginVersion: version, - mavenApiVersion : VER_MAVEN_API, - eclipseAetherVersion : VER_ECLIPSE_AETHER, - spotlessLibVersion : libVersion, - jsr305Version : VER_JSR_305, - additionalDependencies : additionalDependencies - ] - - def pomXmlTemplate = project.layout.projectDirectory.file("src/test/resources/pom-build.xml.mustache").asFile.toPath() - - Files.newBufferedReader(pomXmlTemplate).withCloseable { reader -> - Files.newBufferedWriter(newPomXml, UTF_8, CREATE, TRUNCATE_EXISTING).withCloseable { writer -> - def mustache = new DefaultMustacheFactory().compile(reader, "pom") - mustache.execute(writer, versions) - } - } - } -} - -task runMavenBuild(type: Exec, dependsOn: [ - copySourceFiles, - copyMvnw, - createPomXml -]) { - outputs.dir(LOCAL_MAVEN_REPO_DIR) - - workingDir MAVEN_PROJECT_DIR - // -B batch mode to make dependency download logging less verbose - commandLine mvnw("clean install -B -Dmaven.repo.local=${LOCAL_MAVEN_REPO_DIR}") -} - -jar.setActions Arrays.asList() -jar.dependsOn(runMavenBuild) -File jarIn = MAVEN_PROJECT_DIR.file("target/spotless-maven-plugin-${version}.jar").asFile -File jarOut = jar.archivePath -jar.inputs.file(jarIn) -jar.outputs.file(jarOut) -jar.doLast { - Files.copy(jarIn.toPath(), jarOut.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING) -} - -test { useJUnitPlatform() } - apply from: rootProject.file('gradle/special-tests.gradle') -tasks.withType(Test) { - systemProperty "localMavenRepositoryDir", LOCAL_MAVEN_REPO_DIR.asFile - systemProperty "spotlessMavenPluginVersion", project.version - dependsOn(jar) +tasks.withType(Test).configureEach { + useJUnitPlatform() + systemProperty 'spotlessMavenPluginVersion', project.version + dependsOn 'publishToMavenLocal' + dependsOn ':lib:publishToMavenLocal' + dependsOn ':lib-extra:publishToMavenLocal' } + +apply from: rootProject.file("gradle/java-publish.gradle") diff --git a/plugin-maven/src/test/resources/pom-build.xml.mustache b/plugin-maven/src/test/resources/pom-build.xml.mustache deleted file mode 100644 index 3c1d1a7d5b..0000000000 --- a/plugin-maven/src/test/resources/pom-build.xml.mustache +++ /dev/null @@ -1,96 +0,0 @@ - - 4.0.0 - - com.diffplug.spotless - spotless-maven-plugin - {{spotlessMavenPluginVersion}} - maven-plugin - - Spotless Maven Plugin - - - - 3.1.0 - - - - UTF-8 - 1.8 - 1.8 - - - {{mavenApiVersion}} - {{eclipseAetherVersion}} - {{spotlessLibVersion}} - {{jsr305Version}} - - - - - org.apache.maven - maven-core - ${maven.api.version} - provided - - - org.apache.maven - maven-plugin-api - ${maven.api.version} - provided - - - org.apache.maven.plugin-tools - maven-plugin-annotations - ${maven.api.version} - provided - - - org.eclipse.aether - aether-api - ${eclipse.aether.version} - provided - - - org.eclipse.aether - aether-util - ${eclipse.aether.version} - provided - - - com.google.code.findbugs - jsr305 - ${jsr305.version} - provided - - - - com.diffplug.spotless - spotless-lib - ${spotless.lib.version} - - - com.diffplug.spotless - spotless-lib-extra - ${spotless.lib.version} - - -{{{additionalDependencies}}} - - - - - - - - org.apache.maven.plugins - maven-plugin-plugin - 3.5 - - - - - From 48ded12b4812b562065f54db20b4214ddae1f019 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 16:07:18 -0800 Subject: [PATCH 02/17] We now use the default local maven repository. --- .../spotless/maven/MavenIntegrationHarness.java | 6 +----- .../java/com/diffplug/spotless/maven/MavenRunner.java | 10 ++-------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java index e37bb0f13d..ad19f44624 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java @@ -53,7 +53,6 @@ public class MavenIntegrationHarness extends ResourceHarness { */ private static final String SPOTLESS_MAVEN_VERSION_IDE = null; - private static final String LOCAL_MAVEN_REPOSITORY_DIR = "localMavenRepositoryDir"; private static final String SPOTLESS_MAVEN_PLUGIN_VERSION = "spotlessMavenPluginVersion"; private static final String CONFIGURATION = "configuration"; private static final String EXECUTIONS = "executions"; @@ -179,8 +178,7 @@ protected void writePom(String[] executions, String[] configuration, String[] de protected MavenRunner mavenRunner() throws IOException { return MavenRunner.create() - .withProjectDir(rootFolder()) - .withLocalRepository(new File(getSystemProperty(LOCAL_MAVEN_REPOSITORY_DIR))); + .withProjectDir(rootFolder()); } /** @@ -247,8 +245,6 @@ private static String getSystemProperty(String name) { if (SPOTLESS_MAVEN_VERSION_IDE != null) { if (name.equals("spotlessMavenPluginVersion")) { return SPOTLESS_MAVEN_VERSION_IDE; - } else if (name.equals("localMavenRepositoryDir")) { - return new File("build/localMavenRepository").getAbsolutePath(); } else { throw Unhandled.stringException(name); } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java index a86e000187..b5e2392a24 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,6 @@ private MavenRunner() {} private File projectDir; private String[] args; - private File localRepositoryDir; private Map environment = new HashMap<>(); public MavenRunner withProjectDir(File projectDir) { @@ -59,11 +58,6 @@ public MavenRunner withArguments(String... args) { return this; } - public MavenRunner withLocalRepository(File localRepositoryDir) { - this.localRepositoryDir = localRepositoryDir; - return this; - } - public MavenRunner withRemoteDebug(int port) { String address = (Jvm.version() < 9 ? "" : "*:") + port; environment.put("MAVEN_OPTS", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + address); @@ -75,7 +69,7 @@ private Result run() throws IOException, InterruptedException { Objects.requireNonNull(args, "Need to call withArguments() first"); // run maven with the given args in the given directory String argsString = String.join(" ", Arrays.asList(args)); - List cmds = getPlatformCmds("-e -Dmaven.repo.local=" + localRepositoryDir + ' ' + argsString); + List cmds = getPlatformCmds("-e " + argsString); ProcessBuilder builder = new ProcessBuilder(cmds); builder.directory(projectDir); builder.environment().putAll(environment); From 491da2e1fc0968080c6ad4860873c30d142ed1b3 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 16:07:41 -0800 Subject: [PATCH 03/17] We don't need to exclude maven from the initial assemble anymore. --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e302e6637..1f08c201f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,8 +30,7 @@ jobs: - name: spotlessCheck run: ./gradlew spotlessCheck --build-cache - name: assemble testClasses - run: ./gradlew assemble testClasses --build-cache -PSPOTLESS_EXCLUDE_MAVEN=true - # If this gets resolved, remove the EXCLUDE_MAVEN https://github.com/diffplug/spotless/issues/554 + run: ./gradlew assemble testClasses --build-cache build: needs: sanityCheck strategy: From 0f18e245981ad1909aad7bf91cf634446a6d1aab Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 16:18:01 -0800 Subject: [PATCH 04/17] Update changelog. --- plugin-maven/CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugin-maven/CHANGES.md b/plugin-maven/CHANGES.md index 05cc349e9f..6b22962cba 100644 --- a/plugin-maven/CHANGES.md +++ b/plugin-maven/CHANGES.md @@ -3,6 +3,8 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Changes +* Spotless' custom build was replaced by [`maven-plugin-development`](https://github.com/britter/maven-plugin-development). ([#1496](https://github.com/diffplug/spotless/pull/1496) fixes [#554](https://github.com/diffplug/spotless/issues/554)) ## [2.30.0] - 2023-01-13 ### Added From 8b73372dd286fe43efeb23dcdc8dfa03d85f5fda Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 16:20:33 -0800 Subject: [PATCH 05/17] Move maven version constants to the maven buildfile. --- gradle.properties | 8 +------- plugin-maven/build.gradle | 5 +++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index 71f755522f..c3b71fd92e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -28,10 +28,4 @@ VER_DURIAN=1.2.0 VER_JGIT=5.13.1.202206130422-r VER_JUNIT=5.9.2 VER_ASSERTJ=3.24.1 -VER_MOCKITO=4.11.0 - -# Used for Maven Plugin -VER_MAVEN_API=3.0 -VER_ECLIPSE_AETHER=1.1.0 -VER_MUSTACHE=0.9.10 -VER_PLEXUS_RESOURCES=1.2.0 +VER_MOCKITO=4.11.0 \ No newline at end of file diff --git a/plugin-maven/build.gradle b/plugin-maven/build.gradle index 6cf17dd986..e06fce9ace 100644 --- a/plugin-maven/build.gradle +++ b/plugin-maven/build.gradle @@ -34,6 +34,11 @@ mavenPlugin { artifactId = project.artifactIdMaven description = project.description } + +String VER_MAVEN_API = '3.0' +String VER_ECLIPSE_AETHER = '1.1.0' +String VER_MUSTACHE = '0.9.10' +String VER_PLEXUS_RESOURCES = '1.2.0' dependencies { implementation project(':lib') implementation project(':lib-extra') From 5d7c3b741a4518097bffaacf7e6c30342302c1de Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 16:38:18 -0800 Subject: [PATCH 06/17] Move the multimodule harnessing to the only place where it is used. --- .../maven/MavenIntegrationHarness.java | 93 +---------------- .../maven/MultiModuleProjectTest.java | 99 ++++++++++++++++++- 2 files changed, 99 insertions(+), 93 deletions(-) diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java index ad19f44624..15c504fc72 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java @@ -16,9 +16,7 @@ package com.diffplug.spotless.maven; import static com.diffplug.common.base.Strings.isNullOrEmpty; -import static java.util.Arrays.asList; import static java.util.Arrays.stream; -import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.fail; @@ -59,7 +57,6 @@ public class MavenIntegrationHarness extends ResourceHarness { private static final String MODULES = "modules"; private static final String DEPENDENCIES = "dependencies"; private static final String MODULE_NAME = "name"; - private static final String CHILD_ID = "childId"; private static final int REMOTE_DEBUG_PORT = 5005; private final MustacheFactory mustacheFactory = new DefaultMustacheFactory(); @@ -190,10 +187,6 @@ protected MavenRunner mavenRunnerWithRemoteDebug() throws IOException { return mavenRunner().withRemoteDebug(REMOTE_DEBUG_PORT); } - protected MultiModuleProjectCreator multiModuleProject() { - return new MultiModuleProjectCreator(); - } - protected String createPomXmlContent(String pluginVersion, String[] executions, String[] configuration, String[] dependencies) throws IOException { return createPomXmlContent("/pom-test.xml.mustache", pluginVersion, executions, configuration, dependencies); } @@ -207,7 +200,7 @@ protected String createPomXmlContent(String pluginVersion, String[] executions, return createPomXmlContent(pluginVersion, executions, configuration, null); } - private String createPomXmlContent(String pomTemplate, Map params) throws IOException { + protected String createPomXmlContent(String pomTemplate, Map params) throws IOException { URL url = MavenIntegrationHarness.class.getResource(pomTemplate); try (BufferedReader reader = Resources.asCharSource(url, StandardCharsets.UTF_8).openBufferedStream()) { Mustache mustache = mustacheFactory.compile(reader, "pom"); @@ -217,7 +210,7 @@ private String createPomXmlContent(String pomTemplate, Map param } } - private static Map buildPomXmlParams(String pluginVersion, String[] executions, String[] configuration, String[] modules, String[] dependencies) { + protected static Map buildPomXmlParams(String pluginVersion, String[] executions, String[] configuration, String[] modules, String[] dependencies) { Map params = new HashMap<>(); params.put(SPOTLESS_MAVEN_PLUGIN_VERSION, pluginVersion == null ? getSystemProperty(SPOTLESS_MAVEN_PLUGIN_VERSION) : pluginVersion); @@ -276,86 +269,4 @@ private static String[] including(String... includes) { private static String[] formats(String... formats) { return groupWithSteps("formats", formats); } - - protected class MultiModuleProjectCreator { - - private String configSubProject; - private SubProjectFile[] configSubProjectFiles; - private String[] configuration; - private final Map> subProjects = new LinkedHashMap<>(); - - protected MultiModuleProjectCreator withConfigSubProject(String name, SubProjectFile... files) { - configSubProject = name; - configSubProjectFiles = files; - return this; - } - - protected MultiModuleProjectCreator withConfiguration(String... lines) { - configuration = lines; - return this; - } - - protected MultiModuleProjectCreator addSubProject(String name, SubProjectFile... files) { - subProjects.put(name, asList(files)); - return this; - } - - protected void create() throws IOException { - createRootPom(); - createConfigSubProject(); - createSubProjects(); - } - - private void createRootPom() throws IOException { - List modulesList = new ArrayList<>(); - modulesList.add(configSubProject); - modulesList.addAll(subProjects.keySet()); - String[] modules = modulesList.toArray(new String[0]); - - Map rootPomParams = buildPomXmlParams(null, null, configuration, modules, null); - setFile("pom.xml").toContent(createPomXmlContent("/multi-module/pom-parent.xml.mustache", rootPomParams)); - } - - private void createConfigSubProject() throws IOException { - if (configSubProject != null) { - String content = createPomXmlContent("/multi-module/pom-config.xml.mustache", emptyMap()); - setFile(configSubProject + "/pom.xml").toContent(content); - - createSubProjectFiles(configSubProject, asList(configSubProjectFiles)); - } - } - - private void createSubProjects() throws IOException { - for (Map.Entry> entry : subProjects.entrySet()) { - String subProjectName = entry.getKey(); - List subProjectFiles = entry.getValue(); - - String content = createPomXmlContent("/multi-module/pom-child.xml.mustache", singletonMap(CHILD_ID, subProjectName)); - setFile(subProjectName + "/pom.xml").toContent(content); - - createSubProjectFiles(subProjectName, subProjectFiles); - } - } - - private void createSubProjectFiles(String subProjectName, List subProjectFiles) throws IOException { - for (SubProjectFile file : subProjectFiles) { - setFile(subProjectName + '/' + file.to).toResource(file.from); - } - } - } - - protected static class SubProjectFile { - - private final String from; - private final String to; - - private SubProjectFile(String from, String to) { - this.from = from; - this.to = to; - } - - protected static SubProjectFile file(String from, String to) { - return new SubProjectFile(from, to); - } - } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MultiModuleProjectTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MultiModuleProjectTest.java index e67b1bcad3..ae8378c566 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MultiModuleProjectTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MultiModuleProjectTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 DiffPlug + * Copyright 2016-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,15 @@ */ package com.diffplug.spotless.maven; -import static com.diffplug.spotless.maven.MavenIntegrationHarness.SubProjectFile.file; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import org.junit.jupiter.api.Test; @@ -96,4 +104,91 @@ void testConfigurationDependency() throws Exception { assertFile("three/src/main/scala/test1.scala").sameAsResource("scala/scalafmt/basic.cleanWithCustomConf_3.0.0"); assertFile("three/src/test/scala/test2.scala").sameAsResource("scala/scalafmt/basic.cleanWithCustomConf_3.0.0"); } + + private static final String CHILD_ID = "childId"; + + protected MultiModuleProjectCreator multiModuleProject() { + return new MultiModuleProjectCreator(); + } + + class MultiModuleProjectCreator { + private String configSubProject; + private SubProjectFile[] configSubProjectFiles; + private String[] configuration; + private final Map> subProjects = new LinkedHashMap<>(); + + protected MultiModuleProjectCreator withConfigSubProject(String name, SubProjectFile... files) { + configSubProject = name; + configSubProjectFiles = files; + return this; + } + + protected MultiModuleProjectCreator withConfiguration(String... lines) { + configuration = lines; + return this; + } + + protected MultiModuleProjectCreator addSubProject(String name, SubProjectFile... files) { + subProjects.put(name, asList(files)); + return this; + } + + protected void create() throws IOException { + createRootPom(); + createConfigSubProject(); + createSubProjects(); + } + + private void createRootPom() throws IOException { + List modulesList = new ArrayList<>(); + modulesList.add(configSubProject); + modulesList.addAll(subProjects.keySet()); + String[] modules = modulesList.toArray(new String[0]); + + Map rootPomParams = buildPomXmlParams(null, null, configuration, modules, null); + setFile("pom.xml").toContent(createPomXmlContent("/multi-module/pom-parent.xml.mustache", rootPomParams)); + } + + private void createConfigSubProject() throws IOException { + if (configSubProject != null) { + String content = createPomXmlContent("/multi-module/pom-config.xml.mustache", emptyMap()); + setFile(configSubProject + "/pom.xml").toContent(content); + + createSubProjectFiles(configSubProject, asList(configSubProjectFiles)); + } + } + + private void createSubProjects() throws IOException { + for (Map.Entry> entry : subProjects.entrySet()) { + String subProjectName = entry.getKey(); + List subProjectFiles = entry.getValue(); + + String content = createPomXmlContent("/multi-module/pom-child.xml.mustache", singletonMap(CHILD_ID, subProjectName)); + setFile(subProjectName + "/pom.xml").toContent(content); + + createSubProjectFiles(subProjectName, subProjectFiles); + } + } + + private void createSubProjectFiles(String subProjectName, List subProjectFiles) { + for (SubProjectFile file : subProjectFiles) { + setFile(subProjectName + '/' + file.to).toResource(file.from); + } + } + } + + static class SubProjectFile { + + private final String from; + private final String to; + + private SubProjectFile(String from, String to) { + this.from = from; + this.to = to; + } + } + + static SubProjectFile file(String from, String to) { + return new SubProjectFile(from, to); + } } From 7294dbcfa94778d2f2c25e2e7d34237faac33685 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 17:38:08 -0800 Subject: [PATCH 07/17] MavenRunner now uses a single ProcessRunner across an entire test class. --- .../com/diffplug/spotless/ProcessRunner.java | 34 +++++- .../maven/MavenIntegrationHarness.java | 16 +++ .../diffplug/spotless/maven/MavenRunner.java | 111 +++--------------- 3 files changed, 63 insertions(+), 98 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java index c798ed6c07..7a1d0ac774 100644 --- a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java +++ b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 DiffPlug + * Copyright 2020-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,12 @@ package com.diffplug.spotless; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; @@ -55,13 +57,18 @@ public Result shell(String cmd) throws IOException, InterruptedException { /** Executes the given shell command (using {@code cmd} on windows and {@code sh} on unix). */ public Result shellWinUnix(String cmdWin, String cmdUnix) throws IOException, InterruptedException { + return shellWinUnix(null, cmdWin, cmdUnix); + } + + /** Executes the given shell command (using {@code cmd} on windows and {@code sh} on unix). */ + public Result shellWinUnix(File cwd, String cmdWin, String cmdUnix) throws IOException, InterruptedException { List args; if (FileSignature.machineIsWin()) { args = Arrays.asList("cmd", "/c", cmdWin); } else { args = Arrays.asList("sh", "-c", cmdUnix); } - return exec(args); + return exec(cwd, args); } /** Creates a process with the given arguments. */ @@ -76,12 +83,25 @@ public Result exec(byte[] stdin, String... args) throws IOException, Interrupted /** Creates a process with the given arguments. */ public Result exec(List args) throws IOException, InterruptedException { - return exec(new byte[0], args); + return exec((File) null, args); + } + + /** Creates a process with the given arguments. */ + public Result exec(File cwd, List args) throws IOException, InterruptedException { + return exec(cwd, new byte[0], args); } /** Creates a process with the given arguments, the given byte array is written to stdin immediately. */ public Result exec(byte[] stdin, List args) throws IOException, InterruptedException { + return exec(null, stdin, args); + } + + /** Creates a process with the given arguments, the given byte array is written to stdin immediately. */ + public Result exec(File cwd, byte[] stdin, List args) throws IOException, InterruptedException { ProcessBuilder builder = new ProcessBuilder(args); + if (cwd != null) { + builder.directory(cwd); + } Process process = builder.start(); Future outputFut = threadStdOut.submit(() -> drainToBytes(process.getInputStream(), bufStdOut)); Future errorFut = threadStdErr.submit(() -> drainToBytes(process.getErrorStream(), bufStdErr)); @@ -147,6 +167,14 @@ public byte[] stdErr() { return stdErr; } + public String stdOutUtf8() { + return new String(stdOut, StandardCharsets.UTF_8); + } + + public String stdErrUtf8() { + return new String(stdErr, StandardCharsets.UTF_8); + } + /** Returns true if the exit code was not zero. */ public boolean exitNotZero() { return exitCode != 0; diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java index 15c504fc72..1c44eef55e 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java @@ -31,6 +31,8 @@ import java.nio.file.Path; import java.util.*; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import com.github.mustachejava.DefaultMustacheFactory; @@ -40,6 +42,7 @@ import com.diffplug.common.base.Unhandled; import com.diffplug.common.io.Resources; import com.diffplug.spotless.Jvm; +import com.diffplug.spotless.ProcessRunner; import com.diffplug.spotless.ResourceHarness; public class MavenIntegrationHarness extends ResourceHarness { @@ -175,9 +178,22 @@ protected void writePom(String[] executions, String[] configuration, String[] de protected MavenRunner mavenRunner() throws IOException { return MavenRunner.create() + .withRunner(runner) .withProjectDir(rootFolder()); } + private static ProcessRunner runner; + + @BeforeAll + static void setupRunner() throws IOException { + runner = new ProcessRunner(); + } + + @AfterAll + static void closeRunner() throws IOException { + runner.close(); + } + /** * Useful for local development. Allows debugging the Spotless Maven Plugin remotely. * Effectively translates into running {@code mvnDebug} on port 5005. The forked JVM will be diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java index b5e2392a24..4fe454ceba 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java @@ -17,21 +17,15 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; -import com.diffplug.common.base.Throwables; -import com.diffplug.common.io.ByteStreams; -import com.diffplug.spotless.FileSignature; import com.diffplug.spotless.Jvm; +import com.diffplug.spotless.ProcessRunner; /** * Harness for running a maven build, same idea as the @@ -47,6 +41,7 @@ private MavenRunner() {} private File projectDir; private String[] args; private Map environment = new HashMap<>(); + private ProcessRunner runner; public MavenRunner withProjectDir(File projectDir) { this.projectDir = Objects.requireNonNull(projectDir); @@ -58,110 +53,36 @@ public MavenRunner withArguments(String... args) { return this; } + public MavenRunner withRunner(ProcessRunner runner) { + this.runner = runner; + return this; + } + public MavenRunner withRemoteDebug(int port) { String address = (Jvm.version() < 9 ? "" : "*:") + port; environment.put("MAVEN_OPTS", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + address); return this; } - private Result run() throws IOException, InterruptedException { + private ProcessRunner.Result run() throws IOException, InterruptedException { Objects.requireNonNull(projectDir, "Need to call withProjectDir() first"); Objects.requireNonNull(args, "Need to call withArguments() first"); // run maven with the given args in the given directory - String argsString = String.join(" ", Arrays.asList(args)); - List cmds = getPlatformCmds("-e " + argsString); - ProcessBuilder builder = new ProcessBuilder(cmds); - builder.directory(projectDir); - builder.environment().putAll(environment); - Process process = builder.start(); - // slurp and return the stdout, stderr, and exitValue - Slurper output = new Slurper(process.getInputStream()); - Slurper error = new Slurper(process.getErrorStream()); - int exitValue = process.waitFor(); - output.join(); - error.join(); - return new Result(exitValue, output.result(), error.result()); + String argsString = "-e " + String.join(" ", Arrays.asList(args)); + return runner.shellWinUnix(projectDir, "mvnw " + argsString, "./mvnw " + argsString); } /** Runs the command and asserts that exit code is 0. */ - public Result runNoError() throws IOException, InterruptedException { - Result result = run(); - assertThat(result.exitValue()).as("Run without error %s", result).isEqualTo(0); + public ProcessRunner.Result runNoError() throws IOException, InterruptedException { + ProcessRunner.Result result = run(); + assertThat(result.exitCode()).as("Run without error %s", result).isEqualTo(0); return result; } /** Runs the command and asserts that exit code is not 0. */ - public Result runHasError() throws IOException, InterruptedException { - Result result = run(); - assertThat(result.exitValue()).as("Run with error %s", result).isNotEqualTo(0); + public ProcessRunner.Result runHasError() throws IOException, InterruptedException { + ProcessRunner.Result result = run(); + assertThat(result.exitCode()).as("Run with error %s", result).isNotEqualTo(0); return result; } - - public static class Result { - private final int exitValue; - private final String output; - private final String error; - - public Result(int exitValue, String output, String error) { - super(); - this.exitValue = exitValue; - this.output = Objects.requireNonNull(output); - this.error = Objects.requireNonNull(error); - } - - public int exitValue() { - return exitValue; - } - - public String output() { - return output; - } - - public String error() { - return error; - } - - @Override - public String toString() { - return "Result{" + - "exitValue=" + exitValue + - ", output='" + output + '\'' + - ", error='" + error + '\'' + - '}'; - } - } - - /** Prepends any arguments necessary to run a console command. */ - private static List getPlatformCmds(String cmd) { - if (FileSignature.machineIsWin()) { - return Arrays.asList("cmd", "/c", "mvnw " + cmd); - } else { - return Arrays.asList("/bin/sh", "-c", "./mvnw " + cmd); - } - } - - private static class Slurper extends Thread { - private final InputStream input; - private volatile String result; - - Slurper(InputStream input) { - this.input = Objects.requireNonNull(input); - start(); - } - - @Override - public void run() { - try { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - ByteStreams.copy(input, output); - result = output.toString(Charset.defaultCharset().name()); - } catch (Exception e) { - result = Throwables.getStackTraceAsString(e); - } - } - - public String result() { - return result; - } - } } From b314a0126abd90098e1c4d79dacd9ccd551cb35b Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 17:38:26 -0800 Subject: [PATCH 08/17] Adapt maven tests to use ProcessRunner. --- .../spotless/maven/SpotlessCheckMojoTest.java | 8 +++++--- .../maven/incremental/UpToDateCheckingTest.java | 8 ++++---- .../javascript/JavascriptFormatStepTest.java | 5 ++--- .../diffplug/spotless/maven/json/JsonTest.java | 2 +- .../maven/markdown/FlexmarkMavenTest.java | 5 ++--- .../spotless/maven/pom/SortPomMavenTest.java | 4 ++-- .../maven/prettier/PrettierFormatStepTest.java | 16 ++++++++-------- .../typescript/TypescriptFormatStepTest.java | 16 ++++++++-------- .../diffplug/spotless/maven/yaml/YamlTest.java | 6 +++--- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessCheckMojoTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessCheckMojoTest.java index cb37e4a4c5..566851c26c 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessCheckMojoTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/SpotlessCheckMojoTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2022 DiffPlug + * Copyright 2016-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,8 @@ import org.junit.jupiter.api.Test; +import com.diffplug.spotless.ProcessRunner; + class SpotlessCheckMojoTest extends MavenIntegrationHarness { private static final String UNFORMATTED_FILE = "license/MissingLicense.test"; @@ -72,8 +74,8 @@ private void testSpotlessCheck(String fileName, String command, boolean expectEr MavenRunner mavenRunner = mavenRunner().withArguments(command); if (expectError) { - MavenRunner.Result result = mavenRunner.runHasError(); - assertThat(result.output()).contains("The following files had format violations"); + ProcessRunner.Result result = mavenRunner.runHasError(); + assertThat(result.stdOutUtf8()).contains("The following files had format violations"); } else { mavenRunner.runNoError(); } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/incremental/UpToDateCheckingTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/incremental/UpToDateCheckingTest.java index f315c7eefe..6afcba7430 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/incremental/UpToDateCheckingTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/incremental/UpToDateCheckingTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2021-2022 DiffPlug + * Copyright 2021-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -254,15 +254,15 @@ private List writeFiles(String resource, String suffix, int count) throws } private String runSpotlessApply() throws Exception { - return mavenRunnerForGoal("apply").runNoError().output(); + return mavenRunnerForGoal("apply").runNoError().stdOutUtf8(); } private String runSpotlessCheck() throws Exception { - return mavenRunnerForGoal("check").runNoError().output(); + return mavenRunnerForGoal("check").runNoError().stdOutUtf8(); } private String runSpotlessCheckOnUnformattedFiles() throws Exception { - return mavenRunnerForGoal("check").runHasError().output(); + return mavenRunnerForGoal("check").runHasError().stdOutUtf8(); } private MavenRunner mavenRunnerForGoal(String goal) throws IOException { diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/javascript/JavascriptFormatStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/javascript/JavascriptFormatStepTest.java index 5c8a5f04b3..d738e17dac 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/javascript/JavascriptFormatStepTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/javascript/JavascriptFormatStepTest.java @@ -20,9 +20,9 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import com.diffplug.spotless.ProcessRunner; import com.diffplug.spotless.ResourceHarness; import com.diffplug.spotless.maven.MavenIntegrationHarness; -import com.diffplug.spotless.maven.MavenRunner.Result; import com.diffplug.spotless.npm.EslintFormatterStep; import com.diffplug.spotless.npm.EslintStyleGuide; import com.diffplug.spotless.tag.NpmTest; @@ -50,8 +50,7 @@ void eslintConfigFile() throws Exception { setFile(".eslintrc.js").toResource("npm/eslint/javascript/custom_rules/.eslintrc.js"); setFile(TEST_FILE_PATH).toResource("npm/eslint/javascript/custom_rules/javascript-es6.dirty"); - Result result = mavenRunner().withArguments("spotless:apply").runNoError(); - System.out.println(result.output()); + ProcessRunner.Result result = mavenRunner().withArguments("spotless:apply").runNoError(); assertFile(TEST_FILE_PATH).sameAsResource("npm/eslint/javascript/custom_rules/javascript-es6.clean"); } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/json/JsonTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/json/JsonTest.java index e492109faa..884aba79c7 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/json/JsonTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/json/JsonTest.java @@ -57,7 +57,7 @@ public void testFormatJson_WithGson_sortByKeys() throws Exception { setFile("json_test.json").toResource("json/sortByKeysBefore.json"); - String output = mavenRunner().withArguments("spotless:apply").runNoError().output(); + String output = mavenRunner().withArguments("spotless:apply").runNoError().stdOutUtf8(); LOGGER.error(output); System.err.println(output); assertFile("json_test.json").sameAsResource("json/sortByKeysAfter.json"); diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/markdown/FlexmarkMavenTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/markdown/FlexmarkMavenTest.java index a623ca7f3c..eb1c6cc95f 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/markdown/FlexmarkMavenTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/markdown/FlexmarkMavenTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 DiffPlug + * Copyright 2021-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,8 +26,7 @@ public void testFlexmarkWithDefaultConfig() throws Exception { writePomWithMarkdownSteps(""); setFile("markdown_test.md").toResource("markdown/flexmark/FlexmarkUnformatted.md"); - mavenRunner().withArguments("spotless:apply").runNoError().error(); + mavenRunner().withArguments("spotless:apply").runNoError(); assertFile("markdown_test.md").sameAsResource("markdown/flexmark/FlexmarkFormatted.md"); } - } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/pom/SortPomMavenTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/pom/SortPomMavenTest.java index ca9d77a6e3..93eb8a9633 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/pom/SortPomMavenTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/pom/SortPomMavenTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 DiffPlug + * Copyright 2021-2023 DiffPlug * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,7 @@ public void testSortPomWithDefaultConfig() throws Exception { writePomWithPomSteps(""); setFile("pom_test.xml").toResource("pom/pom_dirty.xml"); - mavenRunner().withArguments("spotless:apply").runNoError().error(); + mavenRunner().withArguments("spotless:apply").runNoError(); assertFile("pom_test.xml").sameAsResource("pom/pom_clean_default.xml"); } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java index c0a9267b93..47dab5d152 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/prettier/PrettierFormatStepTest.java @@ -21,8 +21,8 @@ import org.junit.jupiter.api.Test; +import com.diffplug.spotless.ProcessRunner; import com.diffplug.spotless.maven.MavenIntegrationHarness; -import com.diffplug.spotless.maven.MavenRunner.Result; import com.diffplug.spotless.maven.generic.Prettier; import com.diffplug.spotless.tag.NpmTest; @@ -43,7 +43,7 @@ private String prepareRun(String kind, String suffix) throws IOException { return path; } - private Result runExpectingError(String kind, String suffix) throws IOException, InterruptedException { + private ProcessRunner.Result runExpectingError(String kind, String suffix) throws IOException, InterruptedException { String path = prepareRun(kind, suffix); return mavenRunner().withArguments("spotless:apply").runHasError(); } @@ -102,8 +102,8 @@ void unique_dependency_config() throws Exception { " 1.16.4", ""); - Result result = mavenRunner().withArguments("spotless:apply").runHasError(); - assertThat(result.output()).contains(Prettier.ERROR_MESSAGE_ONLY_ONE_CONFIG); + ProcessRunner.Result result = mavenRunner().withArguments("spotless:apply").runHasError(); + assertThat(result.stdOutUtf8()).contains(Prettier.ERROR_MESSAGE_ONLY_ONE_CONFIG); } @Test @@ -156,8 +156,8 @@ void autodetect_npmrc_file() throws Exception { " 1.16.4", " .prettierrc.yml", ""); - Result result = runExpectingError("typescript", suffix); - assertThat(result.output()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); + ProcessRunner.Result result = runExpectingError("typescript", suffix); + assertThat(result.stdOutUtf8()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); } @Test @@ -174,7 +174,7 @@ void select_configured_npmrc_file() throws Exception { " .prettierrc.yml", " ${basedir}/.custom_npmrc", ""); - Result result = runExpectingError("typescript", suffix); - assertThat(result.output()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); + ProcessRunner.Result result = runExpectingError("typescript", suffix); + assertThat(result.stdOutUtf8()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); } } diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/typescript/TypescriptFormatStepTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/typescript/TypescriptFormatStepTest.java index 95097fe467..a09111d30d 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/typescript/TypescriptFormatStepTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/typescript/TypescriptFormatStepTest.java @@ -21,9 +21,9 @@ import org.junit.jupiter.api.Test; +import com.diffplug.spotless.ProcessRunner; import com.diffplug.spotless.ResourceHarness; import com.diffplug.spotless.maven.MavenIntegrationHarness; -import com.diffplug.spotless.maven.MavenRunner.Result; import com.diffplug.spotless.npm.EslintFormatterStep; import com.diffplug.spotless.npm.EslintStyleGuide; import com.diffplug.spotless.tag.NpmTest; @@ -48,7 +48,7 @@ private String prepareRunTsfmt(String kind) throws IOException { return TEST_FILE_PATH; } - private Result runExpectingErrorTsfmt(String kind) throws IOException, InterruptedException { + private ProcessRunner.Result runExpectingErrorTsfmt(String kind) throws IOException, InterruptedException { prepareRunTsfmt(kind); return mavenRunner().withArguments("spotless:apply").runHasError(); } @@ -124,8 +124,8 @@ void testTypescript_2_Configs() throws Exception { setFile("tsfmt.json").toResource("npm/tsfmt/tsfmt/tsfmt.json"); setFile(path).toResource("npm/tsfmt/tsfmt/tsfmt.dirty"); - Result result = mavenRunner().withArguments("spotless:apply").runHasError(); - assertThat(result.output()).contains("must specify exactly one configFile or config"); + ProcessRunner.Result result = mavenRunner().withArguments("spotless:apply").runHasError(); + assertThat(result.stdOutUtf8()).contains("must specify exactly one configFile or config"); } @Test @@ -141,8 +141,8 @@ void testNpmrcIsAutoPickedUp() throws Exception { " ${basedir}/tslint.json", ""); setFile("tslint.json").toResource("npm/tsfmt/tslint/tslint.json"); - Result result = runExpectingErrorTsfmt("tslint"); - assertThat(result.output()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); + ProcessRunner.Result result = runExpectingErrorTsfmt("tslint"); + assertThat(result.stdOutUtf8()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); } @Test @@ -159,8 +159,8 @@ void testNpmrcIsConfigurativelyPickedUp() throws Exception { " ${basedir}/.custom_npmrc", ""); setFile("tslint.json").toResource("npm/tsfmt/tslint/tslint.json"); - Result result = runExpectingErrorTsfmt("tslint"); - assertThat(result.output()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); + ProcessRunner.Result result = runExpectingErrorTsfmt("tslint"); + assertThat(result.stdOutUtf8()).containsPattern("Running npm command.*npm install.* failed with exit code: 1"); } @Test diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/yaml/YamlTest.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/yaml/YamlTest.java index b5a417c536..f17feeb10a 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/yaml/YamlTest.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/yaml/YamlTest.java @@ -21,8 +21,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.diffplug.spotless.ProcessRunner; import com.diffplug.spotless.maven.MavenIntegrationHarness; -import com.diffplug.spotless.maven.MavenRunner.Result; public class YamlTest extends MavenIntegrationHarness { private static final Logger LOGGER = LoggerFactory.getLogger(YamlTest.class); @@ -32,9 +32,9 @@ public void testFormatYaml_WithJackson_defaultConfig_separatorComments() throws writePomWithYamlSteps(""); setFile("yaml_test.yaml").toResource("yaml/separator_comments.yaml"); - Result runNoError = mavenRunner().withArguments("spotless:apply").runNoError(); + ProcessRunner.Result runNoError = mavenRunner().withArguments("spotless:apply").runNoError(); LOGGER.error("result: {}", runNoError); - assertThat(runNoError.exitValue()).as("Run without error %s", runNoError).isEqualTo(0); + assertThat(runNoError.exitCode()).as("Run without error %s", runNoError).isEqualTo(0); LOGGER.error("GOGO"); assertFile("yaml_test.yaml").sameAsResource("yaml/separator_comments.clean.yaml"); } From bc4a2684d118b63818803bc1e99417023a229133 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 17:46:43 -0800 Subject: [PATCH 09/17] Add support for environment variables into ProcessRunner so that MavenRunner's support for remote debug works again. --- .../com/diffplug/spotless/ProcessRunner.java | 21 +++++++++---------- .../diffplug/spotless/maven/MavenRunner.java | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java index 7a1d0ac774..e2149a03d6 100644 --- a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java +++ b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java @@ -24,6 +24,7 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -57,18 +58,18 @@ public Result shell(String cmd) throws IOException, InterruptedException { /** Executes the given shell command (using {@code cmd} on windows and {@code sh} on unix). */ public Result shellWinUnix(String cmdWin, String cmdUnix) throws IOException, InterruptedException { - return shellWinUnix(null, cmdWin, cmdUnix); + return shellWinUnix(null, null, cmdWin, cmdUnix); } /** Executes the given shell command (using {@code cmd} on windows and {@code sh} on unix). */ - public Result shellWinUnix(File cwd, String cmdWin, String cmdUnix) throws IOException, InterruptedException { + public Result shellWinUnix(File cwd, Map environment, String cmdWin, String cmdUnix) throws IOException, InterruptedException { List args; if (FileSignature.machineIsWin()) { args = Arrays.asList("cmd", "/c", cmdWin); } else { args = Arrays.asList("sh", "-c", cmdUnix); } - return exec(cwd, args); + return exec(cwd, environment, new byte[0], args); } /** Creates a process with the given arguments. */ @@ -83,25 +84,23 @@ public Result exec(byte[] stdin, String... args) throws IOException, Interrupted /** Creates a process with the given arguments. */ public Result exec(List args) throws IOException, InterruptedException { - return exec((File) null, args); - } - - /** Creates a process with the given arguments. */ - public Result exec(File cwd, List args) throws IOException, InterruptedException { - return exec(cwd, new byte[0], args); + return exec(null, args); } /** Creates a process with the given arguments, the given byte array is written to stdin immediately. */ public Result exec(byte[] stdin, List args) throws IOException, InterruptedException { - return exec(null, stdin, args); + return exec(null, null, stdin, args); } /** Creates a process with the given arguments, the given byte array is written to stdin immediately. */ - public Result exec(File cwd, byte[] stdin, List args) throws IOException, InterruptedException { + public Result exec(File cwd, Map environment, byte[] stdin, List args) throws IOException, InterruptedException { ProcessBuilder builder = new ProcessBuilder(args); if (cwd != null) { builder.directory(cwd); } + if (environment != null) { + builder.environment().putAll(environment); + } Process process = builder.start(); Future outputFut = threadStdOut.submit(() -> drainToBytes(process.getInputStream(), bufStdOut)); Future errorFut = threadStdErr.submit(() -> drainToBytes(process.getErrorStream(), bufStdErr)); diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java index 4fe454ceba..d878b18c5f 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenRunner.java @@ -69,7 +69,7 @@ private ProcessRunner.Result run() throws IOException, InterruptedException { Objects.requireNonNull(args, "Need to call withArguments() first"); // run maven with the given args in the given directory String argsString = "-e " + String.join(" ", Arrays.asList(args)); - return runner.shellWinUnix(projectDir, "mvnw " + argsString, "./mvnw " + argsString); + return runner.shellWinUnix(projectDir, environment, "mvnw " + argsString, "./mvnw " + argsString); } /** Runs the command and asserts that exit code is 0. */ From 7b5f01949713ea90dbc6928346545d15c704a1f2 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 17:49:33 -0800 Subject: [PATCH 10/17] Fix a bug in how ProcessRunner handled null stdin. --- lib/src/main/java/com/diffplug/spotless/ProcessRunner.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java index e2149a03d6..1356c0ac0d 100644 --- a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java +++ b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java @@ -69,7 +69,7 @@ public Result shellWinUnix(File cwd, Map environment, String cmd } else { args = Arrays.asList("sh", "-c", cmdUnix); } - return exec(cwd, environment, new byte[0], args); + return exec(cwd, environment, null, args); } /** Creates a process with the given arguments. */ @@ -101,6 +101,9 @@ public Result exec(File cwd, Map environment, byte[] stdin, List if (environment != null) { builder.environment().putAll(environment); } + if (stdin == null) { + stdin = new byte[0]; + } Process process = builder.start(); Future outputFut = threadStdOut.submit(() -> drainToBytes(process.getInputStream(), bufStdOut)); Future errorFut = threadStdErr.submit(() -> drainToBytes(process.getErrorStream(), bufStdErr)); From 9d894cd364bcb20bc38d1f22a61e1f37b956f870 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 17:52:02 -0800 Subject: [PATCH 11/17] Update the core changelog since ProcessRunner has gotten a few new methods. --- CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index c08ca86796..bff243b753 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ This document is intended for Spotless developers. We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (starting after version `1.27.0`). ## [Unreleased] +### Added +* `ProcessRunner` has added some convenience methods so it can be used for maven testing. ([#1496](https://github.com/diffplug/spotless/pull/1496)) ## [2.32.0] - 2023-01-13 ### Added From 86c613b08be06ff9dab3a59e1dcc7e1227e59d91 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 17:54:36 -0800 Subject: [PATCH 12/17] Small tweak to reduce diff. --- .../com/diffplug/spotless/maven/MavenIntegrationHarness.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java index 1c44eef55e..5a724408c8 100644 --- a/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java +++ b/plugin-maven/src/test/java/com/diffplug/spotless/maven/MavenIntegrationHarness.java @@ -178,8 +178,8 @@ protected void writePom(String[] executions, String[] configuration, String[] de protected MavenRunner mavenRunner() throws IOException { return MavenRunner.create() - .withRunner(runner) - .withProjectDir(rootFolder()); + .withProjectDir(rootFolder()) + .withRunner(runner); } private static ProcessRunner runner; From aa0c878c8817ef0afcc192e1e5257a3e3d7e83f7 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 17:57:18 -0800 Subject: [PATCH 13/17] Fix spotbugs warning. --- .../main/java/com/diffplug/spotless/ProcessRunner.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java index 1356c0ac0d..41c664cafe 100644 --- a/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java +++ b/lib/src/main/java/com/diffplug/spotless/ProcessRunner.java @@ -31,6 +31,7 @@ import java.util.concurrent.Future; import java.util.function.BiConsumer; +import edu.umd.cs.findbugs.annotations.Nullable; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** @@ -62,7 +63,7 @@ public Result shellWinUnix(String cmdWin, String cmdUnix) throws IOException, In } /** Executes the given shell command (using {@code cmd} on windows and {@code sh} on unix). */ - public Result shellWinUnix(File cwd, Map environment, String cmdWin, String cmdUnix) throws IOException, InterruptedException { + public Result shellWinUnix(@Nullable File cwd, @Nullable Map environment, String cmdWin, String cmdUnix) throws IOException, InterruptedException { List args; if (FileSignature.machineIsWin()) { args = Arrays.asList("cmd", "/c", cmdWin); @@ -78,7 +79,7 @@ public Result exec(String... args) throws IOException, InterruptedException { } /** Creates a process with the given arguments, the given byte array is written to stdin immediately. */ - public Result exec(byte[] stdin, String... args) throws IOException, InterruptedException { + public Result exec(@Nullable byte[] stdin, String... args) throws IOException, InterruptedException { return exec(stdin, Arrays.asList(args)); } @@ -88,12 +89,12 @@ public Result exec(List args) throws IOException, InterruptedException { } /** Creates a process with the given arguments, the given byte array is written to stdin immediately. */ - public Result exec(byte[] stdin, List args) throws IOException, InterruptedException { + public Result exec(@Nullable byte[] stdin, List args) throws IOException, InterruptedException { return exec(null, null, stdin, args); } /** Creates a process with the given arguments, the given byte array is written to stdin immediately. */ - public Result exec(File cwd, Map environment, byte[] stdin, List args) throws IOException, InterruptedException { + public Result exec(@Nullable File cwd, @Nullable Map environment, @Nullable byte[] stdin, List args) throws IOException, InterruptedException { ProcessBuilder builder = new ProcessBuilder(args); if (cwd != null) { builder.directory(cwd); From c51331dc79298ba3a2cdf6356ddcb405dfd65ef1 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Mon, 16 Jan 2023 22:47:38 -0800 Subject: [PATCH 14/17] Centralize test configuration into `special-tests` and make sure it doesn't get overwritten. --- lib-extra/build.gradle | 4 ++-- lib/build.gradle | 5 +---- plugin-gradle/build.gradle | 6 ++---- plugin-maven/build.gradle | 2 -- testlib/build.gradle | 16 ---------------- 5 files changed, 5 insertions(+), 28 deletions(-) diff --git a/lib-extra/build.gradle b/lib-extra/build.gradle index d94992f8d3..08bf286d8d 100644 --- a/lib-extra/build.gradle +++ b/lib-extra/build.gradle @@ -25,8 +25,8 @@ dependencies { // we'll hold the core lib to a high standard spotbugs { reportLevel = 'low' } // low|medium|high (low = sensitive to even minor mistakes) -test { - useJUnitPlatform() +apply from: rootProject.file('gradle/special-tests.gradle') +tasks.named('test') { if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) { // needed for EclipseCdtFormatterStepTest jvmArgs '--add-opens=java.base/java.lang=ALL-UNNAMED' diff --git a/lib/build.gradle b/lib/build.gradle index 3ef2064765..e7b0298132 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -112,10 +112,7 @@ dependencies { // we'll hold the core lib to a high standard spotbugs { reportLevel = 'low' } // low|medium|high (low = sensitive to even minor mistakes) -tasks.withType(Test).configureEach { - useJUnitPlatform() -} - +apply from: rootProject.file('gradle/special-tests.gradle') jar { for (glue in NEEDS_GLUE) { from sourceSets.getByName(glue).output.classesDirs diff --git a/plugin-gradle/build.gradle b/plugin-gradle/build.gradle index 8a3260d943..11258db0e6 100644 --- a/plugin-gradle/build.gradle +++ b/plugin-gradle/build.gradle @@ -27,13 +27,11 @@ dependencies { testImplementation "com.diffplug.durian:durian-testlib:${VER_DURIAN}" } -test { - useJUnitPlatform() +apply from: rootProject.file('gradle/special-tests.gradle') +tasks.named('test') { testLogging.showStandardStreams = true } -apply from: rootProject.file('gradle/special-tests.gradle') - ////////////////////////// // GRADLE PLUGIN PORTAL // ////////////////////////// diff --git a/plugin-maven/build.gradle b/plugin-maven/build.gradle index e06fce9ace..b46cdda708 100644 --- a/plugin-maven/build.gradle +++ b/plugin-maven/build.gradle @@ -67,9 +67,7 @@ dependencies { } apply from: rootProject.file('gradle/special-tests.gradle') - tasks.withType(Test).configureEach { - useJUnitPlatform() systemProperty 'spotlessMavenPluginVersion', project.version dependsOn 'publishToMavenLocal' dependsOn ':lib:publishToMavenLocal' diff --git a/testlib/build.gradle b/testlib/build.gradle index 30c44ece23..4b16572a8c 100644 --- a/testlib/build.gradle +++ b/testlib/build.gradle @@ -21,22 +21,6 @@ dependencies { // we'll hold the testlib to a low standard (prize brevity) spotbugs { reportLevel = 'high' } // low|medium|high (low = sensitive to even minor mistakes) -test { - useJUnitPlatform() - if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) { - // for GJF https://github.com/diffplug/spotless/issues/834 - def args = [ - '--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', - '--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED', - '--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED', - '--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', - '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', - '--add-opens=java.base/java.lang=ALL-UNNAMED' - ] - jvmArgs args - } -} - apply from: rootProject.file('gradle/special-tests.gradle') javadoc { From 87c4a2a23fc9a3e74fd7e525d31dc8e41c9c852d Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 17 Jan 2023 14:42:24 -0800 Subject: [PATCH 15/17] Remove mvnw beacuse we don't need it here anymore. --- plugin-maven/build.gradle | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/plugin-maven/build.gradle b/plugin-maven/build.gradle index b46cdda708..1fad11be70 100644 --- a/plugin-maven/build.gradle +++ b/plugin-maven/build.gradle @@ -11,23 +11,6 @@ version = spotlessChangelog.versionNext apply from: rootProject.file("gradle/java-setup.gradle") apply from: rootProject.file('gradle/spotless-freshmark.gradle') -def mvnw(String args) { - boolean isWin = System.getProperty('os.name').toLowerCase().contains('win') - if (isWin) { - return [ - 'cmd', - '/c', - 'mvnw.cmd -e ' + args - ] - } else { - return [ - '/bin/sh', - '-c', - './mvnw -e ' + args - ] - } -} - apply plugin: 'de.benediktritter.maven-plugin-development' mavenPlugin { name = 'Spotless Maven Plugin' From c3a88cb2df3e1ddae20e388f5fbbdffee48e2e05 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 17 Jan 2023 14:43:08 -0800 Subject: [PATCH 16/17] Inline the mustache dependency because it's only used in one place. --- plugin-maven/build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugin-maven/build.gradle b/plugin-maven/build.gradle index 1fad11be70..ad51318d93 100644 --- a/plugin-maven/build.gradle +++ b/plugin-maven/build.gradle @@ -20,7 +20,6 @@ mavenPlugin { String VER_MAVEN_API = '3.0' String VER_ECLIPSE_AETHER = '1.1.0' -String VER_MUSTACHE = '0.9.10' String VER_PLEXUS_RESOURCES = '1.2.0' dependencies { implementation project(':lib') @@ -42,7 +41,7 @@ dependencies { testImplementation "org.assertj:assertj-core:${VER_ASSERTJ}" testImplementation "org.mockito:mockito-core:${VER_MOCKITO}" testImplementation "com.diffplug.durian:durian-io:${VER_DURIAN}" - testImplementation "com.github.spullara.mustache.java:compiler:${VER_MUSTACHE}" + testImplementation 'com.github.spullara.mustache.java:compiler:0.9.10' testImplementation "org.apache.maven:maven-plugin-api:${VER_MAVEN_API}" testImplementation "org.eclipse.aether:aether-api:${VER_ECLIPSE_AETHER}" testImplementation "org.codehaus.plexus:plexus-resources:${VER_PLEXUS_RESOURCES}" From b256bd48ef418e0f4c04e8409bcca357964c25b3 Mon Sep 17 00:00:00 2001 From: Ned Twigg Date: Tue, 17 Jan 2023 14:48:42 -0800 Subject: [PATCH 17/17] Fix testlib test. --- testlib/build.gradle | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/testlib/build.gradle b/testlib/build.gradle index 4b16572a8c..64d4681805 100644 --- a/testlib/build.gradle +++ b/testlib/build.gradle @@ -22,6 +22,15 @@ dependencies { spotbugs { reportLevel = 'high' } // low|medium|high (low = sensitive to even minor mistakes) apply from: rootProject.file('gradle/special-tests.gradle') +tasks.named('test') { + if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) { + // for Antlr4FormatterStepTest and KtLintStepTest + def args = [ + '--add-opens=java.base/java.lang=ALL-UNNAMED' + ] + jvmArgs args + } +} javadoc { options.addStringOption('Xdoclint:none', '-quiet')