You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by dp...@apache.org on 2019/01/28 18:15:49 UTC

[ignite-teamcity-bot] branch ignite-11105-alias updated: IGNITE-11105 Support Teamcity servers aliases: Aliases and JSON config for JIRA services

This is an automated email from the ASF dual-hosted git repository.

dpavlov pushed a commit to branch ignite-11105-alias
in repository https://gitbox.apache.org/repos/asf/ignite-teamcity-bot.git


The following commit(s) were added to refs/heads/ignite-11105-alias by this push:
     new 2759b53  IGNITE-11105 Support Teamcity servers aliases: Aliases and JSON config for JIRA services
2759b53 is described below

commit 2759b53a1d22193333fd5f6708ee14e8f722c554
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Mon Jan 28 21:15:45 2019 +0300

    IGNITE-11105 Support Teamcity servers aliases: Aliases and JSON config for JIRA services
---
 .../java/org/apache/ignite/ci/HelperConfig.java    |  3 -
 .../org/apache/ignite/ci/conf/BranchesTracked.java |  8 +++
 .../java/org/apache/ignite/ci/jira/Tickets.java    |  1 +
 .../ignite/ci/jira/ignited/IJiraIgnited.java       |  2 +-
 .../apache/ignite/ci/jira/ignited/JiraIgnited.java |  2 +-
 .../ignite/ci/jira/ignited/JiraTicketDao.java      |  2 +-
 .../ignite/ci/jira/ignited/JiraTicketSync.java     | 14 +++-
 .../ignite/ci/jira/ignited/TicketCompacted.java    |  8 ++-
 .../apache/ignite/ci/jira/{ => pure}/Fields.java   | 14 +++-
 .../ignite/ci/jira/pure/IJiraIntegration.java      |  4 +-
 .../java/org/apache/ignite/ci/jira/pure/Jira.java  | 59 ++++++++++-------
 .../apache/ignite/ci/jira/{ => pure}/Status.java   |  4 +-
 .../apache/ignite/ci/jira/{ => pure}/Ticket.java   |  2 +-
 .../conf/IJiraServerConfig.java}                   | 24 +++----
 .../apache/ignite/ci/tcbot/conf/ITcBotConfig.java  |  2 +
 .../ignite/ci/tcbot/conf/JiraServerConfig.java     | 75 ++++++++++++++++++++++
 .../ci/tcbot/conf/LocalFilesBasedConfig.java       | 19 ++++++
 .../tcbot/visa/TcBotTriggerAndSignOffService.java  |  3 +-
 .../apache/ignite/ci/web/rest/TriggerBuilds.java   |  2 +-
 .../ci/tcbot/chain/MockBasedTcBotModule.java       | 12 +++-
 20 files changed, 198 insertions(+), 62 deletions(-)

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 bf5a2ef..11501e5 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
@@ -59,9 +59,6 @@ public class HelperConfig {
     /** JIRA authorization token property name. */
     public static final String GIT_API_URL = "git.api_url";
 
-    /** 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";
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/conf/BranchesTracked.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/conf/BranchesTracked.java
index 98a0817..7097951 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/conf/BranchesTracked.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/conf/BranchesTracked.java
@@ -21,6 +21,7 @@ import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import javax.annotation.Nullable;
+import org.apache.ignite.ci.tcbot.conf.JiraServerConfig;
 import org.apache.ignite.ci.tcbot.conf.TcServerConfig;
 
 /**
@@ -36,6 +37,9 @@ public class BranchesTracked {
     /** Additional list Servers to be used for validation of PRs, but not for tracking any branches. */
     private List<TcServerConfig> servers = new ArrayList<>();
 
+    /** JIRA config to be used . */
+    private List<JiraServerConfig> jiraServers = new ArrayList<>();
+
     /**
      * @return list of internal identifiers of branch.
      */
@@ -89,4 +93,8 @@ public class BranchesTracked {
     public Optional<TcServerConfig> getServer(String name) {
         return servers.stream().filter(s -> name.equals(s.getName())).findAny();
     }
+
+    public Optional<JiraServerConfig> getJiraServer(String name) {
+        return jiraServers.stream().filter(s -> name.equals(s.getName())).findAny();
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java
index 930a1bf..a6e3758 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java
@@ -19,6 +19,7 @@ package org.apache.ignite.ci.jira;
 
 import java.util.Collection;
 import java.util.Collections;
+import org.apache.ignite.ci.jira.pure.Ticket;
 
 /**
  * See example of GSON here
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnited.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnited.java
index be1011a..fa88d26 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnited.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/IJiraIgnited.java
@@ -18,7 +18,7 @@ package org.apache.ignite.ci.jira.ignited;
 
 import java.io.IOException;
 import java.util.Set;
-import org.apache.ignite.ci.jira.Ticket;
+import org.apache.ignite.ci.jira.pure.Ticket;
 import org.jetbrains.annotations.NotNull;
 
 /**
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnited.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnited.java
index 1ffe5ec..2a84f36 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnited.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraIgnited.java
@@ -19,7 +19,7 @@ package org.apache.ignite.ci.jira.ignited;
 import java.io.IOException;
 import java.util.Set;
 import javax.inject.Inject;
-import org.apache.ignite.ci.jira.Ticket;
+import org.apache.ignite.ci.jira.pure.Ticket;
 import org.apache.ignite.ci.jira.pure.IJiraIntegration;
 import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
 import org.jetbrains.annotations.NotNull;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java
index 30def78..7d87f5b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java
@@ -30,7 +30,7 @@ import org.apache.ignite.Ignite;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.ci.db.TcHelperDb;
 import org.apache.ignite.ci.di.AutoProfiling;
-import org.apache.ignite.ci.jira.Ticket;
+import org.apache.ignite.ci.jira.pure.Ticket;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.internal.U;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java
index 0b97084..331d2e5 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java
@@ -17,14 +17,18 @@
 
 package org.apache.ignite.ci.jira.ignited;
 
+import java.lang.reflect.Field;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 import javax.inject.Inject;
 import org.apache.ignite.ci.di.MonitoredTask;
 import org.apache.ignite.ci.di.scheduler.IScheduler;
 import org.apache.ignite.ci.jira.pure.IJiraIntegration;
 import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
-import org.apache.ignite.ci.jira.Ticket;
+import org.apache.ignite.ci.jira.pure.Ticket;
 import org.apache.ignite.ci.jira.Tickets;
 import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
 import org.apache.ignite.internal.util.typedef.F;
@@ -86,9 +90,15 @@ public class JiraTicketSync {
         int srvIdMaskHigh = ITeamcityIgnited.serverIdToInt(srvId);
         IJiraIntegration jira = jiraIntegrationProvider.server(srvId);
 
+        List<String> fields = Arrays.stream(Ticket.class.getDeclaredFields())
+            .map(field -> field.getName())
+            .collect(Collectors.toList());
+
         String projectName = jira.projectName();
         String baseUrl = "search?jql=" + escape("project=" + projectName + " order by updated DESC")
-            + "&fields=status&maxResults=100";
+            + "&" +
+            "fields=status" +
+            "&maxResults=100";
 
         String url = baseUrl;
         Tickets tickets = jira.getTicketsPage(url);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java
index 4eb942e..28ae6a7 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java
@@ -18,9 +18,9 @@
 package org.apache.ignite.ci.jira.ignited;
 
 import com.google.common.base.Objects;
-import org.apache.ignite.ci.jira.Fields;
-import org.apache.ignite.ci.jira.Status;
-import org.apache.ignite.ci.jira.Ticket;
+import org.apache.ignite.ci.jira.pure.Fields;
+import org.apache.ignite.ci.jira.pure.Status;
+import org.apache.ignite.ci.jira.pure.Ticket;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
 
 /**
@@ -36,6 +36,8 @@ public class TicketCompacted {
     /** Id of string: Fields/status/name, value compacted. */
     public int status;
 
+
+
     /**
      * @param ticket Jira ticket.
      * @param comp Compactor.
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Fields.java
similarity index 78%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Fields.java
index 2f6e271..02ed0b2 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Fields.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.pure;
 
 import com.google.common.base.MoreObjects;
 
@@ -26,10 +26,20 @@ public class Fields {
     /** Ticket status. */
     public Status status;
 
-    /** {@inheritDoc} */
+    /** Summary. */
+    public String summary;
+
+    /** Customfield 11050. */
+    public String customfield_11050;
+
+    /** Description. */
+    public String description;
+
     @Override public String toString() {
         return MoreObjects.toStringHelper(this)
             .add("status", status)
+            .add("summary", summary)
+            .add("customfield_11050", customfield_11050)
             .toString();
     }
 }
\ No newline at end of file
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegration.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegration.java
index 9410350..3a0d356 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegration.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/IJiraIntegration.java
@@ -58,7 +58,7 @@ public interface IJiraIntegration {
     /**
      * Produce wrapper for collection of Jira tickets for given server.
      *
-     * @param url Tickets loading URL and parameters.
+     * @param url Tickets loading URL and parameters, URL is relative, should not contain any start slashes.
      * @return Jira tickets.
      */
     public Tickets getTicketsPage(String url);
@@ -78,7 +78,7 @@ public interface IJiraIntegration {
      */
     public String generateCommentUrl(String ticketFullName, int commentId);
 
-    String getJiraApiUrl();
+    String restApiUrl();
 
     /**
      * @return {@code True} if JIRA authorization token is available.
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Jira.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Jira.java
index c11cfcc..f7af47f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Jira.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Jira.java
@@ -23,10 +23,14 @@ import com.google.gson.Gson;
 import java.io.File;
 import java.io.IOException;
 import java.util.Properties;
+import javax.inject.Inject;
 import org.apache.ignite.ci.HelperConfig;
 import org.apache.ignite.ci.di.AutoProfiling;
 import org.apache.ignite.ci.jira.Tickets;
+import org.apache.ignite.ci.tcbot.conf.IJiraServerConfig;
+import org.apache.ignite.ci.tcbot.conf.ITcBotConfig;
 import org.apache.ignite.ci.util.HttpUtil;
+import org.checkerframework.checker.nullness.qual.Nullable;
 import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,41 +44,38 @@ class Jira implements IJiraIntegration {
     /** Logger. */
     private static final Logger logger = LoggerFactory.getLogger(Jira.class);
 
-    /** */
-    private String jiraUrl;
-
     /** JIRA ticket prefix. */
     @NotNull private String jiraTicketPrefix;
 
     /** JIRA authorization token. */
     private String jiraBasicAuthTok;
 
-    /** URL for JIRA integration. */
-    private String jiraApiUrl;
-
     /** Server id. */
     private String srvId;
 
+    /** Config. */
+    @Inject ITcBotConfig cfg;
+
     /** {@inheritDoc} */
     @Override public void init(String srvId) {
         this.srvId = srvId;
+
+        IJiraServerConfig jiraCfg = cfg.getJiraConfig(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);
-
         jiraTicketPrefix = props.getProperty(HelperConfig.JIRA_TICKET_TEMPLATE, "IGNITE-");
 
         jiraBasicAuthTok = HelperConfig.prepareJiraHttpAuthToken(props);
-        jiraApiUrl = props.getProperty(HelperConfig.JIRA_API_URL);
     }
 
     /** {@inheritDoc} */
     @Override public String jiraUrl() {
-        return jiraUrl;
+        return cfg.getJiraConfig(srvId).getUrl();
     }
 
     /** {@inheritDoc} */
@@ -99,6 +100,8 @@ class Jira implements IJiraIntegration {
 
     /** {@inheritDoc} */
     @Override public String generateTicketUrl(String ticketFullName) {
+        @Nullable String jiraUrl = jiraUrl();
+
         Preconditions.checkState(!isNullOrEmpty(jiraUrl), "Jira URL is not configured for this server.");
 
         return jiraUrl + "browse/" + ticketFullName;
@@ -113,11 +116,6 @@ class Jira implements IJiraIntegration {
     }
 
     /** {@inheritDoc} */
-    @Override public String getJiraApiUrl() {
-        return jiraApiUrl;
-    }
-
-    /** {@inheritDoc} */
     @Override public boolean isJiraTokenAvailable() {
         return !Strings.isNullOrEmpty(jiraBasicAuthTok);
     }
@@ -125,26 +123,41 @@ class Jira implements IJiraIntegration {
     /** {@inheritDoc} */
     @AutoProfiling
     @Override public String postJiraComment(String ticket, String comment) throws IOException {
-        if (isNullOrEmpty(jiraApiUrl))
-            throw new IllegalStateException("JIRA API URL is not configured for this server.");
+        String jiraApiUrl = restApiUrl();
 
         String url = jiraApiUrl + "issue/" + ticket + "/comment";
 
         return HttpUtil.sendPostAsStringToJira(jiraBasicAuthTok, url, "{\"body\": \"" + comment + "\"}");
     }
 
+    /** {@inheritDoc} */
+    @Override @NotNull public String restApiUrl() {
+        String jiraUrl = jiraUrl();
+
+        if (isNullOrEmpty(jiraUrl))
+            throw new IllegalStateException("JIRA API URL is not configured for this server.");
+
+        StringBuilder apiUrl = new StringBuilder();
+
+        apiUrl.append(jiraUrl);
+        if (!jiraUrl.endsWith("/"))
+            apiUrl.append("/");
+
+        apiUrl.append("rest/api/2/");
+
+        return apiUrl.toString();
+    }
+
     /**
-     * @param url Url.
+     * @param url Url, relative, should not contain any start slashes.
      * @return Response as gson string.
      */
     public String sendGetToJira(String url) throws IOException {
-        if (isNullOrEmpty(jiraApiUrl))
-            throw new IllegalStateException("JIRA API URL is not configured for this server.");
-
-        return HttpUtil.sendGetToJira(jiraBasicAuthTok, jiraApiUrl + url);
+        return HttpUtil.sendGetToJira(jiraBasicAuthTok, restApiUrl() + url);
     }
 
-    public String getServiceId() {
+    /** {@inheritDoc} */
+    @Override public String getServiceId() {
         return srvId;
     }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Status.java
similarity index 94%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Status.java
index 94d2131..1821c5f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Status.java
@@ -15,9 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.jira;
-
-import com.google.common.base.MoreObjects;
+package org.apache.ignite.ci.jira.pure;
 
 /**
  * Status for Jira ticket.
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Ticket.java
similarity index 98%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Ticket.java
index dc8806f..b8b16b2 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/pure/Ticket.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.jira;
+package org.apache.ignite.ci.jira.pure;
 
 import com.google.common.base.MoreObjects;
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/IJiraServerConfig.java
similarity index 70%
rename from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java
rename to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/IJiraServerConfig.java
index 2f6e271..36f6551 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/IJiraServerConfig.java
@@ -14,22 +14,14 @@
  * 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.MoreObjects;
+package org.apache.ignite.ci.tcbot.conf;
 
 /**
- *
+ * Abstract JIRA server config.
  */
-public class Fields {
-    /** Ticket status. */
-    public Status status;
-
-    /** {@inheritDoc} */
-    @Override public String toString() {
-        return MoreObjects.toStringHelper(this)
-            .add("status", status)
-            .toString();
-    }
-}
\ No newline at end of file
+public interface IJiraServerConfig {
+    /**
+     * Return JIRA URL, e.g. https://issues.apache.org/jira/
+     */
+    public String getUrl();
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ITcBotConfig.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ITcBotConfig.java
index 7281285..d4b422e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ITcBotConfig.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ITcBotConfig.java
@@ -50,4 +50,6 @@ public interface ITcBotConfig {
     }
 
     public ITcServerConfig getTeamcityConfig(String srvName);
+
+    public IJiraServerConfig getJiraConfig(String srvName);
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/JiraServerConfig.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/JiraServerConfig.java
new file mode 100644
index 0000000..24e7ba6
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/JiraServerConfig.java
@@ -0,0 +1,75 @@
+/*
+ * 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.tcbot.conf;
+
+import com.google.common.base.Strings;
+import java.util.ArrayList;
+import java.util.Properties;
+import org.apache.ignite.ci.HelperConfig;
+
+/**
+ *
+ */
+public class JiraServerConfig implements IJiraServerConfig {
+    private String name;
+
+    /**
+     * Tickets for commenting in JIRA and finding out PA tickets.
+     */
+    private String projectCode;
+
+    private String branchTicketTemplate;
+    /** Branch ticket template search fields, list of JIRA fields IDs to be checked for finding out branch. */
+    private ArrayList<String> branchTicketTemplateSearchFields;
+
+    private Properties props;
+    private String url;
+
+    public JiraServerConfig() {
+    }
+
+    public JiraServerConfig(String name, Properties props) {
+        this.name = name;
+        this.props = props;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param props Properties.
+     */
+    public void properties(Properties props) {
+        this.props = props;
+    }
+
+    /**
+     * @param name Name.
+     */
+    public void name(String name) {
+        this.name = name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getUrl() {
+        if (Strings.isNullOrEmpty(url) && props != null)
+            return props.getProperty(HelperConfig.JIRA_URL);
+
+        return url;
+    }
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java
index d24600b..919f8a2 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/LocalFilesBasedConfig.java
@@ -53,6 +53,25 @@ public class LocalFilesBasedConfig implements ITcBotConfig {
             });
     }
 
+    @Override public IJiraServerConfig getJiraConfig(String srvName) {
+        return getTrackedBranches().getJiraServer(srvName)
+            .orElseGet(() -> {
+                JiraServerConfig jCfg = new JiraServerConfig();
+
+                jCfg.name(srvName);
+
+                File workDir = HelperConfig.resolveWorkDir();
+
+                String cfgName = HelperConfig.prepareConfigName(srvName);
+
+                Properties props = HelperConfig.loadAuthProperties(workDir, cfgName);
+
+                jCfg.properties(props);
+
+                return jCfg;
+            });
+    }
+
     /** {@inheritDoc} */
     @Override public String primaryServerId() {
         String srvId = getTrackedBranches().primaryServerId();
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 04f564b..776fc9d 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
@@ -42,7 +42,7 @@ import org.apache.ignite.ci.github.PullRequest;
 import org.apache.ignite.ci.github.ignited.IGitHubConnIgnited;
 import org.apache.ignite.ci.github.ignited.IGitHubConnIgnitedProvider;
 import org.apache.ignite.ci.github.pure.IGitHubConnection;
-import org.apache.ignite.ci.jira.Ticket;
+import org.apache.ignite.ci.jira.pure.Ticket;
 import org.apache.ignite.ci.jira.ignited.IJiraIgnited;
 import org.apache.ignite.ci.jira.ignited.IJiraIgnitedProvider;
 import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
@@ -250,6 +250,7 @@ public class TcBotTriggerAndSignOffService {
      */
     @NotNull public static String getTicketFullName(PullRequest pr, @NotNull String prefix) {
         String ticketId = "";
+
         if (pr.getTitle().toUpperCase().startsWith(prefix)) {
             int beginIdx = prefix.length();
             int endIdx = prefix.length();
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuilds.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuilds.java
index 5f4031c..5c527ba 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuilds.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuilds.java
@@ -125,7 +125,7 @@ public class TriggerBuilds {
 
             IGitHubConnection gh = injector.getInstance(IGitHubConnectionProvider.class).server(srvId);
 
-            return new ServerIntegrationLinks(srvId, gh.gitApiUrl(), jira.getJiraApiUrl());
+            return new ServerIntegrationLinks(srvId, gh.gitApiUrl(), jira.restApiUrl());
         }).filter(Objects::nonNull).collect(Collectors.toSet());
     }
 }
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
index f372d9e..8f63ce4 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/tcbot/chain/MockBasedTcBotModule.java
@@ -32,8 +32,10 @@ import org.apache.ignite.ci.github.pure.IGitHubConnection;
 import org.apache.ignite.ci.github.pure.IGitHubConnectionProvider;
 import org.apache.ignite.ci.jira.pure.IJiraIntegration;
 import org.apache.ignite.ci.jira.pure.IJiraIntegrationProvider;
+import org.apache.ignite.ci.tcbot.conf.IJiraServerConfig;
 import org.apache.ignite.ci.tcbot.conf.ITcBotConfig;
 import org.apache.ignite.ci.tcbot.conf.ITcServerConfig;
+import org.apache.ignite.ci.tcbot.conf.JiraServerConfig;
 import org.apache.ignite.ci.tcbot.conf.TcServerConfig;
 import org.apache.ignite.ci.tcbot.issue.IIssuesStorage;
 import org.apache.ignite.ci.tcbot.user.IUserStorage;
@@ -117,9 +119,15 @@ public class MockBasedTcBotModule extends AbstractModule {
 
                 String cfgName = HelperConfig.prepareConfigName(srvName);
 
-                Properties properties = HelperConfig.loadAuthProperties(workDir, cfgName);
+                return new TcServerConfig(srvName, HelperConfig.loadAuthProperties(workDir, cfgName));
+            }
+
+            @Override public IJiraServerConfig getJiraConfig(String srvName) {
+                File workDir = HelperConfig.resolveWorkDir();
+
+                String cfgName = HelperConfig.prepareConfigName(srvName);
 
-                return new TcServerConfig(srvName, properties);
+                return new JiraServerConfig(srvName, HelperConfig.loadAuthProperties(workDir, cfgName));
             }
         });