Skip to content

Add TESTINGBOT_BUILD env var and embedded build-report page#28

Merged
jochen-testingbot merged 2 commits into
masterfrom
build-report-embed
Jul 16, 2026
Merged

Add TESTINGBOT_BUILD env var and embedded build-report page#28
jochen-testingbot merged 2 commits into
masterfrom
build-report-embed

Conversation

@jochen-testingbot

@jochen-testingbot jochen-testingbot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What

Adds Sauce-Labs-style build grouping plus an embedded build report, closing two of the connected feature-parity gaps from the modernization review:

  1. TESTINGBOT_BUILD env var — a per-build identifier exposed by the freestyle Build Environment wrapper and both pipeline steps (testingbot { }, testingbotTunnel { }). Tests pass its value as their build desired capability so every session from one Jenkins build is grouped under one TestingBot build. This is the TestingBot analog of Sauce Labs' SAUCE_BUILD_NAME.

  2. Embedded "TestingBot Build" page — a new TestingBotBuildReportAction (RunAction2) added to each build that injects credentials. It iframes the build's report at /mini/builds/<clientKey>/<buildId> (the page added in the web app), so the full report — every session, status, video — is viewable without leaving Jenkins.

Security / persistence notes

  • The embed is authenticated with MD5(clientKey:clientSecret:buildId), computed once on the controller. Only the resulting hash is stored on the build — the raw secret is never persisted.
  • The action stores only String fields (clientKey, buildId, authHash). Verified to marshal cleanly under the JEP-200 class filter via a save + reload round-trip.
  • buildId is sanitized to [A-Za-z0-9._-], safe both as a capability value and as a URL path segment.

Validation

  • mvn clean verify (SpotBugs enabled) — clean.
  • hpi:run script-console lifecycle test: action attaches, survives build.save() + reload (no JEP-200 marshal failure), getReportUrl() well-formed, and the auth hash matches MD5(key:secret:buildId) — confirmed byte-identical to the web app's Digest::MD5.hexdigest.
  • Rendered the action page: <h1>TestingBot Build</h1> + iframe pointing at the authenticated report URL with ref=jenkins.

Depends on

The web app route GET /mini/builds/:client_key/:build_id (already added). The embed only works once that endpoint is deployed.

Summary by CodeRabbit

  • New Features

    • Added an embedded TestingBot Build report page to Jenkins builds.
    • Exposes the TESTINGBOT_BUILD environment variable for grouping test sessions in a single report.
    • Supports both freestyle and pipeline configurations, including tunnel-based tests.
    • Displays the embedded report directly within Jenkins with a link to TestingBot.
  • Documentation

    • Added setup instructions and examples for using TESTINGBOT_BUILD as the test build capability.

Exposes a per-build identifier (TESTINGBOT_BUILD) from the freestyle
wrapper and both pipeline steps, the TestingBot analog of Sauce Labs'
SAUCE_BUILD_NAME. Tests that pass its value as their build capability are
grouped under a new TestingBotBuildReportAction page, which iframes the
build's TestingBot report (/mini/builds/<key>/<buildId>) authenticated
with MD5(key:secret:buildId) computed on the controller so the raw secret
is never persisted on the build.

The action stores only Strings (verified to marshal cleanly under the
JEP-200 class filter).
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a Jenkins TestingBotBuildReportAction with an embedded report page, generates a per-build identifier and authentication hash, and exposes TESTINGBOT_BUILD through freestyle and pipeline integrations. README documentation describes using the identifier as the test build capability.

Changes

Embedded TestingBot Build reports

Layer / File(s) Summary
Build report action and embedded page
src/main/java/testingbot/TestingBotBuildReportAction.java, src/main/resources/testingbot/TestingBotBuildReportAction/index.jelly
Creates the Jenkins run action, derives build identifiers and authentication hashes, and renders the embedded TestingBot report page.
Freestyle build environment wiring
src/main/java/testingbot/TestingBotBuildWrapper.java
Threads the report build identifier through TestingBotBuildEnvironment and conditionally publishes TESTINGBOT_BUILD.
Pipeline environment wiring and usage documentation
src/main/java/testingbot/pipeline/TestingBotStep.java, src/main/java/testingbot/pipeline/TestingBotTunnelStep.java, README.md
Publishes TESTINGBOT_BUILD during pipeline and tunnel execution and documents using it as the test build capability.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant JenkinsRun
  participant TestingBotBuildReportAction
  participant BuildEnvironment
  participant TestingBotReport
  JenkinsRun->>TestingBotBuildReportAction: attach credentials and run
  TestingBotBuildReportAction->>TestingBotBuildReportAction: compute buildId and authHash
  JenkinsRun->>BuildEnvironment: publish TESTINGBOT_BUILD
  BuildEnvironment->>TestingBotReport: group sessions by build identifier
  JenkinsRun->>TestingBotReport: load embedded report
  TestingBotReport-->>JenkinsRun: render TestingBot Build page
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding the TESTINGBOT_BUILD env var and an embedded build-report page.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 57: Update the “Embedded TestingBot Build report” heading in the README
to use the configured Markdown setext style instead of the current heading
syntax, preserving the existing heading text.

In `@src/main/java/testingbot/pipeline/TestingBotTunnelStep.java`:
- Around line 239-241: Ensure TestingBotBuildReportAction.attach rejects
credential mismatches on the same Run or replaces the existing action before
exporting TESTINGBOT_BUILD. Apply this consistently at TestingBotTunnelStep.java
lines 239-241 and TestingBotStep.java lines 91-93, preserving the existing
behavior when credentials match.

In `@src/main/java/testingbot/TestingBotBuildReportAction.java`:
- Around line 62-66: Update TestingBotBuildReportAction.attach to synchronize
the lookup-and-creation sequence so parallel calls cannot add duplicate actions;
then return the selected action’s persisted buildId rather than recomputing it
via buildIdFor(run). Preserve the existing action when one is already attached.
- Around line 53-55: Update buildIdFor to use an injective, URL-safe encoding of
the full job name and build number instead of replacing unsupported characters
with hyphens. Preserve deterministic output while ensuring distinct names such
as “qa smoke” and “qa-smoke” cannot produce the same identifier.

In `@src/main/resources/testingbot/TestingBotBuildReportAction/index.jelly`:
- Line 16: Add a descriptive title attribute to the iframe in the TestingBot
build report markup, identifying it as the embedded TestingBot report while
preserving the existing src and styling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9db17927-c2d2-4fbb-97a4-eb85fc7997de

📥 Commits

Reviewing files that changed from the base of the PR and between 2a0f932 and cce2a98.

📒 Files selected for processing (6)
  • README.md
  • src/main/java/testingbot/TestingBotBuildReportAction.java
  • src/main/java/testingbot/TestingBotBuildWrapper.java
  • src/main/java/testingbot/pipeline/TestingBotStep.java
  • src/main/java/testingbot/pipeline/TestingBotTunnelStep.java
  • src/main/resources/testingbot/TestingBotBuildReportAction/index.jelly

Comment thread README.md

A full example that you can use is available on our GitHub [Jenkins-Demo](https://github.com/testingbot/Jenkins-Demo) page.

## Embedded TestingBot Build report

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use the configured setext heading style.

Markdownlint expects a setext heading here.

Proposed fix
-## Embedded TestingBot Build report
+Embedded TestingBot Build report
+--------------------------------
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Embedded TestingBot Build report
Embedded TestingBot Build report
--------------------------------
🧰 Tools
🪛 markdownlint-cli2 (0.23.0)

[warning] 57-57: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 57, Update the “Embedded TestingBot Build report” heading
in the README to use the configured Markdown setext style instead of the current
heading syntax, preserving the existing heading text.

Source: Linters/SAST tools

Comment on lines +239 to +241
// Expose the build id and add the embeddable build-report page so all sessions using
// build=$TESTINGBOT_BUILD are grouped and viewable inside Jenkins.
env.put(TestingBotBuildReportAction.TESTINGBOT_BUILD, TestingBotBuildReportAction.attach(run, tbCredentials));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant files first.
ast-grep outline src/main/java/testingbot/pipeline/TestingBotStep.java --view expanded || true
ast-grep outline src/main/java/testingbot/pipeline/TestingBotTunnelStep.java --view expanded || true
ast-grep outline src/main/java/testingbot/TestingBotBuildReportAction.java --view expanded || true

# Show the relevant line ranges with line numbers.
printf '\n--- TestingBotStep.java ---\n'
sed -n '1,180p' src/main/java/testingbot/pipeline/TestingBotStep.java | cat -n
printf '\n--- TestingBotTunnelStep.java ---\n'
sed -n '200,280p' src/main/java/testingbot/pipeline/TestingBotTunnelStep.java | cat -n
printf '\n--- TestingBotBuildReportAction.java ---\n'
sed -n '1,260p' src/main/java/testingbot/TestingBotBuildReportAction.java | cat -n

Repository: testingbot/TestingBot-Jenkins-Plugin

Length of output: 19661


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n--- usages of TestingBotBuildReportAction.attach ---\n'
rg -n "TestingBotBuildReportAction\.attach\(" src/main/java || true

printf '\n--- TestingBotBuildAction.java ---\n'
sed -n '1,260p' src/main/java/testingbot/TestingBotBuildAction.java | cat -n

printf '\n--- testingbot credential usages ---\n'
rg -n "getCredentialsId\\(|TestingBotCredentials\\.getCredentials|run\\.addAction\\(new TestingBotBuildAction|TestingBotBuildReportAction" src/main/java/testingbot -g '!**/target/**' || true

Repository: testingbot/TestingBot-Jenkins-Plugin

Length of output: 4928


Reject mixed TestingBot credentials on the same run. TestingBotBuildReportAction.attach keeps the first report action on the Run, so a later testingbot {} or testingbotTunnel {} block with different credentials will still export the original report URL/hash. Fail on credential mismatch or replace the attached action before setting TESTINGBOT_BUILD.

  • src/main/java/testingbot/pipeline/TestingBotStep.java#L91-L93
  • src/main/java/testingbot/pipeline/TestingBotTunnelStep.java#L239-L241
📍 Affects 2 files
  • src/main/java/testingbot/pipeline/TestingBotTunnelStep.java#L239-L241 (this comment)
  • src/main/java/testingbot/pipeline/TestingBotStep.java#L91-L93
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/testingbot/pipeline/TestingBotTunnelStep.java` around lines 239
- 241, Ensure TestingBotBuildReportAction.attach rejects credential mismatches
on the same Run or replaces the existing action before exporting
TESTINGBOT_BUILD. Apply this consistently at TestingBotTunnelStep.java lines
239-241 and TestingBotStep.java lines 91-93, preserving the existing behavior
when credentials match.

Comment on lines +53 to +55
public static String buildIdFor(Run<?, ?> run) {
return (run.getParent().getFullName() + "_" + run.getNumber()).replaceAll("[^A-Za-z0-9._-]", "-");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Make the build identifier collision-resistant.

Line 54 maps distinct job names such as qa smoke and qa-smoke to the same ID. With equal build numbers, their TestingBot sessions merge into one report and may cross job boundaries. Use an injective URL-safe encoding instead of replacing characters.

Proposed fix
+import java.util.Base64;
...
 public static String buildIdFor(Run<?, ?> run) {
-    return (run.getParent().getFullName() + "_" + run.getNumber()).replaceAll("[^A-Za-z0-9._-]", "-");
+    String rawId = run.getParent().getFullName() + "_" + run.getNumber();
+    return Base64.getUrlEncoder()
+            .withoutPadding()
+            .encodeToString(rawId.getBytes(StandardCharsets.UTF_8));
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/testingbot/TestingBotBuildReportAction.java` around lines 53 -
55, Update buildIdFor to use an injective, URL-safe encoding of the full job
name and build number instead of replacing unsupported characters with hyphens.
Preserve deterministic output while ensuring distinct names such as “qa smoke”
and “qa-smoke” cannot produce the same identifier.

Comment on lines +62 to +66
public static String attach(Run<?, ?> run, TestingBotCredentials credentials) {
if (run.getAction(TestingBotBuildReportAction.class) == null) {
run.addAction(create(run, credentials));
}
return buildIdFor(run);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Serialize action creation and return the persisted ID.

Lines 63-65 are a non-atomic check-then-add. Parallel Pipeline branches can attach duplicate actions with the same URL name. Synchronize lookup/creation (or use an atomic action API), then return the selected action’s stored buildId; recomputing it can diverge after a job rename.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/testingbot/TestingBotBuildReportAction.java` around lines 62 -
66, Update TestingBotBuildReportAction.attach to synchronize the
lookup-and-creation sequence so parallel calls cannot add duplicate actions;
then return the selected action’s persisted buildId rather than recomputing it
via buildIdFor(run). Preserve the existing action when one is already attached.

<a href="${it.reportUrl}&amp;ref=jenkins" target="_blank">View on TestingBot</a>
<l:ajax>
<div>
<iframe src="${it.reportUrl}&amp;ref=jenkins" style="width: 100%; min-height: 100vh; border: none"></iframe>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Give the embedded report an accessible name.

Screen-reader users cannot identify the iframe’s content. Add a descriptive title.

Proposed fix
-<iframe src="${it.reportUrl}&amp;ref=jenkins" style="width: 100%; min-height: 100vh; border: none"></iframe>
+<iframe title="TestingBot Build report" src="${it.reportUrl}&amp;ref=jenkins" style="width: 100%; min-height: 100vh; border: none"></iframe>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<iframe src="${it.reportUrl}&amp;ref=jenkins" style="width: 100%; min-height: 100vh; border: none"></iframe>
<iframe title="TestingBot Build report" src="${it.reportUrl}&amp;ref=jenkins" style="width: 100%; min-height: 100vh; border: none"></iframe>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/resources/testingbot/TestingBotBuildReportAction/index.jelly` at
line 16, Add a descriptive title attribute to the iframe in the TestingBot build
report markup, identifying it as the embedded TestingBot report while preserving
the existing src and styling.

…itle

Addresses review findings on the build-report feature:
- buildIdFor is now injective: when sanitizing the job name replaces characters
  it appends a short deterministic hash of the raw value, so distinct names like
  "qa smoke" and "qa-smoke" can no longer collapse to the same identifier
  (already-safe names are unchanged).
- attach synchronizes on the run so concurrent steps in one build cannot add
  duplicate actions, returns the persisted build id, and replaces the action when
  a different TestingBot account (client key) is used later in the same build.
- The embedded report iframe gets a descriptive title for accessibility.
@jochen-testingbot jochen-testingbot merged commit 9c1fbf9 into master Jul 16, 2026
4 checks passed
jochen-testingbot added a commit that referenced this pull request Jul 16, 2026
PRs #29 and #30 were merged into the build-report-embed branch, but that branch
had already been squash-merged to master as #28 beforehand, so their code never
reached master. This brings the stranded changes forward, on top of the current
master (which already has #28 and the #31 inline-media feature):

- #29: run the freestyle tunnel on the build's agent (TunnelManager.startOnChannel/
  stopOnChannel + shared registry; wrapper + testingbotTunnel step delegate to it).
- #30: TestingBotChecksPublisher (testingbotChecks) publishing results as a GitHub
  check, plus the checks-api + display-url-api dependencies and docs.

No behavior change versus the already-reviewed #29/#30; only rebased onto master.
The inline-media (#31) files are left untouched.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant