Skip to content

Commit 47d0e68

Browse files
committed
Include Git metadata in Open Test Report XML output
1 parent d73eee8 commit 47d0e68

File tree

3 files changed

+115
-4
lines changed

3 files changed

+115
-4
lines changed

junit-platform-reporting/src/main/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListener.java

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
package org.junit.platform.reporting.open.xml;
1212

1313
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
14+
import static org.junit.platform.commons.util.StringUtils.isNotBlank;
1415
import static org.junit.platform.reporting.open.xml.JUnitFactory.legacyReportingName;
1516
import static org.junit.platform.reporting.open.xml.JUnitFactory.type;
1617
import static org.junit.platform.reporting.open.xml.JUnitFactory.uniqueId;
@@ -30,6 +31,10 @@
3031
import static org.opentest4j.reporting.events.core.CoreFactory.tags;
3132
import static org.opentest4j.reporting.events.core.CoreFactory.uriSource;
3233
import static org.opentest4j.reporting.events.core.CoreFactory.userName;
34+
import static org.opentest4j.reporting.events.git.GitFactory.branch;
35+
import static org.opentest4j.reporting.events.git.GitFactory.commit;
36+
import static org.opentest4j.reporting.events.git.GitFactory.repository;
37+
import static org.opentest4j.reporting.events.git.GitFactory.status;
3338
import static org.opentest4j.reporting.events.java.JavaFactory.classSource;
3439
import static org.opentest4j.reporting.events.java.JavaFactory.classpathResourceSource;
3540
import static org.opentest4j.reporting.events.java.JavaFactory.fileEncoding;
@@ -42,18 +47,27 @@
4247
import static org.opentest4j.reporting.events.root.RootFactory.reported;
4348
import static org.opentest4j.reporting.events.root.RootFactory.started;
4449

50+
import java.io.BufferedReader;
4551
import java.io.IOException;
52+
import java.io.InputStream;
53+
import java.io.InputStreamReader;
54+
import java.io.Reader;
4655
import java.io.UncheckedIOException;
4756
import java.net.InetAddress;
4857
import java.net.UnknownHostException;
58+
import java.nio.charset.Charset;
4959
import java.nio.file.Path;
5060
import java.time.Instant;
5161
import java.util.Map;
62+
import java.util.Optional;
5263
import java.util.concurrent.ConcurrentHashMap;
64+
import java.util.concurrent.TimeUnit;
5365
import java.util.concurrent.atomic.AtomicInteger;
66+
import java.util.function.BiConsumer;
5467

5568
import org.apiguardian.api.API;
5669
import org.junit.platform.commons.JUnitException;
70+
import org.junit.platform.commons.util.ExceptionUtils;
5771
import org.junit.platform.commons.util.StringUtils;
5872
import org.junit.platform.engine.ConfigurationParameters;
5973
import org.junit.platform.engine.TestExecutionResult;
@@ -74,6 +88,7 @@
7488
import org.junit.platform.launcher.listeners.OutputDir;
7589
import org.opentest4j.reporting.events.api.DocumentWriter;
7690
import org.opentest4j.reporting.events.api.NamespaceRegistry;
91+
import org.opentest4j.reporting.events.core.Infrastructure;
7792
import org.opentest4j.reporting.events.core.Result;
7893
import org.opentest4j.reporting.events.core.Sources;
7994
import org.opentest4j.reporting.events.root.Events;
@@ -103,6 +118,7 @@ public void testPlanExecutionStarted(TestPlan testPlan) {
103118
if (isEnabled(config)) {
104119
NamespaceRegistry namespaceRegistry = NamespaceRegistry.builder(Namespace.REPORTING_CORE) //
105120
.add("e", Namespace.REPORTING_EVENTS) //
121+
.add("git", Namespace.REPORTING_GIT) //
106122
.add("java", Namespace.REPORTING_JAVA) //
107123
.add("junit", JUnitFactory.NAMESPACE,
108124
"https://junit.org/junit5/schemas/open-test-reporting/junit-1.9.xsd") //
@@ -138,9 +154,92 @@ private void reportInfrastructure() {
138154
.append(javaVersion(System.getProperty("java.version"))) //
139155
.append(fileEncoding(System.getProperty("file.encoding"))) //
140156
.append(heapSize(), heapSize -> heapSize.withMax(Runtime.getRuntime().maxMemory()));
157+
158+
addGitInfo(infrastructure);
141159
});
142160
}
143161

162+
private static void addGitInfo(Infrastructure infrastructure) {
163+
boolean gitInstalled = exec("git", "--version").isPresent();
164+
if (gitInstalled) {
165+
exec("git", "config", "--get", "remote.origin.url") //
166+
.filter(StringUtils::isNotBlank) //
167+
.ifPresent(
168+
gitUrl -> infrastructure.append(repository(), repository -> repository.withOriginUrl(gitUrl)));
169+
exec("git", "rev-parse", "--abbrev-ref", "HEAD") //
170+
.filter(StringUtils::isNotBlank) //
171+
.ifPresent(branch -> infrastructure.append(branch(branch)));
172+
exec("git", "rev-parse", "--verify", "HEAD") //
173+
.filter(StringUtils::isNotBlank) //
174+
.ifPresent(gitCommitHash -> infrastructure.append(commit(gitCommitHash)));
175+
exec("git", "status", "--porcelain") //
176+
.ifPresent(statusOutput -> infrastructure.append(status(statusOutput),
177+
status -> status.withClean(statusOutput.isEmpty())));
178+
}
179+
}
180+
181+
static Optional<String> exec(String... args) {
182+
183+
Process process = startProcess(args);
184+
185+
try (Reader out = newBufferedReader(process.getInputStream());
186+
Reader err = newBufferedReader(process.getErrorStream())) {
187+
188+
StringBuilder output = new StringBuilder();
189+
readAllChars(out, (chars, numChars) -> output.append(chars, 0, numChars));
190+
191+
readAllChars(err, (__, ___) -> {
192+
// ignore
193+
});
194+
195+
boolean terminated = process.waitFor(10, TimeUnit.SECONDS);
196+
return terminated && process.exitValue() == 0 ? Optional.of(trimAtEnd(output)) : Optional.empty();
197+
}
198+
catch (InterruptedException e) {
199+
throw ExceptionUtils.throwAsUncheckedException(e);
200+
}
201+
catch (IOException ignore) {
202+
return Optional.empty();
203+
}
204+
finally {
205+
process.destroyForcibly();
206+
}
207+
}
208+
209+
private static BufferedReader newBufferedReader(InputStream stream) {
210+
return new BufferedReader(new InputStreamReader(stream, Charset.defaultCharset()));
211+
}
212+
213+
private static Process startProcess(String[] args) {
214+
Process process;
215+
try {
216+
process = Runtime.getRuntime().exec(args);
217+
}
218+
catch (IOException e) {
219+
throw new RuntimeException(e);
220+
}
221+
return process;
222+
}
223+
224+
private static void readAllChars(Reader reader, BiConsumer<char[], Integer> consumer) throws IOException {
225+
char[] buffer = new char[1024];
226+
int numChars;
227+
while ((numChars = reader.read(buffer)) != -1) {
228+
consumer.accept(buffer, numChars);
229+
}
230+
}
231+
232+
private static String trimAtEnd(StringBuilder value) {
233+
int endIndex = value.length();
234+
for (int i = value.length() - 1; i >= 0; i--) {
235+
if (Character.isWhitespace(value.charAt(i))) {
236+
endIndex--;
237+
break;
238+
}
239+
}
240+
return value.substring(0, endIndex);
241+
}
242+
144243
@Override
145244
public void testPlanExecutionFinished(TestPlan testPlan) {
146245
try {
@@ -160,7 +259,7 @@ public void executionSkipped(TestIdentifier testIdentifier, String reason) {
160259
reportStarted(testIdentifier, id);
161260
eventsFileWriter.append(finished(id, Instant.now()), //
162261
finished -> finished.append(result(Result.Status.SKIPPED), result -> {
163-
if (StringUtils.isNotBlank(reason)) {
262+
if (isNotBlank(reason)) {
164263
result.append(reason(reason));
165264
}
166265
}));

platform-tests/src/test/java/org/junit/platform/reporting/open/xml/OpenTestReportGeneratingListenerTests.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ void writesValidXmlReport() throws Exception {
6464
assertThat(validate(xmlFile)).isEmpty();
6565

6666
var expected = """
67-
<e:events xmlns="https://schemas.opentest4j.org/reporting/core/0.1.0" xmlns:e="https://schemas.opentest4j.org/reporting/events/0.1.0" xmlns:java="https://schemas.opentest4j.org/reporting/java/0.1.0"
68-
xmlns:junit="https://schemas.junit.org/open-test-reporting" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
67+
<e:events xmlns="https://schemas.opentest4j.org/reporting/core/0.1.0" xmlns:e="https://schemas.opentest4j.org/reporting/events/0.1.0"
68+
xmlns:git="https://schemas.opentest4j.org/reporting/git/0.1.0"
69+
xmlns:java="https://schemas.opentest4j.org/reporting/java/0.1.0"
70+
xmlns:junit="https://schemas.junit.org/open-test-reporting"
71+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6972
xsi:schemaLocation="https://schemas.junit.org/open-test-reporting https://junit.org/junit5/schemas/open-test-reporting/junit-1.9.xsd">
7073
<infrastructure>
7174
<hostName>${xmlunit.ignore}</hostName>
@@ -75,6 +78,10 @@ void writesValidXmlReport() throws Exception {
7578
<java:javaVersion>${xmlunit.ignore}</java:javaVersion>
7679
<java:fileEncoding>${xmlunit.ignore}</java:fileEncoding>
7780
<java:heapSize max="${xmlunit.isNumber}"/>
81+
<git:repository originUrl="${xmlunit.matchesRegex(https://.+)}"/>
82+
<git:branch>${xmlunit.ignore}</git:branch>
83+
<git:commit>${xmlunit.matchesRegex([0-9a-f]{40})}</git:commit>
84+
<git:status clean="${xmlunit.ignore}">${xmlunit.ignore}</git:status>
7885
</infrastructure>
7986
<e:started id="1" name="dummy" time="${xmlunit.isDateTime}">
8087
<metadata>

platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/XmlAssertions.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ static void verifyContainsExpectedStartedOpenTestReport(Path testResultsDir) {
3434

3535
private static void verifyContent(Path xmlFile) {
3636
var expected = """
37-
<e:events xmlns="https://schemas.opentest4j.org/reporting/core/0.1.0" xmlns:e="https://schemas.opentest4j.org/reporting/events/0.1.0" xmlns:java="https://schemas.opentest4j.org/reporting/java/0.1.0"
37+
<e:events xmlns="https://schemas.opentest4j.org/reporting/core/0.1.0" xmlns:e="https://schemas.opentest4j.org/reporting/events/0.1.0" xmlns:git="https://schemas.opentest4j.org/reporting/git/0.1.0"
38+
xmlns:java="https://schemas.opentest4j.org/reporting/java/0.1.0"
3839
xmlns:junit="https://schemas.junit.org/open-test-reporting" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3940
xsi:schemaLocation="https://schemas.junit.org/open-test-reporting https://junit.org/junit5/schemas/open-test-reporting/junit-1.9.xsd">
4041
<infrastructure>
@@ -45,6 +46,10 @@ private static void verifyContent(Path xmlFile) {
4546
<java:javaVersion>${xmlunit.ignore}</java:javaVersion>
4647
<java:fileEncoding>${xmlunit.ignore}</java:fileEncoding>
4748
<java:heapSize max="${xmlunit.isNumber}"/>
49+
<git:repository originUrl="${xmlunit.matchesRegex(https://.+)}"/>
50+
<git:branch>${xmlunit.ignore}</git:branch>
51+
<git:commit>${xmlunit.matchesRegex([0-9a-f]{40})}</git:commit>
52+
<git:status clean="${xmlunit.ignore}">${xmlunit.ignore}</git:status>
4853
</infrastructure>
4954
<e:started id="1" name="JUnit Jupiter" time="${xmlunit.isDateTime}">
5055
<metadata>

0 commit comments

Comments
 (0)