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/08/16 14:00:29 UTC

[ignite-teamcity-bot] branch master updated: Triggering fix: older master builds were not triggered because build type ID is not checked during check queue job

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 9d1dc6a  Triggering fix: older master builds were not triggered because build type ID is not checked during check queue job
9d1dc6a is described below

commit 9d1dc6a7e405d84b93ccfce0d571db13c8931c6e
Author: Dmitriy Pavlov <dp...@apache.org>
AuthorDate: Fri Aug 16 17:00:24 2019 +0300

    Triggering fix: older master builds were not triggered because build type ID is not checked during check queue job
---
 .../org/apache/ignite/ci/jobs/CheckQueueJob.java   | 89 ++++++++++++++--------
 .../runners/IgniteTeamcityHelperRunnerExample.java |  2 +-
 .../tcbot/visa/TcBotTriggerAndSignOffService.java  | 15 +++-
 .../org/apache/ignite/ci/web/model/Version.java    |  2 +-
 .../ignite/tcbot/engine/board/BoardService.java    |  2 +-
 .../tcbot/engine/conf/ChainAtServerTracked.java    | 32 +++-----
 .../ignite/tcbot/engine/conf/ITrackedChain.java    |  8 +-
 .../apache/ignite/tcignited/ITeamcityIgnited.java  | 17 +++--
 .../ignite/tcignited/TeamcityIgnitedImpl.java      | 22 ++++--
 .../org/apache/ignite/tcservice/ITeamcityConn.java |  8 +-
 .../tcservice/TeamcityServiceConnection.java       | 48 +++++++-----
 11 files changed, 152 insertions(+), 93 deletions(-)

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 e8eac15..fff05e3 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
@@ -17,9 +17,23 @@
 
 package org.apache.ignite.ci.jobs;
 
+import com.google.common.base.Strings;
+import java.text.MessageFormat;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.inject.Inject;
 import org.apache.ignite.ci.teamcity.ignited.BuildRefCompacted;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
 import org.apache.ignite.ci.user.ITcBotUserCreds;
+import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.tcbot.common.exeption.ExceptionUtil;
 import org.apache.ignite.tcbot.common.interceptor.AutoProfiling;
 import org.apache.ignite.tcbot.common.interceptor.MonitoredTask;
@@ -36,13 +50,6 @@ import org.apache.ignite.tcservice.model.user.User;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.inject.Inject;
-import java.text.MessageFormat;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
 /**
  * Trigger build if half of agents are available and there is no self-triggered builds in build queue.
  */
@@ -94,7 +101,7 @@ public class CheckQueueJob implements Runnable {
     /**   */
     @SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})
     @AutoProfiling
-    @MonitoredTask(name = "Check Servers Queue")
+    @MonitoredTask(name = "Check Servers Queue (Triggering)")
     protected String runEx() {
         if (Boolean.valueOf(System.getProperty(AUTO_TRIGGERING_BUILD_DISABLED))) {
             final String msg = "Automatic build triggering was disabled.";
@@ -144,7 +151,7 @@ public class CheckQueueJob implements Runnable {
      */
     @SuppressWarnings({"WeakerAccess", "UnusedReturnValue"})
     @AutoProfiling
-    @MonitoredTask(name = "Check Server Queue", nameExtArgIndex = 0)
+    @MonitoredTask(name = "Check Server Queue (Triggering)", nameExtArgIndex = 0)
     protected String checkQueue(String srvCode, List<ITrackedChain> chains) {
         ITeamcityIgnited tcIgn = tcIgnitedProv.server(srvCode, creds);
 
@@ -180,22 +187,23 @@ public class CheckQueueJob implements Runnable {
             if (!Objects.equals(chain.serverCode(), srvCode))
                 continue;
 
-            String result = checkIfChainTriggerable(chain.serverCode(), chain.tcSuiteId(), chain.tcBranch(), tcIgn, selfLogin, chain);
+            String chainRes = checkIfChainTriggerable(chain.serverCode(), chain.tcSuiteId(), chain.tcBranch(), tcIgn, selfLogin, chain, agentStatus);
 
-            res.append(result).append("; ");
+            res.append(chainRes).append("; ");
         }
 
         return res.toString();
     }
 
     @SuppressWarnings("WeakerAccess")
-    @MonitoredTask(name = "Check Server Queue", nameExtArgsIndexes = {0, 1, 2})
-    protected String checkIfChainTriggerable(String serverCode,
-                                             String buildTypeId,
-                                             String tcBranch,
-                                             ITeamcityIgnited tcIgn,
-                                             String selfLogin,
-                                             ITrackedChain chain) {
+    @MonitoredTask(name = "Check Server Queue (Triggering)", nameExtArgsIndexes = {0, 1, 2})
+    protected String checkIfChainTriggerable(String srvCode,
+        String buildTypeId,
+        String tcBranch,
+        ITeamcityIgnited tcIgn,
+        String selfLogin,
+        ITrackedChain chain,
+        String agentStatus) {
         List<BuildRefCompacted> buildsForBr = tcIgn.getQueuedBuildsCompacted(tcBranch);
 
         for (BuildRefCompacted refComp : buildsForBr) {
@@ -203,9 +211,10 @@ public class CheckQueueJob implements Runnable {
             if (buildId == null)
                 continue; // should not occur;
 
-            final FatBuildCompacted fatBuild = tcIgn.getFatBuild(buildId);
-            final Build build = fatBuild.toBuild(compactor);
-            final Triggered triggered = build.getTriggered();
+            FatBuildCompacted fatBuild = tcIgn.getFatBuild(buildId);
+
+            Build build = fatBuild.toBuild(compactor);
+            Triggered triggered = build.getTriggered();
 
             if (triggered == null) {
                 logger.info("Unable to get triggering info for queued build {} (type={}).", buildId, build.buildTypeId);
@@ -221,13 +230,21 @@ public class CheckQueueJob implements Runnable {
                 continue;
             }
 
+            String buildTypeIdExisting = build.buildTypeId();
+            if (buildTypeIdExisting == null) {
+                logger.info("Unable to get buildTypeId  for queued build {} (type={}).", buildId, build.buildTypeId);
+
+                continue;
+            }
+
             String login = user.username;
 
-            if (selfLogin.equalsIgnoreCase(login)) {
-                final String msg
-                        = MessageFormat.format("Queued build {0} was early triggered " +
-                        "(user {1}, branch {2}, suite {3})." +
-                        " Will not start new build.", buildId, login, tcBranch, build.buildTypeId);
+            if (selfLogin.equalsIgnoreCase(login)
+                && buildTypeIdExisting.trim().equals(Strings.nullToEmpty(buildTypeId).trim())) {
+                String msg
+                    = MessageFormat.format("Queued build {0} was early triggered " +
+                    "(user {1}, branch {2}, suite {3})." +
+                    " Will not start new build.", Integer.toString(buildId), login, tcBranch, buildTypeIdExisting);
 
                 logger.info(msg);
 
@@ -238,17 +255,16 @@ public class CheckQueueJob implements Runnable {
         long curr = System.currentTimeMillis();
         long delay = chain.triggerBuildQuietPeriod();
 
+        long minsPassed = -1;
         if (delay > 0) {
             Long lastStart = startTimes.get(chain);
 
-            long minsPassed;
-
             if (lastStart != null &&
                 (minsPassed = TimeUnit.MILLISECONDS.toMinutes(curr - lastStart)) < delay) {
 
                 final String msg = MessageFormat.format("Skip triggering build, timeout has not expired " +
                                 "(server={0}, suite={1}, branch={2}, delay={3} mins, passed={4} mins)",
-                        serverCode, buildTypeId, tcBranch,
+                    srvCode, buildTypeId, tcBranch,
                         chain.triggerBuildQuietPeriod(), minsPassed);
                 logger.info(msg);
 
@@ -258,9 +274,20 @@ public class CheckQueueJob implements Runnable {
 
         startTimes.put(chain, curr);
 
-        tcIgn.triggerBuild(buildTypeId, tcBranch, true, false, chain.generateBuildParameters());
+        StringBuilder trigComment = new StringBuilder();
+        trigComment.append("Scheduled run ");
+        trigComment.append(agentStatus);
+        if (minsPassed > 0)
+            trigComment.append(" Since last build triggering: ").append(Duration.ofMinutes(minsPassed));
+
+        T2<Build, Set<Integer>> buildAndIds = tcIgn.triggerBuild(buildTypeId, tcBranch, true, false,
+            chain.generateBuildParameters(),
+            true,
+            trigComment.toString());
+
+        Build build = buildAndIds.get1();
 
-        return buildTypeId + " " +  tcBranch  + " triggered; ";
+        return "Build id " + build.getId() + " " + tcBranch + " for " + buildTypeId + " 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 e35ad76..5dbe18c 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
@@ -62,7 +62,7 @@ public class IgniteTeamcityHelperRunnerExample {
             String buildTypeIdAllP = "id8xIgniteGridGainTestsJava8_RunAll";
             //  buildTypeIdAll="IgniteTests24Java8_Queries1";
 
-            helper.triggerBuild(buildTypeIdAll, branchName, true, false, Collections.emptyMap());
+            helper.triggerBuild(buildTypeIdAll, branchName, true, false, Collections.emptyMap(), null);
         }
     }
 
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 b6272c1..f51185e 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
@@ -28,6 +28,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Objects;
@@ -56,6 +57,7 @@ import org.apache.ignite.ci.web.model.hist.VisasHistoryStorage;
 import org.apache.ignite.githubignited.IGitHubConnIgnited;
 import org.apache.ignite.githubignited.IGitHubConnIgnitedProvider;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.jiraignited.IJiraIgnited;
 import org.apache.ignite.jiraignited.IJiraIgnitedProvider;
 import org.apache.ignite.jiraservice.Ticket;
@@ -65,8 +67,6 @@ import org.apache.ignite.tcbot.common.conf.ITcServerConfig;
 import org.apache.ignite.tcbot.engine.conf.ITcBotConfig;
 import org.apache.ignite.tcbot.engine.pr.BranchTicketMatcher;
 import org.apache.ignite.tcbot.engine.pr.PrChainsProcessor;
-import org.apache.ignite.tcbot.engine.ui.DsSuiteUi;
-import org.apache.ignite.tcbot.engine.ui.DsTestFailureUi;
 import org.apache.ignite.tcbot.engine.ui.ShortSuiteUi;
 import org.apache.ignite.tcbot.engine.ui.ShortTestFailureUi;
 import org.apache.ignite.tcbot.persistence.IStringCompactor;
@@ -291,9 +291,16 @@ public class TcBotTriggerAndSignOffService {
 
         //todo consult if there are change differences here https://ci.ignite.apache.org/app/rest/changes?locator=buildType:(id:IgniteTests24Java8_Cache7),pending:true,branch:pull%2F6224%2Fhead
         Build[] builds = new Build[suiteIds.length];
+        Set<Integer> buildidsToSync = new HashSet<>();
 
-        for (int i = 0; i < suiteIds.length; i++)
-            builds[i] = teamcity.triggerBuild(suiteIds[i], branchForTc, false, top != null && top, new HashMap<String, Object>());
+        for (int i = 0; i < suiteIds.length; i++) {
+            T2<Build, Set<Integer>> objects = teamcity.triggerBuild(suiteIds[i], branchForTc, false, top != null && top, new HashMap<>(),
+                false, "");
+            buildidsToSync.addAll(objects.get2());
+            builds[i] = objects.get1();
+        }
+
+        teamcity.fastBuildsSync(buildidsToSync);
 
         if (observe != null && observe)
             jiraRes += observeJira(srvCodeOrAlias, branchForTc, ticketId, prov, parentSuiteId, baseBranchForTc, builds);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Version.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Version.java
index 34e494a..30b2918 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Version.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/Version.java
@@ -28,7 +28,7 @@ package org.apache.ignite.ci.web.model;
     public static final String GITHUB_REF = "https://github.com/apache/ignite-teamcity-bot";
 
     /** TC Bot Version. */
-    public static final String VERSION = "20190815";
+    public static final String VERSION = "20190816";
 
     /** Java version, where Web App is running. */
     public String javaVer;
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/board/BoardService.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/board/BoardService.java
index e134512..e7f9ade 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/board/BoardService.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/board/BoardService.java
@@ -204,7 +204,7 @@ public class BoardService {
         Stream<Issue> stream = issuesStorage.allIssues();
 
         //todo make property how old issues can be considered as configuration parameter
-        long minIssueTs = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(9);
+        long minIssueTs = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(11);
 
         //todo not so good to to call init() twice
         fatBuildDao.init();
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ChainAtServerTracked.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ChainAtServerTracked.java
index 737d760..c77b77f 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ChainAtServerTracked.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ChainAtServerTracked.java
@@ -69,7 +69,7 @@ public class ChainAtServerTracked extends ChainAtServer implements ITrackedChain
     /**
      * @return base (etalon) branch in TC identification t builds
      */
-    @Nonnull public Optional<String> tcBaseBranch() {
+    @Override @Nonnull public Optional<String> tcBaseBranch() {
         if (Strings.isNullOrEmpty(baseBranchForTc))
             return Optional.empty();
 
@@ -97,29 +97,25 @@ public class ChainAtServerTracked extends ChainAtServer implements ITrackedChain
         return Objects.hash(super.hashCode(), branchForRest, baseBranchForTc, triggerBuild, triggerBuildQuietPeriod, triggerParameters);
     }
 
-    /**
-     * @return {@code True} If automatic build triggering enabled.
-     */
-    public boolean triggerBuild() {
+    /** {@inheritDoc} */
+    @Override public boolean triggerBuild() {
         return triggerBuild == null ? false : triggerBuild;
     }
 
-    /**
-     * @return Quiet period in minutes between triggering builds or zero if period is not set and should be ignored.
-     */
-    public int triggerBuildQuietPeriod() {
+    /** {@inheritDoc} */
+    @Override public int triggerBuildQuietPeriod() {
         return triggerBuildQuietPeriod == null ? 0 : triggerBuildQuietPeriod;
     }
 
-    @Override
-    public String tcSuiteId() {
+    /** {@inheritDoc} */
+    @Override  public String tcSuiteId() {
         return suiteId;
     }
 
     /**
      * @return Map with parameter values for current run.
      */
-    @Nonnull public Map<String, Object> generateBuildParameters() {
+    @Override @Nonnull public Map<String, Object> generateBuildParameters() {
         if (triggerParameters == null || triggerParameters.isEmpty())
             return Collections.emptyMap();
 
@@ -145,17 +141,13 @@ public class ChainAtServerTracked extends ChainAtServer implements ITrackedChain
         return triggerParameters.stream().map(BuildParameterSpec::name);
     }
 
-    @Override
-    public String tcBranch() {
+    /** {@inheritDoc} */
+    @Override  public String tcBranch() {
         return branchForRest;
     }
 
-    /**
-     * @return Server ID to access configs within IDataSourceCfgSupplier.
-     */
-    @Override
-    public String serverCode() {
+    /** {@inheritDoc} */
+    @Override public String serverCode() {
         return serverId;
     }
-
 }
diff --git a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITrackedChain.java b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITrackedChain.java
index e88c042..2e3d3cb 100644
--- a/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITrackedChain.java
+++ b/tcbot-engine/src/main/java/org/apache/ignite/tcbot/engine/conf/ITrackedChain.java
@@ -24,6 +24,9 @@ import java.util.Optional;
  *
  */
 public interface ITrackedChain {
+    /**
+     * @return Server Code to access configs within IDataSourceCfgSupplier.
+     */
     public String serverCode();
 
     public String tcBranch();
@@ -31,7 +34,7 @@ public interface ITrackedChain {
     @Nonnull public Optional<String> tcBaseBranch();
 
     /**
-     * @return trigger build quiet period, milliseconds.
+     * @return Quiet period in minutes between triggering builds or zero if period is not set and should be ignored.
      */
     public int triggerBuildQuietPeriod();
 
@@ -40,5 +43,8 @@ public interface ITrackedChain {
 
     public String tcSuiteId();
 
+    /**
+     * @return {@code True} If automatic build triggering enabled.
+     */
     public boolean triggerBuild();
 }
diff --git a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/ITeamcityIgnited.java b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/ITeamcityIgnited.java
index e68fd46..04802ae 100644
--- a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/ITeamcityIgnited.java
+++ b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/ITeamcityIgnited.java
@@ -33,6 +33,7 @@ import org.apache.ignite.ci.teamcity.ignited.buildtype.BuildTypeRefCompacted;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeCompacted;
 import org.apache.ignite.ci.teamcity.ignited.change.RevisionCompacted;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.tcbot.common.conf.ITcServerConfig;
 import org.apache.ignite.tcignited.history.IRunHistory;
 import org.apache.ignite.tcignited.history.ISuiteRunHistory;
@@ -101,17 +102,23 @@ public interface ITeamcityIgnited {
 
     /**
      * Trigger build. Enforces TC Bot to load all builds related to this triggered one.
-     *
      * @param buildTypeId Build type 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.
+*      * <code>put("testSuite", "org.apache.ignite.spi.discovery.tcp.ipfinder.elb.TcpDiscoveryElbIpFinderSelfTest");</code>
+     * @param actualizeReferences enforce loading of triggered builds from TC now. Otherwise, return these IDS.
+     * @param freeTextComments some additional comments to be added to build (chain).
+     */
+    public T2<Build, Set<Integer>> triggerBuild(String buildTypeId, String branchName, boolean cleanRebuild, boolean queueAtTop,
+        Map<String, Object> buildParms, boolean actualizeReferences, @Nullable  String freeTextComments);
+
+    /**
+     * Runs synchronization of provided builds.
+     * @param collect Collect.
      */
-    public Build triggerBuild(String buildTypeId, String branchName, boolean cleanRebuild, boolean queueAtTop,
-        Map<String, Object> buildParms);
+    public void fastBuildsSync(Set<Integer> collect);
 
     /**
      * @param srvId Server id.
diff --git a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/TeamcityIgnitedImpl.java b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/TeamcityIgnitedImpl.java
index ad40e79..148ef71 100644
--- a/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/TeamcityIgnitedImpl.java
+++ b/tcbot-teamcity-ignited/src/main/java/org/apache/ignite/tcignited/TeamcityIgnitedImpl.java
@@ -23,7 +23,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -49,6 +48,7 @@ import org.apache.ignite.ci.teamcity.ignited.change.ChangeCompacted;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeDao;
 import org.apache.ignite.ci.teamcity.ignited.change.ChangeSync;
 import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildCompacted;
+import org.apache.ignite.internal.util.typedef.T2;
 import org.apache.ignite.tcbot.common.conf.ITcServerConfig;
 import org.apache.ignite.tcbot.common.interceptor.AutoProfiling;
 import org.apache.ignite.tcbot.common.interceptor.GuavaCached;
@@ -509,18 +509,26 @@ public class TeamcityIgnitedImpl implements ITeamcityIgnited {
     }
 
     /** {@inheritDoc} */
-    @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);
+    @Override public T2<Build, Set<Integer>> triggerBuild(String buildTypeId, String branchName, boolean cleanRebuild, boolean queueAtTop,
+        Map<String, Object> buildParms, boolean actualizeReferences, @Nullable String freeTextComments) {
+        Build build = conn.triggerBuild(buildTypeId, branchName, cleanRebuild, queueAtTop, buildParms, freeTextComments);
 
         List<BuildRef> deps = build.getSnapshotDependenciesNonNull();
 
         Stream<Integer> allIds = Stream.concat(Stream.of(build.getId()), deps.stream().map(BuildRef::getId));
 
-        //todo may addBuild additional parameter: load builds into DB in sync/async fashion
-        buildRefSync.runActualizeBuildRefs(srvCode, BuildRefSync.SyncMode.ULTRAFAST, allIds.collect(Collectors.toSet()), conn);
+        Set<Integer> collect = allIds.collect(Collectors.toSet());
+        if (!actualizeReferences)
+            return new T2<>(build, collect);
 
-        return build;
+        fastBuildsSync(collect);
+
+        return new T2<>(build, Collections.emptySet());
+    }
+
+    /** {@inheritDoc} */
+    @Override public void fastBuildsSync(Set<Integer> collect) {
+        buildRefSync.runActualizeBuildRefs(srvCode, BuildRefSync.SyncMode.ULTRAFAST, collect, conn);
     }
 
     /** {@inheritDoc} */
diff --git a/tcbot-teamcity/src/main/java/org/apache/ignite/tcservice/ITeamcityConn.java b/tcbot-teamcity/src/main/java/org/apache/ignite/tcservice/ITeamcityConn.java
index fc362ef..6013c2c 100644
--- a/tcbot-teamcity/src/main/java/org/apache/ignite/tcservice/ITeamcityConn.java
+++ b/tcbot-teamcity/src/main/java/org/apache/ignite/tcservice/ITeamcityConn.java
@@ -19,7 +19,6 @@ package org.apache.ignite.tcservice;
 
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.util.List;
 import java.util.Map;
@@ -28,7 +27,6 @@ import java.util.concurrent.atomic.AtomicReference;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import org.apache.ignite.tcbot.common.interceptor.AutoProfiling;
 import org.apache.ignite.tcservice.model.agent.Agent;
 import org.apache.ignite.tcservice.model.changes.Change;
 import org.apache.ignite.tcservice.model.changes.ChangesList;
@@ -110,11 +108,11 @@ public interface ITeamcityConn {
      * @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.
+* <code>put("testSuite", "org.apache.ignite.spi.discovery.tcp.ipfinder.elb.TcpDiscoveryElbIpFinderSelfTest");</code>
+     * @param freeTextComments
      */
     public Build triggerBuild(String buildTypeId, @Nonnull String branchName, boolean cleanRebuild, boolean queueAtTop,
-        @Nullable Map<String, Object> buildParms);
+        @Nullable Map<String, Object> buildParms, @Nullable String freeTextComments);
 
     /**
      * @param buildId Build id.
diff --git a/tcbot-teamcity/src/main/java/org/apache/ignite/tcservice/TeamcityServiceConnection.java b/tcbot-teamcity/src/main/java/org/apache/ignite/tcservice/TeamcityServiceConnection.java
index c0037fe..bc8e825 100644
--- a/tcbot-teamcity/src/main/java/org/apache/ignite/tcservice/TeamcityServiceConnection.java
+++ b/tcbot-teamcity/src/main/java/org/apache/ignite/tcservice/TeamcityServiceConnection.java
@@ -18,8 +18,25 @@
 package org.apache.ignite.tcservice;
 
 import com.google.common.base.Strings;
-import org.apache.ignite.tcbot.common.conf.ITcServerConfig;
+import java.io.File;
+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.atomic.AtomicReference;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.xml.bind.JAXBException;
 import org.apache.ignite.tcbot.common.conf.IDataSourcesConfigSupplier;
+import org.apache.ignite.tcbot.common.conf.ITcServerConfig;
 import org.apache.ignite.tcbot.common.conf.TcBotWorkDir;
 import org.apache.ignite.tcbot.common.exeption.ExceptionUtil;
 import org.apache.ignite.tcbot.common.exeption.ServiceConflictException;
@@ -48,17 +65,6 @@ import org.apache.ignite.tcservice.util.XmlUtil;
 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.*;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.Collectors;
-
-import static java.util.concurrent.CompletableFuture.supplyAsync;
-
 /**
  * Class for access to Teamcity REST API without any caching.
  *
@@ -154,8 +160,8 @@ public class TeamcityServiceConnection implements ITeamcity {
         @Nonnull String branchName,
         boolean cleanRebuild,
         boolean queueAtTop,
-        @Nullable Map<String, Object> buildParms
-    ) {
+        @Nullable Map<String, Object> buildParms,
+        String freeTextComments) {
         String triggeringOptions =
             " <triggeringOptions" +
                 " cleanSources=\"" + cleanRebuild + "\"" +
@@ -163,8 +169,11 @@ public class TeamcityServiceConnection implements ITeamcity {
                 " queueAtTop=\"" + queueAtTop + "\"" +
                 "/>\n";
 
-        String comments = " <comment><text>Build triggered from Ignite TC Bot" +
-            " [cleanRebuild=" + cleanRebuild + ", top=" + queueAtTop + "]</text></comment>\n";
+        String comments = " <comment><text>" +
+            Strings.nullToEmpty(freeTextComments) + ", " +
+            "Build triggered from Ignite TC Bot" +
+            " [cleanRebuild=" + cleanRebuild + ", top=" + queueAtTop + "]" +
+            "</text></comment>\n";
 
         Map<String, Object> props = new HashMap<>();
 
@@ -194,7 +203,12 @@ public class TeamcityServiceConnection implements ITeamcity {
             logger.info("Triggering build: buildTypeId={}, branchName={}, cleanRebuild={}, queueAtTop={}, buildParms={}",
                 buildTypeId, branchName, cleanRebuild, queueAtTop, props);
 
-            try (StringReader reader = new StringReader(HttpUtil.sendPostAsString(basicAuthTok, url, sb.toString()))) {
+            String body = sb.toString();
+
+            if (logger.isDebugEnabled())
+                logger.debug("(TRIGGER REQUEST):\n" + body);
+
+            try (StringReader reader = new StringReader(HttpUtil.sendPostAsString(basicAuthTok, url, body))) {
                 return XmlUtil.load(Build.class, reader);
             }
             catch (JAXBException e) {