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/05/08 18:21:56 UTC

[ignite-teamcity-bot] branch master updated: IGNITE-10095: Support Build Parameters specifying in triggering and tagging builds (#122)

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 b02303f  IGNITE-10095: Support Build Parameters specifying in triggering and tagging builds (#122)
b02303f is described below

commit b02303fd0d73a16c4773c9271d8f629e1e3fbebd
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Wed May 8 21:21:51 2019 +0300

    IGNITE-10095: Support Build Parameters specifying in triggering and tagging builds (#122)
---
 conf/apache.auth.properties                        |  32 ------
 conf/branches.json                                 |  67 +++++++++++--
 .../main/java/org/apache/ignite/ci/ITeamcity.java  |  32 +++---
 .../apache/ignite/ci/IgnitePersistentTeamcity.java |  24 +++--
 .../apache/ignite/ci/IgniteTeamcityConnection.java | 100 +++++++++++--------
 .../apache/ignite/ci/analysis/MultBuildRunCtx.java |   4 +
 .../ignite/ci/analysis/SingleBuildRunCtx.java      |  37 +++++++
 .../java/org/apache/ignite/ci/db/Persisted.java    |   2 +-
 .../org/apache/ignite/ci/jobs/CheckQueueJob.java   |   3 +-
 .../runners/IgniteTeamcityHelperRunnerExample.java |   5 +-
 .../ignite/ci/tcbot/chain/BuildChainProcessor.java |   7 +-
 .../ignite/ci/tcbot/chain/PrChainsProcessor.java   |   3 +-
 .../ignite/ci/tcbot/conf/BuildParameterSpec.java   |  94 +++++++++++++++++
 .../ignite/ci/tcbot/conf/ChainAtServerTracked.java |  62 +++++++++---
 .../ignite/ci/tcbot/conf/ITcServerConfig.java      |   4 +
 .../conf/ParameterValueSpec.java}                  |  16 ++-
 .../ignite/ci/tcbot/conf/TcServerConfig.java       |  24 +++++
 .../tcbot/visa/TcBotTriggerAndSignOffService.java  |   2 +-
 .../org/apache/ignite/ci/tcmodel/Properties.java   |  18 ++--
 .../ignite/ci/tcmodel/conf/bt/Parameters.java      |  21 ++--
 .../apache/ignite/ci/tcmodel/conf/bt/Property.java |  32 ++++--
 .../org/apache/ignite/ci/tcmodel/result/Build.java |  27 ++++-
 .../ci/teamcity/ignited/ITeamcityIgnited.java      |  17 +++-
 .../ci/teamcity/ignited/TeamcityIgnitedImpl.java   |  16 +--
 .../teamcity/ignited/buildtype/BuildTypeSync.java  |   6 +-
 .../ignited/buildtype/ParametersCompacted.java     |  46 ++++++++-
 .../ci/teamcity/ignited/change/ChangeSync.java     |   2 +-
 .../ignited/fatbuild/FatBuildCompacted.java        |  42 +++++++-
 .../ignited/fatbuild/ProactiveFatBuildSync.java    |  14 +--
 .../ignited/fatbuild/StatisticsCompacted.java      |  10 +-
 .../teamcity/ignited/fatbuild/TestCompacted.java   |  32 ++++--
 .../ci/teamcity/ignited/runhist/Invocation.java    |  16 +++
 .../teamcity/ignited/runhist/InvocationData.java   |   2 +
 .../ci/teamcity/ignited/runhist/RunHistSync.java   |  40 ++++++--
 .../ignite/ci/teamcity/pure/ITeamcityConn.java     |  23 +++--
 .../ci/web/model/current/SuiteCurrentStatus.java   |   5 +
 .../src/main/webapp/css/style-1.5.css              |   7 ++
 .../src/main/webapp/js/testfails-2.1.js            | 111 +++++++++++----------
 .../ignited/IgnitedTcInMemoryIntegrationTest.java  |  12 +++
 .../ci/teamcity/ignited/TeamcityIgnitedMock.java   |   6 +-
 ignite-tc-helper-web/src/test/resources/build.xml  |   1 +
 41 files changed, 762 insertions(+), 262 deletions(-)

diff --git a/conf/apache.auth.properties b/conf/apache.auth.properties
deleted file mode 100644
index 974ba25..0000000
--- a/conf/apache.auth.properties
+++ /dev/null
@@ -1,32 +0,0 @@
-## Teamcity Integration Parameters
-# Teamcity Host, HTTPs is highly recommended because of Basic Auth used.
-host=https://ci.ignite.apache.org/
-
-# TC bot downloaded logs path
-logs=apache_logs
-
-## GitHub integration parameters.
-# REST API Url for GitHub. Includes owner (apache) and project (ignite)
-git.api_url=https://api.github.com/repos/apache/ignite/
-
-# Specify GitHub Auth token (if needed), go to User->Settings->Developers options->create new.
-# Created token needs to be encrypted using org.apache.ignite.ci.tcbot.conf.PasswordEncoder
-github.auth_token=
-
-## Branch identification rules
-# PR-less contribution branch name mandatory prefix
-git.branch_prefix=ignite-
-
-## JIRA integration parameters.
-jira.api_url=https://issues.apache.org/jira/rest/api/2/
-
-# JIRA Url, HTTPs is highly recommended because of Basic Auth used.
-jira.url=https://issues.apache.org/jira/
-
-# Ticket template: project code and dash.
-jira.ticket_template=IGNITE-
-
-# Specify JIRA Auth token (if needed).
-# Base-64 pre-encoded username and password, which will be included into Basic Auth requests.
-# Encoded token needs to be encrypted using org.apache.ignite.ci.tcbot.conf.PasswordEncoder
-jira.auth_token=
\ No newline at end of file
diff --git a/conf/branches.json b/conf/branches.json
index 90d93cb..3623c32 100644
--- a/conf/branches.json
+++ b/conf/branches.json
@@ -1,14 +1,36 @@
 {
   // Default server (service) code, internal identification
   "primaryServerCode": "apache",
-  /**/
+  /* Teamcity Integration Parameters */
   "tcServers": [
     {
-      //code of current server
+      /* Service Code for internal identification */
       "code": "public",
 
       // reference to another TC server service code to be used instead.
       "reference": "apache"
+    },
+    {
+      /* Service Code for internal identification */
+      "code": "apache",
+      /** Teamcity Host, HTTPs is highly recommended because of Basic Auth used.*/
+      "host": "https://ci.ignite.apache.org/",
+      /** Downloaded build logs relative path. */
+      logsDir: "apache_logs",
+      /** Default tracked branch name in internal identification of TC bot. */
+      defaultTrackedBranch: "master",
+      /** Build parameters, which may be used for filtering Run history and tagging builds. */
+      "filteringParameters": [
+        {
+          "name": "env.JAVA_HOME",
+          "selection": [
+            {"value":"%env.JDK_ORA_18%", "label":"JDK8"},
+            {"value":"%env.JDK_ORA_9%", "label":"JDK9"},
+            {"value":"%env.JDK_ORA_10%", "label":"JDK10"},
+            {"value":"%env.JDK_OPEN_11%", "label":"JDK11"}
+          ]
+        }
+      ]
     }
   ],
   /* Set of JIRA servers/projects configured */
@@ -22,23 +44,33 @@
       // "branchNumPrefix": "IGNITE-",
       /* JIRA Url, HTTPs is highly recommended because of Basic Auth used. */
       "url": "https://issues.apache.org/jira/",
-      /** JIRA Auth token to access, use PasswordEncoder#encodeJiraTok to get from clear username/password */
+      /** JIRA Auth token to access,
+        Base-64 pre-encoded username and password, which will be included into Basic Auth requests.
+        Encoded token needs to be encrypted using org.apache.ignite.ci.tcbot.conf.PasswordEncoder,
+        use PasswordEncoder#encodeJiraTok to get from clear username/password */
       "authTok": "" //todo specify
     }
   ],
-  /* Set of GitHub services configured */
+  /* Set of GitHub services configured: GitHub integration parameters.*/
   "gitHubConfigs": [
     {
       "code": "apache",
       /* More for preffering branches gives branch for PR to be default branch for triggering builds on TC. */
       "preferBranches": false,
 
+      /** Branch identification rules: PR-less contribution branch name mandatory prefix */
+      "branchPrefix": "ignite-",
+
       /*
-      Git Auth token encoded to access non-public GitHub repos, use {@link org.apache.ignite.ci.conf.PasswordEncoder#encodeJiraTok
-       to set up value in a config. For public GitHub repos token gives more velocity
+        Specify GitHub Auth token (if needed), go to User->Settings->Developers options->create new.
+        Created token needs to be encrypted using org.apache.ignite.ci.tcbot.conf.PasswordEncoder,
+        use {@link org.apache.ignite.ci.conf.PasswordEncoder#encodeJiraTok} to set up value in a config.
+        Git Auth token encoded to access non-public GitHub repos. For public GitHub repos token gives more velocity.
        */
       "authTok": "",
       //todo specify token
+
+      /* REST API Url for GitHub. Includes owner (apache) and project (ignite). */
       "apiUrl": "https://api.github.com/repos/apache/ignite/"
     }
   ],
@@ -79,28 +111,41 @@
           "suiteId": "IgniteTests24Java8_RunAllNightly",
           "branchForRest": "\u003cdefault\u003e",
           "triggerBuild": true,
-          "triggerBuildQuietPeriod": 30 //triggering quiet period in minutes
+          /* Triggering quiet period in minutes. Protects from too-often triggering in case build is too fast, e.g. compilation failure. */
+          "triggerBuildQuietPeriod": 30,
+          "triggerParameters": [
+            {
+              name: "reverse.dep.*.env.JAVA_HOME",
+              randomValue: true,
+              "selection": [
+                {value:"%env.JDK_ORA_18%", label:"JDK8"},
+                {value:"%env.JDK_ORA_9%", label:"JDK9"},
+                {value:"%env.JDK_ORA_10%", label:"JDK10"},
+                {value:"%env.JDK_OPEN_11%", label:"JDK11"}
+              ]
+            }
+          ]
         }
       ]
     },
     {
-      "id": "ignite-2.7",
+      "id": "ignite-2.7.5",
       "chains": [
         {
           "serverId": "apache",
           "suiteId": "IgniteTests24Java8_RunAll",
-          "branchForRest": "ignite-2.7",
+          "branchForRest": "ignite-2.7.5",
           "baseBranchForTc": "\u003cdefault\u003e"
         }
       ]
     },
     {
-      "id": "ignite-2.7-nightly",
+      "id": "ignite-2.7.5-nightly",
       "chains": [
         {
           "serverId": "apache",
           "suiteId": "IgniteTests24Java8_RunAllNightly",
-          "branchForRest": "ignite-2.7",
+          "branchForRest": "ignite-2.7.5",
           "baseBranchForTc": "\u003cdefault\u003e",
           "triggerBuild": true,
           "triggerBuildQuietPeriod": 30 //triggering quiet period in minutes
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
index c9be5dc..6f933c8 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
@@ -17,34 +17,38 @@
 
 package org.apache.ignite.ci;
 
+import com.google.common.collect.Sets;
+import java.io.File;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
 import org.apache.ignite.ci.analysis.LogCheckResult;
 import org.apache.ignite.ci.analysis.SingleBuildRunCtx;
-import org.apache.ignite.ci.tcmodel.agent.Agent;
-import org.apache.ignite.ci.tcmodel.conf.BuildType;
-import org.apache.ignite.ci.tcmodel.hist.BuildRef;
-import org.apache.ignite.ci.tcmodel.result.Build;
 import org.apache.ignite.ci.tcmodel.user.User;
 import org.apache.ignite.ci.teamcity.pure.ITeamcityConn;
 import org.apache.ignite.ci.util.Base64Util;
-import org.apache.ignite.ci.util.FutureUtil;
-import org.jetbrains.annotations.NotNull;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
 
 /**
  * API for calling methods from REST service:
  * https://confluence.jetbrains.com/display/TCD10/REST+API
  */
 public interface ITeamcity extends ITeamcityConn {
+    /** Default. */
     public String DEFAULT = "<default>";
+
+    /** Branch synonym: Refs heads master. */
     public String REFS_HEADS_MASTER = "refs/heads/master";
 
+    /** Branch synonym: Master. */
+    public String MASTER = "master";
+
+    /** Some fake property to avoid merging build in queue: Tcbot trigger time. */
+    public String TCBOT_TRIGGER_TIME = "tcbot.triggerTime";
+
+    /** Default list of properties to be skipped in saving in FAT builds. */
+    public Set<String> AVOID_SAVE_PROPERTIES = Sets.newHashSet(TCBOT_TRIGGER_TIME, "build.query.loginTs");
+
     CompletableFuture<File> unzipFirstFile(CompletableFuture<File> fut);
 
     CompletableFuture<File> downloadBuildLogZip(int id);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgnitePersistentTeamcity.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgnitePersistentTeamcity.java
index b297196..f83c455 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgnitePersistentTeamcity.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgnitePersistentTeamcity.java
@@ -19,11 +19,11 @@ package org.apache.ignite.ci;
 
 import java.io.File;
 import java.util.List;
+import java.util.Map;
 import java.util.SortedSet;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Function;
 import javax.annotation.Nullable;
@@ -36,6 +36,7 @@ import org.apache.ignite.ci.analysis.SingleBuildRunCtx;
 import org.apache.ignite.ci.db.DbMigrations;
 import org.apache.ignite.ci.db.TcHelperDb;
 import org.apache.ignite.ci.di.AutoProfiling;
+import org.apache.ignite.ci.tcbot.conf.ITcServerConfig;
 import org.apache.ignite.ci.tcmodel.agent.Agent;
 import org.apache.ignite.ci.tcmodel.changes.Change;
 import org.apache.ignite.ci.tcmodel.changes.ChangesList;
@@ -81,9 +82,9 @@ public class IgnitePersistentTeamcity implements IAnalyticsEnabledTeamcity, ITea
 
     @Override public void init(ITeamcity conn) {
         this.teamcity = conn;
-        this.serverId = conn.serverId();
+        this.serverId = conn.serverCode();
 
-        DbMigrations migrations = new DbMigrations(ignite, conn.serverId());
+        DbMigrations migrations = new DbMigrations(ignite, conn.serverCode());
 
         migrations.dataMigration(visasHistStorage.visas());
     }
@@ -112,10 +113,15 @@ public class IgnitePersistentTeamcity implements IAnalyticsEnabledTeamcity, ITea
     }
 
     /** {@inheritDoc} */
-    @Override public String serverId() {
+    @Override public String serverCode() {
         return serverId;
     }
 
+    /** {@inheritDoc} */
+    @Override public ITcServerConfig config() {
+        return teamcity.config();
+    }
+
     @NotNull private String ignCacheNme(String cache) {
         return ignCacheNme(cache, serverId);
     }
@@ -125,11 +131,6 @@ public class IgnitePersistentTeamcity implements IAnalyticsEnabledTeamcity, ITea
     }
 
     /** {@inheritDoc} */
-    @Override public String host() {
-        return teamcity.host();
-    }
-
-    /** {@inheritDoc} */
     @Override public Build getBuild(int buildId) {
         return teamcity.getBuild(buildId);
     }
@@ -210,8 +211,9 @@ public class IgnitePersistentTeamcity implements IAnalyticsEnabledTeamcity, ITea
 
     /** {@inheritDoc} */
     @AutoProfiling
-    @Override public Build triggerBuild(String buildTypeId, @NotNull String branchName, boolean cleanRebuild, boolean queueAtTop) {
-        return teamcity.triggerBuild(buildTypeId, branchName, cleanRebuild, queueAtTop);
+    @Override public Build triggerBuild(String buildTypeId, @NotNull String branchName, boolean cleanRebuild,
+        boolean queueAtTop, Map<String, Object> buildParms) {
+        return teamcity.triggerBuild(buildTypeId, branchName, cleanRebuild, queueAtTop, buildParms);
     }
 
     /** {@inheritDoc} */
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityConnection.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityConnection.java
index da570d6..6f5574f 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityConnection.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityConnection.java
@@ -21,6 +21,32 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Stopwatch;
 import com.google.common.base.Strings;
 import com.google.common.util.concurrent.MoreExecutors;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.io.UncheckedIOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.SortedSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.xml.bind.JAXBException;
 import org.apache.ignite.ci.analysis.ISuiteResults;
 import org.apache.ignite.ci.analysis.LogCheckResult;
 import org.apache.ignite.ci.analysis.LogCheckTask;
@@ -56,20 +82,6 @@ import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.inject.Inject;
-import javax.xml.bind.JAXBException;
-import java.io.*;
-import java.util.SortedSet;
-import java.util.List;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
 import static java.util.concurrent.CompletableFuture.supplyAsync;
 import static org.apache.ignite.ci.HelperConfig.ensureDirExist;
 import static org.apache.ignite.ci.util.XmlUtil.xmlEscapeText;
@@ -111,7 +123,7 @@ public class IgniteTeamcityConnection implements ITeamcity {
         this.executor = MoreExecutors.directExecutor();
     }
 
-    public ITcServerConfig config() {
+    @Override public ITcServerConfig config() {
         return cfg.getTeamcityConfig(this.srvCode);
     }
 
@@ -200,40 +212,51 @@ public class IgniteTeamcityConnection implements ITeamcity {
     /** {@inheritDoc} */
     @AutoProfiling
     @Override public Build triggerBuild(
-            String buildTypeId,
-            @NotNull @Nonnull String branchName,
-            boolean cleanRebuild,
-            boolean queueAtTop
+        String buildTypeId,
+        @NotNull @Nonnull String branchName,
+        boolean cleanRebuild,
+        boolean queueAtTop,
+        @Nullable Map<String, Object> buildParms
     ) {
         String triggeringOptions =
             " <triggeringOptions" +
                 " cleanSources=\"" + cleanRebuild + "\"" +
                 " rebuildAllDependencies=\"" + cleanRebuild + "\"" +
                 " queueAtTop=\"" + queueAtTop + "\"" +
-                "/>";
+                "/>\n";
 
         String comments = " <comment><text>Build triggered from Ignite TC Bot" +
             " [cleanRebuild=" + cleanRebuild + ", top=" + queueAtTop + "]</text></comment>\n";
 
-        String param = "<build branchName=\"" + xmlEscapeText(branchName) + "\">\n" +
-            "    <buildType id=\"" +
-            buildTypeId + "\"/>\n" +
-            comments +
-            triggeringOptions +
-            //some fake property to avoid merging build in queue
-            "    <properties>\n" +
-            "        <property name=\"build.query.loginTs\" value=\"" + System.currentTimeMillis() + "\"/>\n" +
-            // "        <property name=\"testSuite\" value=\"org.apache.ignite.spi.discovery.tcp.ipfinder.elb.TcpDiscoveryElbIpFinderSelfTest\"/>\n" +
-            "    </properties>\n" +
-            "</build>";
+        Map<String, Object> props = new HashMap<>();
+
+        if (buildParms != null)
+            props.putAll(buildParms);
+
+        props.put(TCBOT_TRIGGER_TIME, System.currentTimeMillis()); //
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("<build branchName=\"").append(xmlEscapeText(branchName)).append("\">\n");
+        sb.append(" <buildType id=\"").append(buildTypeId).append("\"/>\n");
+        sb.append(comments);
+        sb.append(triggeringOptions);
+        sb.append(" <properties>\n");
+
+        props.forEach((k, v) -> {
+            sb.append("  <property name=\"").append(k).append("\"");
+            sb.append(" value=\"").append(xmlEscapeText(Objects.toString(v))).append("\"/>\n");
+        });
+
+        sb.append(" </properties>\n");
+        sb.append("</build>");
 
         String url = host() + "app/rest/buildQueue";
 
         try {
-            logger.info("Triggering build: buildTypeId={}, branchName={}, cleanRebuild={}, queueAtTop={}",
-                buildTypeId, branchName, cleanRebuild, queueAtTop);
+            logger.info("Triggering build: buildTypeId={}, branchName={}, cleanRebuild={}, queueAtTop={}, buildParms={}",
+                buildTypeId, branchName, cleanRebuild, queueAtTop, props);
 
-            try (StringReader reader = new StringReader(HttpUtil.sendPostAsString(basicAuthTok, url, param))) {
+            try (StringReader reader = new StringReader(HttpUtil.sendPostAsString(basicAuthTok, url, sb.toString()))) {
                 return XmlUtil.load(Build.class, reader);
             }
             catch (JAXBException e) {
@@ -290,13 +313,6 @@ public class IgniteTeamcityConnection implements ITeamcity {
         }, executor);
     }
 
-    /**
-     * @return Normalized Host address, ends with '/'.
-     */
-    @Override public String host() {
-        return config().host();
-    }
-
     /** {@inheritDoc} */
     @Override public List<Project> getProjects() {
         return sendGetXmlParseJaxb(host() + "app/rest/latest/projects", ProjectsList.class).projects();
@@ -352,7 +368,7 @@ public class IgniteTeamcityConnection implements ITeamcity {
     }
 
     /** {@inheritDoc} */
-    @Override public String serverId() {
+    @Override public String serverCode() {
         return srvCode;
     }
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/MultBuildRunCtx.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/MultBuildRunCtx.java
index 96cfb85..cd56ec5 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/MultBuildRunCtx.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/MultBuildRunCtx.java
@@ -457,4 +457,8 @@ public class MultBuildRunCtx implements ISuiteResults {
     public Stream<LogCheckResult> getLogChecksIfFinished() {
         return buildsStream().map(SingleBuildRunCtx::getLogCheckIfFinished).filter(Objects::nonNull);
     }
+
+    public Set<String> tags() {
+        return buildsStream().flatMap(b -> b.tags().stream()).collect(Collectors.toSet());
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/SingleBuildRunCtx.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/SingleBuildRunCtx.java
index e49ca3d..5433d4b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/SingleBuildRunCtx.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/analysis/SingleBuildRunCtx.java
@@ -22,14 +22,21 @@ import com.google.common.base.Strings;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
 import java.util.stream.Stream;
 import javax.annotation.Nonnull;
+import org.apache.ignite.ci.tcbot.conf.BuildParameterSpec;
+import org.apache.ignite.ci.tcbot.conf.ITcServerConfig;
+import org.apache.ignite.ci.tcbot.conf.ParameterValueSpec;
 import org.apache.ignite.ci.tcmodel.result.tests.TestOccurrenceFull;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
+import org.apache.ignite.ci.teamcity.ignited.buildtype.ParametersCompacted;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeCompacted;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.ProblemCompacted;
@@ -53,6 +60,9 @@ public class SingleBuildRunCtx implements ISuiteResults {
     /** Logger check result future. */
     private CompletableFuture<LogCheckResult> logCheckResFut;
 
+    /** Tags found from filtering-enabled parameters. */
+    private Set<String> tags = new HashSet<>();
+
     /**
      * @param buildCompacted Build compacted.
      * @param compactor Compactor.
@@ -246,4 +256,31 @@ public class SingleBuildRunCtx implements ISuiteResults {
                 return duration;
             }).sum();
     }
+
+    public void addTag(String label) {
+        this.tags.add(label);
+    }
+
+    public Set<String> tags() {
+        return tags;
+    }
+
+    public void addTagsFromParameters(ParametersCompacted parameters, ITcServerConfig tcCfg,
+        IStringCompactor compactor) {
+        for (BuildParameterSpec parm : tcCfg.filteringParameters()) {
+            if (!parm.isFilled())
+                continue;
+
+            String propVal = parameters.getProperty(compactor, parm.name());
+
+            if (Strings.isNullOrEmpty(propVal))
+                continue;
+
+            parm.selection().stream()
+                .filter(v -> Objects.equals(v.value(), propVal))
+                .findAny()
+                .ifPresent(v -> addTag(v.label()));
+
+        }
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/Persisted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/Persisted.java
index ec2e45c..ed5e251 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/Persisted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/Persisted.java
@@ -18,7 +18,7 @@
 package org.apache.ignite.ci.db;
 
 /**
- * Marker interface for object saved into cache
+ * Marker interface for objects saved into a cache.
  */
 public @interface Persisted {
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jobs/CheckQueueJob.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jobs/CheckQueueJob.java
index 21b6048..d513e26 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jobs/CheckQueueJob.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jobs/CheckQueueJob.java
@@ -257,7 +257,8 @@ public class CheckQueueJob implements Runnable {
 
             startTimes.put(chain, curr);
 
-            tcIgn.triggerBuild(chain.suiteId, chain.branchForRest, true, false);
+            Map<String, Object> parms = chain.buildParameters();
+            tcIgn.triggerBuild(chain.suiteId, chain.branchForRest(), true, false, parms);
 
             res.append(chain.branchForRest).append(" ").append(chain.suiteId).append(" triggered; ");
         }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/IgniteTeamcityHelperRunnerExample.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/IgniteTeamcityHelperRunnerExample.java
index fc6b3f9..85118e0 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/IgniteTeamcityHelperRunnerExample.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/runners/IgniteTeamcityHelperRunnerExample.java
@@ -17,6 +17,9 @@
 
 package org.apache.ignite.ci.runners;
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -61,7 +64,7 @@ public class IgniteTeamcityHelperRunnerExample {
             String buildTypeIdAllP = "id8xIgniteGridGainTestsJava8_RunAll";
             //  buildTypeIdAll="IgniteTests24Java8_Queries1";
 
-            helper.triggerBuild(buildTypeIdAll, branchName, true, false);
+            helper.triggerBuild(buildTypeIdAll, branchName, true, false, Collections.emptyMap());
         }
     }
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessor.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessor.java
index 9664a3a..c876da4 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessor.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/chain/BuildChainProcessor.java
@@ -52,6 +52,7 @@ import org.apache.ignite.ci.teamcity.ignited.IRunHistory;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
 import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
 import org.apache.ignite.ci.teamcity.ignited.SyncMode;
+import org.apache.ignite.ci.teamcity.ignited.buildtype.ParametersCompacted;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistSync;
 import org.apache.ignite.ci.util.FutureUtil;
@@ -274,7 +275,7 @@ public class BuildChainProcessor {
      * Runs deep collection of all related statistics for particular build.
      *
      * @param buildCompacted Build ref from history with references to tests.
-     * @param tcIgnited
+     * @param tcIgnited TC connection.
      * @return Full context.
      */
     public SingleBuildRunCtx loadChanges(@Nonnull FatBuildCompacted buildCompacted,
@@ -283,6 +284,10 @@ public class BuildChainProcessor {
 
         ctx.setChanges(tcIgnited.getAllChanges(buildCompacted.changes()));
 
+        ParametersCompacted parameters = buildCompacted.parameters();
+        if (parameters != null)
+            ctx.addTagsFromParameters(parameters, tcIgnited.config(), this.compactor);
+
         return ctx;
     }
 
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 bae99e1..1be01b3 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
@@ -32,7 +32,6 @@ import org.apache.ignite.ci.analysis.mode.ProcessLogsMode;
 import org.apache.ignite.ci.di.AutoProfiling;
 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.ignited.IJiraIgnited;
 import org.apache.ignite.ci.jira.ignited.IJiraIgnitedProvider;
@@ -145,7 +144,7 @@ public class PrChainsProcessor {
             baseBranch,
             mode);
 
-        final ChainAtServerCurrentStatus chainStatus = new ChainAtServerCurrentStatus(teamcity.serverId(), branchForTc);
+        final ChainAtServerCurrentStatus chainStatus = new ChainAtServerCurrentStatus(teamcity.serverCode(), branchForTc);
 
         chainStatus.baseBranchForTc = baseBranch;
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/BuildParameterSpec.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/BuildParameterSpec.java
new file mode 100644
index 0000000..ec3e85a
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/BuildParameterSpec.java
@@ -0,0 +1,94 @@
+/*
+ * 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.Collections;
+import java.util.List;
+import java.util.Objects;
+import org.jetbrains.annotations.Nullable;
+
+public class BuildParameterSpec {
+    /** Parameter (property) Name. */
+    private String name;
+
+    /** Value to use for triggering build. */
+    private String value;
+
+    /** Use Random value, valid only for triggering parameters specifucation. */
+    @Nullable private Boolean randomValue;
+
+    /**
+     * For triggering parameters: possble random values.
+     * For filtering parameters: used as value for selection and displaying result.
+     */
+    @Nullable private List<ParameterValueSpec> selection = new ArrayList<>();
+
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        BuildParameterSpec param = (BuildParameterSpec)o;
+        return Objects.equals(name, param.name) &&
+            Objects.equals(value, param.value) &&
+            Objects.equals(randomValue, param.randomValue) &&
+            Objects.equals(selection, param.selection);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int hashCode() {
+        return Objects.hash(name, value, randomValue, selection);
+    }
+
+    /**
+     * @return {@link #name}.
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * @return some valid value for property or null.
+     */
+    public Object generateValue() {
+        if (!randomValue)
+            return value;
+
+        if (selection.isEmpty())
+            return value;
+
+        int idx = (int)(Math.random() * selection.size());
+
+        ParameterValueSpec spec = selection.get(idx);
+
+        return spec.value();
+    }
+
+    public boolean isFilled() {
+        return !Strings.isNullOrEmpty(name);
+    }
+
+    public List<ParameterValueSpec> selection() {
+        return (selection == null || selection.isEmpty())
+            ? Collections.emptyList()
+            : Collections.unmodifiableList(selection);
+    }
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ChainAtServerTracked.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ChainAtServerTracked.java
index b4cd6a0..f60cd2e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ChainAtServerTracked.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ChainAtServerTracked.java
@@ -18,10 +18,16 @@
 package org.apache.ignite.ci.tcbot.conf;
 
 import com.google.common.base.Strings;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.stream.Stream;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import org.jetbrains.annotations.NotNull;
 
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.base.Strings.isNullOrEmpty;
@@ -31,7 +37,7 @@ import static com.google.common.base.Strings.isNullOrEmpty;
  */
 @SuppressWarnings("PublicField")
 public class ChainAtServerTracked extends ChainAtServer {
-    /** Branch identifier by TC identification for REST api */
+    /** Branch identifier by TC identification for REST API. */
     @Nonnull public String branchForRest;
 
     /** TC identified base branch: null means the same as &lt;default>, master. For not tracked branches. */
@@ -43,6 +49,9 @@ public class ChainAtServerTracked extends ChainAtServer {
     /** Automatic build triggering quiet period in minutes. */
     @Nullable private Integer triggerBuildQuietPeriod;
 
+    /** Build parameters for Triggerring. */
+    @Nullable private List<BuildParameterSpec> triggerParameters;
+
     /** @return {@link #suiteId} */
     @Nonnull public String getSuiteIdMandatory() {
         checkState(!isNullOrEmpty(suiteId), "Invalid config: suiteId should be filled " + this);
@@ -69,30 +78,25 @@ public class ChainAtServerTracked extends ChainAtServer {
         return Optional.ofNullable(baseBranchForTc);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean equals(Object o) {
+    /** {@inheritDoc} */
+    @Override public boolean equals(Object o) {
         if (this == o)
             return true;
-
         if (o == null || getClass() != o.getClass())
             return false;
-
         if (!super.equals(o))
             return false;
-
         ChainAtServerTracked tracked = (ChainAtServerTracked)o;
-
         return Objects.equals(branchForRest, tracked.branchForRest) &&
+            Objects.equals(baseBranchForTc, tracked.baseBranchForTc) &&
             Objects.equals(triggerBuild, tracked.triggerBuild) &&
-            Objects.equals(triggerBuildQuietPeriod, tracked.triggerBuildQuietPeriod);
+            Objects.equals(triggerBuildQuietPeriod, tracked.triggerBuildQuietPeriod) &&
+            Objects.equals(triggerParameters, tracked.triggerParameters);
     }
 
     /** {@inheritDoc} */
     @Override public int hashCode() {
-        return Objects.hash(super.hashCode(), branchForRest, triggerBuild, triggerBuildQuietPeriod);
+        return Objects.hash(super.hashCode(), branchForRest, baseBranchForTc, triggerBuild, triggerBuildQuietPeriod, triggerParameters);
     }
 
     /**
@@ -108,4 +112,38 @@ public class ChainAtServerTracked extends ChainAtServer {
     public int getTriggerBuildQuietPeriod() {
         return triggerBuildQuietPeriod == null ? 0 : triggerBuildQuietPeriod;
     }
+
+    /**
+     * @return Map with parameter values for current run.
+     */
+    @NotNull public Map<String, Object> buildParameters() {
+        if (triggerParameters == null || triggerParameters.isEmpty())
+            return Collections.emptyMap();
+
+        Map<String, Object> values = new HashMap<>();
+
+        triggerParameters.forEach(
+            p -> {
+                String name = p.name();
+                Object val = p.generateValue();
+
+                if (!Strings.isNullOrEmpty(name) && val != null)
+                    values.put(name, val);
+            }
+        );
+
+        return values;
+    }
+
+    public Stream<String> buildParametersKeys() {
+        if (triggerParameters == null || triggerParameters.isEmpty())
+            return Stream.empty();
+
+        return triggerParameters.stream().map(BuildParameterSpec::name);
+    }
+
+    /** */
+    public String branchForRest() {
+        return branchForRest;
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ITcServerConfig.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ITcServerConfig.java
index e08a21b..a03b66e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ITcServerConfig.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ITcServerConfig.java
@@ -16,6 +16,7 @@
  */
 package org.apache.ignite.ci.tcbot.conf;
 
+import java.util.Collection;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -43,4 +44,7 @@ public interface ITcServerConfig {
      */
     @NotNull public String defaultTrackedBranch();
 
+    @NotNull public Collection<String> filteringParametersKeys();
+
+    @NotNull public Collection<BuildParameterSpec> filteringParameters();
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/Persisted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ParameterValueSpec.java
similarity index 73%
copy from ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/Persisted.java
copy to ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ParameterValueSpec.java
index ec2e45c..c63ac7e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/db/Persisted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/ParameterValueSpec.java
@@ -15,10 +15,20 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.ci.db;
+package org.apache.ignite.ci.tcbot.conf;
 
 /**
- * Marker interface for object saved into cache
+ * Some parameter value, which label may be used in UI.
  */
-public @interface Persisted {
+public class ParameterValueSpec {
+    private String value;
+    private String label;
+
+    public String value() {
+        return value;
+    }
+
+    public String label() {
+        return label;
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/TcServerConfig.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/TcServerConfig.java
index fe078ee..a6660ac 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/TcServerConfig.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/TcServerConfig.java
@@ -17,7 +17,12 @@
 package org.apache.ignite.ci.tcbot.conf;
 
 import com.google.common.base.Strings;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 import java.util.Properties;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import org.apache.ignite.ci.HelperConfig;
 import org.jetbrains.annotations.NotNull;
@@ -48,6 +53,9 @@ public class TcServerConfig implements ITcServerConfig {
     /** Default tracked branch name in internal identification of TC bot. */
     @Nullable private String defaultTrackedBranch;
 
+    /** Build parameters which may be used for filtering. */
+    @Nullable private List<BuildParameterSpec> filteringParameters = new ArrayList<>();
+
     public TcServerConfig() {
 
     }
@@ -103,6 +111,22 @@ public class TcServerConfig implements ITcServerConfig {
         return DEFAULT_TRACKED_BRANCH_NAME;
     }
 
+    /** {@inheritDoc} */
+    @Override public Collection<String> filteringParametersKeys() {
+        if (filteringParameters == null || filteringParameters.isEmpty())
+            return Collections.emptySet();
+
+        return filteringParameters.stream().map(BuildParameterSpec::name).collect(Collectors.toSet());
+    }
+
+    /** {@inheritDoc} */
+    @NotNull @Override public Collection<BuildParameterSpec> filteringParameters() {
+        if (filteringParameters == null || filteringParameters.isEmpty())
+            return Collections.emptySet();
+
+        return Collections.unmodifiableList(filteringParameters);
+    }
+
     /**
      * @param props Properties.
      */
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 c8bc647..00299bc 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
@@ -266,7 +266,7 @@ public class TcBotTriggerAndSignOffService {
         Build[] builds = new Build[suiteIds.length];
 
         for (int i = 0; i < suiteIds.length; i++)
-            builds[i] = teamcity.triggerBuild(suiteIds[i], branchForTc, false, top != null && top);
+            builds[i] = teamcity.triggerBuild(suiteIds[i], branchForTc, false, top != null && top, new HashMap<String, Object>());
 
         if (observe != null && observe)
             jiraRes += observeJira(srvId, branchForTc, ticketId, prov, parentSuiteId, builds);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/Properties.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/Properties.java
index f03a7ed..192ec42 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/Properties.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/Properties.java
@@ -80,9 +80,9 @@ public class Properties {
      *
      */
     public List<Property> getProperty() {
-        if (property == null) {
-            property = new ArrayList<Property>();
-        }
+        if (property == null)
+            property = new ArrayList<>();
+
         return this.property;
     }
 
@@ -101,13 +101,13 @@ public class Properties {
     /**
      * Sets the value of the count property.
      *
-     * @param value
+     * @param val
      *     allowed object is
      *     {@link Integer }
      *
      */
-    public void setCount(Integer value) {
-        this.count = value;
+    public void setCount(Integer val) {
+        this.count = val;
     }
 
     /**
@@ -125,12 +125,12 @@ public class Properties {
     /**
      * Sets the value of the href property.
      *
-     * @param value
+     * @param val
      *     allowed object is
      *     {@link String }
      *
      */
-    public void setHref(String value) {
-        this.href = value;
+    public void setHref(String val) {
+        this.href = val;
     }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/conf/bt/Parameters.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/conf/bt/Parameters.java
index de93c4b..9f92e33 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/conf/bt/Parameters.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/conf/bt/Parameters.java
@@ -19,8 +19,6 @@ package org.apache.ignite.ci.tcmodel.conf.bt;
 
 import com.google.common.base.MoreObjects;
 import java.util.ArrayList;
-import org.jetbrains.annotations.Nullable;
-
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -28,6 +26,7 @@ import java.util.Optional;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Collection of parameters in build
@@ -40,21 +39,24 @@ public class Parameters {
     public Parameters() {
     }
 
-    public Parameters(List<Property> properties) {
-        this.properties = properties == null ? null : new ArrayList<>(properties);
+    public Parameters(List<Property> props) {
+        this.properties = props == null ? null : new ArrayList<>(props);
     }
 
+    /**
+     * @param key Key of parameter.
+     */
     @Nullable public String getParameter(String key) {
         if (properties == null)
             return null;
 
         final Optional<Property> any = properties.stream().filter(property ->
             Objects.equals(property.name, key)).findAny();
-        return any.map(Property::getValue).orElse(null);
+        return any.map(Property::value).orElse(null);
     }
 
     public List<Property> properties() {
-        if (this.properties==null)
+        if (this.properties == null)
             return Collections.emptyList();
 
         return Collections.unmodifiableList(this.properties);
@@ -91,4 +93,11 @@ public class Parameters {
             .add("properties", properties)
             .toString();
     }
+
+    /**
+     * @return {@code true} if this list contains no elements
+     */
+    public boolean isEmpty() {
+        return properties == null || properties.isEmpty();
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/conf/bt/Property.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/conf/bt/Property.java
index af4b2c7..3f87d0a 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/conf/bt/Property.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/conf/bt/Property.java
@@ -29,30 +29,40 @@ import org.jetbrains.annotations.Nullable;
  */
 @XmlAccessorType(XmlAccessType.FIELD)
 public class Property {
+    /** Parameter Name/Key. */
     @XmlAttribute String name;
+
+    /** Parameter Value. */
     @XmlAttribute String value;
+
+    /** Flag indicating that value is inherited from a template. */
     @XmlAttribute Boolean inherited;
 
     public Property() {
     }
 
-    public Property(String name, String value) {
+    public Property(String name, String val) {
         this.name = name;
-        this.value = value;
+        this.value = val;
         this.inherited = null;
     }
 
-    public Property(String name, String value, Boolean inherited) {
+    public Property(String name, String val, Boolean inherited) {
         this.name = name;
-        this.value = value;
+        this.value = val;
         this.inherited = inherited;
     }
 
-    @Nullable
-    public String getValue() {
+    /**
+     * @return {@link #value}
+     */
+    @Nullable public String value() {
         return value;
     }
 
+    /**
+     * @return {@link #name}
+     */
     public String name() {
         return name;
     }
@@ -65,16 +75,16 @@ public class Property {
         if (!(o instanceof Property))
             return false;
 
-        Property property = (Property)o;
+        Property prop = (Property)o;
 
-        return Objects.equals(name, property.name) &&
-            Objects.equals(getValue(), property.getValue()) &&
-            Objects.equals(inherited, property.inherited);
+        return Objects.equals(name, prop.name) &&
+            Objects.equals(value(), prop.value()) &&
+            Objects.equals(inherited, prop.inherited);
     }
 
     /** {@inheritDoc} */
     @Override public int hashCode() {
-        return Objects.hash(name, getValue(), inherited);
+        return Objects.hash(name, value(), inherited);
     }
 
     /** {@inheritDoc} */
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/Build.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/Build.java
index 9af0c1b..a3871e0 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/Build.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/result/Build.java
@@ -31,6 +31,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlTransient;
 import org.apache.ignite.ci.tcmodel.changes.ChangesListRef;
 import org.apache.ignite.ci.tcmodel.conf.BuildType;
+import org.apache.ignite.ci.tcmodel.conf.bt.Parameters;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.tcmodel.vcs.Revision;
 import org.apache.ignite.ci.tcmodel.vcs.Revisions;
@@ -65,7 +66,7 @@ public class Build extends BuildRef {
 
     @XmlElement(name = "statistics") public StatisticsRef statisticsRef;
 
-    /** Changes included into build.*/
+    /** Changes included into build. */
     @XmlElement(name = "changes") public ChangesListRef changesRef;
 
     /** Information about build triggering. */
@@ -73,6 +74,9 @@ public class Build extends BuildRef {
 
     @XmlElement(name = "revisions") private Revisions revisions;
 
+    /** Build parameters. */
+    @Nullable @XmlElement(name = "properties") private Parameters properties;
+
     @NotNull public static Build createFakeStub() {
         return new Build();
     }
@@ -187,4 +191,25 @@ public class Build extends BuildRef {
         this.revisions = new Revisions();
         this.revisions.revisions(revisions);
     }
+
+    /**
+     * @param s Parameter key.
+     */
+    @Nullable public String parameter(String s) {
+        return properties == null ? null : properties.getParameter(s);
+    }
+
+    /**
+     * @return {@link #properties}
+     */
+    @Nullable public Parameters parameters() {
+        return properties;
+    }
+
+    /**
+     * @param parameters Parameters to be saved as {@link #properties}.
+     */
+    public void parameters(Parameters parameters) {
+        this.properties = parameters;
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java
index 276facc..7520f48 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/ITeamcityIgnited.java
@@ -19,12 +19,14 @@ package org.apache.ignite.ci.teamcity.ignited;
 import com.google.common.base.Strings;
 import java.util.Collection;
 import java.util.Date;
+import java.util.Map;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import javax.annotation.Nullable;
 import org.apache.ignite.ci.analysis.SuiteInBranch;
 import org.apache.ignite.ci.analysis.TestInBranch;
+import org.apache.ignite.ci.tcbot.conf.ITcServerConfig;
 import org.apache.ignite.ci.tcmodel.agent.Agent;
 import org.apache.ignite.ci.tcmodel.mute.MuteInfo;
 import org.apache.ignite.ci.tcmodel.result.Build;
@@ -44,12 +46,17 @@ public interface ITeamcityIgnited {
     /**
      * @return Internal server ID as string
      */
-    String serverId();
+    public String serverId();
+
+    /**
+     * @return TeamCity configuration.
+     */
+    public ITcServerConfig config();
 
     /**
      * @return Normalized Host address, ends with '/'.
      */
-    public String host();
+    default public String host() {return config().host();}
 
     /**
      * Return all builds for branch and suite, without relation to its status.
@@ -99,8 +106,12 @@ public interface ITeamcityIgnited {
      * @param branchName Branch name.
      * @param cleanRebuild Rebuild all dependencies.
      * @param queueAtTop Put at the top of the build queue.
+     * @param buildParms addtitional build parameters, for example Java home or test suite. Use
+     *      * <code>put("testSuite", "org.apache.ignite.spi.discovery.tcp.ipfinder.elb.TcpDiscoveryElbIpFinderSelfTest");</code>
+     *      * to specify test suite to run.
      */
-    public Build triggerBuild(String buildTypeId, String branchName, boolean cleanRebuild, boolean queueAtTop);
+    public Build triggerBuild(String buildTypeId, String branchName, boolean cleanRebuild, boolean queueAtTop,
+        Map<String, Object> buildParms);
 
     /**
      * @param srvId Server id.
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java
index 1825b2d..cabb443 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedImpl.java
@@ -41,6 +41,7 @@ import org.apache.ignite.ci.di.AutoProfiling;
 import org.apache.ignite.ci.di.MonitoredTask;
 import org.apache.ignite.ci.di.cache.GuavaCached;
 import org.apache.ignite.ci.di.scheduler.IScheduler;
+import org.apache.ignite.ci.tcbot.conf.ITcServerConfig;
 import org.apache.ignite.ci.tcbot.trends.MasterTrendsService;
 import org.apache.ignite.ci.tcmodel.agent.Agent;
 import org.apache.ignite.ci.tcmodel.conf.Project;
@@ -78,7 +79,6 @@ import static org.apache.ignite.ci.tcmodel.hist.BuildRef.STATUS_UNKNOWN;
  *
  */
 public class TeamcityIgnitedImpl implements ITeamcityIgnited {
-
     /** Default project id. */
     public static final String DEFAULT_PROJECT_ID = "IgniteTests24Java8";
 
@@ -88,9 +88,10 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
     /** Max build id diff to enforce reload during incremental refresh. */
     public static final int MAX_ID_DIFF_TO_ENFORCE_CONTINUE_SCAN = 3000;
 
+    /** Default synonyms. */
     private static final List<String> DEFAULT_SYNONYMS
             = Collections.unmodifiableList(
-                    Lists.newArrayList(ITeamcity.DEFAULT, ITeamcity.REFS_HEADS_MASTER, "master"));
+                    Lists.newArrayList(ITeamcity.DEFAULT, ITeamcity.REFS_HEADS_MASTER, ITeamcity.MASTER));
 
     /** Server (service) code. */
     private String srvCode;
@@ -150,7 +151,7 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
     private int srvIdMaskHigh;
 
     public void init(ITeamcityConn conn) {
-        String srvCode = conn.serverId();
+        String srvCode = conn.serverCode();
 
         this.srvCode = srvCode;
         this.conn = conn;
@@ -179,8 +180,8 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
     }
 
     /** {@inheritDoc} */
-    @Override public String host() {
-        return conn.host();
+    @Override public ITcServerConfig config() {
+        return conn.config();
     }
 
     /** {@inheritDoc} */
@@ -472,8 +473,9 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
     }
 
     /** {@inheritDoc} */
-    @Override public Build triggerBuild(String buildTypeId, String branchName, boolean cleanRebuild, boolean queueAtTop) {
-        Build build = conn.triggerBuild(buildTypeId, branchName, cleanRebuild, queueAtTop);
+    @Override public Build triggerBuild(String buildTypeId, String branchName, boolean cleanRebuild, boolean queueAtTop,
+        Map<String, Object> buildParms) {
+        Build build = conn.triggerBuild(buildTypeId, branchName, cleanRebuild, queueAtTop, buildParms);
 
         //todo may add additional parameter: load builds into DB in sync/async fashion
         buildRefSync.runActualizeBuildRefs(srvCode, false, Sets.newHashSet(build.getId()), conn);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildtype/BuildTypeSync.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildtype/BuildTypeSync.java
index 997429a..46ca440 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildtype/BuildTypeSync.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildtype/BuildTypeSync.java
@@ -107,7 +107,7 @@ public class BuildTypeSync {
      * @param conn Pure HTTP Connection API.
      */
     private void ensureActualizeBuildTypeRefsRequested(int srvIdMaskHigh, String projectId, ITeamcityConn conn) {
-        scheduler.sheduleNamed(taskName("actualizeAllBuildTypeRefs", conn.serverId(), projectId),
+        scheduler.sheduleNamed(taskName("actualizeAllBuildTypeRefs", conn.serverCode(), projectId),
             () -> reindexBuildTypeRefs(srvIdMaskHigh, projectId, conn), 4, TimeUnit.HOURS);
     }
 
@@ -119,7 +119,7 @@ public class BuildTypeSync {
      * @param conn Pure HTTP Connection API.
      */
     private void ensureActualizeBuildTypesRequested(int srvIdMaskHigh, String projectId, ITeamcityConn conn) {
-        scheduler.sheduleNamed(taskName("actualizeAllBuildTypeRefs", "actualizeAllBuildTypes", conn.serverId()),
+        scheduler.sheduleNamed(taskName("actualizeAllBuildTypeRefs", "actualizeAllBuildTypes", conn.serverCode()),
             () -> reindexBuildTypes(srvIdMaskHigh, projectId, conn), 24, TimeUnit.HOURS);
     }
 
@@ -169,7 +169,7 @@ public class BuildTypeSync {
                     updated += (buildTypeDao.saveBuildType(srvIdMaskHigh, buildType, exBuildType) != null) ? 1 : 0;
                 } catch (Exception e) {
                     if (Throwables.getRootCause(e) instanceof FileNotFoundException) {
-                        logger.info("Loading buildType [" + id + "] for server [" + conn.serverId() + "] failed:" +
+                        logger.info("Loading buildType [" + id + "] for server [" + conn.serverCode() + "] failed:" +
                             e.getMessage(), e);
 
                         removed += markRemoved(srvIdMaskHigh, id) ? 1 : 0;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildtype/ParametersCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildtype/ParametersCompacted.java
index ebac6b9..e969fd5 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildtype/ParametersCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/buildtype/ParametersCompacted.java
@@ -22,15 +22,26 @@ import com.google.common.base.Strings;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.function.BiConsumer;
+import javax.annotation.Nullable;
+import org.apache.ignite.ci.db.Persisted;
 import org.apache.ignite.ci.tcmodel.conf.bt.Parameters;
 import org.apache.ignite.ci.tcmodel.conf.bt.Property;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
 import org.apache.ignite.internal.util.GridIntList;
 
+/**
+ * Properties (Build/Build Type parameters) compacted value for storing in TC Bot DB
+ */
+@Persisted
 public class ParametersCompacted {
+    /** Property Keys (Names), int value is coming from the compatcor. */
     private GridIntList keys;
+
+    /** Property Values, int value is coming from the compatcor. */
     private GridIntList values;
 
+
     /**
      * Default constructor.
      */
@@ -50,7 +61,7 @@ public class ParametersCompacted {
             if (Strings.isNullOrEmpty(name))
                 continue;
 
-            String strVal = next.getValue();
+            String strVal = next.value();
             if (Strings.isNullOrEmpty(strVal))
                 continue;
 
@@ -124,4 +135,37 @@ public class ParametersCompacted {
             .add("values", values)
             .toString();
     }
+
+
+    public void forEach(IStringCompactor compactor, BiConsumer<String, String> consumer) {
+        forEach((k,v)-> consumer.accept(compactor.getStringFromId(k), compactor.getStringFromId(v)));
+    }
+
+    public void forEach(BiConsumer<Integer, Integer> consumer) {
+        int size = keys.size();
+
+        for (int i = 0; i < size; i++) {
+            int nameid = keys.get(i);
+
+            if (i >= values.size())
+                break;
+
+            int valId = values.get(i);
+
+            consumer.accept(nameid, valId);
+        }
+    }
+
+    @Nullable
+    public String getProperty(IStringCompactor compactor, String parmKey) {
+        Integer present = compactor.getStringIdIfPresent(parmKey);
+        if (present == null)
+            return null;
+
+        int propStrId = findPropertyStringId(present);
+        if (propStrId < 0)
+            return null;
+
+        return compactor.getStringFromId(propStrId);
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/change/ChangeSync.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/change/ChangeSync.java
index 7e00f56..55f74a6 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/change/ChangeSync.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/change/ChangeSync.java
@@ -56,7 +56,7 @@ public class ChangeSync {
             change = conn.getChange(changeId);
         } catch (Exception e) {
             if (Throwables.getRootCause(e) instanceof FileNotFoundException) {
-                logger.info("Loading changeId [" + changeId + "] for server [" + conn.serverId() + "] failed:" + e.getMessage(), e);
+                logger.info("Loading changeId [" + changeId + "] for server [" + conn.serverCode() + "] failed:" + e.getMessage(), e);
 
                 change = new Change();
             } else if (Throwables.getRootCause(e) instanceof SAXParseException) {
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/FatBuildCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/FatBuildCompacted.java
index 8ec87d5..7bfa146 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/FatBuildCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/FatBuildCompacted.java
@@ -17,6 +17,7 @@
 package org.apache.ignite.ci.teamcity.ignited.fatbuild;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.base.Strings;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -27,9 +28,12 @@ import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import org.apache.ignite.ci.ITeamcity;
 import org.apache.ignite.ci.analysis.IVersionedEntity;
 import org.apache.ignite.ci.db.Persisted;
 import org.apache.ignite.ci.tcmodel.conf.BuildType;
+import org.apache.ignite.ci.tcmodel.conf.bt.Parameters;
+import org.apache.ignite.ci.tcmodel.conf.bt.Property;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.tcmodel.result.Build;
 import org.apache.ignite.ci.tcmodel.result.TestOccurrencesRef;
@@ -44,6 +48,7 @@ import org.apache.ignite.ci.tcmodel.vcs.Revisions;
 import org.apache.ignite.ci.tcmodel.vcs.VcsRootInstance;
 import org.apache.ignite.ci.teamcity.ignited.BuildRefCompacted;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
+import org.apache.ignite.ci.teamcity.ignited.buildtype.ParametersCompacted;
 import org.apache.ignite.ci.teamcity.ignited.change.RevisionCompacted;
 import org.apache.ignite.ci.teamcity.ignited.runhist.Invocation;
 import org.apache.ignite.ci.teamcity.ignited.runhist.InvocationData;
@@ -116,6 +121,9 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
 
     @Nullable private RevisionCompacted revisions[];
 
+    /** Build parameters compacted, excluding dynamic parameters. */
+    @Nullable private ParametersCompacted buildParameters;
+
     /** {@inheritDoc} */
     @Override public int version() {
         return _ver;
@@ -200,13 +208,24 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
         }
 
         Revisions revisions = build.getRevisions();
-        if(revisions!=null) {
+        if (revisions != null) {
             this.revisions = revisions.revisions()
                 .stream()
                 .filter(b -> b.version() != null)
                 .map(revision -> new RevisionCompacted(compactor, revision))
                 .toArray(RevisionCompacted[]::new);
         }
+
+        Parameters parameters = build.parameters();
+
+        if (parameters != null) {
+            List<Property> propList = parameters.properties().stream()
+                .filter(prop -> !Strings.isNullOrEmpty(prop.name()))
+                .filter(prop -> !ITeamcity.AVOID_SAVE_PROPERTIES.contains(prop.name())).collect(Collectors.toList());
+
+            if (!propList.isEmpty())
+                this.buildParameters = new ParametersCompacted(compactor, propList);
+        }
     }
 
     public FatBuildCompacted setFakeStub(boolean val) {
@@ -240,7 +259,7 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
 
     /**
      * @param compactor Compactor.
-     * @param res Response.
+     * @param res Resulting build.
      */
     private void fillBuildFields(IStringCompactor compactor, Build res) {
         if (startDate > 0)
@@ -322,6 +341,14 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
                         .vcsRootId(vcsRootId));
             }).collect(Collectors.toList()));
         }
+
+        if (buildParameters != null) {
+            List<Property> props = new ArrayList<>();
+
+            buildParameters.forEach(compactor, (k, v) -> props.add(new Property(k, v)));
+
+            res.parameters(new Parameters(props));
+        }
     }
 
     /**
@@ -417,12 +444,13 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
             Objects.equals(statistics, that.statistics) &&
             Arrays.equals(changesIds, that.changesIds) &&
             Objects.equals(triggered, that.triggered) &&
-            Arrays.equals(revisions, that.revisions);
+            Arrays.equals(revisions, that.revisions) &&
+            Objects.equals(buildParameters, that.buildParameters);
     }
 
     /** {@inheritDoc} */
     @Override public int hashCode() {
-        int res = Objects.hash(super.hashCode(), _ver, startDate, finishDate, queuedDate, projectId, name, tests, flags, problems, statistics, triggered);
+        int res = Objects.hash(super.hashCode(), _ver, startDate, finishDate, queuedDate, projectId, name, tests, flags, problems, statistics, triggered, buildParameters);
         res = 31 * res + Arrays.hashCode(snapshotDeps);
         res = 31 * res + Arrays.hashCode(changesIds);
         res = 31 * res + Arrays.hashCode(revisions);
@@ -441,7 +469,7 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
     /**
      *
      */
-    public boolean isFakeStub() {
+    @Override public boolean isFakeStub() {
         if (getId() == null)
             return true;
 
@@ -637,4 +665,8 @@ public class FatBuildCompacted extends BuildRefCompacted implements IVersionedEn
 
         return Collections.unmodifiableList(Arrays.asList(revisions));
     }
+
+    @Nullable public ParametersCompacted parameters() {
+        return buildParameters;
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/ProactiveFatBuildSync.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/ProactiveFatBuildSync.java
index 94a1970..826ee4a 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/ProactiveFatBuildSync.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/ProactiveFatBuildSync.java
@@ -110,14 +110,14 @@ public class ProactiveFatBuildSync {
 
         int ldrToActivate = ThreadLocalRandom.current().nextInt(FAT_BUILD_PROACTIVE_TASKS);
 
-        scheduler.sheduleNamed(taskName("loadFatBuilds" + ldrToActivate, conn.serverId()),
-                () -> loadFatBuilds(ldrToActivate, conn.serverId()), 2, TimeUnit.MINUTES);
+        scheduler.sheduleNamed(taskName("loadFatBuilds" + ldrToActivate, conn.serverCode()),
+                () -> loadFatBuilds(ldrToActivate, conn.serverCode()), 2, TimeUnit.MINUTES);
 
     }
 
     @NotNull
     public synchronized SyncTask getSyncTask(ITeamcityConn conn) {
-        final SyncTask syncTask = buildToLoad.computeIfAbsent(conn.serverId(), s -> new SyncTask());
+        final SyncTask syncTask = buildToLoad.computeIfAbsent(conn.serverCode(), s -> new SyncTask());
 
         syncTask.conn = conn;
 
@@ -308,12 +308,12 @@ public class ProactiveFatBuildSync {
         if (savedVer.isFakeStub())
             refCompacted.setId(buildId); //to provide possiblity to save the build
 
-        final String srvName = conn.serverId();
-        final int srvIdMask = ITeamcityIgnited.serverIdToInt(srvName);
+        final String srvCode = conn.serverCode();
+        final int srvIdMask = ITeamcityIgnited.serverIdToInt(srvCode);
 
         buildRefDao.save(srvIdMask, refCompacted);
 
-        runHistSync.saveToHistoryLater(srvName, savedVer);
+        runHistSync.saveToHistoryLater(srvCode, savedVer);
 
         return savedVer;
     }
@@ -330,7 +330,7 @@ public class ProactiveFatBuildSync {
     @Nullable public FatBuildCompacted reloadBuild(ITeamcityConn conn, int buildId, @Nullable FatBuildCompacted existingBuild) {
         //todo some sort of locking to avoid double requests
 
-        final String srvName = conn.serverId();
+        final String srvName = conn.serverCode();
         final int srvIdMask = ITeamcityIgnited.serverIdToInt(srvName);
 
         if (existingBuild != null && existingBuild.isOutdatedEntityVersion()) {
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/StatisticsCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/StatisticsCompacted.java
index 02254a0..1d66c5b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/StatisticsCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/StatisticsCompacted.java
@@ -19,6 +19,7 @@ package org.apache.ignite.ci.teamcity.ignited.fatbuild;
 
 import com.google.common.base.Strings;
 import java.util.List;
+import org.apache.ignite.ci.db.Persisted;
 import org.apache.ignite.ci.tcmodel.conf.bt.Property;
 import org.apache.ignite.ci.tcmodel.result.stat.Statistics;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
@@ -27,11 +28,18 @@ import org.apache.ignite.internal.util.GridLongList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * Statistics values to be saved in compacted form.
+ */
+@Persisted
 public class StatisticsCompacted {
     /** Logger. */
     private static final Logger logger = LoggerFactory.getLogger(StatisticsCompacted.class);
 
+    /** Statistics Keys (Names), int value is coming from the compatcor. */
     private GridIntList keys;
+
+    /** Statistics Parsed Values as long. */
     private GridLongList values;
 
     public StatisticsCompacted() {
@@ -48,7 +56,7 @@ public class StatisticsCompacted {
             if (Strings.isNullOrEmpty(name))
                 continue;
 
-            final String valStr = next.getValue();
+            final String valStr = next.value();
             if (Strings.isNullOrEmpty(valStr))
                 continue;
 
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/TestCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/TestCompacted.java
index 07c49aa..11a2502 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/TestCompacted.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/fatbuild/TestCompacted.java
@@ -24,6 +24,8 @@ import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.Objects;
+import java.util.TreeMap;
+import java.util.function.BiPredicate;
 import org.apache.ignite.ci.analysis.RunStat;
 import org.apache.ignite.ci.tcbot.common.StringFieldCompacted;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
@@ -364,19 +366,35 @@ public class TestCompacted {
         return null;
     }
 
-    public Invocation toInvocation(IStringCompactor compactor, FatBuildCompacted build) {
+    /**
+     * @param compactor
+     * @param build
+     * @param paramsFilter parameters filter to find out parameters to be saved in RunHistory (for future filtering).
+     * @return
+     */
+    public Invocation toInvocation(IStringCompactor compactor,
+        FatBuildCompacted build,
+        BiPredicate<Integer, Integer> paramsFilter) {
         final boolean failedTest = isFailedTest(compactor);
 
-
         final int failCode = failedTest
-                ? (isIgnoredTest() || isMutedTest())
-                ? InvocationData.MUTED
-                : InvocationData.FAILURE
-                : InvocationData.OK;
+            ? (isIgnoredTest() || isMutedTest())
+            ? InvocationData.MUTED
+            : InvocationData.FAILURE
+            : InvocationData.OK;
 
-        return new Invocation(build.getId())
+        Invocation invocation = new Invocation(build.getId())
             .withStatus(failCode)
             .withStartDate(build.getStartDateTs())
             .withChanges(build.changes());
+
+        java.util.Map<Integer, Integer> importantParms = new TreeMap<>();
+
+        build.parameters().forEach((k, v) -> {
+            if (paramsFilter.test(k, v))
+                importantParms.put(k, v);
+        });
+
+        return invocation.withParameters(importantParms);
     }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/Invocation.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/Invocation.java
index d64b540..f3fbbe0 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/Invocation.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/Invocation.java
@@ -20,10 +20,14 @@ package org.apache.ignite.ci.teamcity.ignited.runhist;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.apache.ignite.ci.db.Persisted;
 
 /**
  * Run history element: invocation of build or test.
  */
+@Persisted
 public class Invocation {
     /** VCS Change not filled. */
     public static final int CHANGE_NOT_FILLED = 2;
@@ -46,6 +50,9 @@ public class Invocation {
     /** Build Start date as timestamp. */
     private long startDate;
 
+    /** Additional (important) build Pareters, which can be used for filtering. */
+    @Nullable private Map<Integer, Integer> parms;
+
     /**
      * Creates invocation.
      * @param buildId Build id.
@@ -131,4 +138,13 @@ public class Invocation {
     @Override public int hashCode() {
         return Objects.hashCode(buildId, status, changePresent, startDate);
     }
+
+    public Invocation withParameters(Map<Integer, Integer> parms) {
+        if (parms == null || parms.isEmpty())
+            return this;
+
+        this.parms = parms;
+
+        return this;
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/InvocationData.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/InvocationData.java
index 88ca10f..b6782c8 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/InvocationData.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/InvocationData.java
@@ -26,12 +26,14 @@ import java.util.TreeMap;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.ignite.ci.analysis.RunStat;
+import org.apache.ignite.ci.db.Persisted;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.jetbrains.annotations.NotNull;
 
 /**
  *
  */
+@Persisted
 public class InvocationData {
     /** Max days to keep test invocatoin data in run statistics: affects Bot Visa. */
     public static final int MAX_DAYS = 21;
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistSync.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistSync.java
index eb40e36..d5f804d 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistSync.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/runhist/RunHistSync.java
@@ -18,11 +18,13 @@
 package org.apache.ignite.ci.teamcity.ignited.runhist;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
@@ -35,6 +37,9 @@ import org.apache.ignite.ci.di.AutoProfiling;
 import org.apache.ignite.ci.di.MonitoredTask;
 import org.apache.ignite.ci.di.scheduler.IScheduler;
 import org.apache.ignite.ci.tcbot.TcBotSystemProperties;
+import org.apache.ignite.ci.tcbot.conf.ChainAtServerTracked;
+import org.apache.ignite.ci.tcbot.conf.ITcBotConfig;
+import org.apache.ignite.ci.tcbot.conf.ITcServerConfig;
 import org.apache.ignite.ci.teamcity.ignited.IStringCompactor;
 import org.apache.ignite.ci.teamcity.ignited.ITeamcityIgnited;
 import org.apache.ignite.ci.teamcity.ignited.buildref.BuildRefDao;
@@ -69,6 +74,8 @@ public class RunHistSync {
     /** Build DAO. */
     @Inject private FatBuildDao fatBuildDao;
 
+    @Inject private ITcBotConfig cfg;
+
     /** Build to save to history. */
     @GuardedBy("this")
     private final Map<String, SyncTask> buildToSave = new HashMap<>();
@@ -89,17 +96,19 @@ public class RunHistSync {
     }
 
     /**
-     * @param srvVame Server id.
+     * @param srvCode Server code (internal identification).
      * @param build Build.
      */
-    public void saveToHistoryLater(String srvVame, FatBuildCompacted build) {
+    public void saveToHistoryLater(String srvCode, FatBuildCompacted build) {
         if (!validForStatistics(build))
             return;
 
-        int srvId = ITeamcityIgnited.serverIdToInt(srvVame);
+        int srvId = ITeamcityIgnited.serverIdToInt(srvCode);
         if (histDao.buildWasProcessed(srvId, build.id()))
             return;
 
+        Set<Integer> allTriggeringBuildParameters = getFilteringParameters(srvCode);
+
         boolean saveNow = false;
 
         int branchNameNormalized = compactor.getStringId(normalizeBranch(build.branchName(compactor)));
@@ -109,7 +118,7 @@ public class RunHistSync {
         build.getAllTests().forEach(t -> {
             RunHistKey histKey = new RunHistKey(srvId, t.testName(), branchNameNormalized);
             List<Invocation> list = testInvMap.computeIfAbsent(histKey, k -> new ArrayList<>());
-            list.add(t.toInvocation(compactor, build));
+            list.add(t.toInvocation(compactor, build, (k, v) -> allTriggeringBuildParameters.contains(k)));
 
             cntTests.incrementAndGet();
         });
@@ -120,7 +129,7 @@ public class RunHistSync {
         int cnt = cntTests.get();
 
         synchronized (this) {
-            final SyncTask syncTask = buildToSave.computeIfAbsent(srvVame, s -> new SyncTask());
+            final SyncTask syncTask = buildToSave.computeIfAbsent(srvCode, s -> new SyncTask());
 
             if (syncTask.sheduledTestsCnt() + cnt <= MAX_TESTS_QUEUE)
                 syncTask.addLater(testInvMap, cnt, buildInvKey, buildInv);
@@ -138,11 +147,28 @@ public class RunHistSync {
         else {
             int ldrToActivate = ThreadLocalRandom.current().nextInt(HIST_LDR_TASKS) + 1;
 
-            scheduler.sheduleNamed(taskName("saveBuildToHistory." + ldrToActivate, srvVame),
-                () -> saveBuildToHistory(srvVame, ldrToActivate), 1, TimeUnit.MINUTES);
+            scheduler.sheduleNamed(taskName("saveBuildToHistory." + ldrToActivate, srvCode),
+                () -> saveBuildToHistory(srvCode, ldrToActivate), 1, TimeUnit.MINUTES);
         }
     }
 
+    @NotNull public Set<Integer> getFilteringParameters(String srvCode) {
+        Set<String> triggerParameters = this.cfg.getTrackedBranches().getBranches().stream().flatMap(
+            b -> b.getChainsStream()
+                .filter(ChainAtServerTracked::isTriggerBuild)
+                .filter(chain -> Objects.equals(chain.getServerId(), srvCode))
+                .flatMap(ChainAtServerTracked::buildParametersKeys)
+        ).collect(Collectors.toSet());
+
+        ITcServerConfig tcCfg = cfg.getTeamcityConfig(srvCode);
+
+        Collection<String> filtering = tcCfg.filteringParametersKeys();
+
+        triggerParameters.addAll(filtering);
+
+        return triggerParameters.stream().map(k -> compactor.getStringId(k)).collect(Collectors.toSet());
+    }
+
     @MonitoredTask(name = "Save Builds To History(srv, runner)", nameExtArgsIndexes = {0, 1})
     @SuppressWarnings("WeakerAccess")
     protected String saveBuildToHistory(String srvName, int ldrToActivate) {
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java
index d0e38dd..bdf7885 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/pure/ITeamcityConn.java
@@ -18,11 +18,12 @@
 package org.apache.ignite.ci.teamcity.pure;
 
 import java.util.List;
+import java.util.Map;
 import java.util.SortedSet;
 import java.util.concurrent.atomic.AtomicReference;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
-
+import org.apache.ignite.ci.tcbot.conf.ITcServerConfig;
 import org.apache.ignite.ci.tcmodel.agent.Agent;
 import org.apache.ignite.ci.tcmodel.changes.Change;
 import org.apache.ignite.ci.tcmodel.changes.ChangesList;
@@ -45,12 +46,19 @@ public interface ITeamcityConn {
      * @return Internal server ID as string
      */
     @Nullable
-    public String serverId();
+    public String serverCode();
+
+    /**
+     * @return TeamCity configuration.
+     */
+    public ITcServerConfig config();
 
     /**
      * @return Normalized Host address, ends with '/'.
      */
-    public String host();
+    default String host() {
+        return config().host();
+    }
 
     /**
      * @param buildId Build id.
@@ -81,13 +89,16 @@ public interface ITeamcityConn {
 
     /**
      * Trigger build.
-     *
-     * @param buildTypeId Build identifier.
+     * @param buildTypeId Build type (suite) identifier.
      * @param branchName Branch name.
      * @param cleanRebuild Rebuild all dependencies.
      * @param queueAtTop Put at the top of the build queue.
+     * @param buildParms addtitional build parameters, for example Java home or test suite. Use
+     * <code>put("testSuite", "org.apache.ignite.spi.discovery.tcp.ipfinder.elb.TcpDiscoveryElbIpFinderSelfTest");</code>
+     * to specify test suite to run.
      */
-    public Build triggerBuild(String buildTypeId, @Nonnull String branchName, boolean cleanRebuild, boolean queueAtTop);
+    public Build triggerBuild(String buildTypeId, @Nonnull String branchName, boolean cleanRebuild, boolean queueAtTop,
+        @Nullable Map<String, Object> buildParms);
 
     /**
      * @param buildId Build id.
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/SuiteCurrentStatus.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/SuiteCurrentStatus.java
index 5a13b8a..454f9dc 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/SuiteCurrentStatus.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/SuiteCurrentStatus.java
@@ -20,6 +20,7 @@ package org.apache.ignite.ci.web.model.current;
 import com.google.common.base.Strings;
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -128,6 +129,8 @@ import static org.apache.ignite.ci.util.UrlUtil.escape;
     /** Possible blocker: filled for PR and builds checks, mean there was stable execution in master, but */
     public Boolean possibleBlocker;
 
+    public Set<String> tags = new HashSet<>();
+
     public void initFromContext(ITeamcityIgnited tcIgnited,
         @Nonnull final MultBuildRunCtx suite,
         @Nullable final String baseBranch) {
@@ -221,6 +224,8 @@ import static org.apache.ignite.ci.util.UrlUtil.escape;
         this.suiteId = suite.suiteId();
         branchName = branchForLink(suite.branchName());
         // todo implement this logic in suite possibleBlocker = suite.hasPossibleBlocker();
+
+        tags = suite.tags();
     }
 
     private void initSuiteStat(ITeamcityIgnited tcIgnited,
diff --git a/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css b/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css
index 65c1b77..de84f61 100644
--- a/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css
+++ b/ignite-tc-helper-web/src/main/webapp/css/style-1.5.css
@@ -587,3 +587,10 @@ div.tooltip {
 	transition: transform .25s;
 	display: inline-block;
 }
+
+.buildTag {
+	border: 1px solid #cfcfcf;
+	-webkit-box-shadow: 2px 4px 1px 0px rgba(224,224,224,1);
+	-moz-box-shadow: 2px 4px 1px 0px rgba(224,224,224,1);
+	box-shadow: 2px 4px 1px 0px rgba(224,224,224,1);
+}
\ No newline at end of file
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 c1117a0..04ace45 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
@@ -90,15 +90,15 @@ function showChainResultsWithSettings(result, settings) {
 
 
 /**
- * @param server - see org.apache.ignite.ci.web.model.current.ChainAtServerCurrentStatus Java Class.
+ * @param chain - see org.apache.ignite.ci.web.model.current.ChainAtServerCurrentStatus Java Class.
  * @param settings - see Settings JavaScript class.
  */
-function showChainCurrentStatusData(server, settings) {
-    if(!isDefinedAndFilled(server))
+function showChainCurrentStatusData(chain, settings) {
+    if(!isDefinedAndFilled(chain))
         return;
 
-    if(isDefinedAndFilled(server.buildNotFound) && server.buildNotFound ) {
-        return "<tr><td><b>Error: Build not found for branch [" + server.branchName + "]</b>" +
+    if(isDefinedAndFilled(chain.buildNotFound) && chain.buildNotFound ) {
+        return "<tr><td><b>Error: Build not found for branch [" + chain.branchName + "]</b>" +
             "<br><br><span style='color:grey; font-size:12px;'>Perhaps, more than 2 weeks have passed since the last build " +
             "run. <br>There is no data on the TC server</span></td></tr>";
     }
@@ -108,22 +108,22 @@ function showChainCurrentStatusData(server, settings) {
     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>";
+    res += "<tr><td><b> Server: </b></td><td>[" + chain.serverId + "]</td></tr>";
 
-    if (isDefinedAndFilled(server.prNum)) {
+    if (isDefinedAndFilled(chain.prNum)) {
         res += "<tr><td><b> PR: </b></td><td>";
 
-        if (isDefinedAndFilled(server.webToPr))
-            res += "<a href='" + server.webToPr + "'>[#" + server.prNum + "]</a>";
+        if (isDefinedAndFilled(chain.webToPr))
+            res += "<a href='" + chain.webToPr + "'>[#" + chain.prNum + "]</a>";
         else
-            res += "[#" + server.prNum + "]";
+            res += "[#" + chain.prNum + "]";
 
         res += "</td></tr>";
     }
 
-    if (isDefinedAndFilled(server.webToTicket) && isDefinedAndFilled(server.ticketFullName)) {
+    if (isDefinedAndFilled(chain.webToTicket) && isDefinedAndFilled(chain.ticketFullName)) {
         res += "<tr><td><b> Ticket: </b></td><td>";
-        res += "<a href='" + server.webToTicket + "'>[" + server.ticketFullName + "]</a>";
+        res += "<a href='" + chain.webToTicket + "'>[" + chain.ticketFullName + "]</a>";
         res += "</td></tr>";
     }
 
@@ -131,26 +131,26 @@ function showChainCurrentStatusData(server, settings) {
 
     if (isDefinedAndFilled(findGetParameter("suiteId")))
         parentSuitId = findGetParameter("suiteId");
-    else if (isDefinedAndFilled(server))
-        parentSuitId = findGetParameter("buildTypeId", server.webToHist);
+    else if (isDefinedAndFilled(chain))
+        parentSuitId = findGetParameter("buildTypeId", chain.webToHist);
 
     if (isDefinedAndFilled(parentSuitId)) {
         res += "<tr><td><b> Suite: </b></td><td>[" + parentSuitId + "] ";
-        res += " <a href='" + server.webToHist + "'>[TC history]</a>";
+        res += " <a href='" + chain.webToHist + "'>[TC history]</a>";
         res += "</td></tr>";
     }
 
     res += "</table>";
     res += "</br>";
 
-    if (isDefinedAndFilled(server.chainName)) {
-        res += server.chainName + " ";
+    if (isDefinedAndFilled(chain.chainName)) {
+        res += chain.chainName + " ";
     }
 
     res += "<b>Chain result: </b>";
 
-    if (isDefinedAndFilled(server.failedToFinish) && isDefinedAndFilled(server.failedTests))
-        res += server.failedToFinish + " suites and " + server.failedTests + " tests failed";
+    if (isDefinedAndFilled(chain.failedToFinish) && isDefinedAndFilled(chain.failedTests))
+        res += chain.failedToFinish + " suites and " + chain.failedTests + " tests failed";
     else
         res += "empty";
 
@@ -163,8 +163,8 @@ function showChainCurrentStatusData(server, settings) {
 
     var cntFailed = 0;
     var suitesFailedList = "";
-    for (var i = 0; i < server.suites.length; i++) {
-        var suite = server.suites[i];
+    for (var i = 0; i < chain.suites.length; i++) {
+        var suite = chain.suites[i];
 
         if (!isDefinedAndFilled(suite.suiteId))
             continue;
@@ -178,44 +178,44 @@ function showChainCurrentStatusData(server, settings) {
         cntFailed++;
     }
 
-    if (suitesFailedList.length !== 0 && isDefinedAndFilled(server.serverId) && isDefinedAndFilled(server.branchName)) {
+    if (suitesFailedList.length !== 0 && isDefinedAndFilled(chain.serverId) && isDefinedAndFilled(chain.branchName)) {
         mInfo += "Trigger failed " + cntFailed + " builds";
         mInfo += " <a href='javascript:void(0);' ";
-        mInfo += " onClick='triggerBuilds(\"" + server.serverId + "\", \"" + parentSuitId + "\", " +
-            "\"" + suitesFailedList + "\", \"" + server.branchName + "\", false, false, null, \"" + server.prNum + "\")' ";
+        mInfo += " onClick='triggerBuilds(\"" + chain.serverId + "\", \"" + parentSuitId + "\", " +
+            "\"" + suitesFailedList + "\", \"" + chain.branchName + "\", false, false, null, \"" + chain.prNum + "\")' ";
         mInfo += " title='trigger builds'>in queue</a> ";
 
         mInfo += " <a href='javascript:void(0);' ";
-        mInfo += " onClick='triggerBuilds(\"" + server.serverId + "\", \"" + parentSuitId + "\", " +
-            "\"" + suitesFailedList + "\", \"" + server.branchName + "\", true, false, null, \"" + server.prNum + "\")' ";
+        mInfo += " onClick='triggerBuilds(\"" + chain.serverId + "\", \"" + parentSuitId + "\", " +
+            "\"" + suitesFailedList + "\", \"" + chain.branchName + "\", true, false, null, \"" + chain.prNum + "\")' ";
         mInfo += " title='trigger builds'>on top</a><br>";
     }
 
-    mInfo += "Duration: " + server.durationPrintable + " " +
-        "(Net Time: " + server.durationNetTimePrintable + "," +
-        " Tests: " + server.testsDurationPrintable + "," +
-        " Src. Update: " + server.sourceUpdateDurationPrintable + "," +
-        " Artifacts Publishing: " + server.artifcactPublishingDurationPrintable + "," +
-        " Dependecies Resolving: " + server.dependeciesResolvingDurationPrintable + "," +
-        " Timeouts: " + server.lostInTimeouts + ")<br>";
+    mInfo += "Duration: " + chain.durationPrintable + " " +
+        "(Net Time: " + chain.durationNetTimePrintable + "," +
+        " Tests: " + chain.testsDurationPrintable + "," +
+        " Src. Update: " + chain.sourceUpdateDurationPrintable + "," +
+        " Artifacts Publishing: " + chain.artifcactPublishingDurationPrintable + "," +
+        " Dependecies Resolving: " + chain.dependeciesResolvingDurationPrintable + "," +
+        " Timeouts: " + chain.lostInTimeouts + ")<br>";
 
-    if (isDefinedAndFilled(server.topLongRunning) && server.topLongRunning.length > 0) {
+    if (isDefinedAndFilled(chain.topLongRunning) && chain.topLongRunning.length > 0) {
         mInfo += "Top long running:<br>";
 
         mInfo += "<table>";
-        for (var j = 0; j < server.topLongRunning.length; j++) {
-            mInfo += showTestFailData(server.topLongRunning[j], false, settings);
+        for (var j = 0; j < chain.topLongRunning.length; j++) {
+            mInfo += showTestFailData(chain.topLongRunning[j], false, settings);
         }
         mInfo += "</table>";
     }
 
 
-    if (isDefinedAndFilled(server.logConsumers) && server.logConsumers.length > 0) {
+    if (isDefinedAndFilled(chain.logConsumers) && chain.logConsumers.length > 0) {
         mInfo += "Top Log Consumers:<br>";
 
         mInfo += "<table>";
-        for (var k = 0; k < server.logConsumers.length; k++) {
-            mInfo += showTestFailData(server.logConsumers[k], false, settings);
+        for (var k = 0; k < chain.logConsumers.length; k++) {
+            mInfo += showTestFailData(chain.logConsumers[k], false, settings);
         }
         mInfo += "</table>";
     }
@@ -234,13 +234,13 @@ function showChainCurrentStatusData(server, settings) {
     // }
 
     if (settings.isJiraAvailable()) {
-        res += "<button onclick='commentJira(\"" + server.serverId + "\", \"" + server.branchName + "\", \""
+        res += "<button onclick='commentJira(\"" + chain.serverId + "\", \"" + chain.branchName + "\", \""
             + parentSuitId + "\")'>Comment JIRA</button>&nbsp;&nbsp;";
 
         var blockersList = "";
 
-        for (var l = 0; l < server.suites.length; l++) {
-            var suite0 = server.suites[l];
+        for (var l = 0; l < chain.suites.length; l++) {
+            var suite0 = chain.suites[l];
 
             var suiteOrNull = suiteWithCriticalFailuresOnly(suite0);
 
@@ -252,16 +252,16 @@ function showChainCurrentStatusData(server, settings) {
             }
         }
 
-        res += "<button onclick='triggerBuilds(\"" + server.serverId + "\", \"" + parentSuitId + "\", \"" +
-            blockersList + "\", \"" + server.branchName + "\", false, false, null,  \"" + + server.prNum + "\")'> " +
+        res += "<button onclick='triggerBuilds(\"" + chain.serverId + "\", \"" + parentSuitId + "\", \"" +
+            blockersList + "\", \"" + chain.branchName + "\", false, false, null,  \"" + + chain.prNum + "\")'> " +
             "Re-run possible blockers</button><br>";
 
-        res += "<button onclick='triggerBuilds(\"" + server.serverId + "\", \"" + parentSuitId + "\", \"" +
-            blockersList + "\", \"" + server.branchName + "\", false, true, null, \"" + + server.prNum +"\")'> " +
+        res += "<button onclick='triggerBuilds(\"" + chain.serverId + "\", \"" + parentSuitId + "\", \"" +
+            blockersList + "\", \"" + chain.branchName + "\", false, true, null, \"" + + chain.prNum +"\")'> " +
             "Re-run possible blockers & Comment JIRA</button><br>";
     }
 
-    if (isDefinedAndFilled(server.baseBranchForTc)) {
+    if (isDefinedAndFilled(chain.baseBranchForTc)) {
         // if (settings.isGithubAvailable())
         //     res+="<br>";
 
@@ -269,17 +269,17 @@ function showChainCurrentStatusData(server, settings) {
             res+="<br>";
 
         res += "Base branch";
-        res += ": " + server.baseBranchForTc.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
+        res += ": " + chain.baseBranchForTc.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
     }
 
     res += "&nbsp;</td></tr>";
 
-    res += addBlockersData(server, settings);
+    res += addBlockersData(chain, settings);
 
-    for (var m = 0; m < server.suites.length; m++) {
-        var subSuite = server.suites[m];
+    for (var m = 0; m < chain.suites.length; m++) {
+        var subSuite = chain.suites[m];
 
-        res += showSuiteData(subSuite, settings, server.prNum);
+        res += showSuiteData(subSuite, settings, chain.prNum);
     }
 
     res += "<tr><td colspan='4'>&nbsp;</td></tr>";
@@ -655,6 +655,13 @@ function showSuiteData(suite, settings, prNum) {
 
     res += "</a> ]";
 
+    if(isDefinedAndFilled(suite.tags)) {
+        for (let i = 0; i < suite.tags.length; i++) {
+            const tag = suite.tags[i];
+            res += " <span class='buildTag'>" + tag + "</span>" ;
+        }
+    }
+
     if (isDefinedAndFilled(suite.runningBuildCount) && suite.runningBuildCount !== 0) {
         res += " <img src='https://image.flaticon.com/icons/png/128/2/2745.png' width=12px height=12px> ";
         res += " " + suite.runningBuildCount + " running";
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java
index 04964fd..daa7b77 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/IgnitedTcInMemoryIntegrationTest.java
@@ -477,6 +477,11 @@ public class IgnitedTcInMemoryIntegrationTest {
         assertEquals(refBuild.getStartDate(), actBuild.getStartDate());
         assertEquals(refBuild.getFinishDate(), actBuild.getFinishDate());
 
+        assertParameter(refBuild, actBuild, "env.JAVA_HOME");
+        assertParameter(refBuild, actBuild, "reverse.dep.*.env.JAVA_HOME");
+        assertNotNull(refBuild.parameter(ITeamcity.TCBOT_TRIGGER_TIME));
+        assertNull(actBuild.parameter(ITeamcity.TCBOT_TRIGGER_TIME));
+
         final Triggered refTrig = refBuild.getTriggered();
         final Triggered actTrig = actBuild.getTriggered();
         assertNotNull(refTrig);
@@ -532,6 +537,13 @@ public class IgnitedTcInMemoryIntegrationTest {
         assertEquals(refRev0.vcsBranchName(), actRev0.vcsBranchName());
         assertEquals(refRev0.vcsRootInstance().id(), actRev0.vcsRootInstance().id());
         assertEquals(refRev0.vcsRootInstance().vcsRootId(), actRev0.vcsRootInstance().vcsRootId());
+
+
+    }
+
+    public void assertParameter(Build refBuild, Build actBuild, String parmKey) {
+        assertNotNull(refBuild.parameter(parmKey));
+        assertEquals(refBuild.parameter(parmKey), actBuild.parameter(parmKey));
     }
 
     private void saveTmpFile(Object obj, String name) throws IOException, JAXBException {
diff --git a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
index 8006701..2354722 100644
--- a/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
+++ b/ignite-tc-helper-web/src/test/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedMock.java
@@ -129,12 +129,12 @@ public class TeamcityIgnitedMock {
             if (!build.isFinished(c))
                 continue;
 
-            build.getAllTests().forEach(t -> {
-                RunHistKey histKey = new RunHistKey(srvId, t.testName(), build.branchName());
+            build.getAllTests().forEach(testCompacted -> {
+                RunHistKey histKey = new RunHistKey(srvId, testCompacted.testName(), build.branchName());
 
                 final RunHistCompacted hist = histCache.computeIfAbsent(histKey, RunHistCompacted::new);
 
-                Invocation inv = t.toInvocation(c, build);
+                Invocation inv = testCompacted.toInvocation(c, build, (k, v) -> true);
 
                 hist.addInvocation(inv);
             });
diff --git a/ignite-tc-helper-web/src/test/resources/build.xml b/ignite-tc-helper-web/src/test/resources/build.xml
index 46e0903..541f723 100644
--- a/ignite-tc-helper-web/src/test/resources/build.xml
+++ b/ignite-tc-helper-web/src/test/resources/build.xml
@@ -37,6 +37,7 @@
         <property name="TEST_SUITE" value="IgniteCacheMvccTestSuite" inherited="true"/>
         <property name="XMS" value="2g" inherited="true"/>
         <property name="XMX" value="2g" inherited="true"/>
+        <property name="tcbot.triggerTime" value="12345"/>
     </properties>
     <statistics href="/app/rest/latest/builds/id:2153237/statistics"/>
     <snapshot-dependencies count="1">