package com.ullink.slack.review.gerrit; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.common.base.Function; import com.google.common.net.UrlEscapers; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.ullink.slack.review.Constants; import com.ullink.slack.review.HttpHelper; import com.ullink.slack.review.gerrit.ChangeInfo.IssuePriority; import com.ullink.slack.review.gerrit.ChangeInfo.IssueType; @Singleton public class GerritChangeInfoService { @Inject @Named(Constants.GERRIT_URL) private String gerritURL; @Inject @Named(Constants.JIRA_URL) private String jiraURL; @Inject @Named(Constants.JIRA_USER) private String jiraUser; @Inject @Named(Constants.JIRA_PASSWORD) private String jiraPassword; private static class JIRAParserFunction implements Function<String, JIRAInfo> { String jiraId; public JIRAParserFunction(String jiraId) { this.jiraId = jiraId; } @Override public JIRAInfo apply(String input) { JsonParser parser = new JsonParser(); JsonObject obj = parser.parse(input).getAsJsonObject(); JsonObject fieldsJSON = obj.get("fields").getAsJsonObject(); JsonElement priorityNameElement = fieldsJSON.get("priority").getAsJsonObject().get("name"); String priority = priorityNameElement != null ? priorityNameElement.getAsString() : null; JsonElement issueTypeNameElement = fieldsJSON.get("issuetype").getAsJsonObject().get("name"); String issueType = issueTypeNameElement != null ? issueTypeNameElement.getAsString() : null; return new JIRAInfo(IssuePriority.fromString(priority), IssueType.fromString(issueType), jiraId); } } public ChangeInfo getChangeInfo(String changeId, boolean fetchJiraInfo) throws IOException { ListenableFuture<String> jsonChangeInfoHolder = HttpHelper.getAsyncFromHttp(new URL(gerritURL + "changes/" + changeId + "/detail")); ListenableFuture<String> jsonCommitMessageHolder = HttpHelper.getAsyncFromHttp(new URL(gerritURL + "changes/" + changeId + "/revisions/current/commit")); try { List<String> changeJSONInfos; try { changeJSONInfos = Futures.<String> successfulAsList(jsonChangeInfoHolder, jsonCommitMessageHolder).get(20000, TimeUnit.MILLISECONDS); } catch (Exception e) { // TODO improve exception handling e.printStackTrace(); return null; } ChangeInfo changeInfo = new ChangeInfoJSONParser(changeJSONInfos.get(0), changeJSONInfos.get(1)).parse(); String relatedChangesInfo = HttpHelper.getFromHttp(new URL(gerritURL + "changes/?q=change:" + changeInfo.getChangeId())); String cherryPickId = CherryPicksHelper.getCherryPickLegacyId(relatedChangesInfo); if (!changeId.equals(cherryPickId)) { changeInfo.setCherryPickedFrom(cherryPickId); } if (changeInfo.getRelatedJira().size() > 0 && fetchJiraInfo) { List<ListenableFuture<JIRAInfo>> jiraInfoFutures = new ArrayList<ListenableFuture<JIRAInfo>>(); for (Iterator<Entry<String, JIRAInfo>> entryIterator = changeInfo.getRelatedJira().entrySet().iterator(); entryIterator.hasNext();) { Entry<String, JIRAInfo> entry = entryIterator.next(); jiraInfoFutures.add(Futures.transform(HttpHelper.getAsyncFromHttp(new URL(jiraURL + "rest/api/2/issue/" + entry.getKey()), jiraUser, jiraPassword), new JIRAParserFunction(entry.getKey()))); } ListenableFuture<List<JIRAInfo>> jiraInfosFuture = Futures.<JIRAInfo> successfulAsList(jiraInfoFutures); List<JIRAInfo> jiraInfos; try { jiraInfos = jiraInfosFuture.get(20000, TimeUnit.MILLISECONDS); } catch (Exception e) { // TODO improve exception handling e.printStackTrace(); return null; } for (JIRAInfo jiraInfo : jiraInfos) { changeInfo.getRelatedJira().put(jiraInfo.getJiraId(), jiraInfo); } } return changeInfo; } catch (java.text.ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } } public boolean isMergedOrAbandoned(String changeId) { try { ListenableFuture<String> jsonChangeInfoHolder = HttpHelper.getAsyncFromHttp(new URL(gerritURL + "changes/" + changeId + "/detail")); String json = jsonChangeInfoHolder.get(20000, TimeUnit.MILLISECONDS); json = json.substring(4); JsonParser parser = new JsonParser(); JsonObject jsonObj = parser.parse(json).getAsJsonObject(); JsonElement statusElement = jsonObj.get("status"); String status = statusElement != null ? statusElement.getAsString() : null; return "MERGED".equals(status) || "ABANDONED".equals(status); } catch (Exception e) { e.printStackTrace(); } return false; } public boolean projectExists(String projectId) throws IOException { ListenableFuture<String> jsonChangeInfoHolder = HttpHelper.getAsyncFromHttp(new URL(gerritURL + "projects/" + UrlEscapers.urlPathSegmentEscaper().escape(projectId))); try { String json = jsonChangeInfoHolder.get(20000, TimeUnit.MILLISECONDS); if ("NOT FOUND".equalsIgnoreCase(json.trim())) { return false; } json = json.substring(4); JsonParser parser = new JsonParser(); JsonObject jsonObj = parser.parse(json).getAsJsonObject(); JsonElement stateElement = jsonObj.get("state"); String state = stateElement != null ? stateElement.getAsString() : null; return "ACTIVE".equals(state); } catch (Exception e) { e.printStackTrace(); } return false; } public boolean userExists(String userId) throws IOException { ListenableFuture<String> jsonChangeInfoHolder = HttpHelper.getAsyncFromHttp(new URL(gerritURL + "accounts/" + UrlEscapers.urlPathSegmentEscaper().escape(userId))); try { String json = jsonChangeInfoHolder.get(20000, TimeUnit.MILLISECONDS); if ("NOT FOUND".equalsIgnoreCase(json.trim())) { return false; } return true; } catch (Exception e) { e.printStackTrace(); } return false; } }