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 2018/11/10 13:06:02 UTC
[ignite-teamcity-bot] branch master updated: IGNITE-9939 [Tc Bot] Add visas caсhing and monitoring[D[F - Fixes #40.
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 efdd0c7 IGNITE-9939 [Tc Bot] Add visas caсhing and monitoring[D[F - Fixes #40.
efdd0c7 is described below
commit efdd0c7e0dbda0ae05edbf42775330133b1f7180
Author: ololo3000 <pm...@gmail.com>
AuthorDate: Sat Nov 10 16:05:50 2018 +0300
IGNITE-9939 [Tc Bot] Add visas caсhing and monitoring[D[F - Fixes #40.
Signed-off-by: Dmitriy Pavlov <dp...@apache.org>
---
.../main/java/org/apache/ignite/ci/ITcHelper.java | 5 +-
.../main/java/org/apache/ignite/ci/TcHelper.java | 139 ++++++++++++-------
.../org/apache/ignite/ci/di/IgniteTcBotModule.java | 3 +-
.../apache/ignite/ci/jira/IJiraIntegration.java | 3 +-
.../apache/ignite/ci/observer/BuildObserver.java | 19 ++-
.../org/apache/ignite/ci/observer/BuildsInfo.java | 99 ++++++++++++--
.../ignite/ci/observer/CompactBuildsInfo.java | 95 +++++++++++++
.../apache/ignite/ci/observer/ObserverTask.java | 68 +++++++---
.../tcbot/visa/TcBotTriggerAndSignOffService.java | 72 +++++++++-
.../visa/VisaStatus.java} | 39 +++---
.../apache/ignite/ci/tcmodel/hist/BuildRef.java | 5 +
.../ci/web/model/CompactContributionKey.java | 62 +++++++++
.../model/CompactVisa.java} | 38 +++---
.../model/CompactVisaRequest.java} | 38 +++---
.../model/ContributionKey.java} | 32 ++---
.../model/JiraCommentResponse.java} | 25 ++--
.../java/org/apache/ignite/ci/web/model/Visa.java | 84 ++++++++++++
.../model/VisaRequest.java} | 48 ++++---
.../ci/web/model/hist/VisasHistoryStorage.java | 118 ++++++++++++++++
.../ignite/ci/web/rest/visa/TcBotVisaService.java | 16 ++-
.../src/main/webapp/js/common-1.6.js | 3 +-
ignite-tc-helper-web/src/main/webapp/visas.html | 150 +++++++++++++++++++++
22 files changed, 966 insertions(+), 195 deletions(-)
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 25a5bd0..481ffa1 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
@@ -24,6 +24,7 @@ import org.apache.ignite.ci.issue.IssuesStorage;
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.Visa;
/**
* Teamcity Bot main interface. This inteface became too huge.
@@ -67,7 +68,7 @@ public interface ITcHelper extends ITcServerProvider {
* @param buildTypeId Suite name.
* @param branchForTc Branch for TeamCity.
* @param ticket JIRA ticket full name.
- * @return {@code True} if JIRA was notified.
+ * @return {@code Visa} which contains info about JIRA notification.
*/
- String notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc, String ticket);
+ Visa notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc, String ticket);
}
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 b40ba69..3c56b4e 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,12 +17,15 @@
package org.apache.ignite.ci;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.ignite.ci.tcbot.chain.PrChainsProcessor;
import org.apache.ignite.ci.conf.BranchesTracked;
import org.apache.ignite.ci.issue.IssueDetector;
import org.apache.ignite.ci.issue.IssuesStorage;
import org.apache.ignite.ci.jira.IJiraIntegration;
import org.apache.ignite.ci.tcmodel.hist.BuildRef;
+import org.apache.ignite.ci.web.model.JiraCommentResponse;
+import org.apache.ignite.ci.web.model.Visa;
import org.apache.ignite.ci.tcmodel.result.problems.ProblemOccurrence;
import org.apache.ignite.ci.teamcity.restcached.ITcServerProvider;
import org.apache.ignite.ci.user.ICredentialsProv;
@@ -68,7 +71,11 @@ public class TcHelper implements ITcHelper, IJiraIntegration {
@Inject private PrChainsProcessor prChainsProcessor;
+ /** */
+ private final ObjectMapper objectMapper;
+
public TcHelper() {
+ objectMapper = new ObjectMapper();
}
/** {@inheritDoc} */
@@ -132,7 +139,7 @@ public class TcHelper implements ITcHelper, IJiraIntegration {
}
/** {@inheritDoc} */
- @Override public String notifyJira(
+ @Override public Visa notifyJira(
String srvId,
ICredentialsProv prov,
String buildTypeId,
@@ -144,15 +151,23 @@ public class TcHelper implements ITcHelper, IJiraIntegration {
List<BuildRef> builds = teamcity.getFinishedBuildsIncludeSnDepFailed(buildTypeId, branchForTc);
if (builds.isEmpty())
- return "JIRA wasn't commented - no finished builds to analyze.";
+ return new Visa("JIRA wasn't commented - no finished builds to analyze.");
BuildRef build = builds.get(builds.size() - 1);
- String comment;
+
+ int blockers;
+
+ JiraCommentResponse res;
try {
- comment = generateJiraComment(buildTypeId, build.branchName, srvId, prov, build.webUrl);
+ List<SuiteCurrentStatus> suitesStatuses = getSuitesStatuses(buildTypeId, build.branchName, srvId, prov);
- teamcity.sendJiraComment(ticket, comment);
+ String comment = generateJiraComment(suitesStatuses, build.webUrl);
+
+ blockers = suitesStatuses.stream().mapToInt(suite ->
+ suite.testFailures.size()).sum();
+
+ res = objectMapper.readValue(teamcity.sendJiraComment(ticket, comment), JiraCommentResponse.class);
}
catch (Exception e) {
String errMsg = "Exception happened during commenting JIRA ticket " +
@@ -160,10 +175,10 @@ public class TcHelper implements ITcHelper, IJiraIntegration {
logger.error(errMsg);
- return "JIRA wasn't commented - " + errMsg;
+ return new Visa("JIRA wasn't commented - " + errMsg);
}
- return JIRA_COMMENTED;
+ return new Visa(JIRA_COMMENTED, res, blockers);
}
/**
@@ -171,17 +186,14 @@ public class TcHelper implements ITcHelper, IJiraIntegration {
* @param branchForTc Branch for TeamCity.
* @param srvId Server id.
* @param prov Credentials.
- * @param webUrl Build URL.
- * @return Comment, which should be sent to the JIRA ticket.
+ * @return List of suites with possible blockers.
*/
- private String generateJiraComment(
- String buildTypeId,
+ public List<SuiteCurrentStatus> getSuitesStatuses(String buildTypeId,
String branchForTc,
String srvId,
- ICredentialsProv prov,
- String webUrl
- ) {
- StringBuilder res = new StringBuilder();
+ ICredentialsProv prov) {
+ List<SuiteCurrentStatus> res = new ArrayList<>();
+
TestFailuresSummary summary = prChainsProcessor.getTestFailuresSummary(
prov, srvId, buildTypeId, branchForTc,
FullQueryParams.LATEST, null, null, false);
@@ -193,54 +205,61 @@ public class TcHelper implements ITcHelper, IJiraIntegration {
Map<String, List<SuiteCurrentStatus>> fails = findFailures(server);
- for (List<SuiteCurrentStatus> suites : fails.values()) {
- for (SuiteCurrentStatus suite : suites) {
- res.append("{color:#d04437}").append(suite.name).append("{color}");
- res.append(" [[tests ").append(suite.failedTests);
+ fails.forEach((k, v) -> res.addAll(v));
+ }
+ }
- if (suite.result != null && !suite.result.isEmpty())
- res.append(' ').append(suite.result);
+ return res;
+ }
- res.append('|').append(suite.webToBuild).append("]]\\n");
+ /** */
+ private String generateJiraComment(List<SuiteCurrentStatus> suites, String webUrl) {
+ StringBuilder res = new StringBuilder();
+
+ for (SuiteCurrentStatus suite : suites) {
+ res.append("{color:#d04437}").append(suite.name).append("{color}");
+ res.append(" [[tests ").append(suite.failedTests);
- for (TestFailure failure : suite.testFailures) {
- res.append("* ");
+ if (suite.result != null && !suite.result.isEmpty())
+ res.append(' ').append(suite.result);
- if (failure.suiteName != null && failure.testName != null)
- res.append(failure.suiteName).append(": ").append(failure.testName);
- else
- res.append(failure.name);
+ res.append('|').append(suite.webToBuild).append("]]\\n");
- FailureSummary recent = failure.histBaseBranch.recent;
+ for (TestFailure failure : suite.testFailures) {
+ res.append("* ");
- if (recent != null) {
- if (recent.failureRate != null) {
- res.append(" - ").append(recent.failureRate).append("% fails in last ")
- .append(MAX_LATEST_RUNS).append(" master runs.");
- }
- else if (recent.failures != null && recent.runs != null) {
- res.append(" - ").append(recent.failures).append(" fails / ")
- .append(recent.runs).append(" runs.");
- }
- }
+ if (failure.suiteName != null && failure.testName != null)
+ res.append(failure.suiteName).append(": ").append(failure.testName);
+ else
+ res.append(failure.name);
- res.append("\\n");
- }
+ FailureSummary recent = failure.histBaseBranch.recent;
- res.append("\\n");
+ if (recent != null) {
+ if (recent.failureRate != null) {
+ res.append(" - ").append(recent.failureRate).append("% fails in last ")
+ .append(MAX_LATEST_RUNS).append(" master runs.");
+ }
+ else if (recent.failures != null && recent.runs != null) {
+ res.append(" - ").append(recent.failures).append(" fails / ")
+ .append(recent.runs).append(" runs.");
}
}
- if (res.length() > 0) {
- res.insert(0, "{panel:title=Possible Blockers|" +
- "borderStyle=dashed|borderColor=#ccc|titleBGColor=#F7D6C1}\\n")
- .append("{panel}");
- }
- else {
- res.append("{panel:title=No blockers found!|" +
- "borderStyle=dashed|borderColor=#ccc|titleBGColor=#D6F7C1}{panel}");
- }
+ res.append("\\n");
}
+
+ res.append("\\n");
+ }
+
+ if (res.length() > 0) {
+ res.insert(0, "{panel:title=Possible Blockers|" +
+ "borderStyle=dashed|borderColor=#ccc|titleBGColor=#F7D6C1}\\n")
+ .append("{panel}");
+ }
+ else {
+ res.append("{panel:title=No blockers found!|" +
+ "borderStyle=dashed|borderColor=#ccc|titleBGColor=#D6F7C1}{panel}");
}
res.append("\\n").append("[TeamCity Run All Results|").append(webUrl).append(']');
@@ -249,6 +268,24 @@ public class TcHelper implements ITcHelper, IJiraIntegration {
}
/**
+ * @param buildTypeId Suite name.
+ * @param branchForTc Branch for TeamCity.
+ * @param srvId Server id.
+ * @param prov Credentials.
+ * @param webUrl Build URL.
+ * @return Comment, which should be sent to the JIRA ticket.
+ */
+ private String generateJiraComment(
+ String buildTypeId,
+ String branchForTc,
+ String srvId,
+ ICredentialsProv prov,
+ String webUrl
+ ) {
+ return generateJiraComment(getSuitesStatuses(buildTypeId, branchForTc,srvId, prov), webUrl);
+ }
+
+ /**
* @param srv Server.
* @return Failures for given server.
*/
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 b2aa2d8..618b681 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
@@ -42,6 +42,7 @@ import org.apache.ignite.ci.user.ICredentialsProv;
import org.apache.ignite.ci.util.ExceptionUtil;
import org.apache.ignite.ci.web.BackgroundUpdater;
import org.apache.ignite.ci.web.TcUpdatePool;
+import org.apache.ignite.ci.web.model.Visa;
import org.apache.ignite.ci.web.rest.exception.ServiceStartingException;
/**
@@ -90,7 +91,7 @@ public class IgniteTcBotModule extends AbstractModule {
private static class Jira implements IJiraIntegration {
@Inject ITcHelper helper;
- @Override public String notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
+ @Override public Visa notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
String ticket) {
return helper.notifyJira(srvId, prov, buildTypeId, branchForTc, ticket);
}
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/IJiraIntegration.java
index a20ead4..aa1084c 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/IJiraIntegration.java
@@ -17,6 +17,7 @@
package org.apache.ignite.ci.jira;
+import org.apache.ignite.ci.web.model.Visa;
import org.apache.ignite.ci.user.ICredentialsProv;
/**
@@ -34,6 +35,6 @@ public interface IJiraIntegration {
* @param ticket JIRA ticket full name. E.g. IGNITE-5555
* @return {@code True} if JIRA was notified.
*/
- public String notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
+ public Visa notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
String ticket);
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/BuildObserver.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/BuildObserver.java
index 1e08eb8..cf29468 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/BuildObserver.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/BuildObserver.java
@@ -23,6 +23,8 @@ import java.util.Timer;
import javax.inject.Inject;
import org.apache.ignite.ci.tcmodel.result.Build;
import org.apache.ignite.ci.user.ICredentialsProv;
+import org.apache.ignite.ci.web.model.VisaRequest;
+import org.apache.ignite.ci.web.model.hist.VisasHistoryStorage;
/**
*
@@ -37,6 +39,9 @@ public class BuildObserver {
/** Task, which should be done periodically. */
private ObserverTask observerTask;
+ /** Visas History Storage. */
+ @Inject private VisasHistoryStorage visasStorage;
+
/**
*/
@Inject
@@ -58,10 +63,15 @@ public class BuildObserver {
/**
* @param srvId Server id.
* @param prov Credentials.
+ * @param branchForTc Branch for TC.
* @param ticket JIRA ticket name.
*/
- public void observe(String srvId, ICredentialsProv prov, String ticket, Build... builds) {
- observerTask.addBuild(new BuildsInfo(srvId, prov, ticket, builds));
+ public void observe(String srvId, ICredentialsProv prov, String ticket, String branchForTc, Build... builds) {
+ BuildsInfo buildsInfo = new BuildsInfo(srvId, prov, ticket, branchForTc, builds);
+
+ visasStorage.put(new VisaRequest(buildsInfo));
+
+ observerTask.addInfo(buildsInfo);
}
/**
@@ -70,10 +80,11 @@ public class BuildObserver {
*/
public String getObservationStatus(String srvId, String branch) {
StringBuilder sb = new StringBuilder();
- Collection<BuildsInfo> builds = observerTask.getBuilds();
+
+ Collection<BuildsInfo> builds = observerTask.getInfos();
for (BuildsInfo bi : builds) {
- if (Objects.equals(bi.branchName, branch)
+ if (Objects.equals(bi.branchForTc, branch)
&& Objects.equals(bi.srvId, srvId)) {
sb.append(bi.ticket).append(" to be commented, waiting for builds. ");
sb.append(bi.finishedBuildsCount());
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/BuildsInfo.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/BuildsInfo.java
index ba8b48a..d3b17c0 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/BuildsInfo.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/BuildsInfo.java
@@ -17,17 +17,34 @@
package org.apache.ignite.ci.observer;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
import org.apache.ignite.ci.tcmodel.result.Build;
+import org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor;
import org.apache.ignite.ci.user.ICredentialsProv;
+import org.apache.ignite.ci.web.model.ContributionKey;
/**
*
*/
public class BuildsInfo {
+ /** */
+ public static final String FINISHED_STATE = "finished";
+
+ /** */
+ public static final String RUNNING_STATE = "running";
+
+ /** */
+ public static final String FINISHED_WITH_FAILURES_STATE = "finished with failures";
+
+ /** */
+ public final String userName;
+
/** Server id. */
public final String srvId;
@@ -35,42 +52,85 @@ public class BuildsInfo {
public final String buildTypeId;
/** Branch name. */
- public final String branchName;
+ public final String branchForTc;
/** JIRA ticket full name. */
public final String ticket;
+ /** */
+ public final Date date;
+
/** Finished builds. */
- private final Map<Build, Boolean> finishedBuilds = new HashMap<>();
+ private final Map<Integer, Boolean> finishedBuilds = new HashMap<>();
+
+ /** */
+ public BuildsInfo(CompactBuildsInfo buildsInfo, IgniteStringCompactor strCompactor) {
+ this.userName = strCompactor.getStringFromId(buildsInfo.userName);
+ this.date = buildsInfo.date;
+ this.srvId = strCompactor.getStringFromId(buildsInfo.srvId);
+ this.ticket = strCompactor.getStringFromId(buildsInfo.ticket);
+ this.branchForTc = strCompactor.getStringFromId(buildsInfo.branchForTc);
+ this.buildTypeId = strCompactor.getStringFromId(buildsInfo.buildTypeId);
+ this.finishedBuilds.putAll(buildsInfo.getFinishedBuilds());
+ }
/**
* @param srvId Server id.
* @param prov Prov.
+ * @param branchForTc Branch for TC.
* @param ticket Ticket.
* @param builds Builds.
*/
- public BuildsInfo(String srvId, ICredentialsProv prov, String ticket, Build[] builds) {
+ public BuildsInfo(String srvId, ICredentialsProv prov, String ticket, String branchForTc, Build... builds) {
+ this.userName = prov.getUser(srvId);
+ this.date = Calendar.getInstance().getTime();
this.srvId = srvId;
this.ticket = ticket;
- this.buildTypeId = builds.length > 1 ? "IgniteTests24Java8_RunAll" : builds[0].buildTypeId;
- this.branchName = builds[0].branchName;
+ this.branchForTc = branchForTc;
+ this.buildTypeId = builds.length == 1 ? builds[0].buildTypeId : "IgniteTests24Java8_RunAll";
for (Build build : builds)
- finishedBuilds.put(build, false);
+ finishedBuilds.put(build.getId(), false);
}
/**
* @param teamcity Teamcity.
*/
- public boolean isFinished(IAnalyticsEnabledTeamcity teamcity) {
- for (Map.Entry<Build, Boolean> entry : finishedBuilds.entrySet()) {
+ public String getState(IAnalyticsEnabledTeamcity teamcity) {
+ for (Map.Entry<Integer, Boolean> entry : finishedBuilds.entrySet()) {
+ if (entry.getValue() == null)
+ return FINISHED_WITH_FAILURES_STATE;
+
if (!entry.getValue()) {
- Build build = teamcity.getBuild(entry.getKey().getId());
- entry.setValue(build.isFinished());
+ Build build = teamcity.getBuild(entry.getKey());
+
+ if (build.isFinished()) {
+ if (build.isUnknown()) {
+ entry.setValue(null);
+
+ return FINISHED_WITH_FAILURES_STATE;
+ }
+
+ entry.setValue(true);
+ }
}
}
- return !finishedBuilds.containsValue(false);
+ return finishedBuilds.containsValue(false) ? RUNNING_STATE : FINISHED_STATE;
+ }
+
+ /**
+ * @param teamcity Teamcity.
+ */
+ public boolean isFinished(IAnalyticsEnabledTeamcity teamcity) {
+ return FINISHED_STATE.equals(getState(teamcity));
+ }
+
+ /**
+ * @param teamcity Teamcity.
+ */
+ public boolean isFinishedWithFailures(IAnalyticsEnabledTeamcity teamcity) {
+ return FINISHED_WITH_FAILURES_STATE.equals(getState(teamcity));
}
/**
@@ -87,6 +147,16 @@ public class BuildsInfo {
return (int)finishedBuilds.values().stream().filter(v -> v).count();
}
+ /** */
+ public ContributionKey getContributionKey() {
+ return new ContributionKey(srvId, ticket, branchForTc);
+ }
+
+ /** */
+ public Map<Integer, Boolean> getBuilds() {
+ return Collections.unmodifiableMap(finishedBuilds);
+ }
+
/** {@inheritDoc} */
@Override public boolean equals(Object o) {
if (this == o)
@@ -99,13 +169,14 @@ public class BuildsInfo {
return Objects.equals(srvId, info.srvId) &&
Objects.equals(buildTypeId, info.buildTypeId) &&
- Objects.equals(branchName, info.branchName) &&
+ Objects.equals(branchForTc, info.branchForTc) &&
Objects.equals(ticket, info.ticket) &&
- Objects.equals(finishedBuilds.keySet(), info.finishedBuilds.keySet());
+ Objects.equals(finishedBuilds.keySet(), info.finishedBuilds.keySet()) &&
+ Objects.equals(date, info.date);
}
/** {@inheritDoc} */
@Override public int hashCode() {
- return Objects.hash(srvId, buildTypeId, branchName, ticket, finishedBuilds.keySet());
+ return Objects.hash(srvId, buildTypeId, branchForTc, ticket, finishedBuilds.keySet(), date);
}
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/CompactBuildsInfo.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/CompactBuildsInfo.java
new file mode 100644
index 0000000..6bab08d
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/observer/CompactBuildsInfo.java
@@ -0,0 +1,95 @@
+/*
+ * 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.observer;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor;
+
+/**
+ *
+ */
+public class CompactBuildsInfo {
+ /** */
+ public final int userName;
+
+ /** Server id. */
+ public final int srvId;
+
+ /** Build type id. */
+ public final int buildTypeId;
+
+ /** Branch name. */
+ public final int branchForTc;
+
+ /** JIRA ticket full name. */
+ public final int ticket;
+
+ /** */
+ public final Date date;
+
+ /** Finished builds. */
+ private final Map<Integer, Boolean> finishedBuilds = new HashMap<>();
+
+ /** */
+ public CompactBuildsInfo(BuildsInfo buildsInfo, IgniteStringCompactor strCompactor) {
+ this.userName = strCompactor.getStringId(buildsInfo.userName);
+ this.date = buildsInfo.date;
+ this.srvId = strCompactor.getStringId(buildsInfo.srvId);
+ this.ticket = strCompactor.getStringId(buildsInfo.ticket);
+ this.branchForTc = strCompactor.getStringId(buildsInfo.branchForTc);
+ this.buildTypeId = strCompactor.getStringId(buildsInfo.buildTypeId);
+ this.finishedBuilds.putAll(buildsInfo.getBuilds());
+ }
+
+ /** */
+ public Map<Integer, Boolean> getFinishedBuilds() {
+ return Collections.unmodifiableMap(finishedBuilds);
+ }
+
+ /** */
+ public BuildsInfo toBuildInfo(IgniteStringCompactor compactor) {
+ return new BuildsInfo(this, compactor);
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (!(o instanceof CompactBuildsInfo))
+ return false;
+
+ CompactBuildsInfo info = (CompactBuildsInfo)o;
+
+ return Objects.equals(srvId, info.srvId) &&
+ Objects.equals(buildTypeId, info.buildTypeId) &&
+ Objects.equals(branchForTc, info.branchForTc) &&
+ Objects.equals(ticket, info.ticket) &&
+ Objects.equals(finishedBuilds.keySet(), info.finishedBuilds.keySet()) &&
+ Objects.equals(date, info.date);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return Objects.hash(srvId, buildTypeId, branchForTc, ticket, finishedBuilds.keySet(), date);
+ }
+}
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 37d6e0f..22f00e7 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
@@ -17,26 +17,29 @@
package org.apache.ignite.ci.observer;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashSet;
-import java.util.Queue;
+import java.util.List;
import java.util.Set;
import java.util.TimerTask;
+import javax.cache.Cache;
import javax.inject.Inject;
import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
import org.apache.ignite.ci.ITcHelper;
+import org.apache.ignite.ci.db.TcHelperDb;
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.teamcity.ignited.IgniteStringCompactor;
import org.apache.ignite.ci.user.ICredentialsProv;
-import org.apache.ignite.configuration.CollectionConfiguration;
+import org.apache.ignite.ci.web.model.Visa;
+import org.apache.ignite.ci.web.model.hist.VisasHistoryStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.apache.ignite.ci.jira.IJiraIntegration.JIRA_COMMENTED;
-
/**
* Checks observed builds for finished status and comments JIRA ticket.
*/
@@ -44,6 +47,9 @@ public class ObserverTask extends TimerTask {
/** Logger. */
private static final Logger logger = LoggerFactory.getLogger(ObserverTask.class);
+ /** */
+ public static final String BUILDS_CACHE_NAME = "compactBuildsInfos";
+
/** Helper. */
@Inject private ITcHelper tcHelper;
@@ -53,28 +59,34 @@ public class ObserverTask extends TimerTask {
/** Ignite. */
@Inject private Ignite ignite;
+ /** */
+ @Inject private VisasHistoryStorage visasHistoryStorage;
+
+ /** */
+ @Inject private IgniteStringCompactor strCompactor;
+
/**
*/
ObserverTask() {
}
/** */
- private Queue<BuildsInfo> buildsQueue() {
- CollectionConfiguration cfg = new CollectionConfiguration();
-
- cfg.setBackups(1);
-
- return ignite.queue("buildsQueue", 0, cfg);
+ private IgniteCache<CompactBuildsInfo, Object> compactInfos() {
+ return ignite.getOrCreateCache(TcHelperDb.getCacheV2TxConfig(BUILDS_CACHE_NAME));
}
/** */
- public Collection<BuildsInfo> getBuilds() {
- return Collections.unmodifiableCollection(buildsQueue());
+ public Collection<BuildsInfo> getInfos() {
+ List<BuildsInfo> buildsInfos = new ArrayList<>();
+
+ compactInfos().forEach(entry -> buildsInfos.add(entry.getKey().toBuildInfo(strCompactor)));
+
+ return buildsInfos;
}
/** */
- public void addBuild(BuildsInfo build) {
- buildsQueue().add(build);
+ public void addInfo(BuildsInfo info) {
+ compactInfos().put(new CompactBuildsInfo(info, strCompactor), new Object());
}
/** {@inheritDoc} */
@@ -100,13 +112,25 @@ public class ObserverTask extends TimerTask {
int notFinishedBuilds = 0;
Set<String> ticketsNotified = new HashSet<>();
- Queue<BuildsInfo> builds = buildsQueue();
+ for (Cache.Entry<CompactBuildsInfo, Object> entry : compactInfos()) {
+ CompactBuildsInfo compactInfo = entry.getKey();
+
+ BuildsInfo info = compactInfo.toBuildInfo(strCompactor);
- for (BuildsInfo info : builds) {
checkedBuilds += info.buildsCount();
IAnalyticsEnabledTeamcity teamcity = tcHelper.server(info.srvId, tcHelper.getServerAuthorizerCreds());
+ if (info.isFinishedWithFailures(teamcity)) {
+ compactInfos().remove(compactInfo);
+
+ logger.error("JIRA will not be commented." +
+ " [ticket: " + info.ticket + ", branch:" + info.branchForTc + "] : " +
+ "one or more re-runned blocker's builds finished with UNKNOWN status.");
+
+ continue;
+ }
+
if (!info.isFinished(teamcity)) {
notFinishedBuilds += info.buildsCount() - info.finishedBuildsCount();
@@ -115,13 +139,15 @@ public class ObserverTask extends TimerTask {
ICredentialsProv creds = tcHelper.getServerAuthorizerCreds();
- String jiraRes = jiraIntegration.notifyJira(info.srvId, creds, info.buildTypeId,
- info.branchName, info.ticket);
+ Visa visa = jiraIntegration.notifyJira(info.srvId, creds, info.buildTypeId,
+ info.branchForTc, info.ticket);
+
+ visasHistoryStorage.updateVisaRequestRes(info.getContributionKey(), info.date, visa);
- if (JIRA_COMMENTED.equals(jiraRes)) {
+ if (visa.isSuccess()) {
ticketsNotified.add(info.ticket);
- builds.remove(info);
+ compactInfos().remove(compactInfo);
}
}
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 5c64286..33ed6a0 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
@@ -19,6 +19,8 @@ package org.apache.ignite.ci.tcbot.visa;
import com.google.common.base.Strings;
import com.google.inject.Provider;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -28,6 +30,7 @@ import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.ws.rs.QueryParam;
import org.apache.ignite.ci.ITcHelper;
+import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
import org.apache.ignite.ci.github.GitHubUser;
import org.apache.ignite.ci.github.PullRequest;
import org.apache.ignite.ci.github.ignited.IGitHubConnIgnitedProvider;
@@ -36,11 +39,16 @@ import org.apache.ignite.ci.github.pure.IGitHubConnectionProvider;
import org.apache.ignite.ci.jira.IJiraIntegration;
import org.apache.ignite.ci.observer.BuildObserver;
import org.apache.ignite.ci.tcmodel.hist.BuildRef;
+import org.apache.ignite.ci.observer.BuildsInfo;
import org.apache.ignite.ci.tcmodel.result.Build;
import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
+import org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor;
+import org.apache.ignite.ci.web.model.VisaRequest;
+import org.apache.ignite.ci.web.model.Visa;
import org.apache.ignite.ci.user.ICredentialsProv;
import org.apache.ignite.ci.web.model.SimpleResult;
+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;
@@ -66,14 +74,66 @@ public class TcBotTriggerAndSignOffService {
@Inject Provider<BuildObserver> observer;
+ /** */
+ @Inject private VisasHistoryStorage visasHistoryStorage;
+
+ /** */
+ @Inject IgniteStringCompactor strCompactor;
+
/** Helper. */
@Inject ITcHelper tcHelper;
/** */
+ SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ /** */
public void startObserver() {
buildObserverProvider.get();
}
+ /** */
+ public List<VisaStatus> getVisasStatus(String srvId, ICredentialsProv prov) {
+ List<VisaStatus> visaStatuses = new ArrayList<>();
+
+ IAnalyticsEnabledTeamcity teamcity = tcHelper.server(srvId, prov);
+
+ for (VisaRequest visaRequest : visasHistoryStorage.getVisas()) {
+ VisaStatus visaStatus = new VisaStatus();
+
+ BuildsInfo info = visaRequest.getInfo();
+
+ Visa visa = visaRequest.getResult();
+
+ visaStatus.date = formatter.format(info.date);
+ visaStatus.branchName = info.branchForTc;
+ visaStatus.userName = info.userName;
+ visaStatus.ticket = info.ticket;
+
+ if (info.isFinished(teamcity)) {
+ if (visa.isEmpty())
+ visaStatus.state = BuildsInfo.FINISHED_STATE + " [ waiting results ]";
+ else if (visa.isSuccess()) {
+ visaStatus.commentUrl = "https://issues.apache.org/jira/browse/" + visaStatus.ticket +
+ "?focusedCommentId=" + visa.getJiraCommentResponse().getId() +
+ "&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-" +
+ visa.getJiraCommentResponse().getId();
+
+ visaStatus.blockers = visa.getBlockers();
+
+ visaStatus.state = BuildsInfo.FINISHED_STATE;
+ }
+ else
+ visaStatus.state = BuildsInfo.FINISHED_WITH_FAILURES_STATE;
+ }
+ else
+ visaStatus.state = info.getState(teamcity);
+
+ visaStatuses.add(visaStatus);
+ }
+
+ return visaStatuses;
+ }
+
/**
* @param pr Pull Request.
* @return JIRA ticket full name or empty string.
@@ -94,7 +154,6 @@ public class TcBotTriggerAndSignOffService {
return ticketId;
}
-
@NotNull public String triggerBuildsAndObserve(
@Nullable String srvId,
@Nullable String branchForTc,
@@ -161,7 +220,7 @@ public class TcBotTriggerAndSignOffService {
ticketFullName = ticketFullName.toUpperCase().startsWith("IGNITE-") ? ticketFullName : "IGNITE-" + ticketFullName;
}
- buildObserverProvider.get().observe(srvId, prov, ticketFullName, builds);
+ buildObserverProvider.get().observe(srvId, prov, ticketFullName, branchForTc, builds);
if (!tcHelper.isServerAuthorized())
return "Ask server administrator to authorize the Bot to enable JIRA notifications.";
@@ -211,9 +270,14 @@ public class TcBotTriggerAndSignOffService {
}
if (!Strings.isNullOrEmpty(ticketFullName)) {
- jiraRes = jiraIntegration.notifyJira(srvId, prov, suiteId, branchForTc, ticketFullName);
+ BuildsInfo buildsInfo = new BuildsInfo(srvId, prov, ticketFullName, branchForTc);
+
+ Visa visa = jiraIntegration.notifyJira(srvId, prov, suiteId, branchForTc, ticketFullName);
+
+ visasHistoryStorage.put(new VisaRequest(buildsInfo)
+ .setResult(visa));
- return new SimpleResult(jiraRes);
+ return new SimpleResult(visa.status);
}
else
return new SimpleResult("JIRA wasn't commented." + (!jiraRes.isEmpty() ? "<br>" + jiraRes : ""));
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/tcbot/visa/VisaStatus.java
similarity index 53%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/visa/VisaStatus.java
index a20ead4..1dfe31f 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/tcbot/visa/VisaStatus.java
@@ -15,25 +15,32 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.tcbot.visa;
-import org.apache.ignite.ci.user.ICredentialsProv;
+import org.jetbrains.annotations.Nullable;
/**
*
*/
-public interface IJiraIntegration {
- /** Message to show user when JIRA ticket was successfully commented by the Bot. */
- public static String JIRA_COMMENTED = "JIRA commented.";
-
- /**
- * @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 {@code True} if JIRA was notified.
- */
- public String notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
- String ticket);
+public class VisaStatus {
+ /** */
+ @Nullable public String userName;
+
+ /** Branch name. */
+ @Nullable public String branchName;
+
+ /** JIRA ticket full name. */
+ @Nullable public String ticket;
+
+ /** */
+ @Nullable public String state;
+
+ /** */
+ @Nullable public String commentUrl;
+
+ /** */
+ @Nullable public String date;
+
+ /** */
+ public int blockers;
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/hist/BuildRef.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/hist/BuildRef.java
index 0ac3293..ee9f7e6 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/hist/BuildRef.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/hist/BuildRef.java
@@ -187,4 +187,9 @@ public class BuildRef extends AbstractRef {
public boolean isRunning() {
return STATE_RUNNING.equals(state());
}
+
+ /** */
+ public boolean isUnknown() {
+ return STATUS_UNKNOWN.equals(status());
+ }
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/CompactContributionKey.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/CompactContributionKey.java
new file mode 100644
index 0000000..2d783fd
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/CompactContributionKey.java
@@ -0,0 +1,62 @@
+/*
+ * 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.web.model;
+
+import java.util.Objects;
+import org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor;
+
+/**
+ *
+ */
+public class CompactContributionKey {
+ /** */
+ public final int srvId;
+
+ /** */
+ public final int ticket;
+
+ /** */
+ public final int branchForTc;
+
+ /** */
+ public CompactContributionKey(ContributionKey key, IgniteStringCompactor strCompactor) {
+ this.branchForTc = strCompactor.getStringId(key.branchForTc);
+ this.srvId = strCompactor.getStringId(key.srvId);
+ this.ticket = strCompactor.getStringId(key.ticket);
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean equals(Object o) {
+ if (this == o)
+ return true;
+
+ if (!(o instanceof CompactContributionKey))
+ return false;
+
+ CompactContributionKey key = (CompactContributionKey)o;
+
+ return Objects.equals(srvId, key.srvId) &&
+ Objects.equals(ticket, key.ticket) &&
+ Objects.equals(branchForTc, key.branchForTc);
+ }
+
+ /** {@inheritDoc} */
+ @Override public int hashCode() {
+ return Objects.hash(srvId, branchForTc, ticket);
+ }
+}
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/web/model/CompactVisa.java
similarity index 52%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/CompactVisa.java
index a20ead4..9d67f07 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/web/model/CompactVisa.java
@@ -15,25 +15,33 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.web.model;
-import org.apache.ignite.ci.user.ICredentialsProv;
+import org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor;
+import org.jetbrains.annotations.Nullable;
/**
*
*/
-public interface IJiraIntegration {
- /** Message to show user when JIRA ticket was successfully commented by the Bot. */
- public static String JIRA_COMMENTED = "JIRA commented.";
+public class CompactVisa {
+ /** */
+ public final int status;
- /**
- * @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 {@code True} if JIRA was notified.
- */
- public String notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
- String ticket);
+ /** */
+ @Nullable public final JiraCommentResponse jiraCommentRes;
+
+ /** */
+ public final int blockers;
+
+ /** */
+ public CompactVisa(Visa visa, IgniteStringCompactor strCompactor) {
+ this.status = strCompactor.getStringId(visa.status);
+ this.blockers = visa.blockers;
+ this.jiraCommentRes = visa.getJiraCommentResponse();
+ }
+
+ /** */
+ public Visa toVisa(IgniteStringCompactor strCompactor) {
+ return new Visa(strCompactor.getStringFromId(status), jiraCommentRes, blockers);
+ }
}
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/web/model/CompactVisaRequest.java
similarity index 51%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/CompactVisaRequest.java
index a20ead4..1fcc59f 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/web/model/CompactVisaRequest.java
@@ -15,25 +15,31 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.web.model;
-import org.apache.ignite.ci.user.ICredentialsProv;
+import org.apache.ignite.ci.observer.CompactBuildsInfo;
+import org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor;
/**
*
*/
-public interface IJiraIntegration {
- /** Message to show user when JIRA ticket was successfully commented by the Bot. */
- public static String JIRA_COMMENTED = "JIRA commented.";
-
- /**
- * @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 {@code True} if JIRA was notified.
- */
- public String notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
- String ticket);
+public class CompactVisaRequest {
+ /** */
+ public final CompactVisa compactVisa;
+
+ /** */
+ public final CompactBuildsInfo compactInfo;
+
+ /** */
+ public CompactVisaRequest(VisaRequest visaReq, IgniteStringCompactor strCompactor) {
+ compactInfo = new CompactBuildsInfo(visaReq.getInfo(), strCompactor);
+
+ compactVisa = new CompactVisa(visaReq.getResult(), strCompactor);
+ }
+
+ /** */
+ public VisaRequest toVisaRequest(IgniteStringCompactor strCompactor) {
+ return new VisaRequest(compactInfo.toBuildInfo(strCompactor)).setResult(compactVisa.toVisa(strCompactor));
+ }
+
}
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/web/model/ContributionKey.java
similarity index 53%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/ContributionKey.java
index a20ead4..fa62ea6 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/web/model/ContributionKey.java
@@ -15,25 +15,25 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
-
-import org.apache.ignite.ci.user.ICredentialsProv;
+package org.apache.ignite.ci.web.model;
/**
*
*/
-public interface IJiraIntegration {
- /** Message to show user when JIRA ticket was successfully commented by the Bot. */
- public static String JIRA_COMMENTED = "JIRA commented.";
+public class ContributionKey {
+ /** */
+ public final String srvId;
+
+ /** */
+ public final String ticket;
+
+ /** */
+ public final String branchForTc;
- /**
- * @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 {@code True} if JIRA was notified.
- */
- public String notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
- String ticket);
+ /** */
+ public ContributionKey(String srvId, String ticket, String branchForTc) {
+ this.branchForTc = branchForTc;
+ this.srvId = srvId;
+ this.ticket = ticket;
+ }
}
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/web/model/JiraCommentResponse.java
similarity index 53%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/JiraCommentResponse.java
index a20ead4..26bde0a 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/web/model/JiraCommentResponse.java
@@ -15,25 +15,20 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.web.model;
-import org.apache.ignite.ci.user.ICredentialsProv;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
*
*/
-public interface IJiraIntegration {
- /** Message to show user when JIRA ticket was successfully commented by the Bot. */
- public static String JIRA_COMMENTED = "JIRA commented.";
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class JiraCommentResponse {
+ /** */
+ private int id;
- /**
- * @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 {@code True} if JIRA was notified.
- */
- public String notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
- String ticket);
+ /** */
+ public int getId() {
+ return id;
+ }
}
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
new file mode 100644
index 0000000..4d234ba
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Visa.java
@@ -0,0 +1,84 @@
+/*
+ * 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.web.model;
+
+import org.apache.ignite.ci.jira.IJiraIntegration;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ *
+ */
+public class Visa {
+ /** */
+ public static final String EMPTY_VISA_STATUS = "emptyVisa";
+
+ /** */
+ public final String status;
+
+ /** */
+ @Nullable public final JiraCommentResponse jiraCommentRes;
+
+ /** */
+ public final int blockers;
+
+ /** */
+ public static Visa emptyVisa() {
+ return new Visa(EMPTY_VISA_STATUS);
+ }
+
+ /** */
+ public Visa(String status) {
+ this.status = status;
+ this.jiraCommentRes = null;
+ this.blockers = 0;
+ }
+
+ /** */
+ public Visa(String status, JiraCommentResponse res, Integer blockers) {
+ this.status = status;
+ this.jiraCommentRes = res;
+ this.blockers = blockers;
+ }
+
+ /** */
+ @Nullable public JiraCommentResponse getJiraCommentResponse() {
+ return jiraCommentRes;
+ }
+
+ /** */
+ @Nullable public int getBlockers() {
+ return blockers;
+ }
+
+ /** */
+ public boolean isSuccess() {
+ return IJiraIntegration.JIRA_COMMENTED.equals(status)
+ && jiraCommentRes != null;
+ }
+
+ /** */
+ public boolean isEmpty() {
+ return EMPTY_VISA_STATUS.equals(status);
+ }
+
+
+ /** */
+ @Override public String toString() {
+ return 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/web/model/VisaRequest.java
similarity index 53%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/VisaRequest.java
index a20ead4..c281a65 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/web/model/VisaRequest.java
@@ -15,25 +15,41 @@
* limitations under the License.
*/
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.web.model;
-import org.apache.ignite.ci.user.ICredentialsProv;
+import org.apache.ignite.ci.observer.BuildsInfo;
+import org.jetbrains.annotations.Nullable;
/**
*
*/
-public interface IJiraIntegration {
- /** Message to show user when JIRA ticket was successfully commented by the Bot. */
- public static String JIRA_COMMENTED = "JIRA commented.";
-
- /**
- * @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 {@code True} if JIRA was notified.
- */
- public String notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc,
- String ticket);
+public class VisaRequest {
+ /** */
+ private BuildsInfo info;
+
+ /** */
+ private Visa visa;
+
+ /** */
+ public VisaRequest(BuildsInfo info) {
+ this.info = info;
+ this.visa = Visa.emptyVisa();
+ }
+
+ /** */
+ @Nullable public BuildsInfo getInfo() {
+ return info;
+ }
+
+ /** */
+ @Nullable public Visa getResult() {
+ return visa;
+ }
+
+ /** */
+ public VisaRequest setResult(Visa res) {
+ this.visa = res;
+
+ return this;
+ }
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/VisasHistoryStorage.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/VisasHistoryStorage.java
new file mode 100644
index 0000000..842d86d
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/hist/VisasHistoryStorage.java
@@ -0,0 +1,118 @@
+/*
+ * 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.web.model.hist;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import javax.cache.Cache;
+import javax.inject.Inject;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.ci.db.TcHelperDb;
+import org.apache.ignite.ci.teamcity.ignited.IgniteStringCompactor;
+import org.apache.ignite.ci.web.model.CompactContributionKey;
+import org.apache.ignite.ci.web.model.CompactVisaRequest;
+import org.apache.ignite.ci.web.model.ContributionKey;
+import org.apache.ignite.ci.web.model.Visa;
+import org.apache.ignite.ci.web.model.VisaRequest;
+
+/**
+ *
+ */
+public class VisasHistoryStorage {
+ /** */
+ private static final String VISAS_CACHE_NAME = "visasCompactCache";
+
+ /** */
+ @Inject
+ private IgniteStringCompactor strCompactor;
+
+ /** */
+ @Inject
+ private Ignite ignite;
+
+ /** */
+ public void clear() {
+ visas().clear();
+ }
+
+ /** */
+ private Cache<CompactContributionKey, Map<Date, CompactVisaRequest>> visas() {
+ return ignite.getOrCreateCache(TcHelperDb.getCacheV2TxConfig(VISAS_CACHE_NAME));
+ }
+
+ /** */
+ public void put(VisaRequest visaReq) {
+ CompactVisaRequest compactVisaReq = new CompactVisaRequest(visaReq, strCompactor);
+
+ CompactContributionKey key = new CompactContributionKey(new ContributionKey(
+ visaReq.getInfo().srvId,
+ visaReq.getInfo().ticket,
+ visaReq.getInfo().branchForTc), strCompactor);
+
+ Map<Date, CompactVisaRequest> contributionVisas = visas().get(key);
+
+ if (contributionVisas == null)
+ contributionVisas = new HashMap<>();
+
+ contributionVisas.put(compactVisaReq.compactInfo.date, compactVisaReq);
+
+ visas().put(key, contributionVisas);
+ }
+
+ /** */
+ public VisaRequest getVisaReq(ContributionKey key, Date date) {
+ Map<Date, CompactVisaRequest> reqs = visas().get(new CompactContributionKey(key, strCompactor));
+
+ if (Objects.isNull(reqs))
+ return null;
+
+ return reqs.get(date).toVisaRequest(strCompactor);
+ }
+
+ /** */
+ public boolean updateVisaRequestRes(ContributionKey key, Date date, Visa visa) {
+ VisaRequest req = getVisaReq(key, date);
+
+ if (req == null)
+ return false;
+
+ req.setResult(visa);
+
+ put(req);
+
+ return true;
+ }
+
+ /** */
+ public Collection<VisaRequest> getVisas() {
+ List<VisaRequest> res = new ArrayList<>();
+
+ visas().forEach(entry -> res.addAll(entry.getValue().values().stream()
+ .map(v -> v.toVisaRequest(strCompactor))
+ .collect(Collectors.toList())));
+
+ return Collections.unmodifiableCollection(res);
+ }
+}
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 5bc1cbf..5b52dfa 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
@@ -16,6 +16,7 @@
*/
package org.apache.ignite.ci.web.rest.visa;
+import java.util.Collection;
import java.util.List;
import javax.annotation.Nonnull;
import javax.servlet.ServletContext;
@@ -27,11 +28,11 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import org.apache.ignite.ci.tcbot.visa.ContributionCheckStatus;
-import org.apache.ignite.ci.user.ICredentialsProv;
import org.apache.ignite.ci.tcbot.visa.ContributionToCheck;
import org.apache.ignite.ci.tcbot.visa.TcBotTriggerAndSignOffService;
+import org.apache.ignite.ci.tcbot.visa.VisaStatus;
+import org.apache.ignite.ci.user.ICredentialsProv;
import org.apache.ignite.ci.web.CtxListener;
-import org.apache.ignite.ci.web.model.SimpleResult;
import org.apache.ignite.ci.web.rest.exception.ServiceUnauthorizedException;
import org.jetbrains.annotations.Nullable;
@@ -50,6 +51,17 @@ public class TcBotVisaService {
* @param srvId Server id.
*/
@GET
+ @Path("history")
+ public Collection<VisaStatus> history(@Nullable @QueryParam("serverId") String srvId) {
+ return CtxListener.getInjector(ctx)
+ .getInstance(TcBotTriggerAndSignOffService.class)
+ .getVisasStatus(srvId, ICredentialsProv.get(req));
+ }
+
+ /**
+ * @param srvId Server id.
+ */
+ @GET
@Path("contributions")
public List<ContributionToCheck> contributions(@Nullable @QueryParam("serverId") String srvId) {
if (!ICredentialsProv.get(req).hasAccess(srvId))
diff --git a/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js b/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
index 5ca9a34..3b5a72c 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
@@ -132,7 +132,8 @@ function showMenu(menuData) {
res += "<a href=\"/comparison.html\">Master Trends</a>";
res += "<a href=\"/compare.html\">Compare builds</a>";
res += "<a href=\"/issues.html\">Issues history</a>";
- //uncomment when Visa history is merged: res += "<a href=\"/visas.html\">Visas history</a>";
+ //uncomment when Visa history is merged:
+ res += "<a href=\"/visas.html\">Visas history</a>";
res += "<div class='topnav-right'>";
diff --git a/ignite-tc-helper-web/src/main/webapp/visas.html b/ignite-tc-helper-web/src/main/webapp/visas.html
new file mode 100644
index 0000000..87c1864
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/webapp/visas.html
@@ -0,0 +1,150 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8">
+ <title>Ignite Teamcity - Visas history</title>
+ <link rel="icon" href="img/leaf-icon-png-7066.png">
+ <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
+ <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
+ <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
+ <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
+ <link rel="stylesheet" href="css/style-1.5.css">
+ <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
+ <script src="js/common-1.6.js"></script>
+ <script src="https://d3js.org/d3.v4.min.js"></script>
+ <script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.js"></script>
+ <script src="https://cdn.datatables.net/1.10.16/js/dataTables.jqueryui.js"></script>
+ <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
+ <link rel="stylesheet" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css">
+ </head>
+<body>
+ <br>
+ <div id="loadStatus"></div>
+ <br>
+ <table id="visasTable" class="cell-border" style="width:100%">
+ <thead>
+ <tr class="ui-widget-header ">
+ <th>.</th>
+ <th>.</th>
+ <th>.</th>
+ <th>.</th>
+ <th>.</th>
+ <th>.</th>
+ </tr>
+ </thead>
+ </table>
+ <br>
+ <div id="version"></div>
+<script>
+function showErrInLoadStatus(jqXHR, exception) {
+ if (jqXHR.status === 0) {
+ $("#loadStatus").html('Not connect.\n Verify Network.');
+ } else if (jqXHR.status === 404) {
+ $("#loadStatus").html('Requested page not found. [404]');
+ } else if (jqXHR.status === 401) {
+ $("#loadStatus").html('Unauthorized [401]');
+
+ setTimeout(function() {
+ window.location.href = "/login.html" + "?backref=" + encodeURIComponent(window.location.href);
+ }, 1000);
+ } else if (jqXHR.status === 403) {
+ $("#loadStatus").html('Forbidden [403]');
+ } else if( jqXHR.status === 418) {
+ $("#loadStatus").html('Services are starting [418], I\'m a teapot');
+ } else if (jqXHR.status === 424) {
+ $("#loadStatus").html('Dependency problem: [424]: ' + jqXHR.responseText);
+ } else if (jqXHR.status === 500) {
+ $("#loadStatus").html('Internal Server Error [500].');
+ } else if (exception === 'parsererror') {
+ $("#loadStatus").html('Requested JSON parse failed.');
+ } else if (exception === 'timeout') {
+ $("#loadStatus").html('Time out error.');
+ } else if (exception === 'abort') {
+ $("#loadStatus").html('Ajax request aborted.');
+ } else {
+ $("#loadStatus").html('Uncaught Error.\n' + jqXHR.responseText);
+ }
+}
+
+$(document).ready(function() {
+ loadData();
+
+ $.ajax({ url: "rest/branches/version", success: showVersionInfo, error: showErrInLoadStatus });
+});
+
+function showVisasTable(result) {
+ let visasTable = $('#visasTable');
+
+ visasTable.dataTable().fnDestroy();
+
+ var table = visasTable.DataTable({
+ "order": [[ 1, 'desc' ]],
+ data: result,
+ "iDisplayLength": 30, //rows to be shown by default
+ stateSave: true,
+ columnDefs: [
+ {
+ targets: '_all',
+ className: 'dt-body-center'
+ },
+ ],
+ columns: [
+ {
+ "data": "state",
+ title: "Status",
+ "render": function (data, type, row, meta) {
+ if (type === 'display') {
+ if (data ==='finished' && row.commentUrl)
+ data = "<a href='" + row.commentUrl + "'>" + data + "</a>";
+ }
+
+ return data;
+ }
+ },
+ {
+ "data": "date",
+ title: "Date"
+ },
+ {
+ "data": "userName",
+ title: "User"
+ },
+ {
+ "data": "branchName",
+ title: "Branch"
+ },
+ {
+ "data": "ticket",
+ title: "Ticket"
+ },
+ {
+ "data": "blockers",
+ title: "Blockers",
+ "render": function (data, type, row, meta) {
+ if (type === 'display') {
+ if (row.state != 'finished')
+ data = "";
+ }
+
+ return data;
+ }
+ }
+
+ ]
+ });
+}
+
+function loadData() {
+ $.ajax({
+ url: "rest/visa/history?serverId=apache",
+ success: function (result) {
+ showVisasTable(result);
+ },
+ error: showErrInLoadStatus
+ }
+ );
+}
+</script>
+</body>
+</html>