Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure allure server is terminated in Windows when cancelling the build #78

Merged
merged 1 commit into from
Oct 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.gradle
/build/
/*/build/
/sandbox/*/build/
*.iml
.idea/

Original file line number Diff line number Diff line change
@@ -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) {
Expand Down Expand Up @@ -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<Any>().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<Any>) {
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()
}
}
}
5 changes: 5 additions & 0 deletions sandbox/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
allprojects {
repositories {
mavenCentral()
}
}
13 changes: 8 additions & 5 deletions sandbox/dsl-groovy/build.gradle
Original file line number Diff line number Diff line change
@@ -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'
}
}
27 changes: 27 additions & 0 deletions sandbox/dsl-groovy/src/test/java/tests/Junit5Test.java
Original file line number Diff line number Diff line change
@@ -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 "<p>HELLO</p>";
}

}
16 changes: 7 additions & 9 deletions sandbox/dsl-kotlin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -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")
}
}
27 changes: 27 additions & 0 deletions sandbox/dsl-kotlin/src/test/java/tests/Junit5Test.java
Original file line number Diff line number Diff line change
@@ -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 "<p>HELLO</p>";
}

}