You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by dp...@apache.org on 2019/01/17 14:40:38 UTC
[ignite-teamcity-bot] branch master updated: IGNITE-10930: PR-less
contributions: handle PR less contributions branch naming - Fixes #107.
This is an automated email from the ASF dual-hosted git repository.
dpavlov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite-teamcity-bot.git
The following commit(s) were added to refs/heads/master by this push:
new 9517e45 IGNITE-10930: PR-less contributions: handle PR less contributions branch naming - Fixes #107.
9517e45 is described below
commit 9517e457aad1a77f95cb3a68a5fd35bb20fe5a3d
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Thu Jan 17 17:40:23 2019 +0300
IGNITE-10930: PR-less contributions: handle PR less contributions branch naming - Fixes #107.
Signed-off-by: Dmitriy Pavlov <dp...@apache.org>
---
conf/apache.auth.properties | 29 +-
.../java/org/apache/ignite/ci/HelperConfig.java | 5 +-
.../ignite/ci/IAnalyticsEnabledTeamcity.java | 1 +
.../main/java/org/apache/ignite/ci/ITcHelper.java | 17 -
.../main/java/org/apache/ignite/ci/ITeamcity.java | 36 --
.../apache/ignite/ci/IgnitePersistentTeamcity.java | 35 +-
.../apache/ignite/ci/IgniteTeamcityConnection.java | 56 +--
.../main/java/org/apache/ignite/ci/TcHelper.java | 177 +--------
.../org/apache/ignite/ci/di/IgniteTcBotModule.java | 13 +-
.../org/apache/ignite/ci/github/PullRequest.java | 2 +-
.../ci/github/ignited/IGitHubConnIgnited.java | 11 -
.../ignite/ci/github/pure/IGitHubConnection.java | 2 +-
.../java/org/apache/ignite/ci/jira/Fields.java | 9 +
.../java/org/apache/ignite/ci/jira/Status.java | 13 +
.../java/org/apache/ignite/ci/jira/Ticket.java | 27 +-
.../java/org/apache/ignite/ci/jira/Tickets.java | 1 +
.../ignite/ci/jira/ignited/IJiraIgnited.java | 65 +++
.../IJiraIgnitedProvider.java} | 7 +-
.../apache/ignite/ci/jira/ignited/JiraIgnited.java | 90 +++++
.../JiraIgnitedModule.java} | 12 +-
.../JiraIgnitedProvider.java} | 27 +-
.../ignite/ci/jira/ignited/JiraTicketDao.java | 17 +-
.../ignite/ci/jira/ignited/JiraTicketSync.java | 54 ++-
.../ignite/ci/jira/ignited/TicketCompacted.java | 26 +-
.../ci/jira/{ => pure}/IJiraIntegration.java | 61 +--
.../jira/{ => pure}/IJiraIntegrationProvider.java | 2 +-
.../org/apache/ignite/ci/jira/{ => pure}/Jira.java | 92 ++++-
.../ci/jira/{ => pure}/JiraIntegrationModule.java | 4 +-
.../jira/{ => pure}/JiraIntegrationProvider.java | 6 +-
.../apache/ignite/ci/observer/ObserverTask.java | 14 +-
.../ignite/ci/tcbot/chain/PrChainsProcessor.java | 8 +-
.../ci/tcbot/visa/ContributionCheckStatus.java | 7 +-
.../ignite/ci/tcbot/visa/ContributionToCheck.java | 5 +-
.../tcbot/visa/TcBotTriggerAndSignOffService.java | 438 +++++++++++++++++----
.../ci/teamcity/ignited/ITeamcityIgnited.java | 2 +
.../ci/teamcity/ignited/TeamcityIgnitedImpl.java | 77 ++--
.../ci/teamcity/ignited/buildref/BuildRefDao.java | 2 +-
.../ignite/ci/teamcity/pure/ITeamcityConn.java | 5 +
.../org/apache/ignite/ci/web/model/Version.java | 2 +-
.../java/org/apache/ignite/ci/web/model/Visa.java | 6 +-
.../model/current/ChainAtServerCurrentStatus.java | 18 +-
.../ignite/ci/web/model/current/UpdateInfo.java | 6 +-
.../apache/ignite/ci/web/rest/TriggerBuilds.java | 5 +-
.../ignite/ci/web/rest/pr/GetPrTestFailures.java | 9 +-
.../ignite/ci/web/rest/visa/TcBotVisaService.java | 10 +-
ignite-tc-helper-web/src/main/webapp/js/prs-1.1.js | 17 +-
ignite-tc-helper-web/src/main/webapp/prs.html | 80 ++--
.../ci/tcbot/chain/MockBasedTcBotModule.java | 8 +-
.../ignited/IgnitedTcInMemoryIntegrationTest.java | 2 +-
.../ci/teamcity/ignited/TeamcityIgnitedMock.java | 2 +
50 files changed, 997 insertions(+), 623 deletions(-)
diff --git a/conf/apache.auth.properties b/conf/apache.auth.properties
index dcc4f07..eb56fbb 100644
--- a/conf/apache.auth.properties
+++ b/conf/apache.auth.properties
@@ -1,15 +1,32 @@
+## Teamcity Integration Parameters
+# Teamcity Host, HTTPs is highly recommended because of Basic Auth used.
host=https://ci.ignite.apache.org/
-
+
+# TC bot downloaded logs path
logs=apache_logs
+## GitHub integration parameters.
+# REST API Url for GitHub. Includes owner (apache) and project (ignite)
git.api_url=https://api.github.com/repos/apache/ignite/
+
+# Specify GitHub Auth token (if needed), go to User->Settings->Developers options->create new.
+# Created token needs to be encrypted using org.apache.ignite.ci.conf.PasswordEncoder
+github.auth_token=
+
+## Branch identification rules
+# PR-less contribution branch name mandatory prefix
+git.branch_prefix=ignite-
+
+## JIRA integration parameters.
jira.api_url=https://issues.apache.org/jira/rest/api/2/
+# JIRA Url, HTTPs is highly recommended because of Basic Auth used.
jira.url=https://issues.apache.org/jira/
-jira.ticket_template=IGNITE-
-#specify JIRA Auth token (if needed)
-jira.auth_token=
+# Ticket template: project code and dash.
+jira.ticket_template=IGNITE-
-#specify GitHub Auth token (if needed)
-github.auth_token=
\ No newline at end of file
+# Specify JIRA Auth token (if needed).
+# Base-64 pre-encoded username and password, which will be included into Basic Auth requests.
+# Encoded token needs to be encrypted using org.apache.ignite.ci.conf.PasswordEncoder
+jira.auth_token=
\ No newline at end of file
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/HelperConfig.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/HelperConfig.java
index f773100..a0cd102 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/HelperConfig.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/HelperConfig.java
@@ -51,6 +51,9 @@ public class HelperConfig {
/** GitHub authorization token property name. */
public static final String GITHUB_AUTH_TOKEN = "github.auth_token";
+ /** Git branch naming prefix for PRLess contributions. */
+ public static final String GIT_BRANCH_PREFIX = "git.branch_prefix";
+
/** JIRA authorization token property name. */
public static final String JIRA_AUTH_TOKEN = "jira.auth_token";
@@ -159,7 +162,7 @@ public class HelperConfig {
* @param props Properties, where token is placed.
* @return Null or decoded auth token for Github.
*/
- @Nullable static String prepareJiraHttpAuthToken(Properties props) {
+ @Nullable public static String prepareJiraHttpAuthToken(Properties props) {
String tok = props.getProperty(JIRA_AUTH_TOKEN);
if (isNullOrEmpty(tok))
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IAnalyticsEnabledTeamcity.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IAnalyticsEnabledTeamcity.java
index 2499adc..00e524b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IAnalyticsEnabledTeamcity.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IAnalyticsEnabledTeamcity.java
@@ -20,6 +20,7 @@ package org.apache.ignite.ci;
/**
* Combination of REST data and persisted statistics.
*/
+@Deprecated
public interface IAnalyticsEnabledTeamcity extends ITeamcity, ITcAnalytics {
public void init(ITeamcity conn);
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITcHelper.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITcHelper.java
index 1c084c1..e93dbab 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITcHelper.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITcHelper.java
@@ -55,21 +55,4 @@ public interface ITcHelper extends ITcServerProvider {
/** */
boolean isServerAuthorized();
- /**
- * @param srvId Server id.
- * @param prov Credentials.
- * @param buildTypeId Suite name.
- * @param branchForTc Branch for TeamCity.
- * @param ticket JIRA ticket full name.
- * @return {@code Visa} which contains info about JIRA notification.
- */
- Visa notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc, String ticket);
-
- /**
- * @param srvId Server id.
- * @param prov Credentials.
- * @param ticketId Ticket.
- * @return Jira tickets.
- */
- Tickets getJiraTickets(String srvId, ICredentialsProv prov, String ticketId);
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
index fa1f3a7..4ce064d 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
@@ -91,42 +91,6 @@ public interface ITeamcity extends ITeamcityConn {
boolean isTeamCityTokenAvailable();
- /**
- * @param tok Jira authorization token.
- */
- void setJiraToken(String tok);
-
- /**
- * @return {@code True} if JIRA authorization token is available.
- */
- boolean isJiraTokenAvailable();
-
- /**
- * @param ticket JIRA ticket full name. E.g 'IGNITE-5555'.
- * @param comment Comment to be placed in the ticket conversation.
- * @return {@code True} if ticket was succesfully commented. Otherwise - {@code false}.
- *
- * @throws IOException If failed to comment JIRA ticket.
- * @throws IllegalStateException If can't find URL to the JIRA.
- */
- public String sendJiraComment(String ticket, String comment) throws IOException;
-
- /**
- * @param url Url.
- * @return Response as gson string.
- */
- String sendGetToJira(String url) throws IOException;
-
- /**
- * @param url URL for JIRA integration.
- */
- void setJiraApiUrl(String url);
-
- /**
- * @return URL for JIRA integration.
- */
- String getJiraApiUrl();
-
default void setAuthData(String user, String pwd) {
setAuthToken(
Base64Util.encodeUtf8String(user + ":" + pwd));
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgnitePersistentTeamcity.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgnitePersistentTeamcity.java
index 76db429..bfa6376 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgnitePersistentTeamcity.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgnitePersistentTeamcity.java
@@ -512,6 +512,11 @@ public class IgnitePersistentTeamcity implements IAnalyticsEnabledTeamcity, ITea
return teamcity.getProjects();
}
+ /** {@inheritDoc} */
+ @Override public String gitBranchPrefix() {
+ return teamcity.gitBranchPrefix();
+ }
+
@Override public Statistics getStatistics(int buildId) {
return teamcity.getStatistics(buildId);
}
@@ -540,36 +545,6 @@ public class IgnitePersistentTeamcity implements IAnalyticsEnabledTeamcity, ITea
}
/** {@inheritDoc} */
- @Override public void setJiraToken(String tok) {
- teamcity.setJiraToken(tok);
- }
-
- /** {@inheritDoc} */
- @Override public boolean isJiraTokenAvailable() {
- return teamcity.isJiraTokenAvailable();
- }
-
- /** {@inheritDoc} */
- @Override public String sendJiraComment(String ticket, String comment) throws IOException {
- return teamcity.sendJiraComment(ticket, comment);
- }
-
- /** {@inheritDoc} */
- @Override public String sendGetToJira(String url) throws IOException {
- return teamcity.sendGetToJira(url);
- }
-
- /** {@inheritDoc} */
- @Override public void setJiraApiUrl(String url) {
- teamcity.setJiraApiUrl(url);
- }
-
- /** {@inheritDoc} */
- @Override public String getJiraApiUrl() {
- return teamcity.getJiraApiUrl();
- }
-
- /** {@inheritDoc} */
@Override public List<Agent> agents(boolean connected, boolean authorized) {
return teamcity.agents(connected, authorized);
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityConnection.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityConnection.java
index 50c707f..6a75fc8 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityConnection.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityConnection.java
@@ -103,11 +103,6 @@ public class IgniteTeamcityConnection implements ITeamcity {
/** Teamcity http connection. */
@Inject private ITeamcityHttpConnection teamcityHttpConn;
- /** JIRA authorization token. */
- private String jiraBasicAuthTok;
-
- /** URL for JIRA integration. */
- private String jiraApiUrl;
private String configName; //main properties file name
private String tcName;
@@ -115,6 +110,10 @@ public class IgniteTeamcityConnection implements ITeamcity {
/** Build logger processing running. */
private ConcurrentHashMap<Integer, CompletableFuture<LogCheckTask>> buildLogProcessingRunning = new ConcurrentHashMap<>();
+ /** Git branch prefix for seach TC runs in PR-less contributions. */
+ @NotNull
+ private String gitBranchPrefix;
+
public Executor getExecutor() {
return executor;
}
@@ -140,8 +139,7 @@ public class IgniteTeamcityConnection implements ITeamcity {
logger.error("Failed to set credentials", e);
}
- setJiraToken(HelperConfig.prepareJiraHttpAuthToken(props));
- setJiraApiUrl(props.getProperty(HelperConfig.JIRA_API_URL));
+ this.gitBranchPrefix = props.getProperty(HelperConfig.GIT_BRANCH_PREFIX, "ignite-");
final File logsDirFile = HelperConfig.resolveLogs(workDir, props);
@@ -160,45 +158,6 @@ public class IgniteTeamcityConnection implements ITeamcity {
return basicAuthTok != null;
}
- /** {@inheritDoc} */
- @Override public void setJiraToken(String tok) {
- jiraBasicAuthTok = tok;
- }
-
- /** {@inheritDoc} */
- @Override public boolean isJiraTokenAvailable() {
- return jiraBasicAuthTok != null;
- }
-
- /** {@inheritDoc} */
- @AutoProfiling
- @Override public String sendJiraComment(String ticket, String comment) throws IOException {
- if (isNullOrEmpty(jiraApiUrl))
- throw new IllegalStateException("JIRA API URL is not configured for this server.");
-
- String url = jiraApiUrl + "issue/" + ticket + "/comment";
-
- return HttpUtil.sendPostAsStringToJira(jiraBasicAuthTok, url, "{\"body\": \"" + comment + "\"}");
- }
-
- /** {@inheritDoc} */
- @Override public String sendGetToJira(String url) throws IOException {
- if (isNullOrEmpty(jiraApiUrl))
- throw new IllegalStateException("JIRA API URL is not configured for this server.");
-
- return HttpUtil.sendGetToJira(jiraBasicAuthTok, jiraApiUrl + url);
- }
-
- /** {@inheritDoc} */
- @Override public void setJiraApiUrl(String url) {
- jiraApiUrl = url;
- }
-
- /** {@inheritDoc} */
- @Override public String getJiraApiUrl() {
- return jiraApiUrl;
- }
-
/** {@inheritDoc} */
@AutoProfiling
@@ -377,6 +336,11 @@ public class IgniteTeamcityConnection implements ITeamcity {
}
/** {@inheritDoc} */
+ @Override public String gitBranchPrefix() {
+ return gitBranchPrefix;
+ }
+
+ /** {@inheritDoc} */
@Override public List<BuildType> getBuildTypes(String projectId) {
return sendGetXmlParseJaxb(host + "app/rest/latest/projects/" + projectId, Project.class)
.getBuildTypesNonNull();
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/TcHelper.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/TcHelper.java
index cbd550b..a1e275d 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/TcHelper.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/TcHelper.java
@@ -17,45 +17,21 @@
package org.apache.ignite.ci;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.gson.Gson;
-import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
-import org.apache.ignite.ci.jira.Tickets;
-import org.apache.ignite.ci.tcbot.issue.IssueDetector;
import org.apache.ignite.ci.issue.IssuesStorage;
-import org.apache.ignite.ci.jira.IJiraIntegration;
-import org.apache.ignite.ci.tcbot.chain.PrChainsProcessor;
-import org.apache.ignite.ci.tcmodel.result.Build;
-import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
-import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
-import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
-import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeRefCompacted;
-import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.ci.tcbot.issue.IssueDetector;
import org.apache.ignite.ci.teamcity.restcached.ITcServerProvider;
import org.apache.ignite.ci.user.ICredentialsProv;
import org.apache.ignite.ci.user.UserAndSessionsStorage;
-import org.apache.ignite.ci.web.model.JiraCommentResponse;
-import org.apache.ignite.ci.web.model.Visa;
-import org.apache.ignite.ci.web.model.current.SuiteCurrentStatus;
-import org.apache.ignite.ci.web.model.current.TestFailure;
-import org.apache.ignite.ci.web.model.hist.FailureSummary;
import org.jetbrains.annotations.Nullable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.apache.ignite.ci.util.XmlUtil.xmlEscapeText;
/**
* TC Bot implementation. To be migrated to smaller injected classes
*/
@Deprecated
public class TcHelper implements ITcHelper {
- /** Logger. */
- private static final Logger logger = LoggerFactory.getLogger(TcHelper.class);
-
/** Stop guard. */
private AtomicBoolean stop = new AtomicBoolean();
@@ -70,18 +46,6 @@ public class TcHelper implements ITcHelper {
@Inject private UserAndSessionsStorage userAndSessionsStorage;
- @Inject private PrChainsProcessor prChainsProcessor;
-
- @Inject private ITeamcityIgnitedProvider tcProv;
-
- @Inject private IStringCompactor compactor;
-
- /** */
- private final ObjectMapper objectMapper;
-
- public TcHelper() {
- objectMapper = new ObjectMapper();
- }
/** {@inheritDoc} */
@Override public void setServerAuthorizerCreds(ICredentialsProv creds) {
@@ -126,145 +90,6 @@ public class TcHelper implements ITcHelper {
}
- /** {@inheritDoc} */
- @Override public Visa notifyJira(
- String srvId,
- ICredentialsProv prov,
- String buildTypeId,
- String branchForTc,
- String ticket
- ) {
- IAnalyticsEnabledTeamcity teamcity = server(srvId, prov);
-
- ITeamcityIgnited tcIgnited = tcProv.server(srvId, prov);
-
- List<Integer> builds = tcIgnited.getLastNBuildsFromHistory(buildTypeId, branchForTc, 1);
-
- if (builds.isEmpty())
- return new Visa("JIRA wasn't commented - no finished builds to analyze.");
-
- Integer buildId = builds.get(0);
-
- FatBuildCompacted fatBuild = tcIgnited.getFatBuild(buildId);
- Build build = fatBuild.toBuild(compactor);
-
- build.webUrl = tcIgnited.host() + "viewLog.html?buildId=" + build.getId() + "&buildTypeId=" + build.buildTypeId;
-
- int blockers;
-
- JiraCommentResponse res;
-
- try {
- List<SuiteCurrentStatus> suitesStatuses = prChainsProcessor.getBlockersSuitesStatuses(buildTypeId, build.branchName, srvId, prov);
-
- if (suitesStatuses == null)
- return new Visa("JIRA wasn't commented - no finished builds to analyze.");
-
- String comment = generateJiraComment(suitesStatuses, build.webUrl, buildTypeId, tcIgnited);
-
- blockers = suitesStatuses.stream()
- .mapToInt(suite -> {
- if (suite.testFailures.isEmpty())
- return 1;
-
- return suite.testFailures.size();
- })
- .sum();
-
- res = objectMapper.readValue(teamcity.sendJiraComment(ticket, comment), JiraCommentResponse.class);
- }
- catch (Exception e) {
- String errMsg = "Exception happened during commenting JIRA ticket " +
- "[build=" + build.getId() + ", errMsg=" + e.getMessage() + ']';
-
- logger.error(errMsg);
-
- return new Visa("JIRA wasn't commented - " + errMsg);
- }
-
- return new Visa(IJiraIntegration.JIRA_COMMENTED, res, blockers);
- }
-
- /** {@inheritDoc} */
- @Override public Tickets getJiraTickets(String srvId, ICredentialsProv prov, String url) {
- IAnalyticsEnabledTeamcity teamcity = server(srvId, prov);
-
- try {
- return new Gson().fromJson(teamcity.sendGetToJira(url), Tickets.class);
- }
- catch (Exception e) {
- String errMsg = "Exception happened during receiving JIRA tickets " +
- "[url=" + url + ", errMsg=" + e.getMessage() + ']';
-
- logger.error(errMsg);
-
- return new Tickets();
- }
- }
-
- /**
- * @param suites Suite Current Status.
- * @param webUrl Build URL.
- * @return Comment, which should be sent to the JIRA ticket.
- */
- private String generateJiraComment(List<SuiteCurrentStatus> suites, String webUrl, String buildTypeId,
- ITeamcityIgnited tcIgnited) {
- BuildTypeRefCompacted bt = tcIgnited.getBuildTypeRef(buildTypeId);
-
- String suiteName = (bt != null ? bt.name(compactor) : buildTypeId);
-
- StringBuilder res = new StringBuilder();
-
- for (SuiteCurrentStatus suite : suites) {
- res.append("{color:#d04437}").append(suite.name).append("{color}");
- res.append(" [[tests ").append(suite.failedTests);
-
- if (suite.result != null && !suite.result.isEmpty())
- res.append(' ').append(suite.result);
-
- res.append('|').append(suite.webToBuild).append("]]\\n");
-
- for (TestFailure failure : suite.testFailures) {
- res.append("* ");
-
- if (failure.suiteName != null && failure.testName != null)
- res.append(failure.suiteName).append(": ").append(failure.testName);
- else
- res.append(failure.name);
-
- FailureSummary recent = failure.histBaseBranch.recent;
-
- if (recent != null) {
- if (recent.failureRate != null) {
- res.append(" - ").append(recent.failureRate).append("% fails in last ")
- .append(recent.runs).append(" master runs.");
- }
- else if (recent.failures != null && recent.runs != null) {
- res.append(" - ").append(recent.failures).append(" fails / ")
- .append(recent.runs).append(" master runs.");
- }
- }
-
- res.append("\\n");
- }
-
- res.append("\\n");
- }
-
- if (res.length() > 0) {
- res.insert(0, "{panel:title=" + suiteName + ": Possible Blockers|" +
- "borderStyle=dashed|borderColor=#ccc|titleBGColor=#F7D6C1}\\n")
- .append("{panel}");
- }
- else {
- res.append("{panel:title=").append(suiteName).append(": No blockers found!|")
- .append("borderStyle=dashed|borderColor=#ccc|titleBGColor=#D6F7C1}{panel}");
- }
-
- res.append("\\n").append("[TeamCity *").append(suiteName).append("* Results|").append(webUrl).append(']');
-
- return xmlEscapeText(res.toString());
- }
public void close() {
if (stop.compareAndSet(false, true))
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/di/IgniteTcBotModule.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/di/IgniteTcBotModule.java
index bbb68ec..e45db99 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/di/IgniteTcBotModule.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/di/IgniteTcBotModule.java
@@ -21,6 +21,10 @@ import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.internal.SingletonScope;
import com.google.inject.matcher.Matchers;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import javax.inject.Provider;
import org.apache.ignite.Ignite;
import org.apache.ignite.ci.ITcHelper;
import org.apache.ignite.ci.TcHelper;
@@ -28,7 +32,7 @@ import org.apache.ignite.ci.db.Ignite1Init;
import org.apache.ignite.ci.di.cache.GuavaCachedModule;
import org.apache.ignite.ci.di.scheduler.SchedulerModule;
import org.apache.ignite.ci.github.ignited.GitHubIgnitedModule;
-import org.apache.ignite.ci.jira.JiraIntegrationModule;
+import org.apache.ignite.ci.jira.ignited.JiraIgnitedModule;
import org.apache.ignite.ci.observer.BuildObserver;
import org.apache.ignite.ci.observer.ObserverTask;
import org.apache.ignite.ci.tcbot.TcBotBusinessServicesModule;
@@ -40,11 +44,6 @@ import org.apache.ignite.ci.web.TcUpdatePool;
import org.apache.ignite.ci.web.model.hist.VisasHistoryStorage;
import org.apache.ignite.ci.web.rest.exception.ServiceStartingException;
-import javax.inject.Provider;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
/**
*
*/
@@ -81,7 +80,7 @@ public class IgniteTcBotModule extends AbstractModule {
bind(BackgroundUpdater.class).in(new SingletonScope());
install(new TeamcityIgnitedModule());
- install(new JiraIntegrationModule());
+ install(new JiraIgnitedModule());
install(new GitHubIgnitedModule());
install(new SchedulerModule());
install(new TcBotBusinessServicesModule());
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/PullRequest.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/PullRequest.java
index 1763274..e434417 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/PullRequest.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/PullRequest.java
@@ -61,7 +61,7 @@ public class PullRequest implements IVersionedEntity {
* @return Pull Request time update.
*/
public String getTimeUpdate() {
- return updatedAt;
+ return updatedAt;
}
/**
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/IGitHubConnIgnited.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/IGitHubConnIgnited.java
index 81d36c9..c61619b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/IGitHubConnIgnited.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/IGitHubConnIgnited.java
@@ -35,17 +35,6 @@ public interface IGitHubConnIgnited {
/** */
public PullRequest getPullRequest(int prNum);
- /** */
- @AutoProfiling
- @Nullable
- public default PullRequest getPullRequest(String branchForTc) {
- Integer prId = IGitHubConnection.convertBranchToId(branchForTc);
-
- Preconditions.checkNotNull(prId, "Invalid TC branch name");
-
- return getPullRequest(prId);
- }
-
/**
* Send POST request with given body.
*
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/pure/IGitHubConnection.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/pure/IGitHubConnection.java
index 2bf08ca..b2ab22a 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/pure/IGitHubConnection.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/pure/IGitHubConnection.java
@@ -55,7 +55,7 @@ public interface IGitHubConnection {
/**
* @return PR id from string "pull/XXXX/head"
*/
- public @Nullable static Integer convertBranchToId(String branchForTc) {
+ @Nullable public static Integer convertBranchToId(String branchForTc) {
Integer res = null;
if (Objects.isNull(branchForTc))
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java
index f9aa8e9..2f6e271 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java
@@ -17,10 +17,19 @@
package org.apache.ignite.ci.jira;
+import com.google.common.base.MoreObjects;
+
/**
*
*/
public class Fields {
/** Ticket status. */
public Status status;
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("status", status)
+ .toString();
+ }
}
\ No newline at end of file
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java
index 62ceeb3..94d2131 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java
@@ -17,10 +17,18 @@
package org.apache.ignite.ci.jira;
+import com.google.common.base.MoreObjects;
+
/**
* Status for Jira ticket.
*/
public class Status {
+ /** Patch Available status name. */
+ public static final String PA_NAME = "Patch Available";
+
+ /** In Progress status name. */
+ public static final String IP_NAME = "In Progress";
+
/** Status text (open, resolved, etc). */
public String name;
@@ -30,4 +38,9 @@ public class Status {
public Status(String name) {
this.name = name;
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return name;
+ }
}
\ No newline at end of file
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java
index 5160471..dc8806f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java
@@ -17,6 +17,8 @@
package org.apache.ignite.ci.jira;
+import com.google.common.base.MoreObjects;
+
/**
* See example of GSON here
* https://issues.apache.org/jira/rest/api/2/issue/IGNITE-123
@@ -32,11 +34,11 @@ public class Ticket {
public Fields fields;
/**
- * @param ticketTemplate Ticket name template.
- * @return Ignite id (like 123 in IGNITE-123).
+ * @param ticketPrefix Ticket name fixed prefix.
+ * @return Ignite ticket Number ignoring project code (like 123 in IGNITE-123).
*/
- public int igniteId(String ticketTemplate) {
- return Integer.valueOf(key.substring(ticketTemplate.length()));
+ public int igniteId(String ticketPrefix) {
+ return Integer.valueOf(key.substring(ticketPrefix.length()));
}
/**
@@ -45,4 +47,21 @@ public class Ticket {
public String status() {
return fields.status.name;
}
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("id", id)
+ .add("key", key)
+ .add("fields", fields)
+ .toString();
+ }
+
+ /**
+ * Checks if ticket relates to some Active (In progress/Patch Available) Contribution.
+ */
+ public boolean isActiveContribution() {
+ return Status.PA_NAME.equals(status())
+ || Status.IP_NAME.equals(status());
+ }
}
\ No newline at end of file
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java
index f265b37..930a1bf 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java
@@ -24,6 +24,7 @@ import java.util.Collections;
* See example of GSON here
* https://issues.apache.org/jira/rest/api/2/search?jql=project%20=%20IGNITE%20order%20by%20updated%20DESC&fields=status
*/
+@SuppressWarnings("PublicField")
public class Tickets {
/** Start at. */
public int startAt;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnited.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnited.java
new file mode 100644
index 0000000..be1011a
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnited.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.ci.jira.ignited;
+
+import java.io.IOException;
+import java.util.Set;
+import org.apache.ignite.ci.jira.Ticket;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ *
+ */
+public interface IJiraIgnited {
+ /**
+ *
+ */
+ @NotNull public String ticketPrefix();
+
+ /**
+ *
+ */
+ @NotNull public String projectName();
+
+
+ /**
+ * @return Jira tickets.
+ */
+ public Set<Ticket> getTickets();
+
+ /**
+ * @param ticketFullName Ticket full name (e.g IGNITE-8331)
+ * @return URL which is used as link to Jira comment with specified id.
+ */
+ public String generateCommentUrl(String ticketFullName, int commentId);
+
+ /**
+ * @param id Ticket full ID (e.g IGNITE-8331)
+ * @return URL which is used as link to Jira ticket with specified name.
+ */
+ public String generateTicketUrl(String id);
+
+
+ /**
+ * @param ticket JIRA ticket full name. E.g 'IGNITE-5555'.
+ * @param comment Comment to be placed in the ticket conversation.
+ * @return {@code True} if ticket was succesfully commented. Otherwise - {@code false}.
+ * @throws IOException If failed to comment JIRA ticket.
+ * @throws IllegalStateException If can't find URL to the JIRA.
+ */
+ public String postJiraComment(String ticket, String comment) throws IOException;
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegrationProvider.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnitedProvider.java
similarity index 86%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegrationProvider.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnitedProvider.java
index 095379b..8ca0db5 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegrationProvider.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnitedProvider.java
@@ -14,15 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.ignited;
/**
*
*/
-public interface IJiraIntegrationProvider {
+public interface IJiraIgnitedProvider {
/**
* @param srvId Server id.
*/
- public IJiraIntegration server(String srvId);
+ public IJiraIgnited server(String srvId);
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnited.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnited.java
new file mode 100644
index 0000000..1ffe5ec
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnited.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ignite.ci.jira.ignited;
+
+import java.io.IOException;
+import java.util.Set;
+import javax.inject.Inject;
+import org.apache.ignite.ci.jira.Ticket;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
+import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ *
+ */
+class JiraIgnited implements IJiraIgnited {
+ /** Pure HTTP Jira connection. */
+ private IJiraIntegration jira;
+
+ /** Jira ticket DAO. */
+ @Inject private JiraTicketDao jiraTicketDao;
+
+ /** Jira ticket Sync. */
+ @Inject private JiraTicketSync jiraTicketSync;
+
+ /** Server id. */
+ private String srvId;
+
+ /** Server id mask high. */
+ private int srvIdMaskHigh;
+
+ /**
+ * @param jira Pure Jira integration.
+ */
+ public void init(IJiraIntegration jira) {
+ this.jira = jira;
+
+ srvId = jira.getServiceId();
+
+ srvIdMaskHigh = ITeamcityIgnited.serverIdToInt(srvId);
+
+ jiraTicketDao.init();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String ticketPrefix() {
+ return jira.ticketPrefix();
+ }
+
+ /** {@inheritDoc} */
+ @NotNull @Override public String projectName() {
+ return jira.projectName();
+ }
+
+ /** {@inheritDoc} */
+ @Override public Set<Ticket> getTickets() {
+ jiraTicketSync.ensureActualizeJiraTickets(srvId);
+
+ return jiraTicketDao.getTickets(srvIdMaskHigh, ticketPrefix());
+ }
+
+ /** {@inheritDoc} */
+ @Override public String generateCommentUrl(String ticketFullName, int commentId) {
+ return jira.generateCommentUrl(ticketFullName, commentId);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String generateTicketUrl(String id) {
+ return jira.generateTicketUrl(id);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String postJiraComment(String ticket, String comment) throws IOException {
+ return jira.postJiraComment(ticket, comment);
+ }
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationModule.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnitedModule.java
similarity index 75%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationModule.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnitedModule.java
index a4b6bfc..ef237d4 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationModule.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnitedModule.java
@@ -14,19 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.ignited;
import com.google.inject.AbstractModule;
-import com.google.inject.internal.SingletonScope;
+import org.apache.ignite.ci.jira.pure.JiraIntegrationModule;
/**
*
*/
-public class JiraIntegrationModule extends AbstractModule {
+public class JiraIgnitedModule extends AbstractModule {
/** {@inheritDoc} */
@Override protected void configure() {
- bind(IJiraIntegration.class).to(Jira.class);
- bind(IJiraIntegrationProvider.class).to(JiraIntegrationProvider.class).in(new SingletonScope());
+ bind(IJiraIgnitedProvider.class).to(JiraIgnitedProvider.class);
+
+ install(new JiraIntegrationModule());
}
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationProvider.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnitedProvider.java
similarity index 71%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationProvider.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnitedProvider.java
index 62a6618..451c75f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationProvider.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnitedProvider.java
@@ -14,8 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.ignited;
import com.google.common.base.Strings;
import com.google.common.cache.Cache;
@@ -24,19 +23,22 @@ import com.google.inject.Provider;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
+import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
import org.apache.ignite.ci.util.ExceptionUtil;
/**
- * Class for providing {@link IJiraIntegration} instance for specified Jira
- * server. Instance for each server is cached with defining instance
- * expiration time.
+ *
*/
-public class JiraIntegrationProvider implements IJiraIntegrationProvider {
+public class JiraIgnitedProvider implements IJiraIgnitedProvider {
+ /** */
+ @Inject IJiraIntegrationProvider pureProv;
+
/** */
- @Inject Provider<IJiraIntegration> factory;
+ @Inject Provider<JiraIgnited> factory;
/** */
- private final Cache<String, IJiraIntegration> srvs
+ private final Cache<String, IJiraIgnited> srvs
= CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterAccess(16, TimeUnit.MINUTES)
@@ -44,14 +46,15 @@ public class JiraIntegrationProvider implements IJiraIntegrationProvider {
.build();
/** */
- @Override public IJiraIntegration server(String srvId) {
+ @Override public IJiraIgnited server(String srvId) {
try {
return srvs.get(Strings.nullToEmpty(srvId), () -> {
- IJiraIntegration jiraIntegration = factory.get();
+ IJiraIntegration pure = pureProv.server(srvId);
- jiraIntegration.init(srvId);
+ JiraIgnited ignited = factory.get();
+ ignited.init(pure);
- return jiraIntegration;
+ return ignited;
});
}
catch (ExecutionException e) {
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java
index ee3bb30..6502488 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java
@@ -44,7 +44,7 @@ public class JiraTicketDao {
/** Ignite provider. */
@Inject private Provider<Ignite> igniteProvider;
- /** Builds cache. */
+ /** JIRA tickets cache : (srvId || ticketNuber) -> Ticket data compacted. */
private IgniteCache<Long, TicketCompacted> jiraCache;
/** Compactor. */
@@ -59,9 +59,10 @@ public class JiraTicketDao {
/**
* @param srvIdMaskHigh Server id mask high.
+ * @param ticketPrefix Fixed prefix for JIRA tickets.
* @return Jira tickets.
*/
- public Set<Ticket> getTickets(int srvIdMaskHigh) {
+ public Set<Ticket> getTickets(int srvIdMaskHigh, String ticketPrefix) {
Preconditions.checkNotNull(jiraCache, "init() was not called");
long srvId = (long) srvIdMaskHigh << 32;
@@ -69,7 +70,7 @@ public class JiraTicketDao {
for (Cache.Entry<Long, TicketCompacted> entry : jiraCache) {
if ((entry.getKey() & srvId) == srvId)
- res.add(entry.getValue().toTicket(compactor));
+ res.add(entry.getValue().toTicket(compactor, ticketPrefix));
}
return res;
@@ -79,7 +80,7 @@ public class JiraTicketDao {
* Combine server and project into key for storage.
*
* @param srvIdMaskHigh Server id mask high.
- * @param igniteId Ticket.
+ * @param igniteId Ticket number without project name.
* @return Key from server-project pair.
*/
public static long ticketToCacheKey(int srvIdMaskHigh, int igniteId) {
@@ -91,10 +92,10 @@ public class JiraTicketDao {
*
* @param srvIdMaskHigh Server id mask high.
* @param chunk Chunk.
- * @param ticketTemplate Ticket name template.
+ * @param ticketPrefix Ticket name template.
*/
@AutoProfiling
- public void saveChunk(int srvIdMaskHigh, Collection<Ticket> chunk, String ticketTemplate) {
+ public void saveChunk(int srvIdMaskHigh, Collection<Ticket> chunk, String ticketPrefix) {
Preconditions.checkNotNull(jiraCache, "init() was not called");
if (F.isEmpty(chunk))
@@ -103,8 +104,8 @@ public class JiraTicketDao {
HashMap<Long, TicketCompacted> compactedTickets = new HashMap<>(U.capacity(chunk.size()));
for (Ticket ticket : chunk) {
- long key = ticketToCacheKey(srvIdMaskHigh, ticket.igniteId(ticketTemplate));
- TicketCompacted val = new TicketCompacted(ticket, compactor, ticketTemplate);
+ long key = ticketToCacheKey(srvIdMaskHigh, ticket.igniteId(ticketPrefix));
+ TicketCompacted val = new TicketCompacted(ticket, compactor, ticketPrefix);
compactedTickets.put(key, val);
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java
index b7fbfd7..178ced6 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java
@@ -22,16 +22,18 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import org.apache.ignite.ci.di.MonitoredTask;
import org.apache.ignite.ci.di.scheduler.IScheduler;
-import org.apache.ignite.ci.jira.IJiraIntegration;
-import org.apache.ignite.ci.jira.IJiraIntegrationProvider;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
+import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
import org.apache.ignite.ci.jira.Ticket;
import org.apache.ignite.ci.jira.Tickets;
-import org.apache.ignite.ci.teamcity.pure.ITeamcityConn;
-import org.apache.ignite.ci.user.ICredentialsProv;
+import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
import org.apache.ignite.internal.util.typedef.F;
+import org.jetbrains.annotations.NotNull;
+
+import static org.apache.ignite.ci.util.UrlUtil.escape;
/**
- *
+ * Sync serving requests for all JIRA servers.
*/
public class JiraTicketSync {
/** Scheduler. */
@@ -44,26 +46,36 @@ public class JiraTicketSync {
@Inject IJiraIntegrationProvider jiraIntegrationProvider;
/**
- * @param taskName Task name.
- * @param srvIdMaskHigh Server id mask high.
- * @param creds Credentials.
- * @param conn Connection.
+ * @param srvId Server ID
*/
- public void ensureActualizeJiraTickets(String taskName, int srvIdMaskHigh, ICredentialsProv creds, ITeamcityConn conn) {
- scheduler.sheduleNamed(taskName, () -> actualizeJiraTickets(srvIdMaskHigh, conn, creds), 15, TimeUnit.MINUTES);
+ public void ensureActualizeJiraTickets(String srvId) {
+ scheduler.sheduleNamed(taskName("actualizeJiraTickets", srvId),
+ () -> actualizeJiraTickets(srvId), 15, TimeUnit.MINUTES);
}
/**
- * @param srvIdMaskHigh Server id mask high.
- * @param conn Connection.
- * @param creds Credentials.
+ * @param taskName Task name.
+ * @param srvId Service ID
+ * @return Task name concatenated with server name.
+ */
+ @NotNull
+ private String taskName(String taskName, String srvId) {
+ return JiraTicketSync.class.getSimpleName() + "." + taskName + "." + srvId;
+ }
+ /**
+ * @param srvId Server internal identification.
*/
@MonitoredTask(name = "Actualize Jira", nameExtArgsIndexes = {0})
- private String actualizeJiraTickets(int srvIdMaskHigh, ITeamcityConn conn, ICredentialsProv creds) {
- String srvId = conn.serverId();
+ protected String actualizeJiraTickets(String srvId) {
+ int srvIdMaskHigh = ITeamcityIgnited.serverIdToInt(srvId);
IJiraIntegration jira = jiraIntegrationProvider.server(srvId);
- String url = "search?jql=project%20=%20IGNITE%20order%20by%20updated%20DESC&fields=status&maxResults=100";
- Tickets tickets = jira.getTickets(srvId, creds, url);
+
+ String projectName = jira.projectName();
+ String baseUrl = "search?jql=" + escape("project=" + projectName + " order by updated DESC")
+ + "&fields=status&maxResults=100";
+
+ String url = baseUrl;
+ Tickets tickets = jira.getTicketsPage(srvId, url);
Collection<Ticket> page = tickets.issuesNotNull();
if (F.isEmpty(page))
@@ -74,16 +86,16 @@ public class JiraTicketSync {
int ticketsSaved = page.size();
while (tickets.nextStart() > 0) {
- url = "search?jql=project%20=%20IGNITE%20order%20by%20updated%20DESC&fields=status&maxResults=100&startAt=" +
- tickets.nextStart();
+ url = baseUrl + "&startAt=" + tickets.nextStart();
- tickets = jira.getTickets(srvId, creds, url);
+ tickets = jira.getTicketsPage(srvId, url);
page = tickets.issuesNotNull();
if (F.isEmpty(page))
break;
+ //todo find not updated chunk and exit
jiraDao.saveChunk(srvIdMaskHigh, page, jira.ticketPrefix());
ticketsSaved += page.size();
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java
index 094ae6e..d1a22f9 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java
@@ -17,6 +17,7 @@
package org.apache.ignite.ci.jira.ignited;
+import com.google.common.base.Objects;
import org.apache.ignite.ci.jira.Fields;
import org.apache.ignite.ci.jira.Status;
import org.apache.ignite.ci.jira.Ticket;
@@ -48,15 +49,36 @@ public class TicketCompacted {
/**
* @param comp Compactor.
+ * @param ticketPrefix Ticket name fixed prefix for the project.
*/
- public Ticket toTicket(IStringCompactor comp) {
+ public Ticket toTicket(IStringCompactor comp, String ticketPrefix) {
Ticket ticket = new Ticket();
ticket.id = id;
- ticket.key = "IGNITE-" + igniteId;
+ ticket.key = ticketPrefix + igniteId;
ticket.fields = new Fields();
ticket.fields.status = new Status(comp.getStringFromId(status));
return ticket;
}
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ TicketCompacted compacted = (TicketCompacted)o;
+
+ return id == compacted.id &&
+ igniteId == compacted.igniteId &&
+ status == compacted.status;
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return Objects.hashCode(id, igniteId, status);
+ }
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegration.java
similarity index 62%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegration.java
index c66a736..6ff8fea 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegration.java
@@ -15,64 +15,71 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.pure;
-import org.apache.ignite.ci.web.model.Visa;
-import org.apache.ignite.ci.user.ICredentialsProv;
+import java.io.IOException;
+import org.apache.ignite.ci.jira.Tickets;
import org.jetbrains.annotations.NotNull;
/**
* Reperesents methods to provide interaction with Jira servers.
*/
public interface IJiraIntegration {
- /** Message to show user when JIRA ticket was successfully commented by the Bot. */
- public static String JIRA_COMMENTED = "JIRA commented.";
+
+ /** @return JIRA ticket prefix. */
+ @NotNull public String ticketPrefix();
/**
- * Produce visa message(see {@link Visa}) based on passed
- * parameters and publish it as a comment for specified ticket
- * on Jira server.
*
- * @param srvId TC Server ID to take information about token from.
- * @param prov Credentials.
- * @param buildTypeId Suite name.
- * @param branchForTc Branch for TeamCity.
- * @param ticket JIRA ticket full name. E.g. IGNITE-5555
- * @return {@link Visa} instance.
*/
- public Visa notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
- String ticket);
+ @NotNull public default String projectName() {
+ return ticketPrefix().replaceAll("-", "");
+ }
+
+ /**
+ * @return Internal identified service ID.
+ */
+ public void init(String srvId);
+
+ /**
+ * @return Internal identified service ID.
+ */
+ public String getServiceId();
+
+ /**
+ * @param ticket JIRA ticket full name. E.g 'IGNITE-5555'.
+ * @param comment Comment to be placed in the ticket conversation.
+ * @return {@code True} if ticket was succesfully commented. Otherwise - {@code false}.
+ * @throws IOException If failed to comment JIRA ticket.
+ * @throws IllegalStateException If can't find URL to the JIRA.
+ */
+ public String postJiraComment(String ticket, String comment) throws IOException;
/**
* Produce wrapper for collection of Jira tickets for given server.
*
* @param srvId Server id.
- * @param prov Prov.
- * @param ticketId Ticket id.
+ * @param url Tickets loading URL and parameters.
* @return Jira tickets.
*/
- public Tickets getTickets(String srvId, ICredentialsProv prov, String ticketId);
+ public Tickets getTicketsPage(@Deprecated String srvId, String url);
/** */
public String jiraUrl();
- /** @return JIRA ticket prefix. */
- @NotNull public String ticketPrefix();
-
- /** */
- public void init(String srvId);
-
/**
* @param ticketFullName Ticket full name (e.g IGNITE-8331)
- *
* @return URL which is used as link to Jira ticket with specified name.
*/
public String generateTicketUrl(String ticketFullName);
/**
* @param ticketFullName Ticket full name (e.g IGNITE-8331)
- *
* @return URL which is used as link to Jira comment with specified id.
*/
public String generateCommentUrl(String ticketFullName, int commentId);
+
+ String getJiraApiUrl();
+
+ boolean isJiraTokenAvailable();
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegrationProvider.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegrationProvider.java
similarity index 95%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegrationProvider.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegrationProvider.java
index 095379b..984233b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegrationProvider.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegrationProvider.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.pure;
/**
*
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Jira.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Jira.java
similarity index 50%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Jira.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Jira.java
index b413193..e5a006e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Jira.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Jira.java
@@ -15,26 +15,30 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.pure;
import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
import java.io.File;
+import java.io.IOException;
import java.util.Properties;
-import javax.inject.Inject;
import org.apache.ignite.ci.HelperConfig;
-import org.apache.ignite.ci.ITcHelper;
-import org.apache.ignite.ci.user.ICredentialsProv;
-import org.apache.ignite.ci.web.model.Visa;
+import org.apache.ignite.ci.di.AutoProfiling;
+import org.apache.ignite.ci.jira.Tickets;
+import org.apache.ignite.ci.util.HttpUtil;
import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static com.google.common.base.Strings.isNullOrEmpty;
/**
*
*/
-public class Jira implements IJiraIntegration {
- /** */
- @Inject ITcHelper helper;
+class Jira implements IJiraIntegration {
+ /** Logger. */
+ private static final Logger logger = LoggerFactory.getLogger(Jira.class);
/** */
private String jiraUrl;
@@ -42,8 +46,16 @@ public class Jira implements IJiraIntegration {
/** JIRA ticket prefix. */
@NotNull private String jiraTicketPrefix;
+ /** JIRA authorization token. */
+ private String jiraBasicAuthTok;
+
+ /** URL for JIRA integration. */
+ private String jiraApiUrl;
+ private String srvId;
+
/** {@inheritDoc} */
@Override public void init(String srvId) {
+ this.srvId = srvId;
final File workDir = HelperConfig.resolveWorkDir();
final String cfgName = HelperConfig.prepareConfigName(srvId);
@@ -53,8 +65,16 @@ public class Jira implements IJiraIntegration {
jiraUrl = props.getProperty(HelperConfig.JIRA_URL);
jiraTicketPrefix = props.getProperty(HelperConfig.JIRA_TICKET_TEMPLATE, "IGNITE-");
+
+ jiraBasicAuthTok = HelperConfig.prepareJiraHttpAuthToken(props);
+ jiraApiUrl = props.getProperty(HelperConfig.JIRA_API_URL);
}
+ /**
+ * @return {@code True} if JIRA authorization token is available.
+ */
+ // boolean isJiraTokenAvailable();
+
/** {@inheritDoc} */
@Override public String jiraUrl() {
return jiraUrl;
@@ -66,14 +86,18 @@ public class Jira implements IJiraIntegration {
}
/** {@inheritDoc} */
- @Override public Visa notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
- String ticket) {
- return helper.notifyJira(srvId, prov, buildTypeId, branchForTc, ticket);
- }
-
- /** {@inheritDoc} */
- @Override public Tickets getTickets(String srvId, ICredentialsProv prov, String url) {
- return helper.getJiraTickets(srvId, prov, url);
+ @Override public Tickets getTicketsPage(String srvId, String url) {
+ try {
+ return new Gson().fromJson(sendGetToJira(url), Tickets.class);
+ }
+ catch (Exception e) {
+ String errMsg = "Exception happened during receiving JIRA tickets " +
+ "[url=" + url + ", errMsg=" + e.getMessage() + ']';
+
+ logger.error(errMsg);
+
+ return new Tickets();
+ }
}
/** {@inheritDoc} */
@@ -90,4 +114,40 @@ public class Jira implements IJiraIntegration {
"&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-" +
commentId;
}
+
+ /** {@inheritDoc} */
+ @Override public String getJiraApiUrl() {
+ return jiraApiUrl;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean isJiraTokenAvailable() {
+ return !Strings.isNullOrEmpty(jiraBasicAuthTok);
+ }
+
+ /** {@inheritDoc} */
+ @AutoProfiling
+ @Override public String postJiraComment(String ticket, String comment) throws IOException {
+ if (isNullOrEmpty(jiraApiUrl))
+ throw new IllegalStateException("JIRA API URL is not configured for this server.");
+
+ String url = jiraApiUrl + "issue/" + ticket + "/comment";
+
+ return HttpUtil.sendPostAsStringToJira(jiraBasicAuthTok, url, "{\"body\": \"" + comment + "\"}");
+ }
+
+ /**
+ * @param url Url.
+ * @return Response as gson string.
+ */
+ public String sendGetToJira(String url) throws IOException {
+ if (isNullOrEmpty(jiraApiUrl))
+ throw new IllegalStateException("JIRA API URL is not configured for this server.");
+
+ return HttpUtil.sendGetToJira(jiraBasicAuthTok, jiraApiUrl + url);
+ }
+
+ public String getServiceId() {
+ return srvId;
+ }
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationModule.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/JiraIntegrationModule.java
similarity index 94%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationModule.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/JiraIntegrationModule.java
index a4b6bfc..3c19a9f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationModule.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/JiraIntegrationModule.java
@@ -15,13 +15,13 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.pure;
import com.google.inject.AbstractModule;
import com.google.inject.internal.SingletonScope;
/**
- *
+ * JIRA pure integration module
*/
public class JiraIntegrationModule extends AbstractModule {
/** {@inheritDoc} */
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationProvider.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/JiraIntegrationProvider.java
similarity index 89%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationProvider.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/JiraIntegrationProvider.java
index 62a6618..c2c8cdc 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationProvider.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/JiraIntegrationProvider.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.pure;
import com.google.common.base.Strings;
import com.google.common.cache.Cache;
@@ -24,6 +24,8 @@ import com.google.inject.Provider;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
+import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
import org.apache.ignite.ci.util.ExceptionUtil;
/**
@@ -31,7 +33,7 @@ import org.apache.ignite.ci.util.ExceptionUtil;
* server. Instance for each server is cached with defining instance
* expiration time.
*/
-public class JiraIntegrationProvider implements IJiraIntegrationProvider {
+class JiraIntegrationProvider implements IJiraIntegrationProvider {
/** */
@Inject Provider<IJiraIntegration> factory;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/ObserverTask.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/ObserverTask.java
index f3a5197..24b32d5 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/ObserverTask.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/ObserverTask.java
@@ -30,8 +30,9 @@ import javax.inject.Inject;
import org.apache.ignite.ci.ITcHelper;
import org.apache.ignite.ci.di.AutoProfiling;
import org.apache.ignite.ci.di.MonitoredTask;
-import org.apache.ignite.ci.jira.IJiraIntegration;
-import org.apache.ignite.ci.jira.IJiraIntegrationProvider;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
+import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
+import org.apache.ignite.ci.tcbot.visa.TcBotTriggerAndSignOffService;
import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
@@ -62,11 +63,10 @@ public class ObserverTask extends TimerTask {
@Inject private ITeamcityIgnitedProvider teamcityIgnitedProvider;
/** */
- @Inject private IJiraIntegrationProvider jiraIntegrationProvider;
-
- /** */
@Inject private VisasHistoryStorage visasHistStorage;
+ @Inject private TcBotTriggerAndSignOffService visaIssuer;
+
/** */
private ReentrantLock observationLock = new ReentrantLock();
@@ -192,9 +192,7 @@ public class ObserverTask extends TimerTask {
if (!visa.isSuccess()) {
ICredentialsProv creds = tcHelper.getServerAuthorizerCreds();
- IJiraIntegration jiraIntegration = jiraIntegrationProvider.server(info.srvId);
-
- Visa updatedVisa = jiraIntegration.notifyJira(info.srvId, creds, info.buildTypeId,
+ Visa updatedVisa = visaIssuer.notifyJira(info.srvId, creds, info.buildTypeId,
info.branchForTc, info.ticket);
visasHistStorage.updateLastVisaRequest(info.getContributionKey(), (req -> req.setResult(updatedVisa)));
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessor.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessor.java
index f981abd..8c280e9 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessor.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessor.java
@@ -24,8 +24,8 @@ import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
import org.apache.ignite.ci.analysis.MultBuildRunCtx;
import org.apache.ignite.ci.github.ignited.IGitHubConnIgnited;
import org.apache.ignite.ci.github.ignited.IGitHubConnIgnitedProvider;
-import org.apache.ignite.ci.jira.IJiraIntegration;
-import org.apache.ignite.ci.jira.IJiraIntegrationProvider;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
+import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
import org.apache.ignite.ci.tcmodel.result.problems.ProblemOccurrence;
import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
@@ -108,7 +108,7 @@ public class PrChainsProcessor {
IJiraIntegration jiraIntegration = jiraIntegrationProvider.server(srvId);
- res.setJavaFlags(teamcity, gitHubConn);
+ res.setJavaFlags(teamcity, gitHubConn, jiraIntegration);
LatestRebuildMode rebuild;
if (FullQueryParams.HISTORY.equals(act))
@@ -160,7 +160,7 @@ public class PrChainsProcessor {
//fail rate reference is always default (master)
chainStatus.initFromContext(tcIgnited, teamcity, ctx, teamcity, baseBranch);
- chainStatus.initJiraAndGitInfo(jiraIntegration, gitHubConnIgnited);
+ chainStatus.initJiraAndGitInfo(tcIgnited, jiraIntegration, gitHubConnIgnited);
}
res.addChainOnServer(chainStatus);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/ContributionCheckStatus.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/ContributionCheckStatus.java
index a710870..ba7e027 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/ContributionCheckStatus.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/ContributionCheckStatus.java
@@ -20,10 +20,14 @@ import java.util.LinkedList;
import java.util.List;
/**
- * Status of contribution check details returned from server
+ * Status of contribution check details returned from server. UI model for displaying detailed {@link
+ * ContributionToCheck} status.
*/
@SuppressWarnings("PublicField") public class ContributionCheckStatus {
+ /** Queued builds. */
public int queuedBuilds;
+
+ /** Running builds. */
public int runningBuilds;
/** Suite id. */
@@ -41,6 +45,7 @@ import java.util.List;
/** Observations status: Filled if build observer has something sheduled related to {@link #resolvedBranch} */
public String observationsStatus;
+ /** Web links to queued suites. */
public List<String> webLinksQueuedSuites = new LinkedList<>();
public ContributionCheckStatus() {
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/ContributionToCheck.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/ContributionToCheck.java
index 1a2a308..6238b23 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/ContributionToCheck.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/ContributionToCheck.java
@@ -17,10 +17,11 @@
package org.apache.ignite.ci.tcbot.visa;
/**
- *
+ * Short version of contribution status.
+ * Full version is placed in {@link ContributionCheckStatus}.
*/
@SuppressWarnings("PublicField") public class ContributionToCheck {
- /** Pr number. */
+ /** Pr number. Positive value implies PR number, negative value is for JIRA ticket for PR-less contributions. */
public Integer prNumber;
/** Pr title. */
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/TcBotTriggerAndSignOffService.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/TcBotTriggerAndSignOffService.java
index 1ed9dfd..d47933b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/TcBotTriggerAndSignOffService.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/TcBotTriggerAndSignOffService.java
@@ -17,11 +17,14 @@
package org.apache.ignite.ci.tcbot.visa;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.inject.Provider;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashSet;
@@ -42,9 +45,10 @@ import org.apache.ignite.ci.github.PullRequest;
import org.apache.ignite.ci.github.ignited.IGitHubConnIgnited;
import org.apache.ignite.ci.github.ignited.IGitHubConnIgnitedProvider;
import org.apache.ignite.ci.github.pure.IGitHubConnection;
-import org.apache.ignite.ci.github.pure.IGitHubConnectionProvider;
-import org.apache.ignite.ci.jira.IJiraIntegration;
-import org.apache.ignite.ci.jira.IJiraIntegrationProvider;
+import org.apache.ignite.ci.jira.Ticket;
+import org.apache.ignite.ci.jira.ignited.IJiraIgnited;
+import org.apache.ignite.ci.jira.ignited.IJiraIgnitedProvider;
+import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
import org.apache.ignite.ci.observer.BuildObserver;
import org.apache.ignite.ci.observer.BuildsInfo;
import org.apache.ignite.ci.tcbot.chain.PrChainsProcessor;
@@ -57,26 +61,39 @@ import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
import org.apache.ignite.ci.teamcity.ignited.SyncMode;
import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeCompacted;
import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeRefCompacted;
+import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
import org.apache.ignite.ci.user.ICredentialsProv;
import org.apache.ignite.ci.web.model.ContributionKey;
+import org.apache.ignite.ci.web.model.JiraCommentResponse;
import org.apache.ignite.ci.web.model.SimpleResult;
import org.apache.ignite.ci.web.model.Visa;
import org.apache.ignite.ci.web.model.VisaRequest;
import org.apache.ignite.ci.web.model.current.SuiteCurrentStatus;
+import org.apache.ignite.ci.web.model.current.TestFailure;
+import org.apache.ignite.ci.web.model.hist.FailureSummary;
import org.apache.ignite.ci.web.model.hist.VisasHistoryStorage;
import org.apache.ignite.internal.util.typedef.F;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static org.apache.ignite.ci.observer.BuildsInfo.CANCELLED_STATUS;
import static org.apache.ignite.ci.observer.BuildsInfo.FINISHED_STATUS;
import static org.apache.ignite.ci.observer.BuildsInfo.RUNNING_STATUS;
+import static org.apache.ignite.ci.util.XmlUtil.xmlEscapeText;
import static org.apache.ignite.ci.web.rest.parms.FullQueryParams.DEFAULT_TRACKED_BRANCH_NAME;
/**
- * Provides method for TC Bot Visa obtaining
+ * TC Bot Visa Facade.
+ * Provides method for TC Bot Visa obtaining.
+ * Contains features for adding comment to the ticket based on latest state.
+ *
*/
public class TcBotTriggerAndSignOffService {
+ /** Logger. */
+ private static final Logger logger = LoggerFactory.getLogger(TcBotTriggerAndSignOffService.class);
+
/** */
private static final ThreadLocal<DateFormat> THREAD_FORMATTER = new ThreadLocal<DateFormat>() {
@Override protected DateFormat initialValue() {
@@ -87,20 +104,20 @@ public class TcBotTriggerAndSignOffService {
/** Build observer provider. */
@Inject Provider<BuildObserver> buildObserverProvider;
- /** GitHub (pure) HTTP connection provider. */
- @Inject IGitHubConnectionProvider gitHubConnProvider;
-
/** GitHub connection ignited provider. */
@Inject IGitHubConnIgnitedProvider gitHubConnIgnitedProvider;
/** TC ignited provider. */
@Inject ITeamcityIgnitedProvider tcIgnitedProv;
- /** */
- @Inject IJiraIntegrationProvider jiraIntegrationProvider;
+ /** Direct connection to JIRA provider */
+ @Inject IJiraIgnitedProvider jiraIgnProv;
+
+ /** Direct connection to JIRA provider */
+ @Inject IJiraIntegrationProvider jiraPureProvider;
/** */
- @Inject private VisasHistoryStorage visasHistoryStorage;
+ @Inject private VisasHistoryStorage visasHistStorage;
/** */
@Inject private IStringCompactor strCompactor;
@@ -111,9 +128,11 @@ public class TcBotTriggerAndSignOffService {
/** Helper. */
@Inject ITcHelper tcHelper;
-
@Inject PrChainsProcessor prChainsProcessor;
+ /** Jackson serializer. */
+ private final ObjectMapper objMapper = new ObjectMapper();
+
/** */
public void startObserver() {
buildObserverProvider.get();
@@ -125,9 +144,9 @@ public class TcBotTriggerAndSignOffService {
ITeamcityIgnited ignited = tcIgnitedProv.server(srvId, prov);
- IJiraIntegration jiraIntegration = jiraIntegrationProvider.server(srvId);
+ IJiraIgnited jiraIntegration = jiraIgnProv.server(srvId);
- for (VisaRequest visaRequest : visasHistoryStorage.getVisas()) {
+ for (VisaRequest visaRequest : visasHistStorage.getVisas()) {
VisaStatus visaStatus = new VisaStatus();
BuildsInfo info = visaRequest.getInfo();
@@ -181,23 +200,46 @@ public class TcBotTriggerAndSignOffService {
public Set<MuteInfo> getMutes(String srvId, String projectId, ICredentialsProv creds) {
ITeamcityIgnited ignited = tcIgnitedProv.server(srvId, creds);
- Set<MuteInfo> infos = ignited.getMutes(projectId, creds);
+ Set<MuteInfo> mutes = ignited.getMutes(projectId, creds);
+
+ IJiraIgnited jiraIgn = jiraIgnProv.server(srvId);
+
+ String browseUrl = jiraIgn.generateTicketUrl("");
+
+ insertTicketStatus(mutes, jiraIgn.getTickets(), browseUrl);
- for (MuteInfo info : infos)
+ for (MuteInfo info : mutes)
info.assignment.muteDate = THREAD_FORMATTER.get().format(new Date(info.assignment.timestamp()));
- return infos;
+ return mutes;
}
/**
- * @param pr Pull Request.
- * @return JIRA ticket full name or empty string.
+ * Insert ticket status for all mutes, if they have ticket in description.
+ * @param mutes Mutes.
+ * @param tickets Tickets.
+ * @param browseUrl JIRA URL for browsing tickets, e.g. https://issues.apache.org/jira/browse/
*/
- @Deprecated
- @NotNull public static String getTicketFullName(PullRequest pr) {
- String prefix = "IGNITE-";
+ private void insertTicketStatus(Set<MuteInfo> mutes, Collection<Ticket> tickets, String browseUrl) {
+ for (MuteInfo mute : mutes) {
+ if (F.isEmpty(mute.assignment.text))
+ continue;
+
+ int pos = mute.assignment.text.indexOf(browseUrl);
+
+ if (pos == -1)
+ continue;
+
+ for (Ticket ticket : tickets) {
+ String muteTicket = mute.assignment.text.substring(pos + browseUrl.length());
- return getTicketFullName(pr, prefix);
+ if (ticket.key.equals(muteTicket)) {
+ mute.ticketStatus = ticket.status();
+
+ break;
+ }
+ }
+ }
}
/**
@@ -262,24 +304,30 @@ public class TcBotTriggerAndSignOffService {
String parentSuiteId,
Build... builds
) {
- IJiraIntegration jiraIntegration = jiraIntegrationProvider.server(srvId);
+ IJiraIgnited jiraIntegration = jiraIgnProv.server(srvId);
String prefix = jiraIntegration.ticketPrefix();
if (F.isEmpty(ticketFullName)) {
try {
- IGitHubConnIgnited gitHubConn = gitHubConnIgnitedProvider.server(srvId);
+ ticketFullName = prLessTicket(srvId, branchForTc, prov, prefix);
- PullRequest pr = gitHubConn.getPullRequest(branchForTc);
+ PullRequest pr = null;
- ticketFullName = getTicketFullName(pr, prefix);
+ if (Strings.isNullOrEmpty(ticketFullName)) {
+ pr = findPrForBranch(srvId, branchForTc);
- if (ticketFullName.isEmpty()) {
- return "JIRA ticket will not be notified after the tests are completed - " +
- "PR title \"" + pr.getTitle() + "\" should starts with \"" + prefix + "-NNNNN\"." +
+ if (pr != null)
+ ticketFullName = getTicketFullName(pr, prefix);
+ }
+
+ if (Strings.isNullOrEmpty(ticketFullName)) {
+ return "JIRA ticket will not be notified - " +
+ "PR title \"" + (pr == null ? "" : pr.getTitle()) + "\" should starts with \"" + prefix + "NNNNN\"." +
" Please, rename PR according to the" +
" <a href='https://cwiki.apache.org/confluence/display/IGNITE/How+to+Contribute" +
- "#HowtoContribute-1.CreateGitHubpull-request'>contributing guide</a>.";
+ "#HowtoContribute-1.CreateGitHubpull-request'>contributing guide</a>" +
+ " or use branch name according ticket name.";
}
}
catch (Exception e) {
@@ -316,24 +364,28 @@ public class TcBotTriggerAndSignOffService {
ICredentialsProv prov) {
String jiraRes = "";
- IJiraIntegration jiraIntegration = jiraIntegrationProvider.server(srvId);
-
- String prefix = jiraIntegration.ticketPrefix();
+ String prefix = jiraIgnProv.server(srvId).ticketPrefix();
if (Strings.isNullOrEmpty(ticketFullName)) {
try {
- IGitHubConnIgnited gitHubConn = gitHubConnIgnitedProvider.server(srvId);
- PullRequest pr = gitHubConn.getPullRequest(branchForTc);
+ ticketFullName = prLessTicket(srvId, branchForTc, prov, prefix);
- ticketFullName = getTicketFullName(pr, prefix);
+ PullRequest pr = null;
- if (ticketFullName.isEmpty()) {
+ if (Strings.isNullOrEmpty(ticketFullName)) {
+ pr = findPrForBranch(srvId, branchForTc);
+
+ if (pr != null)
+ ticketFullName = getTicketFullName(pr, prefix);
+ }
+
+ if (Strings.isNullOrEmpty(ticketFullName)) {
jiraRes = "JIRA ticket can't be commented - " +
- "PR title \"" + pr.getTitle() + "\" should starts with \"" + prefix + "NNNNN\"." +
+ "PR title \"" + (pr == null ? "" : pr.getTitle()) + "\" should starts with \"" + prefix + "NNNNN\"." +
" Please, rename PR according to the" +
" <a href='https://cwiki.apache.org/confluence/display/IGNITE/How+to+Contribute" +
"#HowtoContribute-1.CreateGitHubpull-request'>contributing guide</a>" +
- " or enter ticket id in the form.";
+ " or use branch name according ticket name.";
}
}
catch (RuntimeException e) {
@@ -347,17 +399,16 @@ public class TcBotTriggerAndSignOffService {
if (!Strings.isNullOrEmpty(ticketFullName)) {
BuildsInfo buildsInfo = new BuildsInfo(srvId, prov, ticketFullName, branchForTc, suiteId);
- VisaRequest lastVisaReq = visasHistoryStorage.getLastVisaRequest(buildsInfo.getContributionKey());
+ VisaRequest lastVisaReq = visasHistStorage.getLastVisaRequest(buildsInfo.getContributionKey());
if (Objects.nonNull(lastVisaReq) && lastVisaReq.isObserving())
return new SimpleResult("Jira wasn't commented." +
" \"Re-run possible blockers & Comment JIRA\" was triggered for current branch." +
" Wait for the end or cancel exsiting observing.");
+ Visa visa = notifyJira(srvId, prov, suiteId, branchForTc, ticketFullName);
- Visa visa = jiraIntegration.notifyJira(srvId, prov, suiteId, branchForTc, ticketFullName);
-
- visasHistoryStorage.put(new VisaRequest(buildsInfo).setResult(visa));
+ visasHistStorage.put(new VisaRequest(buildsInfo).setResult(visa));
return new SimpleResult(visa.status);
}
@@ -365,17 +416,65 @@ public class TcBotTriggerAndSignOffService {
return new SimpleResult("JIRA wasn't commented." + (!jiraRes.isEmpty() ? "<br>" + jiraRes : ""));
}
+ @Nullable public PullRequest findPrForBranch(
+ @Nullable @QueryParam("serverId") String srvId,
+ @Nullable @QueryParam("branchName") String branchForTc) {
+ Integer prId = IGitHubConnection.convertBranchToId(branchForTc);
+
+ if (prId == null)
+ return null;
+
+ IGitHubConnIgnited gh = gitHubConnIgnitedProvider.server(srvId);
+
+ return gh.getPullRequest(prId);
+ }
+
+ /**
+ * @param srvId Server id.
+ * @param branchForTc Branch for tc.
+ * @param prov Credentials Prov.
+ * @param ticketPrefix Ticket prefix.
+ */
+ @Nullable public String prLessTicket(@Nullable @QueryParam("serverId") String srvId,
+ String branchForTc, ICredentialsProv prov, String ticketPrefix) {
+ return prLessTicket(branchForTc, ticketPrefix, tcIgnitedProv.server(srvId, prov));
+ }
+
+ /**
+ * @param branchForTc Branch for tc.
+ * @param ticketPrefix Ticket prefix.
+ * @param tcIgn Tc ign.
+ */
+ @Nullable public static String prLessTicket(String branchForTc, String ticketPrefix, ITeamcityIgnited tcIgn) {
+ String branchPrefix = tcIgn.gitBranchPrefix();
+
+ if (!branchForTc.startsWith(branchPrefix))
+ return null;
+
+ try {
+ int ticketNum = Integer.parseInt(branchForTc.substring(branchPrefix.length()));
+
+ return ticketPrefix + ticketNum;
+ }
+ catch (NumberFormatException ignored) {
+ }
+ return null;
+ }
+
/**
* @param srvId Server id.
+ * @param credsProv Credentials
*/
- public List<ContributionToCheck> getContributionsToCheck(String srvId) {
- IJiraIntegration jiraIntegration = jiraIntegrationProvider.server(srvId);
+ public List<ContributionToCheck> getContributionsToCheck(String srvId,
+ ICredentialsProv credsProv) {
+ IJiraIgnited jiraIntegration = jiraIgnProv.server(srvId);
List<PullRequest> requests = gitHubConnIgnitedProvider.server(srvId).getPullRequests();
if (requests == null)
return null;
- return requests.stream().map(pr -> {
+
+ List<ContributionToCheck> contribsList = requests.stream().map(pr -> {
ContributionToCheck check = new ContributionToCheck();
check.prNumber = pr.getNumber();
check.prTitle = pr.getTitle();
@@ -387,6 +486,10 @@ public class TcBotTriggerAndSignOffService {
check.prAuthor = user.login();
check.prAuthorAvatarUrl = user.avatarUrl();
}
+ else {
+ check.prAuthor = "";
+ check.prAuthorAvatarUrl = "";
+ }
String prefix = jiraIntegration.ticketPrefix();
check.jiraIssueId = Strings.emptyToNull(getTicketFullName(pr, prefix));
@@ -396,21 +499,61 @@ public class TcBotTriggerAndSignOffService {
return check;
}).collect(Collectors.toList());
+
+
+ Set<Ticket> tickets = jiraIntegration.getTickets();
+
+ List<Ticket> paTickets = tickets.stream().filter(Ticket::isActiveContribution).collect(Collectors.toList());
+
+ ITeamcityIgnited tcIgn = tcIgnitedProv.server(srvId, credsProv);
+
+ paTickets.forEach(ticket -> {
+ int ticketId = ticket.igniteId(jiraIntegration.ticketPrefix());
+ String branch = tcIgn.gitBranchPrefix() + ticketId;
+
+ String defBtForMaster = findDefaultBranchBuildType(srvId);
+
+ if(tcIgn.getAllBuildsCompacted(defBtForMaster, branch).isEmpty())
+ return; //Skipping contributions without builds
+
+ ContributionToCheck contribution = new ContributionToCheck();
+
+ contribution.jiraIssueId = ticket.key;
+ contribution.jiraIssueUrl = jiraIntegration.generateTicketUrl( ticket.key);
+ contribution.tcBranchName = branch;
+
+ contribution.prNumber = -ticketId;
+ contribution.prTitle = ""; //todo ticket title
+ contribution.prHtmlUrl = "";
+ contribution.prTimeUpdate = ""; //todo ticket updateTime
+
+ contribution.prAuthor = "";
+ contribution.prAuthorAvatarUrl = "";
+
+ contribsList.add(contribution);
+ });
+
+ return contribsList;
}
@Nonnull private List<BuildRefCompacted> findBuildsForPr(String suiteId, String prId,
IGitHubConnIgnited ghConn, ITeamcityIgnited srv) {
- List<BuildRefCompacted> buildHist = srv.getAllBuildsCompacted(suiteId, branchForTcA(prId));
+
+ List<BuildRefCompacted> buildHist = srv.getAllBuildsCompacted(suiteId, branchForTcDefault(prId, srv));
if (!buildHist.isEmpty())
return buildHist;
+ Integer prNum = Integer.valueOf(prId);
+ if (prNum < 0)
+ return buildHist; // Don't iterate for other options if PR ID is absent
+
buildHist = srv.getAllBuildsCompacted(suiteId, branchForTcB(prId));
if (!buildHist.isEmpty())
return buildHist;
- PullRequest pr = ghConn.getPullRequest(Integer.valueOf(prId));
+ PullRequest pr = ghConn.getPullRequest(prNum);
if (pr != null) {
GitHubBranch head = pr.head();
@@ -428,11 +571,19 @@ public class TcBotTriggerAndSignOffService {
return Collections.emptyList();
}
- String branchForTcA(String prId) {
+ private String branchForTcDefault(String prId, ITeamcityIgnited srv) {
+ Integer prNum = Integer.valueOf(prId);
+ if (prNum < 0)
+ return srv.gitBranchPrefix() + (-prNum); // Checking "ignite-10930" builds only
+
+ return branchForTcA(prId);
+ }
+
+ private String branchForTcA(String prId) {
return "pull/" + prId + "/head";
}
- String branchForTcB(String prId) {
+ private String branchForTcB(String prId) {
return "pull/" + prId + "/merge";
}
@@ -449,17 +600,11 @@ public class TcBotTriggerAndSignOffService {
IGitHubConnIgnited ghConn = gitHubConnIgnitedProvider.server(srvId);
- StringBuilder buildTypeId = new StringBuilder();
+ String defBtForMaster = findDefaultBranchBuildType(srvId);
- HelperConfig.getTrackedBranches().get(DEFAULT_TRACKED_BRANCH_NAME)
- .ifPresent(
- b -> b.getChainsStream()
- .filter(c -> Objects.equals(srvId, c.serverId))
- .filter(c -> c.branchForRest.equals(ITeamcity.DEFAULT))
- .findFirst()
- .ifPresent(ch -> buildTypeId.append(ch.suiteId)));
-
- BuildTypeCompacted buildType = buildTypeId.length() > 0 ? teamcity.getBuildType(buildTypeId.toString()) : null;
+ BuildTypeCompacted buildType = Strings.isNullOrEmpty(defBtForMaster)
+ ? null
+ : teamcity.getBuildType(defBtForMaster);
List<String> compositeBuildTypeIds;
String projectId;
@@ -476,21 +621,36 @@ public class TcBotTriggerAndSignOffService {
compositeBuildTypeIds = new ArrayList<>();
- if (buildTypeId.length() > 0)
- compositeBuildTypeIds.add(buildTypeId.toString());
+ if (!Strings.isNullOrEmpty(defBtForMaster))
+ compositeBuildTypeIds.add(defBtForMaster);
}
for (String btId : compositeBuildTypeIds) {
- List<BuildRefCompacted> forTests = findBuildsForPr(btId, prId, ghConn, teamcity);
+ List<BuildRefCompacted> compBuilds = findBuildsForPr(btId, prId, ghConn, teamcity);
- statuses.add(forTests.isEmpty() ? new ContributionCheckStatus(btId, branchForTcA(prId)) :
- contributionStatus(srvId, btId, forTests, teamcity, prId));
+ statuses.add(compBuilds.isEmpty()
+ ? new ContributionCheckStatus(btId, branchForTcDefault(prId, teamcity))
+ : contributionStatus(srvId, btId, compBuilds, teamcity, prId));
}
return statuses;
}
+ @NotNull public String findDefaultBranchBuildType(String srvId) {
+ StringBuilder buildTypeId = new StringBuilder();
+
+ HelperConfig.getTrackedBranches().get(DEFAULT_TRACKED_BRANCH_NAME)
+ .ifPresent(
+ b -> b.getChainsStream()
+ .filter(c -> Objects.equals(srvId, c.serverId))
+ .filter(c -> c.branchForRest.equals(ITeamcity.DEFAULT))
+ .findFirst()
+ .ifPresent(ch -> buildTypeId.append(ch.suiteId)));
+
+ return buildTypeId.toString();
+ }
+
/**
* @param srvId Server id.
* @param suiteId Suite id.
@@ -520,7 +680,7 @@ public class TcBotTriggerAndSignOffService {
status.resolvedBranch = status.branchWithFinishedSuite;
//todo take into account running/queued
else
- status.resolvedBranch = !builds.isEmpty() ? builds.get(0).branchName(compactor) : branchForTcA(prId);
+ status.resolvedBranch = !builds.isEmpty() ? builds.get(0).branchName(compactor) : branchForTcDefault(prId, teamcity);
String observationsStatus = buildObserverProvider.get().getObservationStatus(new ContributionKey(srvId, status.resolvedBranch));
@@ -574,4 +734,150 @@ public class TcBotTriggerAndSignOffService {
return status;
}
+ /**
+ * @param srvId Server id.
+ * @param prov Credentials.
+ * @param buildTypeId Suite name.
+ * @param branchForTc Branch for TeamCity.
+ * @param ticket JIRA ticket full name.
+ * @return {@code Visa} which contains info about JIRA notification.
+ */
+ //Visa notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc, String ticket);
+
+
+ /**
+ * Produce visa message(see {@link Visa}) based on passed
+ * parameters and publish it as a comment for specified ticket
+ * on Jira server.
+ *
+ * @param srvId TC Server ID to take information about token from.
+ * @param prov Credentials.
+ * @param buildTypeId Suite name.
+ * @param branchForTc Branch for TeamCity.
+ * @param ticket JIRA ticket full name. E.g. IGNITE-5555
+ * @return {@link Visa} instance.
+ */
+ public Visa notifyJira(
+ String srvId,
+ ICredentialsProv prov,
+ String buildTypeId,
+ String branchForTc,
+ String ticket
+ ) {
+ ITeamcityIgnited tcIgnited = tcIgnitedProv.server(srvId, prov);
+
+ IJiraIgnited jira = jiraIgnProv.server(srvId);
+
+ List<Integer> builds = tcIgnited.getLastNBuildsFromHistory(buildTypeId, branchForTc, 1);
+
+ if (builds.isEmpty())
+ return new Visa("JIRA wasn't commented - no finished builds to analyze.");
+
+ Integer buildId = builds.get(0);
+
+ FatBuildCompacted fatBuild = tcIgnited.getFatBuild(buildId);
+ Build build = fatBuild.toBuild(compactor);
+
+ build.webUrl = tcIgnited.host() + "viewLog.html?buildId=" + build.getId() + "&buildTypeId=" + build.buildTypeId;
+
+ int blockers;
+
+ JiraCommentResponse res;
+
+ try {
+ List<SuiteCurrentStatus> suitesStatuses = prChainsProcessor.getBlockersSuitesStatuses(buildTypeId, build.branchName, srvId, prov);
+
+ if (suitesStatuses == null)
+ return new Visa("JIRA wasn't commented - no finished builds to analyze.");
+
+ String comment = generateJiraComment(suitesStatuses, build.webUrl, buildTypeId, tcIgnited);
+
+ blockers = suitesStatuses.stream()
+ .mapToInt(suite -> {
+ if (suite.testFailures.isEmpty())
+ return 1;
+
+ return suite.testFailures.size();
+ })
+ .sum();
+
+ res = objMapper.readValue(jira.postJiraComment(ticket, comment), JiraCommentResponse.class);
+ }
+ catch (Exception e) {
+ String errMsg = "Exception happened during commenting JIRA ticket " +
+ "[build=" + build.getId() + ", errMsg=" + e.getMessage() + ']';
+
+ logger.error(errMsg);
+
+ return new Visa("JIRA wasn't commented - " + errMsg);
+ }
+
+ return new Visa(Visa.JIRA_COMMENTED, res, blockers);
+ }
+
+
+ /**
+ * @param suites Suite Current Status.
+ * @param webUrl Build URL.
+ * @return Comment, which should be sent to the JIRA ticket.
+ */
+ private String generateJiraComment(List<SuiteCurrentStatus> suites, String webUrl, String buildTypeId,
+ ITeamcityIgnited tcIgnited) {
+ BuildTypeRefCompacted bt = tcIgnited.getBuildTypeRef(buildTypeId);
+
+ String suiteName = (bt != null ? bt.name(compactor) : buildTypeId);
+
+ StringBuilder res = new StringBuilder();
+
+ for (SuiteCurrentStatus suite : suites) {
+ res.append("{color:#d04437}").append(suite.name).append("{color}");
+ res.append(" [[tests ").append(suite.failedTests);
+
+ if (suite.result != null && !suite.result.isEmpty())
+ res.append(' ').append(suite.result);
+
+ res.append('|').append(suite.webToBuild).append("]]\\n");
+
+ for (TestFailure failure : suite.testFailures) {
+ res.append("* ");
+
+ if (failure.suiteName != null && failure.testName != null)
+ res.append(failure.suiteName).append(": ").append(failure.testName);
+ else
+ res.append(failure.name);
+
+ FailureSummary recent = failure.histBaseBranch.recent;
+
+ if (recent != null) {
+ if (recent.failureRate != null) {
+ res.append(" - ").append(recent.failureRate).append("% fails in last ")
+ .append(recent.runs).append(" master runs.");
+ }
+ else if (recent.failures != null && recent.runs != null) {
+ res.append(" - ").append(recent.failures).append(" fails / ")
+ .append(recent.runs).append(" master runs.");
+ }
+ }
+
+ res.append("\\n");
+ }
+
+ res.append("\\n");
+ }
+
+ if (res.length() > 0) {
+ res.insert(0, "{panel:title=" + suiteName + ": Possible Blockers|" +
+ "borderStyle=dashed|borderColor=#ccc|titleBGColor=#F7D6C1}\\n")
+ .append("{panel}");
+ }
+ else {
+ res.append("{panel:title=").append(suiteName).append(": No blockers found!|")
+ .append("borderStyle=dashed|borderColor=#ccc|titleBGColor=#D6F7C1}{panel}");
+ }
+
+ res.append("\\n").append("[TeamCity *").append(suiteName).append("* Results|").append(webUrl).append(']');
+
+ return xmlEscapeText(res.toString());
+ }
+
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java
index 16f44e0..28b6ca4 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java
@@ -179,4 +179,6 @@ public interface ITeamcityIgnited {
@Nullable public IRunStat getSuiteRunStatAllBranches(String suiteBuildTypeId);
List<String> getAllProjectsIds();
+
+ String gitBranchPrefix();
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java
index 65930eb..3938c27 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java
@@ -19,7 +19,22 @@ package org.apache.ignite.ci.teamcity.ignited;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.OptionalInt;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import javax.inject.Inject;
import org.apache.ignite.ci.ITeamcity;
import org.apache.ignite.ci.analysis.SuiteInBranch;
import org.apache.ignite.ci.analysis.TestInBranch;
@@ -27,45 +42,35 @@ import org.apache.ignite.ci.di.AutoProfiling;
import org.apache.ignite.ci.di.MonitoredTask;
import org.apache.ignite.ci.di.cache.GuavaCached;
import org.apache.ignite.ci.di.scheduler.IScheduler;
-import org.apache.ignite.ci.jira.ignited.JiraTicketDao;
-import org.apache.ignite.ci.jira.ignited.JiraTicketSync;
-import org.apache.ignite.ci.jira.Ticket;
import org.apache.ignite.ci.tcbot.trends.MasterTrendsService;
import org.apache.ignite.ci.tcmodel.conf.Project;
import org.apache.ignite.ci.tcmodel.mute.MuteInfo;
-import org.apache.ignite.ci.teamcity.ignited.mute.MuteDao;
-import org.apache.ignite.ci.teamcity.ignited.mute.MuteSync;
+import org.apache.ignite.ci.tcmodel.result.Build;
import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildCondition;
import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildConditionDao;
-import org.apache.ignite.ci.tcmodel.result.Build;
import org.apache.ignite.ci.teamcity.ignited.buildref.BuildRefDao;
import org.apache.ignite.ci.teamcity.ignited.buildref.BuildRefSync;
+import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeCompacted;
+import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeDao;
import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeRefCompacted;
import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeRefDao;
import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeSync;
-import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeCompacted;
-import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeDao;
import org.apache.ignite.ci.teamcity.ignited.change.ChangeCompacted;
import org.apache.ignite.ci.teamcity.ignited.change.ChangeDao;
import org.apache.ignite.ci.teamcity.ignited.change.ChangeSync;
import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildDao;
import org.apache.ignite.ci.teamcity.ignited.fatbuild.ProactiveFatBuildSync;
+import org.apache.ignite.ci.teamcity.ignited.mute.MuteDao;
+import org.apache.ignite.ci.teamcity.ignited.mute.MuteSync;
import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistCompactedDao;
import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistSync;
import org.apache.ignite.ci.teamcity.pure.ITeamcityConn;
import org.apache.ignite.ci.user.ICredentialsProv;
-import org.apache.ignite.internal.util.typedef.F;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.annotation.Nullable;
-import javax.inject.Inject;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
import static org.apache.ignite.ci.tcmodel.hist.BuildRef.STATUS_UNKNOWN;
/**
@@ -114,12 +119,6 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
/** Mute Sync. */
@Inject private MuteSync muteSync;
- /** Jira ticket DAO. */
- @Inject private JiraTicketDao jiraTicketDao;
-
- /** Jira ticket Sync. */
- @Inject private JiraTicketSync jiraTicketSync;
-
/** Changes DAO. */
@Inject private ChangeDao changesDao;
@@ -158,7 +157,6 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
changesDao.init();
runHistCompactedDao.init();
muteDao.init();
- jiraTicketDao.init();
}
/**
@@ -344,44 +342,14 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
/** {@inheritDoc} */
@Override public Set<MuteInfo> getMutes(String projectId, ICredentialsProv creds) {
muteSync.ensureActualizeMutes(taskName("actualizeMutes"), projectId, srvIdMaskHigh, conn);
- jiraTicketSync.ensureActualizeJiraTickets(taskName("actualizeJiraTickets"), srvIdMaskHigh, creds, conn);
SortedSet<MuteInfo> mutes = muteDao.getMutes(srvIdMaskHigh);
- Collection<Ticket> tickets = jiraTicketDao.getTickets(srvIdMaskHigh);
- insertTicketStatus(mutes, tickets);
return mutes;
}
- /**
- * Insert ticket status for all mutes, if they have ticket in description.
- *
- * @param mutes Mutes.
- * @param tickets Tickets.
- */
- private void insertTicketStatus(SortedSet<MuteInfo> mutes, Collection<Ticket> tickets) {
- for (MuteInfo mute : mutes) {
- if (F.isEmpty(mute.assignment.text))
- continue;
-
- int pos = mute.assignment.text.indexOf("https://issues.apache.org/jira/browse/");
-
- if (pos == -1)
- continue;
-
- for (Ticket ticket : tickets) {
- String muteTicket = mute.assignment.text.substring(pos +
- "https://issues.apache.org/jira/browse/".length());
- if (ticket.key.equals(muteTicket)) {
- mute.ticketStatus = ticket.status();
-
- break;
- }
- }
- }
- }
/** {@inheritDoc} */
@AutoProfiling
@@ -434,6 +402,11 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
}
/** {@inheritDoc} */
+ @Override public String gitBranchPrefix() {
+ return conn.gitBranchPrefix();
+ }
+
+ /** {@inheritDoc} */
@Override public List<String> getCompositeBuildTypesIdsSortedByBuildNumberCounter(String projectId) {
return buildTypeSync.getCompositeBuildTypesIdsSortedByBuildNumberCounter(srvIdMaskHigh, projectId, conn);
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildref/BuildRefDao.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildref/BuildRefDao.java
index 0d33822..e254e9a 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildref/BuildRefDao.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildref/BuildRefDao.java
@@ -153,7 +153,7 @@ public class BuildRefDao {
return getBuildsForBranch(srvId, bracnhNameQry).stream()
.filter(e -> e.buildTypeId() == buildTypeIdId)
- .collect(Collectors.toList());
+ .collect(Collectors.toList());
}
/**
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java
index 4a1bfeb..4c69296 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java
@@ -109,4 +109,9 @@ public interface ITeamcityConn {
* @return List of all project available at Teamcity server.
*/
List<Project> getProjects();
+
+ /**
+ * @return Branch name mandatory prefix for all PR-less contributions, e.g. "ignite-".
+ */
+ public String gitBranchPrefix();
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Version.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Version.java
index 8d4f178..f3c1fb3 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Version.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Version.java
@@ -28,7 +28,7 @@ package org.apache.ignite.ci.web.model;
public static final String GITHUB_REF = "https://github.com/apache/ignite-teamcity-bot";
/** TC Bot Version. */
- public static final String VERSION = "20190114";
+ public static final String VERSION = "20190117";
/** TC Bot Version. */
public String version = VERSION;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Visa.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Visa.java
index 5c694cc..201db9b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Visa.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Visa.java
@@ -17,7 +17,6 @@
package org.apache.ignite.ci.web.model;
-import org.apache.ignite.ci.jira.IJiraIntegration;
import org.jetbrains.annotations.Nullable;
/**
@@ -29,6 +28,9 @@ public class Visa {
/** Determines Visa with no results and info. */
public static final String EMPTY_VISA_STATUS = "emptyVisa";
+ /** Message to show user when JIRA ticket was successfully commented by the Bot. */
+ public static final String JIRA_COMMENTED = "JIRA commented.";
+
/** */
public final String status;
@@ -71,7 +73,7 @@ public class Visa {
/** */
public boolean isSuccess() {
- return IJiraIntegration.JIRA_COMMENTED.equals(status)
+ return JIRA_COMMENTED.equals(status)
&& jiraCommentRes != null;
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java
index b1d10ff..5d4402b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/ChainAtServerCurrentStatus.java
@@ -18,6 +18,7 @@
package org.apache.ignite.ci.web.model.current;
import com.google.common.base.Objects;
+import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
@@ -33,7 +34,7 @@ import org.apache.ignite.ci.analysis.MultBuildRunCtx;
import org.apache.ignite.ci.github.PullRequest;
import org.apache.ignite.ci.github.ignited.IGitHubConnIgnited;
import org.apache.ignite.ci.github.pure.IGitHubConnection;
-import org.apache.ignite.ci.jira.IJiraIntegration;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
import org.apache.ignite.ci.tcbot.visa.TcBotTriggerAndSignOffService;
import org.apache.ignite.ci.tcmodel.conf.BuildType;
import org.apache.ignite.ci.analysis.TestInBranch;
@@ -126,7 +127,8 @@ public class ChainAtServerCurrentStatus {
}
/** */
- public void initJiraAndGitInfo(IJiraIntegration jiraIntegration, IGitHubConnIgnited gitHubConnIgnited) {
+ public void initJiraAndGitInfo(ITeamcityIgnited tcIgnited,
+ IJiraIntegration jiraIntegration, IGitHubConnIgnited gitHubConnIgnited) {
Integer prNum = IGitHubConnection.convertBranchToId(branchName);
String prUrl = null;
@@ -135,18 +137,22 @@ public class ChainAtServerCurrentStatus {
String ticketUrl = null;
+ String ticketPrefix = jiraIntegration.ticketPrefix();
+
if (prNum != null) {
PullRequest pullReq = gitHubConnIgnited.getPullRequest(prNum);
if (pullReq != null && pullReq.getTitle() != null) {
prUrl = pullReq.htmlUrl();
- ticketFullName = TcBotTriggerAndSignOffService.getTicketFullName(pullReq, jiraIntegration.ticketPrefix());
-
- if (!ticketFullName.isEmpty())
- ticketUrl = jiraIntegration.generateTicketUrl(ticketFullName);
+ ticketFullName = TcBotTriggerAndSignOffService.getTicketFullName(pullReq, ticketPrefix);
}
}
+ else
+ ticketFullName = TcBotTriggerAndSignOffService.prLessTicket(branchName, ticketPrefix, tcIgnited);
+
+ if (!Strings.isNullOrEmpty(ticketFullName))
+ ticketUrl = jiraIntegration.generateTicketUrl(ticketFullName);
setPrInfo(prNum, prUrl);
setJiraTicketInfo(ticketFullName, ticketUrl);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/UpdateInfo.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/UpdateInfo.java
index 381855d..84810c4 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/UpdateInfo.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/UpdateInfo.java
@@ -19,6 +19,7 @@ package org.apache.ignite.ci.web.model.current;
import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
import org.apache.ignite.ci.github.pure.IGitHubConnection;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
/**
*
@@ -57,16 +58,17 @@ import org.apache.ignite.ci.github.pure.IGitHubConnection;
/**
* @param teamcity TeamCity to get info about tokens.
* @param gitHubConn GitHub integration associated with this server.
+ * @param jiraIntegration
*/
public void setJavaFlags(IAnalyticsEnabledTeamcity teamcity,
- IGitHubConnection gitHubConn) {
+ IGitHubConnection gitHubConn, IJiraIntegration jiraIntegration) {
if (teamcity.isTeamCityTokenAvailable())
javaFlags |= TEAMCITY_FLAG;
if (gitHubConn.isGitTokenAvailable())
javaFlags |= GITHUB_FLAG;
- if (teamcity.isJiraTokenAvailable())
+ if (jiraIntegration.isJiraTokenAvailable())
javaFlags |= JIRA_FLAG;
}
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuilds.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuilds.java
index f983758..d6f0169 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuilds.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuilds.java
@@ -36,6 +36,8 @@ import org.apache.ignite.ci.ITeamcity;
import org.apache.ignite.ci.conf.ServerIntegrationLinks;
import org.apache.ignite.ci.github.pure.IGitHubConnection;
import org.apache.ignite.ci.github.pure.IGitHubConnectionProvider;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
+import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
import org.apache.ignite.ci.user.ICredentialsProv;
import org.apache.ignite.ci.tcbot.visa.TcBotTriggerAndSignOffService;
import org.apache.ignite.ci.web.CtxListener;
@@ -124,10 +126,11 @@ public class TriggerBuilds {
ITcHelper tcHelper = injector.getInstance(ITcHelper.class);
final ICredentialsProv creds = ICredentialsProv.get(req);
ITeamcity teamcity = tcHelper.server(srvId, creds);
+ IJiraIntegration jira = injector.getInstance(IJiraIntegrationProvider.class).server(srvId);
IGitHubConnection gh = injector.getInstance(IGitHubConnectionProvider.class).server(srvId);
- return new ServerIntegrationLinks(srvId, gh.gitApiUrl(), teamcity.getJiraApiUrl());
+ return new ServerIntegrationLinks(srvId, gh.gitApiUrl(), jira.getJiraApiUrl());
}).filter(Objects::nonNull).collect(Collectors.toSet());
}
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/pr/GetPrTestFailures.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/pr/GetPrTestFailures.java
index 88d9d30..7745e73 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/pr/GetPrTestFailures.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/pr/GetPrTestFailures.java
@@ -17,6 +17,7 @@
package org.apache.ignite.ci.web.rest.pr;
+import com.google.common.base.Preconditions;
import com.google.inject.Injector;
import javax.annotation.Nonnull;
import javax.servlet.ServletContext;
@@ -32,6 +33,7 @@ import javax.ws.rs.core.MediaType;
import org.apache.ignite.ci.github.PullRequest;
import org.apache.ignite.ci.github.ignited.IGitHubConnIgnited;
import org.apache.ignite.ci.github.ignited.IGitHubConnIgnitedProvider;
+import org.apache.ignite.ci.github.pure.IGitHubConnection;
import org.apache.ignite.ci.tcbot.chain.PrChainsProcessor;
import org.apache.ignite.ci.teamcity.ignited.SyncMode;
import org.apache.ignite.ci.user.ICredentialsProv;
@@ -140,7 +142,12 @@ public class GetPrTestFailures {
PullRequest pr;
try {
- pr = srv.getPullRequest(branchForTc);
+ Integer prId = IGitHubConnection.convertBranchToId(branchForTc);
+
+ if (prId == null)
+ return "Invalid TC branch name: [" + branchForTc + "]";
+
+ pr = srv.getPullRequest(prId);
}
catch (RuntimeException e) {
return "Exception happened - " + e.getMessage();
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/visa/TcBotVisaService.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/visa/TcBotVisaService.java
index 3ce734c..f7bfa78 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/visa/TcBotVisaService.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/visa/TcBotVisaService.java
@@ -75,15 +75,18 @@ public class TcBotVisaService {
/**
* @param srvId Server id.
+ * @return Contribution list for PRs and branches can be checked by TC bot.
*/
@GET
@Path("contributions")
public List<ContributionToCheck> contributions(@Nullable @QueryParam("serverId") String srvId) {
- if (!ICredentialsProv.get(req).hasAccess(srvId))
+ ICredentialsProv credsProv = ICredentialsProv.get(req);
+
+ if (!credsProv.hasAccess(srvId))
throw ServiceUnauthorizedException.noCreds(srvId);
return CtxListener.getInjector(ctx)
- .getInstance(TcBotTriggerAndSignOffService.class).getContributionsToCheck(srvId);
+ .getInstance(TcBotTriggerAndSignOffService.class).getContributionsToCheck(srvId, credsProv);
}
@GET
@@ -107,7 +110,8 @@ public class TcBotVisaService {
if (!prov.hasAccess(srvId))
throw ServiceUnauthorizedException.noCreds(srvId);
- TcBotTriggerAndSignOffService instance = CtxListener.getInjector(ctx).getInstance(TcBotTriggerAndSignOffService.class);
+ TcBotTriggerAndSignOffService instance = CtxListener.getInjector(ctx)
+ .getInstance(TcBotTriggerAndSignOffService.class);
return instance.currentVisaStatus(srvId, prov, suiteId, tcBranch);
}
diff --git a/ignite-tc-helper-web/src/main/webapp/js/prs-1.1.js b/ignite-tc-helper-web/src/main/webapp/js/prs-1.1.js
index e96428c..2ecb6fc 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/prs-1.1.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/prs-1.1.js
@@ -81,7 +81,7 @@ function showContributionsTable(result, srvId, suiteId) {
"data": "prTimeUpdate",
title: "Update Time",
"render": function (data, type, row, meta) {
- if (type === 'display') {
+ if (type === 'display' && isDefinedAndFilled(data) && data.length >0) {
let date = new Date(data);
data = normalizeDateNum(date.getFullYear()) + '-' + normalizeDateNum(date.getMonth() + 1) +
@@ -96,7 +96,7 @@ function showContributionsTable(result, srvId, suiteId) {
"data": "prHtmlUrl",
title: "PR Number",
"render": function (data, type, row, meta) {
- if (type === 'display') {
+ if (type === 'display' && row.prNumber > 0) {
data = "<a href='" + data + "'>#" + row.prNumber + "</a>";
}
@@ -111,7 +111,7 @@ function showContributionsTable(result, srvId, suiteId) {
"data": "prAuthor",
title: "Author",
"render": function (data, type, row, meta) {
- if (type === 'display') {
+ if (type === 'display' && isDefinedAndFilled(row.prAuthorAvatarUrl) && row.prAuthorAvatarUrl.length >0) {
data = "<img src='" + row.prAuthorAvatarUrl + "' width='20px' height='20px'> " + data + "";
}
@@ -256,9 +256,14 @@ function formatContributionDetails(row, srvId) {
" </tr>";
//References
- res += " <tr>\n" +
- " <td>Edit PR: " + "<a href='" + row.prHtmlUrl + "'>#" + row.prNumber + "</a>" + "</td>\n" +
- " <td id='viewQueuedBuildsFor" + prId + "'></td>\n" +
+ res += " <tr>\n";
+
+ if (row.prNumber > 0)
+ res += " <td>Edit PR: " + "<a href='" + row.prHtmlUrl + "'>#" + row.prNumber + "</a>" + "</td>\n";
+ else
+ res += " <td></td>\n";
+
+ res += " <td id='viewQueuedBuildsFor" + prId + "'></td>\n" +
" <td></td>\n" +
" <td></td>\n" +
" </tr>";
diff --git a/ignite-tc-helper-web/src/main/webapp/prs.html b/ignite-tc-helper-web/src/main/webapp/prs.html
index ca254b2..1eabc89 100644
--- a/ignite-tc-helper-web/src/main/webapp/prs.html
+++ b/ignite-tc-helper-web/src/main/webapp/prs.html
@@ -35,6 +35,59 @@
loadData();
});
+ function showTabs() {
+ var index = 'prsCheck_lastOpenedTab'; // Define friendly index name
+ var dataStore = window.sessionStorage; // Define friendly data store name
+ var oldIndex;
+ try {
+ // getter: Fetch previous value
+ oldIndex = dataStore.getItem(index);
+ } catch (e) {
+ // getter: Always default to first tab in error state
+ oldIndex = 0;
+ }
+ $('#tabs').tabs({
+ // The zero-based index of the panel that is active (open)
+ active: oldIndex,
+ // Triggered after a tab has been activated
+ activate: function (event, ui) {
+ // Get future value
+ var newIndex = ui.newTab.parent().children().index(ui.newTab);
+ // Set future value
+ dataStore.setItem(index, newIndex)
+ }
+ });
+ }
+
+ function showServerContribTabs(result) {
+ const processed = new Set();
+ for (let chainAtServer of result) {
+ let serverId = chainAtServer.serverId;
+
+ if (processed.has(serverId))
+ continue;
+
+ processed.add(serverId);
+
+ let selSrv = findGetParameter("server");
+ if (isDefinedAndFilled(selSrv)) {
+ if (serverId !== selSrv)
+ continue;
+ }
+
+ let tabsInsertion = $("#tabs-insertionPoint");
+ let tabId = "tabs-" + serverId;
+ let tabRef = "#" + tabId;
+ tabsInsertion.prepend("<li><a href=\"" + tabRef + "\">" + serverId + "</a></li>");
+
+ tabsInsertion.after("<div id=\"" + tabId + "\">" + "</div>");
+
+ requestTableForServer(serverId, chainAtServer.suiteId, $(tabRef));
+ }
+
+ showTabs();
+ }
+
function loadData() {
$("#loadStatus").html("<img src='https://www.wallies.com/filebin/images/loading_apple.gif' width=20px height=20px> Please wait");
@@ -52,32 +105,7 @@
showFormAndSuitesForPrCheck(result);
showCommentJiraForm(result);
- const processed = new Set();
- for (let chainAtServer of result) {
- let serverId = chainAtServer.serverId;
-
- if(processed.has(serverId))
- continue;
-
- processed.add(serverId);
-
- let selSrv = findGetParameter("server");
- if (isDefinedAndFilled(selSrv)) {
- if (serverId !== selSrv)
- continue;
- }
-
- let tabsInsertion = $("#tabs-insertionPoint");
- let tabId = "tabs-" + serverId;
- let tabRef = "#" + tabId;
- tabsInsertion.prepend("<li><a href=\"" + tabRef + "\">" + serverId + "</a></li>");
-
- tabsInsertion.after("<div id=\"" + tabId + "\">" + "</div>");
-
- requestTableForServer(serverId, chainAtServer.suiteId, $(tabRef));
- }
-
- $( "#tabs" ).tabs();
+ showServerContribTabs(result);
},
error: showErrInLoadStatus
});
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
index 26c9340..f734d13 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
@@ -17,6 +17,7 @@
package org.apache.ignite.ci.tcbot.chain;
+import com.google.common.base.Preconditions;
import com.google.inject.AbstractModule;
import com.google.inject.internal.SingletonScope;
import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
@@ -26,8 +27,8 @@ import org.apache.ignite.ci.github.ignited.IGitHubConnIgnited;
import org.apache.ignite.ci.github.ignited.IGitHubConnIgnitedProvider;
import org.apache.ignite.ci.github.pure.IGitHubConnection;
import org.apache.ignite.ci.github.pure.IGitHubConnectionProvider;
-import org.apache.ignite.ci.jira.IJiraIntegration;
-import org.apache.ignite.ci.jira.IJiraIntegrationProvider;
+import org.apache.ignite.ci.jira.pure.IJiraIntegration;
+import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
import org.apache.ignite.ci.tcbot.conf.ITcBotConfig;
import org.apache.ignite.ci.tcbot.issue.IIssuesStorage;
import org.apache.ignite.ci.tcbot.user.IUserStorage;
@@ -40,6 +41,7 @@ import org.apache.ignite.ci.user.ICredentialsProv;
import org.mockito.Mockito;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
@@ -76,7 +78,7 @@ public class MockBasedTcBotModule extends AbstractModule {
when(pullReq.getTitle()).thenReturn("");
- when(gitHubConnIgnited.getPullRequest(anyString())).thenReturn(pullReq);
+ when(gitHubConnIgnited.getPullRequest(anyInt())).thenReturn(pullReq);
when(gitHubConnIgnitedProvider.server(anyString())).thenReturn(gitHubConnIgnited);
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java
index 357adb6..e768ceb 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java
@@ -46,7 +46,7 @@ import org.apache.ignite.ci.analysis.TestInBranch;
import org.apache.ignite.ci.db.TcHelperDb;
import org.apache.ignite.ci.di.scheduler.DirectExecNoWaitScheduler;
import org.apache.ignite.ci.di.scheduler.IScheduler;
-import org.apache.ignite.ci.jira.IJiraIntegrationProvider;
+import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
import org.apache.ignite.ci.tcbot.chain.PrChainsProcessorTest;
import org.apache.ignite.ci.tcmodel.changes.ChangesList;
import org.apache.ignite.ci.tcmodel.conf.BuildType;
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
index 2e0489a..b5b1ace 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
@@ -116,6 +116,8 @@ public class TeamcityIgnitedMock {
return runHistCompacted;
});
+ when(tcIgnited.gitBranchPrefix()).thenReturn("ignite-");
+
return tcIgnited;
}