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 2018/10/03 16:44:57 UTC

[ignite-teamcity-bot] 01/02: IGNITE-9697 Autocomplete branch for TC field - Fixes #24.

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 ce7aef2b1d0ac5cf6c2e28dc6d59d9a53023846f
Author: Dmitrii Ryabov <So...@gmail.com>
AuthorDate: Wed Oct 3 19:32:34 2018 +0300

    IGNITE-9697 Autocomplete branch for TC field - Fixes #24.
    
    Signed-off-by: Dmitriy Pavlov <dp...@apache.org>
---
 .../java/org/apache/ignite/ci/HelperConfig.java    |   6 +
 .../main/java/org/apache/ignite/ci/ITeamcity.java  |  19 +++
 .../apache/ignite/ci/IgnitePersistentTeamcity.java |  20 +++
 .../apache/ignite/ci/IgniteTeamcityConnection.java |  42 +++++-
 .../ignite/ci/conf/ServerIntegrationLinks.java     |  43 ++++++
 .../apache/ignite/ci/web/rest/TriggerBuild.java    |  20 +++
 ignite-tc-helper-web/src/main/webapp/index.html    |  12 +-
 .../src/main/webapp/js/common-1.6.js               | 156 +++++++++++++++++++++
 ignite-tc-helper-web/src/main/webapp/services.html |  13 +-
 9 files changed, 321 insertions(+), 10 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 67be102..c39fd1e 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
@@ -54,6 +54,12 @@ public class HelperConfig {
     /** JIRA authorization token property name. */
     public static final String JIRA_AUTH_TOKEN = "jira.auth_token";
 
+    /** JIRA authorization token property name. */
+    public static final String GIT_API_URL = "git.api_url";
+
+    /** JIRA authorization token property name. */
+    public static final String JIRA_API_URL = "jira.api_url";
+
     /** Slack authorization token property name. */
     public static final String SLACK_AUTH_TOKEN = "slack.auth_token";
     public static final String SLACK_CHANNEL = "slack.channel";
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITeamcity.java
index 3193ea8..8f58657 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
@@ -319,6 +319,25 @@ public interface ITeamcity {
      */
     boolean sendJiraComment(String ticket, String comment);
 
+    /**
+     * @param url URL for git integration.
+     */
+    void setGitApiUrl(String url);
+
+    /**
+     * @return URL for git integration.
+     */
+    String getGitApiUrl();
+
+    /**
+     * @param url URL for JIRA integration.
+     */
+    void setJiraApiUrl(String url);
+
+    /**
+     * @return URL for JIRA integration.
+     */
+    String getJiraApiUrl();
 
     default void setAuthData(String user, String password) {
         setAuthToken(
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 ec53d9b..2e9f873 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
@@ -1169,6 +1169,26 @@ public class IgnitePersistentTeamcity implements IAnalyticsEnabledTeamcity, ITea
     }
 
     /** {@inheritDoc} */
+    @Override public void setGitApiUrl(String url) {
+        teamcity.setGitApiUrl(url);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getGitApiUrl() {
+        return teamcity.getGitApiUrl();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setJiraApiUrl(String url) {
+        teamcity.setJiraApiUrl(url);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getJiraApiUrl() {
+        return teamcity.getJiraApiUrl();
+    }
+
+    /** {@inheritDoc} */
     @Override public PullRequest getPullRequest(String branchForTc) {
         return teamcity.getPullRequest(branchForTc);
     }
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 6b63f1b..3d68ccb 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
@@ -104,6 +104,12 @@ public class IgniteTeamcityConnection implements ITeamcity {
     /**  JIRA authorization token. */
     private String jiraBasicAuthTok;
 
+    /** URL for git integration. */
+    private String gitApiUrl;
+
+    /** URL for JIRA integration. */
+    private String jiraApiUrl;
+
     private String configName; //main properties file name
     private String tcName;
 
@@ -130,8 +136,10 @@ public class IgniteTeamcityConnection implements ITeamcity {
         }
 
         setGitToken(HelperConfig.prepareGithubHttpAuthToken(props));
+        setGitApiUrl(props.getProperty(HelperConfig.GIT_API_URL));
 
         setJiraToken(HelperConfig.prepareJiraHttpAuthToken(props));
+        setJiraApiUrl(props.getProperty(HelperConfig.JIRA_API_URL));
 
         final File logsDirFile = HelperConfig.resolveLogs(workDir, props);
 
@@ -173,8 +181,14 @@ public class IgniteTeamcityConnection implements ITeamcity {
     /** {@inheritDoc} */
     @AutoProfiling
     @Override public boolean sendJiraComment(String ticket, String comment) {
+        if (isNullOrEmpty(jiraApiUrl)) {
+            logger.error("Failed to notify JIRA [errMsg=JIRA API URL is not configured for this server.]");
+
+            return false;
+        }
+
         try {
-            String url = "https://issues.apache.org/jira/rest/api/2/issue/" + ticket + "/comment";
+            String url = jiraApiUrl + "issue/" + ticket + "/comment";
 
             HttpUtil.sendPostAsStringToJira(jiraBasicAuthTok, url, "{\"body\": \"" + comment + "\"}");
 
@@ -188,8 +202,31 @@ public class IgniteTeamcityConnection implements ITeamcity {
     }
 
     /** {@inheritDoc} */
+    @Override public void setGitApiUrl(String url) {
+        gitApiUrl = url;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getGitApiUrl() {
+        return gitApiUrl;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setJiraApiUrl(String url) {
+        jiraApiUrl = url;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getJiraApiUrl() {
+        return jiraApiUrl;
+    }
+
+    /** {@inheritDoc} */
     @AutoProfiling
     @Override public PullRequest getPullRequest(String branchForTc) {
+        if (!isNullOrEmpty(gitApiUrl))
+            throw new IllegalStateException("Git API URL is not configured for this server.");
+
         String id = null;
 
         // Get PR id from string "pull/XXXX/head"
@@ -203,8 +240,7 @@ public class IgniteTeamcityConnection implements ITeamcity {
             }
         }
 
-        //todo github address can be probably associated with server
-        String pr = "https://api.github.com/repos/apache/ignite/pulls/" + id;
+        String pr = gitApiUrl + "pulls/" + id;
 
         try (InputStream is = HttpUtil.sendGetToGit(gitAuthTok, pr)) {
             InputStreamReader reader = new InputStreamReader(is);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/conf/ServerIntegrationLinks.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/conf/ServerIntegrationLinks.java
new file mode 100644
index 0000000..a0f0eb9
--- /dev/null
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/conf/ServerIntegrationLinks.java
@@ -0,0 +1,43 @@
+/*
+ * 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.conf;
+
+/**
+ *
+ */
+public class ServerIntegrationLinks {
+    /** Server ID. */
+    public final String srvId;
+
+    /** URL for git integration. */
+    public final String gitApiUrl;
+
+    /** URL for JIRA integration. */
+    public final String jiraApiUrl;
+
+    /**
+     * @param srvId Server ID.
+     * @param gitApiUrl URL for git integration.
+     * @param jiraApiUrl URL for JIRA integration.
+     */
+    public ServerIntegrationLinks(String srvId, String gitApiUrl, String jiraApiUrl) {
+        this.srvId = srvId;
+        this.gitApiUrl = gitApiUrl;
+        this.jiraApiUrl = jiraApiUrl;
+    }
+}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuild.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuild.java
index c5da089..6a0ce3a 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuild.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/rest/TriggerBuild.java
@@ -20,6 +20,9 @@ package org.apache.ignite.ci.web.rest;
 import com.google.common.base.Strings;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.GET;
@@ -30,6 +33,7 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import org.apache.ignite.ci.ITcHelper;
 import org.apache.ignite.ci.ITeamcity;
+import org.apache.ignite.ci.conf.ServerIntegrationLinks;
 import org.apache.ignite.ci.github.PullRequest;
 import org.apache.ignite.ci.observer.BuildObserver;
 import org.apache.ignite.ci.tcmodel.result.Build;
@@ -222,4 +226,20 @@ public class TriggerBuild {
         return new SimpleResult("OK");
     }
 
+    @GET
+    @Path("integrationUrls")
+    public Set<ServerIntegrationLinks> getIntegrationUrls(@NotNull @QueryParam("serverIds") String srvIds) {
+        final ICredentialsProv prov = ICredentialsProv.get(req);
+
+        String[] srvIds0 = srvIds.split(",");
+
+        return Arrays.stream(srvIds0).map(srvId -> {
+            if (!prov.hasAccess(srvId))
+                return null;
+
+            ITeamcity teamcity = CtxListener.server(srvId, context, req);
+
+            return new ServerIntegrationLinks(srvId, teamcity.getGitApiUrl(), teamcity.getGitApiUrl());
+        }).filter(Objects::nonNull).collect(Collectors.toSet());
+    }
 }
diff --git a/ignite-tc-helper-web/src/main/webapp/index.html b/ignite-tc-helper-web/src/main/webapp/index.html
index 1dc6eba..2e0dd83 100644
--- a/ignite-tc-helper-web/src/main/webapp/index.html
+++ b/ignite-tc-helper-web/src/main/webapp/index.html
@@ -43,6 +43,7 @@ function loadData() {
         success: function(result) {
             $("#loadStatus").html("");
             showSuitesForPrCheckData(result);
+            tryToFillAutocompleteLists();
         },
         error: showErrInLoadStatus
     });
@@ -51,6 +52,7 @@ function loadData() {
         url: "rest/branches/getServerIds",
         success: function(result) {
             $("#loadStatus").html("");
+            setupAutocompleteList(result);
             showBuildsOnServers(result);
         },
         error: showErrInLoadStatus
@@ -78,24 +80,26 @@ function showCurrentBranchesData(result) {
 
 function showSuitesForPrCheckData(result) {
     var res = "";
+
     for (var i = 0; i < result.length; i++) {
         var chainAtServer = result[i];
-        //res+="<a href='pr.html?serverId=private&branchForTc=ignite-gg-12790-1&suiteId=id8xIgniteGridGainTests_RunAll="+id+"'>Check PR</a><br>";
 
         res += "<form action='pr.html'>";
         res += "Server: <input type='text' name='serverId' value=" + chainAtServer.serverId + " readonly>";
         res += "Chain: <input type='text' name='suiteId' value=" + chainAtServer.suiteId + ">";
-        res += "Base branch: <input type='text' name='baseBranchForTc'  title='Etalon branch,e.g refs/heads/master'> ";
-        res += "<b>Branch:</b> <input type='text' name='branchForTc' title='Tested branch, e.g. pull/4790/head or ignite-9349' required> ";
+        res += "Base branch: <input class='branchForTc" + chainAtServer.serverId +
+            "' type='text' name='baseBranchForTc'  title='Etalon branch, e.g refs/heads/master'> ";
+        res += "<b>Branch:</b> <input class='branchForTc" + chainAtServer.serverId +
+            "' type='text' name='branchForTc' title='Tested branch, e.g. pull/4790/head or ignite-9349' required> ";
         res += "<input type='submit' name='action' value='Latest' title='Show latest runs'>";
         // res+="<input type='submit' name='action' value='Chain'>";
         res += "<input type='submit' name='action' value='History' title='Show last 10 runs merged'>";
         res += "</form>";
     }
+
     $("#suitesForPrCheck").html(res);
 }
 
-
 function showBuildsOnServers(result) {
     var res = "";
     for (var i = 0; i < result.length; i++) {
diff --git a/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js b/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
index 08cffdf..8f15680 100644
--- a/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
+++ b/ignite-tc-helper-web/src/main/webapp/js/common-1.6.js
@@ -210,3 +210,159 @@ function tcHelperLogout() {
     } catch (e) {
     }
 }
+
+/**
+ * Change autocomplete filter to show results only when they starts from written text.
+ */
+$.ui.autocomplete.filter = function (array, term) {
+    var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex(term), "i");
+
+    return $.grep(array, function (value) {
+        return matcher.test(value.label || value.value || value);
+    });
+};
+
+var callbackRegistry = {};
+
+/**
+ * Send request to another site.
+ *
+ * @param url URL.
+ * @param onSuccess Function for success response.
+ * @param onError Function for fail response.
+ */
+function scriptRequest(url, onSuccess, onError) {
+    var scriptOk = false;
+    var callbackName = 'cb' + String(Math.random()).slice(-6);
+
+    url += ~url.indexOf('?') ? '&' : '?';
+    url += 'callback=callbackRegistry.' + callbackName;
+
+    callbackRegistry[callbackName] = function(data) {
+        scriptOk = true;
+
+        delete callbackRegistry[callbackName];
+
+        onSuccess(data);
+    };
+
+    function checkCallback() {
+        if (scriptOk)
+            return;
+
+        delete callbackRegistry[callbackName];
+
+        console.error("Request to \"" + url + "\" was failed.")
+    }
+
+    var script = document.createElement('script');
+
+    script.onload = script.onerror = checkCallback;
+    script.src = url;
+
+    document.body.appendChild(script);
+}
+
+/** Key-value map. Key - server id. Value - url to git api. */
+var gitUrls = new Map();
+
+/** Branches for TeamCity. */
+var branchesForTc = {};
+
+/**
+ * Fill git URLs and send requests to them.
+ *
+ * @param srvIds - Set of server IDs.
+ */
+function setupAutocompleteList(srvIds) {
+    for (let srvId of srvIds)
+        gitUrls.set(srvId, "");
+
+    startFillAutocompleteListsProcess();
+}
+
+/**
+ * Retrieves recent PR numbers and fills autocomplete lists for the fields branchForTc.
+ */
+function startFillAutocompleteListsProcess() {
+    _receiveIntegrationUrls();
+}
+
+/**
+ * Receive api links for the servers.
+ *
+ * @private
+ */
+function _receiveIntegrationUrls() {
+    var url = "rest/build/integrationUrls?serverIds=";
+
+    for (let key of gitUrls.keys())
+        url += key + ",";
+
+    $.ajax({
+        url: url,
+        success: function (result) {
+            _fillGitUrls(result);
+            _sendRequestsToFillAutocompleteLists();
+        }
+    });
+}
+
+/**
+ * Fill git api URLs.
+ *
+ * @param result Array of ServerIntegrationLinks.
+ *
+ * @private
+ */
+function _fillGitUrls(result) {
+    for (let links of result)
+        gitUrls.set(links.srvId, links.gitApiUrl);
+}
+
+/**
+ * Send requests to the git to get pull requests for the branch autocomplete lists.
+ *
+ * @private
+ */
+function _sendRequestsToFillAutocompleteLists() {
+    for (var entry of gitUrls.entries())
+        scriptRequest(entry[1] + "pulls?sort=updated&direction=desc", _fillBranchAutocompleteList);
+}
+
+/**
+ * Takes all "branchForTc<server>" and add autocomplete list to them.
+ *
+ * @param result Response from git.
+ */
+function _fillBranchAutocompleteList(result) {
+    if (!result.data || !result.data[0])
+        return;
+
+    for (var entry of gitUrls.entries()) {
+        if (!result.data[0].url.startsWith(entry[1]))
+            continue;
+
+        branchesForTc[entry[0]] = [{label:"master", value:"refs/heads/master"}];
+
+        for (let pr of result.data)
+            branchesForTc[entry[0]].push({label: pr.number, value: "pull/" + pr.number + "/head"});
+
+        $(".branchForTc" + entry[0]).autocomplete({source: branchesForTc[entry[0]]});
+    }
+}
+
+/**
+ * Fills autocomplete lists for the branchForTc fields, if lists are available.
+ */
+function tryToFillAutocompleteLists() {
+    for (var entry of gitUrls.entries()) {
+        var fields = $(".branchForTc" + entry[0]);
+
+        for (let field of fields) {
+            if (branchesForTc[entry[0]] && branchesForTc[entry[0]].length > 1 &&
+                field.autocomplete("option", "source").length < 2)
+                field.autocomplete({source: branchesForTc[entry[0]]});
+        }
+    }
+}
diff --git a/ignite-tc-helper-web/src/main/webapp/services.html b/ignite-tc-helper-web/src/main/webapp/services.html
index 17746f0..eb33737 100644
--- a/ignite-tc-helper-web/src/main/webapp/services.html
+++ b/ignite-tc-helper-web/src/main/webapp/services.html
@@ -37,10 +37,16 @@ function loadData() {
         success: function(result) {
             $("#loadStatus").html("");
             showSuitesForTeamCityRunData(result);
+            tryToFillAutocompleteLists();
             showCommentJiraForm(result);
         },
         error: showErrInLoadStatus
     });
+
+    $.ajax({
+        url: "rest/branches/getServerIds",
+        success: setupAutocompleteList
+    });
 }
 
 function showSuitesForTeamCityRunData(result) {
@@ -55,7 +61,8 @@ function showSuitesForTeamCityRunData(result) {
 
         res += "Server: <input type='text' name='serverId' value='" + chainAtServer.serverId + "' readonly>";
         res += "Chain: <input type='text' name='suiteId' value='" + chainAtServer.suiteId + "' readonly>";
-        res += "Branch: <input type='text' name='branchForTc' required> ";
+        res += "Branch: <input type='text' name='branchForTc' class='branchForTc" + chainAtServer.serverId +
+            "' required> ";
         res += "Ticket: <input type='text' name='ticketId'>";
         res += "<button name='jira' type='button' onclick='trigBuild(\"tests\")'>Start tests</button>";
         res += "<button name='jira' onclick='trigBuild(\"tests+jira\")'>Start tests and comment JIRA ticket on ready</button>";
@@ -85,12 +92,12 @@ function showCommentJiraForm(result) {
 
         res += "Server: <input type='text' name='serverId' value=" + chainAtServer.serverId +" readonly>" ;
         res += "Chain: <input type='text' name='suiteId' value='" + chainAtServer.suiteId + "' readonly>";
-        res += "Branch: <input type='text' name='branchForTc' required> ";
+        res += "Branch: <input type='text' name='branchForTc' class='branchForTc" + chainAtServer.serverId +
+            "' required> ";
         res += "Ticket: <input type='text' name='ticketId'> ";
         res += "<button name='action' onclick='notifyJira()'>Notify</button>";
     }
 
-    //todo enabled this once feature is ready
     $("#notifyJira").html(res);
 }