Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a replacement API for jira interaction #3829

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
<!-- Jira official client -->
<dependency>
<groupId>com.atlassian.jira</groupId>
<artifactId>jira-rest-java-client-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import groovy.io.FileType
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
import io.jenkins.infra.repository_permissions_updater.jira.JiraAPI
import io.jenkins.lib.support_log_formatter.SupportLogFormatter
import org.yaml.snakeyaml.Yaml
import org.yaml.snakeyaml.error.YAMLException;
Expand Down Expand Up @@ -175,11 +176,11 @@ class ArtifactoryPermissionsUpdater {
issueTrackersByPlugin.put(definition.name, definition.issues.collect { tracker ->
if (tracker.isJira() || tracker.isGitHubIssues()) {
def ret = [type: tracker.getType(), reference: tracker.getReference()]
def viewUrl = tracker.getViewUrl(JiraAPI.getInstance())
def viewUrl = tracker.getViewUrl()
if (viewUrl) {
ret += [ viewUrl: viewUrl ]
}
def reportUrl = tracker.getReportUrl(JiraAPI.getInstance())
def reportUrl = tracker.getReportUrl()
if (reportUrl) {
ret += [ reportUrl: reportUrl ]
}
Expand Down Expand Up @@ -242,7 +243,7 @@ class ArtifactoryPermissionsUpdater {
if (!definition.cd?.exclusive) {
users definition.developers.collectEntries { developer ->
def existsInArtifactory = KnownUsers.existsInArtifactory(developer)
def existsInJira = KnownUsers.existsInJira(developer) || JiraAPI.getInstance().isUserPresent(developer)
def existsInJira = KnownUsers.existsInJira(developer) || JiraAPI.instance().isUserPresent(developer)

if (!existsInArtifactory && !existsInJira) {
reportChecksApiDetails(developer + " needs to log in to Artifactory and Jira",
Expand Down Expand Up @@ -286,7 +287,7 @@ class ArtifactoryPermissionsUpdater {
}
} else {
definition.developers.each { developer ->
def existsInJira = KnownUsers.existsInJira(developer) || JiraAPI.getInstance().isUserPresent(developer)
def existsInJira = KnownUsers.existsInJira(developer) || JiraAPI.instance().isUserPresent(developer)

if (!existsInJira) {
reportChecksApiDetails(developer + " needs to log in to Jira",
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import io.jenkins.infra.repository_permissions_updater.jira.JiraAPI;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand Down Expand Up @@ -60,24 +61,9 @@ public boolean isGitHubIssues() {
return true;
}

@SuppressFBWarnings(value = "NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD",
justification = "All calls are guarded by jira null check in isJira()")
private String loadComponentId(JiraComponentSource source) {
String jiraComponentId = jira;
if (!jira.matches("[0-9]+")) {
// CreateIssueDetails needs the numeric Jira component ID
jiraComponentId = source.getComponentId(jira);
if (jiraComponentId == null) {
LOGGER.warning("Failed to determine Jira component ID for '" + jira + "', the component may not exist");
return null;
}
}
return jiraComponentId;
}

public String getViewUrl(JiraComponentSource source) {
public String getViewUrl() {
if (isJira()) {
final String id = loadComponentId(source);
final Long id = JiraAPI.instance().getComponentId(jira);
if (id != null) {
return "https://issues.jenkins.io/issues/?jql=component=" + id;
}
Expand All @@ -89,12 +75,12 @@ public String getViewUrl(JiraComponentSource source) {
throw new IllegalStateException("Invalid issue tracker: " + github + " / " + jira);
}

public String getReportUrl(JiraComponentSource source) {
public String getReportUrl() {
if (!report) {
return null;
}
if (isJira()) {
final String id = loadComponentId(source);
final Long id = JiraAPI.instance().getComponentId(jira);
if (id != null) {
return "https://www.jenkins.io/participate/report-issue/redirect/#" + id;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.jenkins.infra.repository_permissions_updater.jira;

public interface JiraAPI {

static JiraAPI instance() {
return JiraAPIImpl.getInstance();
}

Long getComponentId(String componentName);

boolean isUserPresent(String username);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package io.jenkins.infra.repository_permissions_updater.jira;

import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.UserRestClient;
import com.atlassian.jira.rest.client.api.domain.Project;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

class JiraAPIImpl implements JiraAPI {

private static final Logger LOGGER = Logger.getLogger(JiraAPIImpl.class.getName());
private static final String JIRA_URL = System.getProperty("jiraUrl", "https://issues.jenkins.io");
private static final String JIRA_PROJECT = System.getProperty("JIRA_PROJECT", "JENKINS");
private static JiraAPI INSTANCE;

private final Map<String, Boolean> userMapping = new HashMap<>();
private final Map<String, Long> componentNamesToIds = new HashMap<>();

private JiraAPIImpl() {}


private void ensureDataLoaded() {
if (componentNamesToIds.isEmpty()) {
LOGGER.log(Level.INFO, "Retrieving components from Jira...");
final String jiraUsername = System.getProperty("JIRA_USERNAME");
final String jiraPassword = System.getProperty("JIRA_PASSWORD");
try (final JiraRestClient jiraRestClient = new AsynchronousJiraRestClientFactory()
.createWithBasicHttpAuthentication(URI.create(JIRA_URL), jiraUsername, jiraPassword)) {
final Project project = jiraRestClient.getProjectClient().getProject(JIRA_PROJECT).claim();
project.getComponents().forEach(basicComponent -> {
final Long id = basicComponent.getId();
final String name = basicComponent.getName();
LOGGER.log(Level.FINE, "Identified Jira component with ID '%d' and name '%s'", new Object[]{id, name});
componentNamesToIds.put(name, id);
});

} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Something went wrong at retrieving the components from jira", e);
}
}
}

@Override
public Long getComponentId(final String componentName) {
ensureDataLoaded();
return componentNamesToIds.getOrDefault(componentName, -1L);
}

@Override
public boolean isUserPresent(final String username) {
return userMapping.computeIfAbsent(username, this::isUserPresentInternal);
}

private boolean isUserPresentInternal(final String username) {
final String jiraUsername = System.getProperty("JIRA_USERNAME");
final String jiraPassword = System.getProperty("JIRA_PASSWORD");
boolean found;
try (final JiraRestClient jiraRestClient = new AsynchronousJiraRestClientFactory()
.createWithBasicHttpAuthentication(URI.create(JIRA_URL), jiraUsername, jiraPassword)) {
final UserRestClient userClient = jiraRestClient.getUserClient();
userClient.getUser(jiraUsername).claim();
found = true;
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Something went wrong at retrieving the internal user from jira", e);
found = false;
}
return found;
}

static synchronized JiraAPI getInstance() {
if (INSTANCE == null) {
INSTANCE = new JiraAPIImpl();
}
return INSTANCE;
}
}