Skip to content

Conversation

@FinlayRJW
Copy link
Contributor

@FinlayRJW FinlayRJW commented Jan 23, 2026

Before this PR

The TestReportFormattingPlugin relied on internal Gradle APIs (HtmlTestReport, TestReporter, etc.) using reflection to intercept and format test report output. This approach broke frequently across Gradle versions, requiring version-specific reflection hacks for 8.8, 8.11, and now completely
breaking in 9.3.0 where org/gradle/api/internal/tasks/testing/report/HtmlTestReport was removed entirely.

After this PR

Replaces the reflection-heavy internal API approach with a simple post-processing strategy. The plugin now uses FlowScope.always() to run after test tasks complete, walking the generated HTML report directory and reformatting witchcraft log JSON lines in-place. This approach works across all Gradle 8.1+
versions including 9.x without version-specific code

==COMMIT_MSG==
Use post-processing approach for test report formatting to support Gradle 9
==COMMIT_MSG==

Possible downsides?

Drops Gradle 7 support. The post-processing happens after test execution completes rather than during report generation, but the end result is equivalent.

@changelog-app
Copy link

changelog-app bot commented Jan 23, 2026

Generate changelog in changelog/@unreleased

Type (Select exactly one)

  • Feature (Adding new functionality)
  • Improvement (Improving existing functionality)
  • Fix (Fixing an issue with existing functionality)
  • Break (Creating a new major version by breaking public APIs)
  • Deprecation (Removing functionality in a non-breaking way)
  • Migration (Automatically moving data/functionality to a new system)

Description

Use post-processing approach for test report formatting to support Gradle 9

Check the box to generate changelog(s)

  • Generate changelog entry

@FinlayRJW FinlayRJW changed the title maybe rubbish Use post-processing approach for test report formatting to support Gradle 9 Jan 23, 2026
@FinlayRJW FinlayRJW marked this pull request as ready for review January 26, 2026 14:16
@changelog-app
Copy link

changelog-app bot commented Jan 26, 2026

Successfully generated changelog entry!

Need to regenerate?

Simply interact with the changelog bot comment again to regenerate these entries.

🔄 Changelog entries were re-generated at Mon, 26 Jan 2026 14:20:19 UTC!


📋Changelog Preview

💡 Improvements

  • Use post-processing approach for test report formatting to support Gradle 9 (#891)

}
getFlowScope().always(FormatReportAction.class, spec -> spec.getParameters()
.getReportDir()
.set(task.getReports().getHtml()));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't this just a last write wins thing? or am I misunderstanding

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, always creates a new thing each time

Comment on lines +105 to +106
// Gradle 8 uses classes/com.palantir.SimpleTest.html
// Gradle 9 uses com.palantir.SimpleTest/simpleTest.html
Copy link
Contributor

@CRogers CRogers Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is maybe one place where it might be nice for the testing framework to allowing injecting a GradleVersion into the test.

Perhaps overkill, but bonus points if there's some way of calling a method like:

gradleVersion.ifLessThanOrElse(
    GradleVerison.of("9.0.0"),
    "reports/tests/test/classes/com.palantir.SimpleTest.html",
    "reports/tests/test/com.palantir.SimpleTest/simpleTest.html")

...that could be automatically changed by an errorprone to just:

"reports/tests/test/com.palantir.SimpleTest/simpleTest.html"

...if we remove Gradle 8 support.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh I missed your comment

I was going to suggest some sort of parameterised test, that had a version parameter, and you could potentially do Assumptions.assumeThat(...).

I think you could probably even do it without injecting the GradleVersion. Just doing the assumption call during injection or something or class creation.

Comment on lines +105 to +110
// Gradle 8 uses classes/com.palantir.SimpleTest.html
// Gradle 9 uses com.palantir.SimpleTest/simpleTest.html
ArbitraryFile legacyReportFile =
rootProject.buildDir().file("reports/tests/test/classes/com.palantir.SimpleTest.html");
ArbitraryFile newReportFile =
rootProject.buildDir().file("reports/tests/test/com.palantir.SimpleTest/simpleTest.html");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this is a little weird, can we not pass it in as a parameter or something? not sure how well it fits into the framework @CRogers what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could do something quite sensible with @RestrictToGradleVersionsEqualTo if we can get that in which would let us make a version of the test just for gradle 8.14.3

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that still requires you to make two separate tests even though the content is identical

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// Match <pre> tags within stdout/stderr sections: <h2>standard output</h2>...<pre>...</pre>
private static final Pattern OUTPUT_SECTION_PATTERN = Pattern.compile(
"(<h2>standard (?:output|error)</h2>\\s*<span[^>]*>\\s*<pre[^>]*>)(.*?)(</pre>)",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one thing to note is whether or not this regex is greedy, which I think you want

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the current is correct no? The .*? is non-greedy, which is correct here. It stops at the first </pre> after each opening tag, so multiple stdout/stderr sections are matched individually rather than being consumed as one giant match

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants