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

commit 32d6bf85b00261d7cd9d39144f871fa64343c709
Author: Dmitrii Ryabov <[email protected]>
AuthorDate: Wed Sep 12 16:05:06 2018 +0300

    IGNITE-9377 Handle print critical failures to the GitHub PR statuses - 
Fixes #5.
    
    Signed-off-by: Dmitriy Pavlov <[email protected]>
---
 .../java/org/apache/ignite/ci/HelperConfig.java    |  31 ++++++-
 .../main/java/org/apache/ignite/ci/ITeamcity.java  |  34 +++++++
 .../apache/ignite/ci/IgnitePersistentTeamcity.java |  30 +++++-
 .../org/apache/ignite/ci/IgniteTeamcityHelper.java |  69 +++++++++++++-
 .../org/apache/ignite/ci/github/PullRequest.java   |  65 +++++++++++++
 .../java/org/apache/ignite/ci/util/HttpUtil.java   | 102 +++++++++++++++++----
 .../ignite/ci/web/model/current/UpdateInfo.java    |  22 +++++
 .../ignite/ci/web/rest/pr/GetPrTestFailures.java   |  30 ++++++
 .../src/main/webapp/js/testfails-2.1.js            |  80 +++++++++++++++-
 9 files changed, 437 insertions(+), 26 deletions(-)

diff --git 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/HelperConfig.java 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/HelperConfig.java
index 3f2e9b8..b3b51c7 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/HelperConfig.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/HelperConfig.java
@@ -48,6 +48,7 @@ public class HelperConfig {
     @Deprecated
     private static final String PASSWORD = "password";
     public static final String ENCODED_PASSWORD = "encoded_password";
+    public static final String GITHUB_AUTH_TOKEN = "github.auth_token";
     public static final String SLACK_AUTH_TOKEN = "slack.auth_token";
     public static final String SLACK_CHANNEL = "slack.channel";
     public static final String LOGS = "logs";
@@ -117,19 +118,45 @@ public class HelperConfig {
         return ensureDirExist(workDir);
     }
 
+    /**
+     * Extract GitHub authorization token from properties.
+     *
+     * @param props Properties, where token is placed.
+     * @return Null or decoded auth token for Github.
+     */
+    @Nullable static String prepareGithubHttpAuthToken(Properties props) {
+        String pwd = props.getProperty(GITHUB_AUTH_TOKEN);
+
+        if (isNullOrEmpty(pwd))
+            return null;
+
+        pwd = PasswordEncoder.decode(pwd);
+
+        return pwd;
+    }
+
+    /**
+     * Extract TeamCity authorization token from properties.
+     *
+     * @param props Properties, where token is placed.
+     * @param configName Configuration name.
+     * @return Null or decoded auth token for Github.
+     */
     @Nullable static String prepareBasicHttpAuthToken(Properties props, String 
configName) {
         final String user = getMandatoryProperty(props, USERNAME, configName);
         String pwd = props.getProperty(PASSWORD);
         boolean filled = !isNullOrEmpty(pwd);
-        if(!filled) {
+
+        if (!filled) {
             String enc = props.getProperty(ENCODED_PASSWORD);
+
             if(!isNullOrEmpty(enc)) {
                 pwd = PasswordEncoder.decode(enc);
                 filled = true;
             }
         }
 
-        if(!filled)
+        if (!filled)
             return null;
 
         return Base64Util.encodeUtf8String(user + ":" + pwd);
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 d9d8d1d..7e105c7 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
@@ -26,6 +26,7 @@ import javax.annotation.Nullable;
 import org.apache.ignite.ci.analysis.LogCheckResult;
 import org.apache.ignite.ci.analysis.MultBuildRunCtx;
 import org.apache.ignite.ci.analysis.SingleBuildRunCtx;
+import org.apache.ignite.ci.github.PullRequest;
 import org.apache.ignite.ci.tcmodel.agent.Agent;
 import org.apache.ignite.ci.tcmodel.changes.Change;
 import org.apache.ignite.ci.tcmodel.changes.ChangeRef;
@@ -240,8 +241,41 @@ public interface ITeamcity extends AutoCloseable {
      */
     void triggerBuild(String id, String name, boolean cleanRebuild, boolean 
queueAtTop);
 
+    /**
+     * @return {@code True} if TeamCity authorization token is available.
+     */
+    boolean isTeamCityTokenAvailable();
+
+    /**
+     * @param token TeamCity authorization token.
+     */
     void setAuthToken(String token);
 
+    /**
+     * @return {@code True} if GitHub authorization token is available.
+     */
+    boolean isGitTokenAvailable();
+
+    /**
+     * @param token GitHub authorization token.
+     */
+    void setGitToken(String token);
+
+    /**
+     * Send POST request with given body.
+     *
+     * @param url Url.
+     * @param body Request body.
+     * @return {@code True} - if GitHub was notified. {@code False} - 
otherwise.
+     */
+    boolean notifyGit(String url, String body);
+
+    /**
+     * @param branch TeamCity's branch name. Looks like "pull/123/head".
+     * @return Pull Request.
+     */
+    PullRequest getPullRequest(String branch);
+
     default void setAuthData(String user, String password) {
         setAuthToken(
                 Base64Util.encodeUtf8String(user + ":" + password));
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 e89e2f2..16e3a22 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
@@ -52,6 +52,7 @@ import org.apache.ignite.ci.analysis.SuiteInBranch;
 import org.apache.ignite.ci.analysis.TestInBranch;
 import org.apache.ignite.ci.db.DbMigrations;
 import org.apache.ignite.ci.db.TcHelperDb;
+import org.apache.ignite.ci.github.PullRequest;
 import org.apache.ignite.ci.tcmodel.agent.Agent;
 import org.apache.ignite.ci.tcmodel.changes.Change;
 import org.apache.ignite.ci.tcmodel.changes.ChangesList;
@@ -822,12 +823,37 @@ public class IgnitePersistentTeamcity implements 
IAnalyticsEnabledTeamcity, ITea
         teamcity.triggerBuild(id, name, cleanRebuild, queueAtTop);
     }
 
-    @Override
-    public void setAuthToken(String token) {
+    /** {@inheritDoc} */
+    @Override public boolean isTeamCityTokenAvailable() {
+        return teamcity.isTeamCityTokenAvailable();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setAuthToken(String token) {
         teamcity.setAuthToken(token);
     }
 
     /** {@inheritDoc} */
+    @Override public boolean isGitTokenAvailable() {
+        return teamcity.isGitTokenAvailable();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setGitToken(String token) {
+        teamcity.setGitToken(token);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean notifyGit(String url, String body) {
+        return teamcity.notifyGit(url, body);
+    }
+
+    /** {@inheritDoc} */
+    @Override public PullRequest getPullRequest(String branch) {
+        return teamcity.getPullRequest(branch);
+    }
+
+    /** {@inheritDoc} */
     @Override public List<Agent> agents(boolean connected, boolean authorized) 
{
         return teamcity.agents(connected, authorized);
     }
diff --git 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityHelper.java
 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityHelper.java
index d3421b7..cf7ec6a 100644
--- 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityHelper.java
+++ 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/IgniteTeamcityHelper.java
@@ -21,6 +21,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Stopwatch;
 import com.google.common.base.Throwables;
 import com.google.common.util.concurrent.MoreExecutors;
+import com.google.gson.Gson;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -48,6 +49,7 @@ import org.apache.ignite.ci.analysis.LogCheckResult;
 import org.apache.ignite.ci.analysis.LogCheckTask;
 import org.apache.ignite.ci.analysis.MultBuildRunCtx;
 import org.apache.ignite.ci.analysis.SingleBuildRunCtx;
+import org.apache.ignite.ci.github.PullRequest;
 import org.apache.ignite.ci.logs.BuildLogStreamChecker;
 import org.apache.ignite.ci.logs.LogsAnalyzer;
 import org.apache.ignite.ci.logs.handlers.TestLogHandler;
@@ -87,6 +89,7 @@ import static 
org.apache.ignite.ci.HelperConfig.ensureDirExist;
  *
  * See more info about API
  * https://confluence.jetbrains.com/display/TCD10/REST+API
+ * https://developer.github.com/v3/
  */
 public class IgniteTeamcityHelper implements ITeamcity {
     /** Logger. */
@@ -96,7 +99,13 @@ public class IgniteTeamcityHelper implements ITeamcity {
     private final File logsDir;
     /** Normalized Host address, ends with '/'. */
     private final String host;
+
+    /** TeamCity authorization token. */
     private String basicAuthTok;
+
+    /** GitHub authorization token. */
+    private String gitAuthTok;
+
     private final String configName; //main properties file name
     private final String tcName;
 
@@ -120,6 +129,8 @@ public class IgniteTeamcityHelper implements ITeamcity {
             e.printStackTrace();
         }
 
+        setGitToken(HelperConfig.prepareGithubHttpAuthToken(props));
+
         final File logsDirFile = HelperConfig.resolveLogs(workDir, props);
 
         logsDir = ensureDirExist(logsDirFile);
@@ -127,11 +138,67 @@ public class IgniteTeamcityHelper implements ITeamcity {
         this.executor =  MoreExecutors.directExecutor();
     }
 
-    public void setAuthToken(String token) {
+    /** {@inheritDoc} */
+    @Override public boolean isTeamCityTokenAvailable() {
+        return basicAuthTok != null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setAuthToken(String token) {
         basicAuthTok = token;
     }
 
     /** {@inheritDoc} */
+    @Override public boolean isGitTokenAvailable() {
+        return gitAuthTok != null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setGitToken(String token) {
+        gitAuthTok = token;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean notifyGit(String url, String body) {
+        try {
+            HttpUtil.sendPostAsStringToGit(gitAuthTok, url, body);
+
+            return true;
+        }
+        catch (IOException e) {
+            logger.error("Failed to notify Git [errMsg="+e.getMessage()+']');
+
+            return false;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public PullRequest getPullRequest(String branch) {
+        String id = null;
+
+        for (int i = 5; i < branch.length(); i++) {
+            char c = branch.charAt(i);
+
+            if (!Character.isDigit(c)) {
+                id = branch.substring(5, i);
+
+                break;
+            }
+        }
+
+        String pr = "https://api.github.com/repos/"; + serverId() + 
"/ignite/pulls/" + id;
+
+        try (InputStream is = HttpUtil.sendGetToGit(gitAuthTok, pr)) {
+            InputStreamReader reader = new InputStreamReader(is);
+
+            return new Gson().fromJson(reader, PullRequest.class);
+        }
+        catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public List<Agent> agents(boolean connected, boolean authorized) 
{
         String url = "app/rest/agents?locator=connected:" + connected + 
",authorized:" + authorized;
 
diff --git 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/PullRequest.java
 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/PullRequest.java
new file mode 100644
index 0000000..d381d12
--- /dev/null
+++ 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/github/PullRequest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.github;
+
+import com.google.gson.annotations.SerializedName;
+
+/**
+ *
+ */
+public class PullRequest {
+    /** Pull Request number. You can see it at {@code 
apache/ignite/pull/"number"}. */
+    @SerializedName("number") private int num;
+
+    /** Pull Request state. */
+    private String state;
+
+    /** Pull Request title. */
+    private String title;
+
+    /** Pull Request url to get statuses. */
+    @SerializedName("statuses_url") private String statusesUrl;
+
+    /**
+     * @return Pull Request number.
+     */
+    public int getNumber() {
+        return num;
+    }
+
+    /**
+     * @return Pull Request state.
+     */
+    public String getState() {
+        return state;
+    }
+
+    /**
+     * @return Pull Request title.
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * @return Url to get PR statuses.
+     */
+    public String getStatusesUrl() {
+        return statusesUrl;
+    }
+}
diff --git 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/util/HttpUtil.java 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/util/HttpUtil.java
index af82375..8234f8a 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/util/HttpUtil.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/util/HttpUtil.java
@@ -18,11 +18,6 @@
 package org.apache.ignite.ci.util;
 
 import com.google.common.base.Stopwatch;
-import org.apache.ignite.ci.BuildChainProcessor;
-import org.apache.ignite.ci.web.rest.login.ServiceUnauthorizedException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
@@ -36,6 +31,9 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 import java.util.concurrent.TimeUnit;
+import org.apache.ignite.ci.web.rest.login.ServiceUnauthorizedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Methods for sending HTTP requests
@@ -56,6 +54,14 @@ public class HttpUtil {
         return response.toString();
     }
 
+    /**
+     * Send GET request to the TeamCity url.
+     *
+     * @param basicAuthToken Authorization token.
+     * @param url URL.
+     * @return Input stream from connection.
+     * @throws IOException If failed.
+     */
     public static InputStream sendGetWithBasicAuth(String basicAuthToken, 
String url) throws IOException {
         final Stopwatch started = Stopwatch.createStarted();
         URL obj = new URL(url);
@@ -66,12 +72,34 @@ public class HttpUtil {
         con.setRequestProperty("Keep-Alive", "header");
         con.setRequestProperty("accept-charset", 
StandardCharsets.UTF_8.toString());
 
-        int resCode = con.getResponseCode();
+        logger.info(Thread.currentThread().getName() + ": Required: " + 
started.elapsed(TimeUnit.MILLISECONDS)
+            + "ms : Sending 'GET' request to : " + url);
+
+        return getInputStream(con);
+    }
+
+    /**
+     * Send GET request to the GitHub url.
+     *
+     * @param githubAuthToken Authorization token.
+     * @param url URL.
+     * @return Input stream from connection.
+     * @throws IOException If failed.
+     */
+    public static InputStream sendGetToGit(String githubAuthToken, String url) 
throws IOException {
+        Stopwatch started = Stopwatch.createStarted();
+        URL obj = new URL(url);
+        HttpURLConnection con = (HttpURLConnection)obj.openConnection();
+
+        con.setRequestProperty("accept-charset", 
StandardCharsets.UTF_8.toString());
+        con.setRequestProperty("Authorization", "token " + githubAuthToken);
+        con.setRequestProperty("Connection", "Keep-Alive");
+        con.setRequestProperty("Keep-Alive", "header");
 
         logger.info(Thread.currentThread().getName() + ": Required: " + 
started.elapsed(TimeUnit.MILLISECONDS)
             + "ms : Sending 'GET' request to : " + url);
 
-        return getInputStream(url, con, resCode);
+        return getInputStream(con);
     }
 
     public static void sendGetCopyToFile(String tok, String url, File file) 
throws IOException {
@@ -105,24 +133,64 @@ public class HttpUtil {
             writer.write(body); // Write POST query string (if any needed).
         }
 
+        logger.info("\nSending 'POST' request to URL : " + url + "\n" + body);
+
+        return getInputStream(con);
+    }
+
+    /**
+     * Get input stream for successful connection. Throws exception if 
connection response wasn't successful.
+     *
+     * @param con Http connection.
+     * @return Input stream from connection.
+     * @throws IOException If failed.
+     */
+    private static InputStream getInputStream(HttpURLConnection con) throws 
IOException {
         int resCode = con.getResponseCode();
 
-        logger.info("\nSending 'POST' request to URL : " + url + "\n" + body);
+        // Successful responses (with code 200+).
+        if (resCode / 100 == 2)
+            return con.getInputStream();
 
-        return getInputStream(url, con, resCode);
+        if (resCode == 401)
+            throw new ServiceUnauthorizedException("Service " + con.getURL() + 
" returned forbidden error.");
 
+        throw new IllegalStateException("Invalid Response Code : " + resCode + 
":\n"
+                + readIsToString(con.getErrorStream()));
     }
 
-    private static InputStream getInputStream(String url, HttpURLConnection 
con, int resCode) throws IOException {
-        if (resCode == 200) {
-            return con.getInputStream();
-        }
+    /**
+     * Send POST request to the GitHub url.
+     *
+     * @param githubAuthToken Authorization token.
+     * @param url URL.
+     * @param body Request POST params.
+     * @return Response body from given url.
+     * @throws IOException If failed.
+     */
+    public static String sendPostAsStringToGit(String githubAuthToken, String 
url, String body) throws IOException {
+        URL obj = new URL(url);
+        HttpURLConnection con = (HttpURLConnection)obj.openConnection();
+        Charset charset = StandardCharsets.UTF_8;
+
+        con.setRequestProperty("accept-charset", charset.toString());
+        con.setRequestProperty("Authorization", "token " + githubAuthToken);
+        con.setRequestProperty("Connection", "Keep-Alive");
+        con.setRequestProperty("Keep-Alive", "header");
+        con.setRequestProperty("content-type", "application/json");
 
-        if (resCode == 401) {
-            throw new ServiceUnauthorizedException("Service " + url + " 
returned forbidden error");
+        con.setRequestMethod("POST");
+
+        con.setDoOutput(true);
+
+        try (OutputStreamWriter writer = new 
OutputStreamWriter(con.getOutputStream(), charset)){
+            writer.write(body); // Write POST query string (if any needed).
         }
 
-        throw new IllegalStateException("Invalid Response Code : " + resCode + 
":\n"
-                + readIsToString(con.getInputStream()));
+        logger.info("\nSending 'POST' request to URL : " + url + "\n" + body);
+
+        try (InputStream inputStream = getInputStream(con)){
+            return readIsToString(inputStream);
+        }
     }
 }
diff --git 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/UpdateInfo.java
 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/UpdateInfo.java
index 8a20443..50b71f7 100644
--- 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/UpdateInfo.java
+++ 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/current/UpdateInfo.java
@@ -17,10 +17,21 @@
 
 package org.apache.ignite.ci.web.model.current;
 
+import org.apache.ignite.ci.IAnalyticsEnabledTeamcity;
+
 /**
  * Created by Дмитрий on 19.02.2018
  */
 @SuppressWarnings("WeakerAccess") public class UpdateInfo {
+    /** TeamCity auth token availability flag. */
+    public static int TEAMCITY_FLAG = 1;
+
+    /** GitHub auth token availability flag. */
+    public static int GITHUB_FLAG = 2;
+
+    /** Flags to use in javascript. */
+    public Integer javaFlags = 0;
+
     /** Update required, set by background updater. */
     public boolean updateRequired = false;
 
@@ -38,4 +49,15 @@ package org.apache.ignite.ci.web.model.current;
 
         return this;
     }
+
+    /**
+     * @param teamcity TeamCity to get info about tokens.
+     */
+    public void setJavaFlags(IAnalyticsEnabledTeamcity teamcity) {
+        if (teamcity.isTeamCityTokenAvailable())
+            javaFlags = javaFlags | TEAMCITY_FLAG;
+
+        if (teamcity.isGitTokenAvailable())
+            javaFlags = javaFlags | GITHUB_FLAG;
+    }
 }
diff --git 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/pr/GetPrTestFailures.java
 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/pr/GetPrTestFailures.java
index b530b2e..12344b4 100644
--- 
a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/pr/GetPrTestFailures.java
+++ 
b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/pr/GetPrTestFailures.java
@@ -17,10 +17,13 @@
 
 package org.apache.ignite.ci.web.rest.pr;
 
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
 import org.apache.ignite.ci.*;
 import org.apache.ignite.ci.analysis.FullChainRunCtx;
 import org.apache.ignite.ci.analysis.mode.LatestRebuildMode;
 import org.apache.ignite.ci.analysis.mode.ProcessLogsMode;
+import org.apache.ignite.ci.github.PullRequest;
 import org.apache.ignite.ci.tcmodel.hist.BuildRef;
 import org.apache.ignite.ci.user.ICredentialsProv;
 import org.apache.ignite.ci.web.BackgroundUpdater;
@@ -108,6 +111,8 @@ public class GetPrTestFailures {
 
         //using here non persistent TC allows to skip update statistic
         try (IAnalyticsEnabledTeamcity teamcity = tcHelper.server(srvId, 
creds)) {
+            res.setJavaFlags(teamcity);
+
             LatestRebuildMode rebuild;
             if (FullQueryParams.HISTORY.equals(action))
                 rebuild = LatestRebuildMode.ALL;
@@ -167,4 +172,29 @@ public class GetPrTestFailures {
 
         return res;
     }
+
+    @POST
+    @Path("notifyGit")
+    public String getNotifyGit(
+        @Nullable @QueryParam("serverId") String srvId,
+        @Nonnull @QueryParam("suiteId") String suiteId,
+        @Nonnull @QueryParam("branchForTc") String branchForTc,
+        @Nonnull @QueryParam("action") String action,
+        @Nullable @QueryParam("count") Integer count,
+        @Nonnull @FormParam("notifyMsg") String msg) {
+        if (!branchForTc.startsWith("pull/"))
+            return "Given branch is not a pull request. Notify works only for 
pull requests.";
+
+        ITcHelper tcHelper = CtxListener.getTcHelper(context);
+        final ICredentialsProv creds = ICredentialsProv.get(req);
+
+        try (IAnalyticsEnabledTeamcity teamcity = tcHelper.server(srvId, 
creds)) {
+            PullRequest pr = teamcity.getPullRequest(branchForTc);
+            String statusesUrl = pr.getStatusesUrl();
+
+            teamcity.notifyGit(statusesUrl, msg);
+        }
+
+        return "Git was notified.";
+    }
 }
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 3502592..e8af7d6 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
@@ -3,6 +3,9 @@
 //triggerConfirm & triggerDialog element should be provided on page (may be 
hidden)
 var g_initMoreInfoDone = false;
 
+/** Object used to notify git. See ChainAtServerCurrentStatus Java class. */
+var g_srv_to_notify_git;
+
 //@param results - TestFailuresSummary
 function showChainOnServersResults(result) {
     var minFailRateP = findGetParameter("minFailRate");
@@ -10,14 +13,24 @@ function showChainOnServersResults(result) {
 
     var maxFailRateP = findGetParameter("maxFailRate");
     var maxFailRate = maxFailRateP == null ? 100 : parseFloat(maxFailRateP);
-    return showChainResultsWithSettings(result, new Settings(minFailRate, 
maxFailRate));
+
+    return showChainResultsWithSettings(result, new Settings(minFailRate, 
maxFailRate, result.javaFlags));
 }
 
 class Settings {
-    constructor(minFailRate, maxFailRate) {
+    constructor(minFailRate, maxFailRate, javaFlags) {
         this.minFailRate = minFailRate;
         this.maxFailRate = maxFailRate;
+        this.javaFlags = javaFlags;
     }
+
+    isTeamCityAvailable() {
+        return this.javaFlags & 1;
+    };
+
+    isGithubAvailable() {
+        return this.javaFlags & 2
+    };
 }
 
 //@param results - TestFailuresSummary
@@ -67,7 +80,7 @@ function showChainCurrentStatusData(server, settings) {
         altTxt += "duration: " + server.durationPrintable;
 
     res += "<table border='0px'>";
-    res += "<tr bgcolor='#F5F5FF'><td colspan='4'><b><a href='" + 
server.webToHist + "'>";
+    res += "<tr bgcolor='#F5F5FF'><td colspan='3'><b><a href='" + 
server.webToHist + "'>";
 
     if (isDefinedAndFilled(server.chainName)) {
         res += server.chainName + " ";
@@ -141,7 +154,13 @@ function showChainCurrentStatusData(server, settings) {
         res += "<div class='content'>" + mInfo + "</div></span>";
     }
 
-    res += "</td></tr>";
+    if (settings.isGithubAvailable()) {
+        g_srv_to_notify_git = server;
+
+        res += "</td><td><button onclick='notifyGit()'>Update PR 
status</button></td></tr>";
+    }
+    else
+        res += "</td><td>&nbsp;</td></tr>";
 
     res += addBlockersData(server, settings);
 
@@ -218,6 +237,59 @@ function suiteWithCriticalFailuresOnly(suite) {
     return null;
 }
 
+/**
+ * Send POST request to change PR status.
+ *
+ * @returns {string}
+ */
+function notifyGit() {
+    var server = g_srv_to_notify_git;
+    var suites = 0;
+    var tests = 0;
+
+    for (let suite of server.suites) {
+        if (suite.result != "") {
+            suites++;
+
+            continue;
+        }
+
+        for (let testFailure of suite.testFailures) {
+            if (isNewFailedTest(testFailure))
+                tests++;
+        }
+    }
+
+    var state;
+    var desc;
+
+    if (suites == 0 && tests == 0) {
+        state = "success";
+        desc = "No blockers found.";
+    }
+    else {
+        state = "failure";
+        desc = suites + " critical suites, " + tests + " failed tests.";
+    }
+
+    var msg = {
+        state: state,
+        target_url: server.webToHist,
+        description: desc,
+        context: "TeamCity"
+    };
+
+    var notifyGitUrl = "rest/pr/notifyGit"  + parmsForRest();
+
+    $.ajax({
+        url: notifyGitUrl,
+        type: 'POST',
+        data: {notifyMsg: JSON.stringify(msg)},
+        success: function(result) {$("#loadStatus").html(result);},
+        error: showErrInLoadStatus
+    });
+}
+
 function triggerBuild(serverId, suiteId, branchName, top) {
     var queueAtTop = isDefinedAndFilled(top) && top;
     $.ajax({

Reply via email to