From 929546730b618de55f8d72bab2077c29ac41d004 Mon Sep 17 00:00:00 2001 From: Vladimir Sitnikov Date: Thu, 14 Oct 2021 12:43:56 +0300 Subject: [PATCH] make sure allure server is terminated in Windows when cancelling the build (via #78) --- .gitignore | 1 + .../allure/gradle/report/tasks/AllureServe.kt | 82 +++++++++++++++++-- sandbox/build.gradle.kts | 5 ++ sandbox/dsl-groovy/build.gradle | 13 +-- .../src/test/java/tests/Junit5Test.java | 27 ++++++ sandbox/dsl-kotlin/build.gradle.kts | 16 ++-- .../src/test/java/tests/Junit5Test.java | 27 ++++++ 7 files changed, 150 insertions(+), 21 deletions(-) create mode 100644 sandbox/dsl-groovy/src/test/java/tests/Junit5Test.java create mode 100644 sandbox/dsl-kotlin/src/test/java/tests/Junit5Test.java diff --git a/.gitignore b/.gitignore index 651136b..fc49aa8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .gradle /build/ /*/build/ +/sandbox/*/build/ *.iml .idea/ diff --git a/allure-report-plugin/src/main/kotlin/io/qameta/allure/gradle/report/tasks/AllureServe.kt b/allure-report-plugin/src/main/kotlin/io/qameta/allure/gradle/report/tasks/AllureServe.kt index 2f9feff..985efec 100644 --- a/allure-report-plugin/src/main/kotlin/io/qameta/allure/gradle/report/tasks/AllureServe.kt +++ b/allure-report-plugin/src/main/kotlin/io/qameta/allure/gradle/report/tasks/AllureServe.kt @@ -1,11 +1,17 @@ package io.qameta.allure.gradle.report.tasks import io.qameta.allure.gradle.base.tasks.AllureExecTask +import org.apache.tools.ant.taskdefs.condition.Os import org.gradle.api.model.ObjectFactory import org.gradle.api.tasks.Internal import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.options.Option import org.gradle.kotlin.dsl.property +import java.io.File +import java.io.InputStream +import java.io.PrintStream +import java.lang.management.ManagementFactory +import java.util.concurrent.TimeUnit import javax.inject.Inject open class AllureServe @Inject constructor(objects: ObjectFactory) : AllureExecTask(objects) { @@ -34,19 +40,81 @@ open class AllureServe @Inject constructor(objects: ObjectFactory) : AllureExecT fun serveAllureReport() { val rawResults = rawResults.map { it.absolutePath } logger.info("Input directories for $name: $rawResults") - project.exec { - executable(allureExecutable) + val allureArgs = mutableListOf().apply { if (verbose.get()) { - args("--verbose") + add("--verbose") } - args(SERVE_COMMAND) + add(SERVE_COMMAND) host.orNull?.let { - args("--host", it) + add("--host") + add(it) } port.orNull?.let { - args("--port", it) + add("--port") + add(it) + } + addAll(rawResults) + } + + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + // Workaround https://github.com/gradle/gradle/issues/7603 + // The issues is that "terminate process" in Windows does not terminate its children + startWithProcessBuilder(allureExecutable, allureArgs) + return + } + + project.exec { + executable(allureExecutable) + args(allureArgs) + } + } + + private fun startWithProcessBuilder(allureExecutable: File, allureArgs: List) { + val cmd = listOf("cmd", "/c", allureExecutable.toString()) + allureArgs.map { it.toString() } + logger.info("Starting $cmd") + ProcessBuilder(cmd).start().apply { + if (isAlive) { + val allurePid = processOrParentPid + project.gradle.buildFinished { + logger.info("Terminating process $allurePid to stop allure serve") + // /T kills all the children, so it does terminate 'allure serve' command + ProcessBuilder("taskkill", "/PID", allurePid.toString(), "/T", "/F").start().apply { + forwardStreams("terminate allure serve") + waitFor(15, TimeUnit.SECONDS) + } + } + } + outputStream.close() + forwardStreams("allure serve") + waitFor() + } + } + + private val Process.processOrParentPid: Long + get() = try { + // Java 9+ + Process::class.java.getMethod("pid").invoke(this) as Long + } catch (t: Throwable) { + // Almost all the implementations return name as pid@... + // https://stackoverflow.com/a/35885/1261287 + ManagementFactory.getRuntimeMXBean().name.substringBefore('@').toLong().also { + logger.info("Will terminate process $it (Gradle Daemon?) when ctrl+c is pressed. Consider upgrading to Java 11+") } - args(rawResults) + } + + private fun Process.forwardStreams(name: String) = apply { + // ProcessBuilder.inheritIO does not work, see https://github.com/gradle/gradle/issues/16719 + forwardStream("$name stdout", inputStream, System.out) + forwardStream("$name stderr", errorStream, System.err) + } + + private fun forwardStream(streamName: String, inputStream: InputStream?, out: PrintStream) { + Thread { + inputStream?.buffered()?.copyTo(out) + }.apply { + isDaemon = true + name = "Allure serve $streamName forwarder" + start() } } } diff --git a/sandbox/build.gradle.kts b/sandbox/build.gradle.kts index e69de29..5c41c84 100644 --- a/sandbox/build.gradle.kts +++ b/sandbox/build.gradle.kts @@ -0,0 +1,5 @@ +allprojects { + repositories { + mavenCentral() + } +} diff --git a/sandbox/dsl-groovy/build.gradle b/sandbox/dsl-groovy/build.gradle index 9c0888a..67d97c4 100644 --- a/sandbox/dsl-groovy/build.gradle +++ b/sandbox/dsl-groovy/build.gradle @@ -1,12 +1,15 @@ plugins { - id("io.qameta.allure") + id('java-library') + id('io.qameta.allure') +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' } allure { + version = '2.15.0' adapter { - - } - report { - + allureJavaVersion = '2.15.0' } } diff --git a/sandbox/dsl-groovy/src/test/java/tests/Junit5Test.java b/sandbox/dsl-groovy/src/test/java/tests/Junit5Test.java new file mode 100644 index 0000000..6c4e60e --- /dev/null +++ b/sandbox/dsl-groovy/src/test/java/tests/Junit5Test.java @@ -0,0 +1,27 @@ +package tests; + +import io.qameta.allure.Attachment; +import io.qameta.allure.Step; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class Junit5Test { + + @Test + public void testWithAttachment() { + stepMethod(); + assertTrue(true); + } + + @Step("step") + public void stepMethod() { + attachment(); + } + + @Attachment(value = "attachment", type = "text/plain") + public String attachment() { + return "

HELLO

"; + } + +} \ No newline at end of file diff --git a/sandbox/dsl-kotlin/build.gradle.kts b/sandbox/dsl-kotlin/build.gradle.kts index 52d2c1d..0e5cf61 100644 --- a/sandbox/dsl-kotlin/build.gradle.kts +++ b/sandbox/dsl-kotlin/build.gradle.kts @@ -1,17 +1,15 @@ plugins { + id("java-library") id("io.qameta.allure") } +dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:5.8.1") +} + allure { - adapter.frameworks.spock.enabled.set(true) + version.set("2.15.0") adapter { - allureJavaVersion.set("213") - frameworks { - junit5 - cucumber2Jvm { - } - } - } - report { + allureJavaVersion.set("2.15.0") } } diff --git a/sandbox/dsl-kotlin/src/test/java/tests/Junit5Test.java b/sandbox/dsl-kotlin/src/test/java/tests/Junit5Test.java new file mode 100644 index 0000000..6c4e60e --- /dev/null +++ b/sandbox/dsl-kotlin/src/test/java/tests/Junit5Test.java @@ -0,0 +1,27 @@ +package tests; + +import io.qameta.allure.Attachment; +import io.qameta.allure.Step; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class Junit5Test { + + @Test + public void testWithAttachment() { + stepMethod(); + assertTrue(true); + } + + @Step("step") + public void stepMethod() { + attachment(); + } + + @Attachment(value = "attachment", type = "text/plain") + public String attachment() { + return "

HELLO

"; + } + +} \ No newline at end of file