Skip to content

Commit d844cf5

Browse files
Merge pull request #13 from testingbot/modernization
Modernize plugin: Jenkins 2.541.3/Java 17 baseline, tunnel isolation, secret masking
2 parents 58839f0 + 630f605 commit d844cf5

30 files changed

Lines changed: 894 additions & 611 deletions

.github/dependabot.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: maven
4+
directory: /
5+
schedule:
6+
interval: weekly
7+
- package-ecosystem: github-actions
8+
directory: /
9+
schedule:
10+
interval: weekly

.github/workflows/cd.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: cd
2+
on:
3+
workflow_dispatch:
4+
check_run:
5+
types:
6+
- completed
7+
8+
permissions:
9+
checks: read
10+
contents: write
11+
12+
jobs:
13+
maven-cd:
14+
uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@7704ec4236e99ca271bdef1adb675b65b8e283a9 # v1
15+
secrets:
16+
MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}

.github/workflows/ci.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: ci
2+
on:
3+
push:
4+
pull_request:
5+
6+
permissions:
7+
contents: read
8+
9+
jobs:
10+
build:
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
jdk: [17, 21]
15+
runs-on: ubuntu-latest
16+
name: build (JDK ${{ matrix.jdk }})
17+
steps:
18+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
19+
with:
20+
persist-credentials: false
21+
- name: Set up JDK ${{ matrix.jdk }}
22+
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
23+
with:
24+
distribution: temurin
25+
java-version: ${{ matrix.jdk }}
26+
cache: maven
27+
- name: Build and test
28+
run: mvn -B -ntp verify

CHANGELOG

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
Version 1.23
2+
2026-07-15
3+
4+
- Raise baseline to Jenkins 2.541.3 / Java 17, modern parent POM and plugin BOM
5+
- Fix per-build tunnel isolation: parallel pipeline tunnels no longer corrupt or stop each other
6+
- Mask the TestingBot secret in build console logs
7+
- Fix crashes in the build summary listener on non-TestingBot / mixed test suites
8+
- Honor tunnel options and expose SELENIUM_HOST/PORT and TESTINGBOT_TUNNEL_IDENTIFIER env vars
9+
- Add permission checks and POST to credential form endpoints
10+
- Replace deprecated APIs (ACL.SYSTEM2, lookupCredentialsInItem, commons-cli, Guava)
11+
- Remove dead code (vestigial build step, unused tunnel config)
12+
- Add GitHub Actions CI/CD (JEP-229) and Dependabot
13+
114
Version 1.17
215
2022-04-01
316

Jenkinsfile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
See the documentation for more options:
3+
https://github.com/jenkins-infra/pipeline-library/
4+
*/
5+
buildPlugin(
6+
forkCount: '1C', // run this number of tests in parallel for faster feedback
7+
useContainerAgent: true, // set to false if you need to use a full VM
8+
configurations: [
9+
[platform: 'linux', jdk: 21],
10+
[platform: 'windows', jdk: 17],
11+
]
12+
)

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ This will start the tunnel before your job runs. Once the job finishes, the tunn
6969

7070
`testingbotPublisher()` will try to read the JUnit report files and show the test results from TestingBot.
7171

72+
### Environment variables
73+
74+
Inside **both** `testingbot { }` and `testingbotTunnel { }` blocks:
75+
76+
* `TESTINGBOT_KEY` / `TB_KEY` – your TestingBot API key
77+
* `TESTINGBOT_SECRET` / `TB_SECRET` – your TestingBot API secret (masked in the build log)
78+
79+
Inside a `testingbotTunnel { }` block only (these describe the tunnel started for that block):
80+
81+
* `SELENIUM_HOST` / `SELENIUM_PORT` – host and port to point your Selenium client at when using the tunnel
82+
* `TESTINGBOT_TUNNEL_IDENTIFIER` – the identifier of the tunnel started for this block. Pass it in your desired capabilities so parallel builds each use their own tunnel.
83+
84+
Each `testingbotTunnel { }` block starts an isolated tunnel with its own identifier, so parallel pipeline branches no longer interfere with one another.
85+
7286
An example:
7387

7488
```
@@ -115,10 +129,8 @@ To build the plugin, use:
115129

116130
## Releasing the Plugin
117131

118-
To release the plugin, use:
119-
120-
`mvn release:prepare release:perform`
132+
Releases are published automatically through the Jenkins [continuous delivery](https://www.jenkins.io/doc/developer/publishing/releasing-cd/) (JEP-229) flow: merging to the default branch triggers the `cd` GitHub Actions workflow, which builds and publishes an incremental release. There is no manual `mvn release:prepare` step.
121133

122134
## Reporting Issues
123135

124-
Please [file a new issue](https://github.com/testingbot/TestingBot-Jenkins-Plugin/issues).
136+
Please [file a new issue](https://github.com/jenkinsci/testingbot-plugin/issues) on the GitHub repository.

pom.xml

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@
44
<parent>
55
<groupId>org.jenkins-ci.plugins</groupId>
66
<artifactId>plugin</artifactId>
7-
<version>4.16</version>
7+
<version>5.31</version>
88
</parent>
99
<properties>
10-
<jenkins.version>2.338</jenkins.version>
11-
<java.level>8</java.level>
10+
<jenkins.version>2.541.3</jenkins.version>
11+
<gitHubRepo>jenkinsci/testingbot-plugin</gitHubRepo>
1212
<hudsonTags>buildwrapper</hudsonTags>
13-
<findbugs.skip>true</findbugs.skip>
1413
</properties>
1514
<scm>
16-
<connection>scm:git:git://github.com/jenkinsci/testingbot-plugin.git</connection>
17-
<developerConnection>scm:git:git@github.com:jenkinsci/testingbot-plugin.git</developerConnection>
18-
<tag>testingbot-1.20-SNAPSHOT</tag>
15+
<connection>scm:git:https://github.com/${gitHubRepo}.git</connection>
16+
<developerConnection>scm:git:https://github.com/${gitHubRepo}.git</developerConnection>
17+
<tag>HEAD</tag>
18+
<url>https://github.com/${gitHubRepo}</url>
1919
</scm>
20-
<url>https://github.com/jenkinsci/testingbot-plugin</url>
20+
<url>https://github.com/${gitHubRepo}</url>
2121
<developers>
2222
<developer>
2323
<id>testingbot</id>
@@ -31,8 +31,14 @@
3131
<groupId>org.apache.maven.plugins</groupId>
3232
<artifactId>maven-surefire-plugin</artifactId>
3333
<configuration>
34+
<!--
35+
The com.testingbot:TestingBotTunnel artifact is an uber-jar that bundles an
36+
old Jetty, which clashes with the Jenkins test harness' Jetty 12 on the flat
37+
test classpath. That breaks any JenkinsRule-based test, including the
38+
parent-injected one, so it is excluded here. See README (Known limitations).
39+
-->
3440
<excludes>
35-
<exclude>InjectedTest.java</exclude>
41+
<exclude>**/InjectedTest.java</exclude>
3642
</excludes>
3743
</configuration>
3844
</plugin>
@@ -49,7 +55,7 @@
4955
<description>This plugin integrates videos/screenshots of your TestingBot.com Selenium tests</description>
5056
<groupId>testingbot</groupId>
5157
<artifactId>testingbot</artifactId>
52-
<version>1.22-SNAPSHOT</version>
58+
<version>1.23-SNAPSHOT</version>
5359
<packaging>hpi</packaging>
5460
<repositories>
5561
<repository>
@@ -67,8 +73,8 @@
6773
<dependencies>
6874
<dependency>
6975
<groupId>io.jenkins.tools.bom</groupId>
70-
<artifactId>bom-2.235.x</artifactId>
71-
<version>25</version>
76+
<artifactId>bom-2.541.x</artifactId>
77+
<version>6687.v4253d9799d33</version>
7278
<scope>import</scope>
7379
<type>pom</type>
7480
</dependency>
@@ -78,8 +84,23 @@
7884
<dependency>
7985
<groupId>com.testingbot</groupId>
8086
<artifactId>TestingBotTunnel</artifactId>
81-
<version>RELEASE</version>
87+
<version>4.8</version>
8288
<scope>compile</scope>
89+
<!--
90+
Use the self-contained "shaded" classifier and exclude all transitive dependencies.
91+
The tunnel embeds its own server stack (Jetty 11, Jackson, Apache HTTP, commons-cli),
92+
which conflicts with the versions Jenkins manages (e.g. Jetty 12, Jackson 2.22). Those
93+
libraries are only used internally by the tunnel at runtime, where the plugin classloader
94+
keeps them isolated from Jenkins core, so we consume the bundled jar rather than leak an
95+
unreconcilable transitive tree into the plugin build.
96+
-->
97+
<classifier>shaded</classifier>
98+
<exclusions>
99+
<exclusion>
100+
<groupId>*</groupId>
101+
<artifactId>*</artifactId>
102+
</exclusion>
103+
</exclusions>
83104
</dependency>
84105
<dependency>
85106
<groupId>com.testingbot</groupId>
@@ -100,13 +121,6 @@
100121
</exclusion>
101122
</exclusions>
102123
</dependency>
103-
<dependency>
104-
<groupId>org.jmockit</groupId>
105-
<artifactId>jmockit</artifactId>
106-
<version>1.24</version>
107-
<scope>test</scope>
108-
</dependency>
109-
110124
<dependency>
111125
<groupId>junit</groupId>
112126
<artifactId>junit</artifactId>

src/main/java/testingbot/TestReporter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import hudson.model.TaskListener;
2121
import hudson.tasks.junit.TestResultAction;
2222
import java.util.logging.Logger;
23-
import javax.annotation.Nonnull;
23+
import edu.umd.cs.findbugs.annotations.NonNull;
2424
import testingbot.TestingBotBuildWrapper.BuildWrapperItem;
2525

2626
/**
@@ -42,7 +42,7 @@ public TestReporter() {
4242
}
4343

4444
@Override
45-
public TestResultAction.Data contributeTestData(Run<?, ?> run, @Nonnull FilePath workspace, Launcher launcher, TaskListener listener, TestResult testResult) throws IOException, InterruptedException {
45+
public TestResultAction.Data contributeTestData(Run<?, ?> run, @NonNull FilePath workspace, Launcher launcher, TaskListener listener, TestResult testResult) throws IOException, InterruptedException {
4646
boolean foundSession = false;
4747
List<String> sessionIDs = null;
4848
TestingBotCredentials credentials = null;
Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package testingbot;
22

3-
import hudson.model.Action;
3+
import hudson.model.InvisibleAction;
44

5-
public class TestingBotBuildAction implements Action {
5+
public class TestingBotBuildAction extends InvisibleAction {
66

77
private TestingBotCredentials testingbotCredential;
88

99
public TestingBotBuildAction(TestingBotCredentials testingbotCredentials) {
10-
super();
1110
this.testingbotCredential = testingbotCredentials;
1211
}
1312

@@ -18,22 +17,4 @@ public TestingBotCredentials getCredentials() {
1817
public void setCredentials(TestingBotCredentials testingbotCredential) {
1918
this.testingbotCredential = testingbotCredential;
2019
}
21-
22-
@Override
23-
public String getIconFileName() {
24-
// TODO Auto-generated method stub
25-
return null;
26-
}
27-
28-
@Override
29-
public String getDisplayName() {
30-
// TODO Auto-generated method stub
31-
return "tb";
32-
}
33-
34-
@Override
35-
public String getUrlName() {
36-
// TODO Auto-generated method stub
37-
return "tb";
38-
}
3920
}

src/main/java/testingbot/TestingBotBuildSummary.java

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,12 @@
1515
import java.io.Serializable;
1616
import java.util.ArrayList;
1717
import java.util.List;
18-
import java.util.logging.Level;
19-
import java.util.logging.Logger;
2018

2119
public class TestingBotBuildSummary extends InvisibleAction implements Serializable {
2220
private static final long serialVersionUID = 1L;
23-
private final transient AbstractBuild<?,?> build;
24-
public List<TestingBotBuildObject> sessionIds;
25-
21+
private final List<TestingBotBuildObject> sessionIds;
22+
2623
public TestingBotBuildSummary(AbstractBuild<?,?> build, List<TestingBotBuildObject> sessionIds) {
27-
this.build = build;
2824
this.sessionIds = sessionIds;
2925
}
3026

@@ -43,36 +39,54 @@ public static final class RunListenerImpl extends RunListener<AbstractBuild<?,?>
4339
@Override
4440
public void onCompleted(AbstractBuild<?, ?> r, TaskListener listener) {
4541
if (r == null) {
46-
Logger.getLogger(TestingBotBuildSummary.class.getName()).log(Level.INFO, "r is null", "r is null");
4742
return;
4843
}
49-
if (r.getAction(AbstractTestResultAction.class) == null) {
50-
Logger.getLogger(TestingBotBuildSummary.class.getName()).log(Level.INFO, "getaction is null", "getaction is null");
51-
}
52-
44+
45+
// Only act on builds that are actually configured to use TestingBot.
5346
TestingBotBuildAction buildAction = r.getAction(TestingBotBuildAction.class);
5447
TestingBotCredentials credentials = null;
5548
if (buildAction != null) {
56-
credentials = buildAction.getCredentials();
49+
credentials = buildAction.getCredentials();
5750
} else {
58-
TestingBotBuildWrapper.BuildWrapperItem<TestingBotBuildWrapper> wrapperItem =
59-
TestingBotBuildWrapper.findBuildWrapper(r.getParent());
60-
credentials = TestingBotCredentials.getCredentials(wrapperItem.buildItem,
61-
wrapperItem.buildWrapper.getCredentialsId());
51+
TestingBotBuildWrapper.BuildWrapperItem<TestingBotBuildWrapper> wrapperItem =
52+
TestingBotBuildWrapper.findBuildWrapper(r.getParent());
53+
if (wrapperItem == null || wrapperItem.buildWrapper == null) {
54+
return;
55+
}
56+
credentials = TestingBotCredentials.getCredentials(wrapperItem.buildItem,
57+
wrapperItem.buildWrapper.getCredentialsId());
58+
}
59+
if (credentials == null) {
60+
return;
61+
}
62+
63+
AbstractTestResultAction<?> testResultAction = r.getAction(AbstractTestResultAction.class);
64+
if (testResultAction == null) {
65+
return;
66+
}
67+
Object result = testResultAction.getResult();
68+
if (!(result instanceof TestResult)) {
69+
return;
6270
}
63-
71+
TestResult testResult = (TestResult) result;
72+
6473
TestingbotREST apiClient = new TestingbotREST(credentials.getKey(), credentials.getDecryptedSecret());
65-
TestResult testResult = (TestResult) r.getAction(AbstractTestResultAction.class).getResult();
6674
List<TestingBotBuildObject> ids = new ArrayList<>();
6775
for (SuiteResult sr : testResult.getSuites()) {
6876
for (CaseResult cr : sr.getCases()) {
6977
List<String> sessionIds = TestingBotReportFactory.findSessionIDs(cr);
70-
TestingbotTest test = apiClient.getTest(sessionIds.get(0));
71-
TestingBotBuildObject tbo = new TestingBotBuildObject(sessionIds.get(0), cr.getClassName(), cr.getName(), cr.isPassed(), apiClient.getAuthenticationHash(sessionIds.get(0)), test);
78+
if (sessionIds.isEmpty()) {
79+
continue;
80+
}
81+
String sessionId = sessionIds.get(0);
82+
TestingbotTest test = apiClient.getTest(sessionId);
83+
TestingBotBuildObject tbo = new TestingBotBuildObject(sessionId, cr.getClassName(), cr.getName(), cr.isPassed(), apiClient.getAuthenticationHash(sessionId), test);
7284
ids.add(tbo);
7385
}
7486
}
75-
Logger.getLogger(TestingBotBuildSummary.class.getName()).log(Level.INFO, "try to get ids");
87+
if (ids.isEmpty()) {
88+
return;
89+
}
7690
r.addAction(new TestingBotBuildSummary(r, ids));
7791
r.addAction(new TestingBotTestEmbed(ids));
7892
}

0 commit comments

Comments
 (0)