Merge branch 'master' into ignite-11880
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 03fc6ad..516a980 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
@@ -468,7 +468,7 @@
return buildsStream().map(SingleBuildRunCtx::getLogCheckIfFinished).filter(Objects::nonNull);
}
- public Set<String> tags() {
+ @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/issue/Issue.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/issue/Issue.java
index ed80fa0..05236a0 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/issue/Issue.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/issue/Issue.java
@@ -19,10 +19,12 @@
import com.google.common.base.MoreObjects;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
+import javax.annotation.Nonnull;
import org.apache.ignite.tcbot.persistence.Persisted;
import org.apache.ignite.tcbot.common.util.TimeUtil;
import org.jetbrains.annotations.Nullable;
@@ -61,6 +63,9 @@
/** Detected timestamp. */
@Nullable public Long detectedTs;
+ /** Set of build tags detected. */
+ public Set<String> buildTags = new TreeSet<>();
+
public Issue(IssueKey issueKey, IssueType type) {
this.issueKey = issueKey;
this.detectedTs = System.currentTimeMillis();
@@ -150,12 +155,21 @@
}
public String getDisplayName() {
- if(displayName==null)
+ if (displayName == null)
return issueKey.getTestOrBuildName();
return displayName;
}
+ /**
+ * @return Set of build tags detected.
+ */
+ @Nonnull public Set<String> buildTags() {
+ return buildTags == null && buildTags.isEmpty()
+ ? Collections.emptySet()
+ : Collections.unmodifiableSet(buildTags);
+ }
+
/** {@inheritDoc} */
@Override public String toString() {
String tsStart = buildStartTs == null ? null : TimeUtil.timestampToDateTimePrintable(buildStartTs);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/INotificationChannel.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/INotificationChannel.java
index ec8e15e..9dc19d8 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/INotificationChannel.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/INotificationChannel.java
@@ -22,13 +22,31 @@
*
*/
public interface INotificationChannel {
- public boolean isSubscribed(String trackedBranchId);
+ /**
+ * @param trackedBranchId Tracked branch id.
+ */
+ public boolean isSubscribedToBranch(String trackedBranchId);
+ /**
+ * Checks if server related issue can be used for notification. For users it is determined by credentials.
+ *
+ * @param srvCode Server code.
+ */
public boolean isServerAllowed(String srvCode);
+ /**
+ * @param tag Tag from actual build/issue.
+ */
+ public boolean isSubscribedToTag(@Nullable String tag);
+
@Nullable
public String email();
@Nullable
public String slack();
+
+ /**
+ * @return any tags specified for this channel, filtration should be applied.
+ */
+ public boolean hasTagFilter();
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/NotificationChannel.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/NotificationChannel.java
index a621596..d3b524b 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/NotificationChannel.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/conf/NotificationChannel.java
@@ -36,8 +36,11 @@
/** Subscribed to failures in tracked branches. */
private Collection<String> subscribed = new HashSet<>();
+ /** Subscribed to tags. Empty ot null set means all tags are applicable. */
+ private Collection<String> tagsFilter = new HashSet<>();
+
/** {@inheritDoc} */
- @Override public boolean isSubscribed(String trackedBranchId) {
+ @Override public boolean isSubscribedToBranch(String trackedBranchId) {
return subscribed != null && subscribed.contains(trackedBranchId);
}
@@ -47,6 +50,17 @@
}
/** {@inheritDoc} */
+ @Override public boolean isSubscribedToTag(@Nullable String tag) {
+ if (!hasTagFilter())
+ return true;
+
+ if(Strings.isNullOrEmpty(tag))
+ return true; // nothing to filter, consider subscribed
+
+ return tagsFilter.contains(tag);
+ }
+
+ /** {@inheritDoc} */
@Override public String email() {
return email;
}
@@ -56,6 +70,11 @@
return slack;
}
+ /** {@inheritDoc} */
+ @Override public boolean hasTagFilter() {
+ return (tagsFilter != null) && !tagsFilter.isEmpty();
+ }
+
public void slack(String slack) {
this.slack = slack;
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IIssuesStorage.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IIssuesStorage.java
index ccca2df..46a023e 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IIssuesStorage.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IIssuesStorage.java
@@ -30,9 +30,15 @@
*/
public boolean containsIssueKey(IssueKey issueKey);
- void saveIssue(Issue issue);
+ public void saveIssue(Issue issue);
- Stream<Issue> allIssues();
+ public Stream<Issue> allIssues();
- boolean setNotified(IssueKey key, String addr);
+ /**
+ * Checks and saves address was notified (NotThreadSafe)
+ * @param key issue key.
+ * @param addr Address to register as notified.
+ * @return update successful. This address was not notified before.
+ */
+ public boolean setNotified(IssueKey key, String addr);
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java
index c27af80..373aa0d 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcbot/issue/IssueDetector.java
@@ -25,11 +25,13 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
+import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -178,7 +180,13 @@
channels.stream()
.filter(ch -> ch.isServerAllowed(srvCode))
- .filter(ch -> ch.isSubscribed(issue.trackedBranchName))
+ .filter(ch -> ch.isSubscribedToBranch(issue.trackedBranchName))
+ .filter(ch -> {
+ if (ch.hasTagFilter())
+ return issue.buildTags().stream().anyMatch(ch::isSubscribedToTag);
+
+ return true;
+ })
.forEach(channel -> {
String email = channel.email();
String slack = channel.slack();
@@ -262,7 +270,8 @@
final String trackedBranch = res.getTrackedBranch();
for (TestFailure testFailure : suiteCurrentStatus.testFailures) {
- if (registerTestFailIssues(tcIgnited, srvId, normalizeBranch, testFailure, trackedBranch))
+ if (registerTestFailIssues(tcIgnited, srvId, normalizeBranch, testFailure, trackedBranch,
+ suiteCurrentStatus.tags))
newIssues++;
}
@@ -340,6 +349,8 @@
issue.webUrl = suiteFailure.webToHist;
issue.buildStartTs = tcIgnited.getBuildStartTs(issueKey.buildId);
+ issue.buildTags.addAll(suiteFailure.tags);
+
locateChanges(tcIgnited, issueKey.buildId, issue);
logger.info("Register new issue for suite fail: " + issue);
@@ -361,7 +372,8 @@
String srvId,
String normalizeBranch,
TestFailure testFailure,
- String trackedBranch) {
+ String trackedBranch,
+ @Nonnull Set<String> suiteTags) {
String name = testFailure.name;
IRunHistory runStat = tcIgnited.getTestRunHist(name, normalizeBranch);
@@ -414,6 +426,8 @@
issue.displayName = testFailure.testName;
issue.webUrl = testFailure.webUrl;
+ issue.buildTags.addAll(suiteTags);
+
locateChanges(tcIgnited, buildId, issue);
logger.info("Register new issue for test fail: " + issue);
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/TcHelperUser.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/TcHelperUser.java
index 39b9706..f79cdd1 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/TcHelperUser.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/user/TcHelperUser.java
@@ -25,15 +25,18 @@
import java.util.Set;
import java.util.TreeSet;
+import javax.annotation.Nullable;
import org.apache.ignite.tcbot.persistence.IVersionedEntity;
import org.apache.ignite.tcbot.persistence.Persisted;
import org.apache.ignite.ci.tcbot.conf.INotificationChannel;
import org.apache.ignite.tcservice.model.user.User;
import org.apache.ignite.ci.util.CryptUtil;
-import org.jetbrains.annotations.Nullable;
import static javax.xml.bind.DatatypeConverter.printHexBinary;
+/**
+ * TC Bot user. Contains login information and encrypted passwords.
+ */
@Persisted
public class TcHelperUser implements IVersionedEntity, INotificationChannel {
public static final int LATEST_VERSION = 2;
@@ -131,7 +134,7 @@
}
/** {@inheritDoc} */
- @Override public boolean isSubscribed(String trackedBranchId) {
+ @Override public boolean isSubscribedToBranch(String trackedBranchId) {
return subscribedToAllFailures != null && subscribedToAllFailures.contains(trackedBranchId);
}
@@ -141,6 +144,16 @@
}
/** {@inheritDoc} */
+ @Override public boolean isSubscribedToTag(@Nullable String tag) {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean hasTagFilter() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
@Override public String email() {
return email;
}
diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/TcHelperUserUi.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/TcHelperUserUi.java
index ccd341e..b28954d 100644
--- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/TcHelperUserUi.java
+++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/web/model/TcHelperUserUi.java
@@ -39,7 +39,7 @@
fullName = user.fullName;
email = user.email;
allTrackedBranches.forEach(
- branchId -> subscribedAllToBranchFailures.put(branchId, user.isSubscribed(branchId))
+ branchId -> subscribedAllToBranchFailures.put(branchId, user.isSubscribedToBranch(branchId))
);
}
}
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 5bbb383..c9921da 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
@@ -124,7 +124,7 @@
*/
@Nullable public ProblemRef problemRef;
- public Set<String> tags = new HashSet<>();
+ @Nonnull public Set<String> tags = new HashSet<>();
/**
* Possible blocker comment: filled for PR and builds checks, non null value contains problem explanation
@@ -221,7 +221,7 @@
runningBuildCount = suite.runningBuildCount();
queuedBuildCount = suite.queuedBuildCount();
serverId = tcIgnited.serverCode();
- this.suiteId = suite.suiteId();
+ suiteId = suite.suiteId();
branchName = branchForLink(suite.branchName());
tags = suite.tags();