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 15bb973  IGNITE-10436 Add ticket and PR links on report TC Bot page. - 
Fixes #85.
15bb973 is described below

commit 15bb973bb5084b5c7cbf90bfbcb71d07f25e29b3
Author: ololo3000 <[email protected]>
AuthorDate: Mon Dec 3 18:52:52 2018 +0300

    IGNITE-10436 Add ticket and PR links on report TC Bot page. - Fixes #85.
    
    Signed-off-by: Dmitriy Pavlov <[email protected]>
---
 conf/apache.auth.properties                        |  1 +
 .../java/org/apache/ignite/ci/HelperConfig.java    |  3 +
 .../main/java/org/apache/ignite/ci/TcHelper.java   |  4 +-
 .../org/apache/ignite/ci/di/IgniteTcBotModule.java | 19 +-----
 .../ci/github/ignited/GitHubConnIgnitedImpl.java   |  8 +++
 .../ci/github/ignited/IGitHubConnIgnited.java      | 18 +++++
 .../ci/github/pure/GitHubConnectionImpl.java       | 24 ++-----
 .../ignite/ci/github/pure/IGitHubConnection.java   | 30 +++++++++
 .../apache/ignite/ci/jira/IJiraIntegration.java    | 12 ++++
 .../IJiraIntegrationProvider.java}                 | 10 ++-
 .../main/java/org/apache/ignite/ci/jira/Jira.java  | 77 ++++++++++++++++++++++
 .../JiraIntegrationModule.java}                    | 18 ++---
 .../ignite/ci/jira/JiraIntegrationProvider.java    | 59 +++++++++++++++++
 .../apache/ignite/ci/observer/ObserverTask.java    |  7 +-
 .../ignite/ci/tcbot/chain/PrChainsProcessor.java   | 16 +++++
 .../ignite/ci/tcbot/visa/ContributionToCheck.java  |  3 +
 .../tcbot/visa/TcBotTriggerAndSignOffService.java  | 19 ++++--
 .../model/current/ChainAtServerCurrentStatus.java  | 56 ++++++++++++++++
 ignite-tc-helper-web/src/main/webapp/js/prs-1.0.js | 10 ++-
 .../src/main/webapp/js/testfails-2.1.js            | 77 ++++++++++++++--------
 .../ci/tcbot/chain/PrChainsProcessorTest.java      | 25 +++++++
 21 files changed, 409 insertions(+), 87 deletions(-)

diff --git a/conf/apache.auth.properties b/conf/apache.auth.properties
index da84ef6..a022bf7 100644
--- a/conf/apache.auth.properties
+++ b/conf/apache.auth.properties
@@ -5,6 +5,7 @@ logs=apache_logs
 git.api_url=https://api.github.com/repos/apache/ignite/
 jira.api_url=https://issues.apache.org/jira/rest/api/2/
 
+jira.url=https://issues.apache.org/jira/
 
 #specify JIRA Auth token (if needed)
 jira.auth_token=
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 0b6b0a8..741d958 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
@@ -60,6 +60,9 @@ public class HelperConfig {
     /** JIRA authorization token property name. */
     public static final String JIRA_API_URL = "jira.api_url";
 
+    /** JIRA URL to build links to tickets. */
+    public static final String JIRA_URL = "jira.url";
+
     /** Slack authorization token property name. */
     public static final String SLACK_AUTH_TOKEN = "slack.auth_token";
     public static final String SLACK_CHANNEL = "slack.channel";
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 9832d2a..eb66f30 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
@@ -53,7 +53,7 @@ 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, IJiraIntegration {
+public class TcHelper implements ITcHelper {
     /** Logger. */
     private static final Logger logger = 
LoggerFactory.getLogger(TcHelper.class);
 
@@ -199,7 +199,7 @@ public class TcHelper implements ITcHelper, 
IJiraIntegration {
             return new Visa("JIRA wasn't commented - " + errMsg);
         }
 
-        return new Visa(JIRA_COMMENTED, res, blockers);
+        return new Visa(IJiraIntegration.JIRA_COMMENTED, res, blockers);
     }
 
 
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 e61e2bd..d714b99 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
@@ -24,7 +24,6 @@ import com.google.inject.matcher.Matchers;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import javax.inject.Inject;
 import javax.inject.Provider;
 import org.apache.ignite.Ignite;
 import org.apache.ignite.ci.ITcHelper;
@@ -34,16 +33,14 @@ 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.issue.IssueDetector;
-import org.apache.ignite.ci.jira.IJiraIntegration;
+import org.apache.ignite.ci.jira.JiraIntegrationModule;
 import org.apache.ignite.ci.observer.BuildObserver;
 import org.apache.ignite.ci.observer.ObserverTask;
 import org.apache.ignite.ci.tcbot.trends.MasterTrendsService;
 import org.apache.ignite.ci.teamcity.ignited.TeamcityIgnitedModule;
-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.model.hist.VisasHistoryStorage;
 import org.apache.ignite.ci.web.rest.exception.ServiceStartingException;
 
@@ -80,27 +77,15 @@ public class IgniteTcBotModule extends AbstractModule {
         bind(BuildObserver.class).in(new SingletonScope());
         bind(VisasHistoryStorage.class).in(new SingletonScope());
         bind(ITcHelper.class).to(TcHelper.class).in(new SingletonScope());
-
-        bind(IJiraIntegration.class).to(Jira.class).in(new SingletonScope());
-
         bind(BackgroundUpdater.class).in(new SingletonScope());
         bind(MasterTrendsService.class).in(new SingletonScope());
 
         install(new TeamcityIgnitedModule());
+        install(new JiraIntegrationModule());
         install(new GitHubIgnitedModule());
         install(new SchedulerModule());
     }
 
-    //todo now it is just fallback to TC big class, extract JIRA integation 
module
-    private static class Jira implements IJiraIntegration {
-        @Inject ITcHelper helper;
-
-        @Override public Visa notifyJira(String srvId, ICredentialsProv prov, 
String buildTypeId, String branchForTc,
-            String ticket) {
-            return helper.notifyJira(srvId, prov, buildTypeId, branchForTc, 
ticket);
-        }
-    }
-
     private void configProfiling() {
         AutoProfilingInterceptor profilingInterceptor = new 
AutoProfilingInterceptor();
 
diff --git 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/GitHubConnIgnitedImpl.java
 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/GitHubConnIgnitedImpl.java
index 799a769..29a85a1 100644
--- 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/GitHubConnIgnitedImpl.java
+++ 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/GitHubConnIgnitedImpl.java
@@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
+import javax.annotation.Nullable;
 import javax.inject.Inject;
 import javax.inject.Provider;
 import org.apache.ignite.Ignite;
@@ -72,6 +73,13 @@ class GitHubConnIgnitedImpl implements IGitHubConnIgnited {
 
     /** {@inheritDoc} */
     @AutoProfiling
+    @Nullable
+    @Override public PullRequest getPullRequest(int prNum) {
+        return prCache.get(prNumberToCacheKey(prNum));
+    }
+
+    /** {@inheritDoc} */
+    @AutoProfiling
     @Override public List<PullRequest> getPullRequests() {
         scheduler.sheduleNamed(IGitHubConnIgnited.class.getSimpleName() + 
".actualizePrs",
             this::actualizePrs, 2, TimeUnit.MINUTES);
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 31dd8f7..d532589 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
@@ -16,8 +16,12 @@
  */
 package org.apache.ignite.ci.github.ignited;
 
+import com.google.common.base.Preconditions;
 import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.ignite.ci.di.AutoProfiling;
 import org.apache.ignite.ci.github.PullRequest;
+import org.apache.ignite.ci.github.pure.IGitHubConnection;
 
 /**
  *
@@ -27,4 +31,18 @@ public interface IGitHubConnIgnited {
      * @return list of open pull requests
      */
     public List<PullRequest> getPullRequests();
+
+    /** */
+    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);
+    }
 }
diff --git 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/pure/GitHubConnectionImpl.java
 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/pure/GitHubConnectionImpl.java
index 72a0921..60aa34f 100644
--- 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/pure/GitHubConnectionImpl.java
+++ 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/pure/GitHubConnectionImpl.java
@@ -92,24 +92,6 @@ class GitHubConnectionImpl implements IGitHubConnection {
         gitApiUrl = (props.getProperty(HelperConfig.GIT_API_URL));
     }
 
-    /** */
-    private Integer convertBranchToId(String branchForTc) {
-        String id = null;
-
-        // Get PR id from string "pull/XXXX/head"
-        for (int i = 5; i < branchForTc.length(); i++) {
-            char c = branchForTc.charAt(i);
-
-            if (!Character.isDigit(c)) {
-                id = branchForTc.substring(5, i);
-
-                break;
-            }
-        }
-
-        return Integer.parseInt(id);
-    }
-
     /** {@inheritDoc} */
     @AutoProfiling
     @Override public PullRequest getPullRequest(Integer id) {
@@ -130,7 +112,11 @@ class GitHubConnectionImpl implements IGitHubConnection {
     /** {@inheritDoc} */
     @AutoProfiling
     @Override public PullRequest getPullRequest(String branchForTc) {
-        return getPullRequest(convertBranchToId(branchForTc));
+        Integer prId = IGitHubConnection.convertBranchToId(branchForTc);
+
+        Preconditions.checkNotNull(prId, "Invalid TC branch name");
+
+        return getPullRequest(prId);
     }
 
     /** {@inheritDoc} */
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 dba5c2f..03c3c82 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
@@ -17,6 +17,7 @@
 package org.apache.ignite.ci.github.pure;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 import org.apache.ignite.ci.github.PullRequest;
 import org.jetbrains.annotations.Nullable;
@@ -54,4 +55,33 @@ public interface IGitHubConnection {
     String gitApiUrl();
 
     List<PullRequest> getPullRequests(@Nullable String fullUrl, @Nullable 
AtomicReference<String> outLinkNext);
+
+    /**
+     * @return PR id from string "pull/XXXX/head"
+     */
+    public @Nullable static Integer convertBranchToId(String branchForTc) {
+        Integer res = null;
+
+        if (Objects.isNull(branchForTc))
+            return res;
+
+        String id = null;
+
+        for (int i = 5; i < branchForTc.length(); i++) {
+            char c = branchForTc.charAt(i);
+
+            if (!Character.isDigit(c)) {
+                id = branchForTc.substring(5, i);
+
+                break;
+            }
+        }
+
+        try {
+            res = Integer.parseInt(id);
+        }
+        finally {
+            return res;
+        }
+    }
 }
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 aa1084c..f7f34e1 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
@@ -37,4 +37,16 @@ public interface IJiraIntegration {
      */
     public Visa notifyJira(String srvId, ICredentialsProv prov, String 
buildTypeId, String branchForTc,
         String ticket);
+
+    /** */
+    public String jiraUrl();
+
+    /** */
+    public void init(String srvId);
+
+    /** */
+    public String generateTicketUrl(String ticketFullName);
+
+    /** */
+    public String generateCommentUrl(String ticketFullName, int commentId);
 }
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/jira/IJiraIntegrationProvider.java
similarity index 77%
copy from 
ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/IGitHubConnIgnited.java
copy to 
ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegrationProvider.java
index 31dd8f7..095379b 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/jira/IJiraIntegrationProvider.java
@@ -14,17 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.ignite.ci.github.ignited;
 
-import java.util.List;
-import org.apache.ignite.ci.github.PullRequest;
+package org.apache.ignite.ci.jira;
 
 /**
  *
  */
-public interface IGitHubConnIgnited {
+public interface IJiraIntegrationProvider {
     /**
-     * @return list of open pull requests
+     * @param srvId Server id.
      */
-    public List<PullRequest> getPullRequests();
+    public IJiraIntegration server(String srvId);
 }
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/Jira.java
new file mode 100644
index 0000000..b23d840
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Jira.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import com.google.common.base.Preconditions;
+import java.io.File;
+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 static com.google.common.base.Strings.isNullOrEmpty;
+
+/**
+ *
+ */
+public class Jira implements IJiraIntegration {
+    /** */
+    @Inject ITcHelper helper;
+
+    /** */
+    private String jiraUrl;
+
+    /** {@inheritDoc} */
+    @Override public void init(String srvId) {
+        final File workDir = HelperConfig.resolveWorkDir();
+
+        final String cfgName = HelperConfig.prepareConfigName(srvId);
+
+        final Properties props = HelperConfig.loadAuthProperties(workDir, 
cfgName);
+
+        jiraUrl = props.getProperty(HelperConfig.JIRA_URL);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String jiraUrl() {
+        return jiraUrl;
+    }
+
+    /** {@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 String generateTicketUrl(String ticketFullName) {
+        Preconditions.checkState(!isNullOrEmpty(jiraUrl), "Jira URL is not 
configured for this server.");
+
+        return jiraUrl + "browse/" + ticketFullName;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String generateCommentUrl(String ticketFullName, int 
commentId) {
+        return generateTicketUrl(ticketFullName) +
+            "?focusedCommentId=" + commentId +
+            
"&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-"
 +
+            commentId;
+    }
+}
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/jira/JiraIntegrationModule.java
similarity index 66%
copy from 
ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/ignited/IGitHubConnIgnited.java
copy to 
ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationModule.java
index 31dd8f7..a4b6bfc 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/jira/JiraIntegrationModule.java
@@ -14,17 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.ignite.ci.github.ignited;
 
-import java.util.List;
-import org.apache.ignite.ci.github.PullRequest;
+package org.apache.ignite.ci.jira;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.internal.SingletonScope;
 
 /**
  *
  */
-public interface IGitHubConnIgnited {
-    /**
-     * @return list of open pull requests
-     */
-    public List<PullRequest> getPullRequests();
+public class JiraIntegrationModule extends AbstractModule {
+    /** {@inheritDoc} */
+    @Override protected void configure() {
+        bind(IJiraIntegration.class).to(Jira.class);
+        
bind(IJiraIntegrationProvider.class).to(JiraIntegrationProvider.class).in(new 
SingletonScope());
+    }
 }
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/JiraIntegrationProvider.java
new file mode 100644
index 0000000..b841df3
--- /dev/null
+++ 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/JiraIntegrationProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+import com.google.common.base.Strings;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.inject.Provider;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import javax.inject.Inject;
+import org.apache.ignite.ci.util.ExceptionUtil;
+
+/**
+ *
+ */
+public class JiraIntegrationProvider implements IJiraIntegrationProvider {
+    /** */
+    @Inject Provider<IJiraIntegration> factory;
+
+    /** */
+    private final Cache<String, IJiraIntegration> srvs
+        = CacheBuilder.newBuilder()
+        .maximumSize(100)
+        .expireAfterAccess(16, TimeUnit.MINUTES)
+        .softValues()
+        .build();
+
+    /** */
+    @Override public IJiraIntegration server(String srvId) {
+        try {
+            return srvs.get(Strings.nullToEmpty(srvId), () -> {
+                IJiraIntegration jiraIntegration = factory.get();
+
+                jiraIntegration.init(srvId);
+
+                return jiraIntegration;
+            });
+        }
+        catch (ExecutionException e) {
+            throw ExceptionUtil.propagateException(e);
+        }
+    }
+}
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 1d9ed43..41e19f0 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
@@ -32,6 +32,7 @@ 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.user.ICredentialsProv;
 import org.apache.ignite.ci.web.model.ContributionKey;
 import org.apache.ignite.ci.web.model.Visa;
@@ -51,8 +52,8 @@ public class ObserverTask extends TimerTask {
     /** Helper. */
     @Inject private ITcHelper tcHelper;
 
-    /** Helper. */
-    @Inject private IJiraIntegration jiraIntegration;
+    /** */
+    @Inject private IJiraIntegrationProvider jiraIntegrationProvider;
 
     /** */
     @Inject private VisasHistoryStorage visasHistStorage;
@@ -170,6 +171,8 @@ 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,
                         info.branchForTc, info.ticket);
 
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 d5e36db..4ab79b7 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
@@ -22,6 +22,10 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 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.tcmodel.result.problems.ProblemOccurrence;
 import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
 import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnitedProvider;
@@ -62,6 +66,12 @@ public class PrChainsProcessor {
     /** Git hub connection provider. */
     @Inject IGitHubConnectionProvider gitHubConnProvider;
 
+    /** */
+    @Inject IGitHubConnIgnitedProvider gitHubConnIgnitedProvider;
+
+    /** */
+    @Inject IJiraIntegrationProvider jiraIntegrationProvider;
+
     /**
      * @param creds Credentials.
      * @param srvId Server id.
@@ -94,6 +104,10 @@ public class PrChainsProcessor {
 
         IGitHubConnection gitHubConn = gitHubConnProvider.server(srvId);
 
+        IGitHubConnIgnited gitHubConnIgnited = 
gitHubConnIgnitedProvider.server(srvId);
+
+        IJiraIntegration jiraIntegration = 
jiraIntegrationProvider.server(srvId);
+
         res.setJavaFlags(teamcity, gitHubConn);
 
         LatestRebuildMode rebuild;
@@ -145,6 +159,8 @@ public class PrChainsProcessor {
 
             //fail rate reference is always default (master)
             chainStatus.initFromContext(tcIgnited, teamcity, ctx, teamcity, 
baseBranch);
+
+            chainStatus.initJiraAndGitInfo(jiraIntegration, gitHubConnIgnited);
         }
 
         res.addChainOnServer(chainStatus);
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 cd265d3..1a2a308 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
@@ -43,4 +43,7 @@ package org.apache.ignite.ci.tcbot.visa;
 
     /** Pr time update. */
     public String prTimeUpdate;
+
+    /** JIRA ticket url */
+    public String jiraIssueUrl;
 }
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 bd3d77b..bbec0a3 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
@@ -40,6 +40,7 @@ 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.observer.BuildObserver;
 import org.apache.ignite.ci.observer.BuildsInfo;
 import org.apache.ignite.ci.tcbot.chain.PrChainsProcessor;
@@ -87,7 +88,8 @@ public class TcBotTriggerAndSignOffService {
 
     @Inject ITeamcityIgnitedProvider tcIgnitedProv;
 
-    @Inject IJiraIntegration jiraIntegration;
+    /** */
+    @Inject IJiraIntegrationProvider jiraIntegrationProvider;
 
     @Inject ITeamcityIgnitedProvider teamcityIgnitedProvider;
 
@@ -117,6 +119,8 @@ public class TcBotTriggerAndSignOffService {
         IAnalyticsEnabledTeamcity teamcity = tcHelper.server(srvId, prov);
         ITeamcityIgnited ignited = tcIgnitedProv.server(srvId, prov);
 
+        IJiraIntegration jiraIntegration = 
jiraIntegrationProvider.server(srvId);
+
         for (VisaRequest visaRequest : visasHistoryStorage.getVisas()) {
             VisaStatus visaStatus = new VisaStatus();
 
@@ -139,10 +143,8 @@ public class TcBotTriggerAndSignOffService {
 
             if (FINISHED_STATUS.equals(buildsStatus)) {
                 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.commentUrl = jiraIntegration.generateCommentUrl(
+                        visaStatus.ticket, 
visa.getJiraCommentResponse().getId());
 
                     visaStatus.blockers = visa.getBlockers();
 
@@ -312,6 +314,8 @@ public class TcBotTriggerAndSignOffService {
                     " \"Re-run possible blockers & Comment JIRA\" was 
triggered for current branch." +
                     " Wait for the end or cancel exsiting observing.");
 
+            IJiraIntegration jiraIntegration = 
jiraIntegrationProvider.server(srvId);
+
             Visa visa = jiraIntegration.notifyJira(srvId, prov, suiteId, 
branchForTc, ticketFullName);
 
             visasHistoryStorage.put(new VisaRequest(buildsInfo)
@@ -327,6 +331,8 @@ public class TcBotTriggerAndSignOffService {
      * @param srvId Server id.
      */
     public List<ContributionToCheck> getContributionsToCheck(String srvId) {
+        IJiraIntegration jiraIntegration = 
jiraIntegrationProvider.server(srvId);
+
         List<PullRequest> requests = 
gitHubConnIgnitedProvider.server(srvId).getPullRequests();
         if (requests == null)
             return null;
@@ -346,6 +352,9 @@ public class TcBotTriggerAndSignOffService {
 
             check.jiraIssueId = Strings.emptyToNull(getTicketFullName(pr));
 
+            if (!Strings.isNullOrEmpty(check.jiraIssueId))
+                check.jiraIssueUrl = 
jiraIntegration.generateTicketUrl(check.jiraIssueId);
+
             return check;
         }).collect(Collectors.toList());
     }
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 975d8f6..bc8486a 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
@@ -30,6 +30,11 @@ import org.apache.ignite.ci.ITeamcity;
 import org.apache.ignite.ci.analysis.FullChainRunCtx;
 import org.apache.ignite.ci.analysis.IMultTestOccurrence;
 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.tcbot.visa.TcBotTriggerAndSignOffService;
 import org.apache.ignite.ci.tcmodel.conf.BuildType;
 import org.apache.ignite.ci.analysis.TestInBranch;
 import org.apache.ignite.ci.teamcity.ignited.IRunHistory;
@@ -64,6 +69,18 @@ public class ChainAtServerCurrentStatus {
     /** Web Href. to suite particular run */
     public String webToBuild = "";
 
+    /** Filled only for compare page (e.g. pr.html). */
+    public String ticketFullName;
+
+    /** */
+    public String webToTicket;
+
+    /** */
+    public Integer prNum;
+
+    /** */
+    public String webToPr;
+
     /** Suites involved in chain. */
     public List<SuiteCurrentStatus> suites = new ArrayList<>();
 
@@ -96,6 +113,45 @@ public class ChainAtServerCurrentStatus {
         this.branchName = branchTc;
     }
 
+    /** */
+    public void setJiraTicketInfo(@Nullable String ticketFullName, @Nullable 
String webToTicket) {
+        this.ticketFullName = ticketFullName;
+        this.webToTicket = webToTicket;
+    }
+
+    /** */
+    public void setPrInfo(@Nullable Integer prNum, @Nullable String webToPr) {
+        this.prNum = prNum;
+        this.webToPr = webToPr;
+    }
+
+    /** */
+    public void initJiraAndGitInfo(IJiraIntegration jiraIntegration, 
IGitHubConnIgnited gitHubConnIgnited) {
+        Integer prNum = IGitHubConnection.convertBranchToId(branchName);
+
+        String prUrl = null;
+
+        String ticketFullName = null;
+
+        String ticketUrl = null;
+
+        if (prNum != null) {
+            PullRequest pullReq = gitHubConnIgnited.getPullRequest(prNum);
+
+            if (pullReq != null && pullReq.getTitle() != null) {
+                prUrl = pullReq.htmlUrl();
+
+                ticketFullName = 
TcBotTriggerAndSignOffService.getTicketFullName(pullReq);
+
+                if (!ticketFullName.isEmpty())
+                    ticketUrl = 
jiraIntegration.generateTicketUrl(ticketFullName);
+            }
+        }
+
+        setPrInfo(prNum, prUrl);
+        setJiraTicketInfo(ticketFullName, ticketUrl);
+    }
+
     public void initFromContext(ITeamcityIgnited tcIgnited,
                                 @Deprecated ITeamcity teamcity,
                                 FullChainRunCtx ctx,
diff --git a/ignite-tc-helper-web/src/main/webapp/js/prs-1.0.js 
b/ignite-tc-helper-web/src/main/webapp/js/prs-1.0.js
index c7014cf..8833ba2 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/prs-1.0.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/prs-1.0.js
@@ -128,7 +128,15 @@ function showContributionsTable(result, srvId, suiteId) {
             },
             {
                 "data": "jiraIssueId",
-                title: "JIRA Issue"
+                title: "JIRA Issue",
+                "render": function (data, type, row, meta) {
+                    if (type === 'display') {
+                        if (data != null && row.jiraIssueUrl != null)
+                            data = "<a href='" + row.jiraIssueUrl + "'>" + 
data + "</a>";
+                    }
+
+                    return data;
+                }
             },
             {
                 "data": "tcBranchName",
diff --git a/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js 
b/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js
index 770e457..10b0189 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/testfails-2.1.js
@@ -59,21 +59,8 @@ function showChainResultsWithSettings(result, settings) {
     } else
         res += " is absent";
 
-    let suiteId;
-
-    if (isDefinedAndFilled(findGetParameter("suiteId"))) {
-        suiteId = findGetParameter("suiteId");
-    } else if (isDefinedAndFilled(result.servers[0])) {
-        let url = new URL(result.servers[0].webToHist);
-
-        suiteId = url.searchParams.get("buildTypeId");
-    }
-
-    if (isDefinedAndFilled(suiteId))
-        res += " | Suite: <b>" + suiteId + "</b>";
-
     res += "</td></tr>";
-    res += "</table>";
+    res += "</table></br>";
 
     for (var i = 0; i < result.servers.length; i++) {
         var server = result.servers[i];
@@ -99,26 +86,62 @@ function showChainCurrentStatusData(server, settings) {
 
     var res = "";
 
-    res += "<table border='0px'>";
-    res += "<tr bgcolor='#F5F5FF'><td colspan='3'><b><a href='" + 
server.webToHist + "'>";
+    res += "<table style='width: 100%;' border='0px'>";
+    res += "<tr bgcolor='#F5F5FF'><td colspan='3' width='75%'>";
+    res += "<table style='width: 40%'>";
+    res += "<tr><td><b> Server: </b></td><td>[" + server.serverId + 
"]</td></tr>";
+
+    if (isDefinedAndFilled(server.prNum)) {
+        res += "<tr><td><b> PR: </b></td><td>";
+
+        if (isDefinedAndFilled(server.webToPr))
+            res += "<a href='" + server.webToPr + "'>[#" + server.prNum + 
"]</a>";
+        else
+            res += "[#" + server.prNum + "]";
+
+        res += "</td></tr>";
+    }
+
+    if (isDefinedAndFilled(server.webToTicket) && 
isDefinedAndFilled(server.ticketFullName)) {
+        res += "<tr><td><b> Ticket: </b></td><td>";
+        res += "<a href='" + server.webToTicket + "'>[" + 
server.ticketFullName + "]</a>";
+        res += "</td></tr>";
+    }
+
+    let suiteName;
+
+    if (isDefinedAndFilled(findGetParameter("suiteId"))) {
+        suiteName = findGetParameter("suiteId");
+    } else if (isDefinedAndFilled(server)) {
+        let url = new URL(server.webToHist);
+
+        suiteName = url.searchParams.get("buildTypeId");
+    }
+
+    if (isDefinedAndFilled(suiteName)) {
+        res += "<tr><td><b> Suite: </b></td><td>[" + suiteName + "] ";
+        res += " <a href='" + server.webToHist + "'>[TC history]</a>";
+        res += "</td></tr>";
+    }
+
+    res += "</table>";
+    res += "</br>";
 
     if (isDefinedAndFilled(server.chainName)) {
         res += server.chainName + " ";
     }
-    res += server.serverId;
 
-    res += "</a> ";
-    res += "[";
-    res += " <a href='" + server.webToBuild + "' title=''>";
-    res += "tests " + server.failedTests + " suites " + server.failedToFinish 
+ "";
-    res += " </a>";
-    res += "] ";
-    res += "[";
+    res += "<b>Chain result: </b>";
+
+    if (isDefinedAndFilled(server.failedToFinish) && 
isDefinedAndFilled(server.failedTests))
+        res += server.failedToFinish + " suites and " + server.failedTests + " 
tests failed";
+    else
+        res += "empty";
+
+    res += " ";
     res += "<a href='longRunningTestsReport.html'>";
-    res += "long running tests report";
+    res += "Long running tests report";
     res += "</a>";
-    res += "]";
-    res += "</b>";
 
     var mInfo = "";
 
diff --git 
a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java
 
b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java
index 48201b3..453f88f 100644
--- 
a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java
+++ 
b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/PrChainsProcessorTest.java
@@ -31,10 +31,15 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Predicate;
 import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
+import org.apache.ignite.ci.github.PullRequest;
 import org.apache.ignite.ci.ITeamcity;
 import org.apache.ignite.ci.analysis.RunStat;
+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.tcmodel.conf.BuildType;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.tcmodel.result.Build;
@@ -91,6 +96,26 @@ public class PrChainsProcessorTest {
             bind(IGitHubConnectionProvider.class).toInstance(ghProv);
             
when(ghProv.server(anyString())).thenReturn(Mockito.mock(IGitHubConnection.class));
 
+            final IGitHubConnIgnitedProvider gitHubConnIgnitedProvider = 
Mockito.mock(IGitHubConnIgnitedProvider.class);
+
+            
bind(IGitHubConnIgnitedProvider.class).toInstance(gitHubConnIgnitedProvider);
+
+            IGitHubConnIgnited gitHubConnIgnited = 
Mockito.mock(IGitHubConnIgnited.class);
+
+            PullRequest pullReq = Mockito.mock(PullRequest.class);
+
+            when(pullReq.getTitle()).thenReturn("");
+
+            
when(gitHubConnIgnited.getPullRequest(anyString())).thenReturn(pullReq);
+
+            
when(gitHubConnIgnitedProvider.server(anyString())).thenReturn(gitHubConnIgnited);
+
+            final IJiraIntegrationProvider jiraProv = 
Mockito.mock(IJiraIntegrationProvider.class);
+
+            bind(IJiraIntegrationProvider.class).toInstance(jiraProv);
+
+            
when(jiraProv.server(anyString())).thenReturn(Mockito.mock(IJiraIntegration.class));
+
             
bind(ITeamcityIgnitedProvider.class).to(TeamcityIgnitedProviderMock.class).in(new
 SingletonScope());
 
             final ITcServerProvider tcSrvOldProv = 
Mockito.mock(ITcServerProvider.class);

Reply via email to