Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
dfed779
Update GerritServer to use GerritEventSource interface
panicking Jun 27, 2026
fef8c9c
Add HTTPS polling configuration fields and UI
panicking Jun 19, 2026
7f241d4
Wire GerritRestPoller into GerritServer.startConnection()
panicking Jun 19, 2026
2e9970d
Wire GerritRestQueryHandler into GerritServer.getQueryHandler()
panicking Jun 19, 2026
c6137db
Add HTTPS project list loading to GerritProjectListUpdater
panicking Jun 27, 2026
6ec28cd
Add GERRIT_GIT_URL parameter for HTTPS git clone URL
panicking Jun 19, 2026
85b7a75
Add client-side JavaScript to toggle SSH fields dynamically
panicking Jun 20, 2026
32a9ba8
Add snapshot version warning note to HTTPS polling help text
panicking Jun 20, 2026
bacf069
Fix test failures caused by eager GerritQueryHandler caching and null…
panicking Jul 13, 2026
ae0af8d
Update gerrit-events dependency to 2.23.0
panicking Jun 28, 2026
7fe43ae
Extract GerritVoteValues and GerritCommandTemplates from Config
panicking Jul 24, 2026
b2348b7
Remove unnecessary readResolve from GerritVoteValues
panicking Aug 2, 2026
0fbf0ba
Add original Sony Mobile Communications copyright to extracted classes
panicking Aug 2, 2026
9853c7f
Rename getVoteValuesInternal/getCommandTemplatesInternal to getVoteVa…
panicking Aug 2, 2026
840da68
Deprecate Config command getters in favor of GerritCommandTemplates
panicking Aug 2, 2026
104064e
Deprecate Config command setters in favor of GerritCommandTemplates
panicking Aug 2, 2026
4c5a484
Extract getServerConfigOrFirst and getServerOrFirst_ helpers
panicking Aug 2, 2026
1e19e8a
Use Functions.joinPath instead of manual URL concatenation in loadPro…
panicking Aug 2, 2026
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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
<dependency>
<groupId>com.sonymobile.tools.gerrit</groupId>
<artifactId>gerrit-events</artifactId>
<version>2.22.0</version>
<version>2.23.0</version>
<exclusions>
<!-- Provided by gson-api plugin -->
<exclusion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
package com.sonyericsson.hudson.plugins.gerrit.trigger;

import com.sonyericsson.hudson.plugins.gerrit.trigger.utils.StringUtil;
import hudson.Functions;
import com.sonymobile.tools.gerrit.gerritevents.ConnectionListener;
import com.sonymobile.tools.gerrit.gerritevents.GerritEventListener;
import com.sonymobile.tools.gerrit.gerritevents.dto.GerritEvent;
Expand All @@ -34,14 +35,29 @@
import com.sonyericsson.hudson.plugins.gerrit.trigger.config.IGerritHudsonTriggerConfig;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;

import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -264,20 +280,22 @@
if (isConnected()) {
logger.info("Trying to load project list.");
IGerritHudsonTriggerConfig activeConfig = getConfig();
SshConnection sshConnection = SshConnectionFactory.getConnection(
activeConfig.getGerritHostName(),
activeConfig.getGerritSshPort(),
activeConfig.getGerritProxy(),
activeConfig.getGerritAuthentication()
);
List<String> projects = readProjects(sshConnection.executeCommandReader(GERRIT_LS_PROJECTS));
if (activeConfig == null) {

Check warning on line 283 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritProjectListUpdater.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 283 is only partially covered, one branch is missing
logger.error("Could not load project list: config is null for {}", serverName);
return;

Check warning on line 285 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritProjectListUpdater.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 284-285 are not covered by tests
}
List<String> projects;
if (activeConfig.isUseHttpsPoller()) {

Check warning on line 288 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritProjectListUpdater.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 288 is only partially covered, one branch is missing
projects = loadProjectsViaRest(activeConfig);

Check warning on line 289 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritProjectListUpdater.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 289 is not covered by tests
} else {
projects = loadProjectsViaSsh(activeConfig);
}
if (!projects.isEmpty()) {
setGerritProjects(projects);
logger.info("Project list from {} contains {} entries", serverName, projects.size());
} else {
logger.warn("Project list from {} contains 0 projects", serverName);
}
sshConnection.disconnect();
} else {
logger.warn("Could not connect to Gerrit server when updating Gerrit project list: "
+ "Server is not connected (timeout)");
Expand All @@ -289,6 +307,95 @@
}
}

/**
* Loads the project list via the SSH {@code gerrit ls-projects} command.
*
* @param activeConfig the server configuration.
* @return the list of project names.
* @throws SshException if an SSH error occurs.
* @throws IOException if an I/O error occurs.
*/
private List<String> loadProjectsViaSsh(IGerritHudsonTriggerConfig activeConfig)
throws SshException, IOException {
SshConnection sshConnection = SshConnectionFactory.getConnection(
activeConfig.getGerritHostName(),
activeConfig.getGerritSshPort(),
activeConfig.getGerritProxy(),
activeConfig.getGerritAuthentication()
);
try {
return readProjects(sshConnection.executeCommandReader(GERRIT_LS_PROJECTS));
} finally {
sshConnection.disconnect();
}
}

/**
* Loads the project list via the Gerrit REST API.
*
* @param activeConfig the server configuration.
* @return the list of project names.
* @throws IOException if an I/O error occurs.
*/
private List<String> loadProjectsViaRest(IGerritHudsonTriggerConfig activeConfig)
throws IOException {
String frontEndUrl = activeConfig.getGerritFrontEndUrl();
String url = Functions.joinPath(frontEndUrl, "a/projects/?d");

Credentials httpCredentials = activeConfig.getHttpCredentials();
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY, httpCredentials);
HttpClient httpClient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.build();
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpURLConnection.HTTP_OK) {
throw new IOException("HTTP " + statusCode + " for project list query");
}

StringBuilder sb = new StringBuilder();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(response.getEntity().getContent(),
StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
}
String body = sb.toString();
// Strip Gerrit JSON hijacking prevention prefix
if (body.startsWith(")]}'")) {
body = body.substring(")]}'".length());
}
return readProjectsFromJson(body);
}

/**
* Reads project names from a Gerrit REST API projects JSON response.
* The response format is a JSON object where each key is a project name.
*
* @param jsonBody the JSON response body.
* @return the list of project names.
* @throws IOException if JSON parsing fails.
*/
static List<String> readProjectsFromJson(String jsonBody) throws IOException {
List<String> projects = new ArrayList<String>();
try {
JSONObject json = (JSONObject)JSONSerializer.toJSON(jsonBody);
for (Iterator<?> it = json.keys(); it.hasNext();) {
String key = (String)it.next();
if (key != null && !key.isEmpty()) {
projects.add(key);
}
}
} catch (Exception ex) {
throw new IOException("Failed to parse projects JSON response", ex);
}
return projects;

Check warning on line 396 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritProjectListUpdater.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 342-396 are not covered by tests
}

/**
* Get the the server config.
* @return the server config or null if config not found.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@
import com.sonymobile.tools.gerrit.gerritevents.GerritHandler;
import com.sonymobile.tools.gerrit.gerritevents.GerritQueryHandler;
import com.sonymobile.tools.gerrit.gerritevents.GerritConnection;
import com.sonymobile.tools.gerrit.gerritevents.GerritEventSource;
import com.sonymobile.tools.gerrit.gerritevents.GerritRestPoller;
import com.sonymobile.tools.gerrit.gerritevents.GerritRestQueryHandler;
import com.sonymobile.tools.gerrit.gerritevents.dto.GerritEvent;
import com.sonymobile.tools.gerrit.gerritevents.dto.rest.Notify;
import com.sonymobile.tools.gerrit.gerritevents.ssh.Authentication;
Expand Down Expand Up @@ -152,7 +155,7 @@
private transient boolean timeoutWakeup = false;
private transient String connectionResponse = "";
private transient GerritHandler gerritEventManager;
private transient GerritConnection gerritConnection;
private transient GerritEventSource gerritConnection;
private transient GerritProjectListUpdater projectListUpdater;
private IGerritHudsonTriggerConfig config;
private transient GerritConnectionListener gerritConnectionListener;
Expand Down Expand Up @@ -252,7 +255,7 @@
public void setConfig(IGerritHudsonTriggerConfig config) {
checkPermission();
this.config = config;
gerritQueryHnadler = new GerritQueryHandler(config);
gerritQueryHnadler = null;
}

/**
Expand All @@ -262,7 +265,11 @@
*/
public GerritQueryHandler getQueryHandler() {
if (gerritQueryHnadler == null) {
gerritQueryHnadler = new GerritQueryHandler(config);
if (config.isUseHttpsPoller()) {

Check warning on line 268 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 268 is only partially covered, one branch is missing

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe this shoould be "if use rest"?

gerritQueryHnadler = new GerritRestQueryHandler(config);

Check warning on line 269 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 269 is not covered by tests
} else {
gerritQueryHnadler = new GerritQueryHandler(config);
}
}
return gerritQueryHnadler;
}
Expand Down Expand Up @@ -581,9 +588,23 @@
public synchronized void startConnection() {
checkPermission();
if (!config.hasDefaultValues()) {
if (gerritConnection == null) {
if (gerritConnection != null && gerritConnection.isConnected()) {

Check warning on line 591 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 591 is only partially covered, one branch is missing
logger.warn("Already started!");

Check warning on line 592 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 592 is not covered by tests
} else {
// If there's an existing but dead connection, stop it first
if (gerritConnection != null) {
logger.info("{}: Stopping failed connection before restart.", name);
gerritConnection.shutdown(false);
gerritConnection.removeListener(gerritConnectionListener);
gerritConnection.removeListener(missedEventsPlaybackManager);
}
logger.debug("Starting Gerrit connection...");
gerritConnection = new GerritConnection(name, config);
if (config.isUseHttpsPoller()) {

Check warning on line 602 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 602 is only partially covered, one branch is missing
logger.info("{}: Using HTTPS polling for Gerrit events.", name);
gerritConnection = new GerritRestPoller(name, config);

Check warning on line 604 in src/main/java/com/sonyericsson/hudson/plugins/gerrit/trigger/GerritServer.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 603-604 are not covered by tests
} else {
gerritConnection = new GerritConnection(name, config);
}
if (config.isTriggerOnAllComments()) {
logger.info("Will trigger on all comments, even from the configured user.");
} else {
Expand All @@ -598,8 +619,6 @@
gerritConnection.addListener(missedEventsPlaybackManager);

gerritConnection.start();
} else {
logger.warn("Already started!");
}
// Initialize project list update after connection with Gerrit server
projectListUpdater.initProjectListUpdater();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,23 @@ public static GerritServer getFirstServer_() {
return plugin.getFirstServer();
}

/**
* Get the server with the given name, falling back to the first server
* when the named server is not found.
*
* @param name the server name, or null.
* @return the server, or null if no server could be found.
*/
@CheckForNull
//CS IGNORE MethodName FOR NEXT 1 LINES. REASON: Static equivalent marker.
public static GerritServer getServerOrFirst_(String name) {
GerritServer server = getServer_(name);
if (server == null) {
server = getFirstServer_();
}
return server;
}

/**
* Set the list of Gerrit servers.
*
Expand Down
Loading