diff --git a/libs/utils/src/main/java/com/akto/api_clients/JiraApiClient.java b/libs/utils/src/main/java/com/akto/api_clients/JiraApiClient.java index 66fbded8ea..3f18c7c84b 100644 --- a/libs/utils/src/main/java/com/akto/api_clients/JiraApiClient.java +++ b/libs/utils/src/main/java/com/akto/api_clients/JiraApiClient.java @@ -16,7 +16,9 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.NoArgsConstructor; import okhttp3.Credentials; @@ -199,7 +201,7 @@ private static String buildJql(String projectKey, int updatedAfter) { // add pagination if issue size is greater than 1000 public static Map> getTransitions(JiraIntegration jira, List issueKeys, - String targetStatusName) throws Exception { + List targetStatusName) throws Exception { if (issueKeys.size() > 1000) { throw new Exception( "Issue keys list size cannot exceed 1000. Jira transition API supports 1000 issues at a time."); @@ -230,21 +232,25 @@ public static Map> getTransitions(JiraIntegration jira, Li } } - private static Map> parseTransitions(JsonNode root, String statusNameFilter) { + private static Map> parseTransitions(JsonNode root, List jiraStatusNames) { + Set statusWhitelist = jiraStatusNames.stream() + .map(String::toLowerCase) + .collect(Collectors.toSet()); + Map> transitionMap = new HashMap<>(); - JsonNode availableTransitions = root.path("availableTransitions"); - for (JsonNode block : availableTransitions) { + for (JsonNode block : root.path("availableTransitions")) { List issues = new ArrayList<>(); for (JsonNode issueNode : block.path("issues")) { issues.add(issueNode.asText()); } for (JsonNode transition : block.path("transitions")) { - String statusName = transition.path("to").path("statusName").asText(); - if (statusName.equalsIgnoreCase(statusNameFilter)) { + String statusName = transition.path("to").path("statusName").asText().toLowerCase(); + if (statusWhitelist.contains(statusName)) { int transitionId = transition.path("transitionId").asInt(); transitionMap.computeIfAbsent(transitionId, k -> new ArrayList<>()).addAll(issues); + break; } } } diff --git a/libs/utils/src/main/java/com/akto/jobs/executors/TicketSyncJobExecutor.java b/libs/utils/src/main/java/com/akto/jobs/executors/TicketSyncJobExecutor.java index f332e82243..a08cf2045d 100644 --- a/libs/utils/src/main/java/com/akto/jobs/executors/TicketSyncJobExecutor.java +++ b/libs/utils/src/main/java/com/akto/jobs/executors/TicketSyncJobExecutor.java @@ -27,6 +27,7 @@ import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; +import java.util.Collections; import java.util.TimeZone; import okhttp3.Credentials; import okhttp3.Request; @@ -185,9 +186,6 @@ private void updateJiraTickets(JiraIntegration jira, List issu logAndCollect(Level.DEBUG, "Found {} jira statuses mapped with akto status {}. Using the first one", jiraStatuses.size(), aktoStatus); - // Use the first mapped status as the target - String targetJiraStatus = jiraStatuses.get(0); - // Extract issue keys for this status group List issueKeys = statusIssues.stream() .map(TestingRunIssues::getTicketId) @@ -201,12 +199,12 @@ private void updateJiraTickets(JiraIntegration jira, List issu // Get transitions for these issues to reach the target status try { - Map> transitionsMap = JiraApiClient.getTransitions(jira, issueKeys, targetJiraStatus); + Map> transitionsMap = JiraApiClient.getTransitions(jira, issueKeys, jiraStatuses); updateJobHeartbeat(job); if (transitionsMap.isEmpty()) { logAndCollect(Level.INFO, "No transitions found for issues with Akto status: {} to Jira status: {}", - aktoStatus, targetJiraStatus); + aktoStatus, jiraStatuses); continue; } @@ -241,7 +239,7 @@ private void updateJiraTickets(JiraIntegration jira, List issu if (success) { logAndCollect(Level.DEBUG, "Successfully transitioned {} Jira tickets to status: {}. ticketIds: {}", - issueKeys.size(), targetJiraStatus, issueKeys); + issueKeys.size(), jiraStatuses, issueKeys); // Update last updated timestamp in Akto List> writeModels = new ArrayList<>(); for (TestingRunIssues issue : statusIssues) { @@ -256,12 +254,11 @@ private void updateJiraTickets(JiraIntegration jira, List issu TestingRunIssuesDao.instance.getMCollection().bulkWrite(writeModels); } } else { - logAndCollect(Level.ERROR, "Failed to transition Jira tickets to status: {}. ticketIds: {}", targetJiraStatus, - issueKeys); + logger.error("Failed to transition Jira tickets. ticketIds: {}", issueKeys); } } catch (Exception e) { logAndCollect(Level.ERROR, "Error getting transitions or performing bulk transition for Akto status: {} to Jira status: {}", - aktoStatus, targetJiraStatus, e); + aktoStatus, jiraStatuses, e); } } } catch (Exception e) {