asfgit closed pull request #101: IGNITE-10454 add ticket status to mutes URL: https://github.com/apache/ignite-teamcity-bot/pull/101
This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITcHelper.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITcHelper.java index ba70533e..1c084c1d 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITcHelper.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/ITcHelper.java @@ -17,8 +17,7 @@ package org.apache.ignite.ci; -import java.util.Collection; -import java.util.List; +import org.apache.ignite.ci.jira.Tickets; import org.apache.ignite.ci.tcbot.issue.IssueDetector; import org.apache.ignite.ci.issue.IssuesStorage; import org.apache.ignite.ci.teamcity.restcached.ITcServerProvider; @@ -65,4 +64,12 @@ * @return {@code Visa} which contains info about JIRA notification. */ Visa notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc, String ticket); + + /** + * @param srvId Server id. + * @param prov Credentials. + * @param ticketId Ticket. + * @return Jira tickets. + */ + Tickets getJiraTickets(String srvId, ICredentialsProv prov, String ticketId); } 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 29f06807..4a62cb7b 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 @@ -123,6 +123,12 @@ */ public String sendJiraComment(String ticket, String comment) throws IOException; + /** + * @param url Url. + * @return Response as gson string. + */ + String sendGetToJira(String url) throws IOException; + /** * @param url URL for JIRA integration. */ 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 08f7a428..23849a29 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 @@ -595,6 +595,11 @@ public Executor getExecutor() { return teamcity.sendJiraComment(ticket, comment); } + /** {@inheritDoc} */ + @Override public String sendGetToJira(String url) throws IOException { + return teamcity.sendGetToJira(url); + } + /** {@inheritDoc} */ @Override public void setJiraApiUrl(String url) { teamcity.setJiraApiUrl(url); 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 af287190..cd88aea3 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 @@ -180,6 +180,14 @@ public void init(@Nullable String tcName) { return HttpUtil.sendPostAsStringToJira(jiraBasicAuthTok, url, "{\"body\": \"" + comment + "\"}"); } + /** {@inheritDoc} */ + @Override public String sendGetToJira(String url) throws IOException { + if (isNullOrEmpty(jiraApiUrl)) + throw new IllegalStateException("JIRA API URL is not configured for this server."); + + return HttpUtil.sendGetToJira(jiraBasicAuthTok, jiraApiUrl + url); + } + /** {@inheritDoc} */ @Override public void setJiraApiUrl(String url) { jiraApiUrl = url; diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/TcHelper.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/TcHelper.java index c293e91b..f4e8c093 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/TcHelper.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/TcHelper.java @@ -18,12 +18,12 @@ package org.apache.ignite.ci; import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.Collection; +import com.google.gson.Gson; import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; import javax.inject.Inject; -import org.apache.ignite.ci.conf.BranchesTracked; +import org.apache.ignite.ci.jira.Tickets; import org.apache.ignite.ci.tcbot.issue.IssueDetector; import org.apache.ignite.ci.issue.IssuesStorage; import org.apache.ignite.ci.jira.IJiraIntegration; @@ -184,6 +184,22 @@ public TcHelper() { return new Visa(IJiraIntegration.JIRA_COMMENTED, res, blockers); } + /** {@inheritDoc} */ + @Override public Tickets getJiraTickets(String srvId, ICredentialsProv prov, String url) { + IAnalyticsEnabledTeamcity teamcity = server(srvId, prov); + + try { + return new Gson().fromJson(teamcity.sendGetToJira(url), Tickets.class); + } + catch (Exception e) { + String errMsg = "Exception happened during receiving JIRA tickets " + + "[url=" + url + ", errMsg=" + e.getMessage() + ']'; + + logger.error(errMsg); + + return new Tickets(); + } + } /** * @param suites Suite Current Status. diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java new file mode 100644 index 00000000..f9aa8e94 --- /dev/null +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Fields.java @@ -0,0 +1,26 @@ +/* + * 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.jira; + +/** + * + */ +public class Fields { + /** Ticket status. */ + public Status status; +} \ No newline at end of file diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java index d952b2fd..12b3836a 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/IJiraIntegration.java @@ -42,6 +42,16 @@ public Visa notifyJira(String srvId, ICredentialsProv prov, String buildTypeId, String branchForTc, String ticket); + /** + * Produce wrapper for collection of Jira tickets for given server. + * + * @param srvId Server id. + * @param prov Prov. + * @param ticketId Ticket id. + * @return Jira tickets. + */ + public Tickets getTickets(String srvId, ICredentialsProv prov, String ticketId); + /** */ public String jiraUrl(); diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Jira.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Jira.java index b23d840a..8755b90c 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Jira.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Jira.java @@ -60,6 +60,11 @@ return helper.notifyJira(srvId, prov, buildTypeId, branchForTc, ticket); } + /** {@inheritDoc} */ + @Override public Tickets getTickets(String srvId, ICredentialsProv prov, String url) { + return helper.getJiraTickets(srvId, prov, url); + } + /** {@inheritDoc} */ @Override public String generateTicketUrl(String ticketFullName) { Preconditions.checkState(!isNullOrEmpty(jiraUrl), "Jira URL is not configured for this server."); diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java new file mode 100644 index 00000000..62ceeb3d --- /dev/null +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Status.java @@ -0,0 +1,33 @@ +/* + * 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.jira; + +/** + * Status for Jira ticket. + */ +public class Status { + /** Status text (open, resolved, etc). */ + public String name; + + /** + * @param name Name. + */ + public Status(String name) { + this.name = name; + } +} \ No newline at end of file diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java new file mode 100644 index 00000000..f69c1bf7 --- /dev/null +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Ticket.java @@ -0,0 +1,47 @@ +/* + * 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.jira; + +/** + * See example of GSON here + * https://issues.apache.org/jira/rest/api/2/issue/IGNITE-123 + */ +public class Ticket { + /** Id. */ + public long id; + + /** Ticket full name like "IGNITE-123". */ + public String key; + + /** Fields. */ + public Fields fields; + + /** + * @return Ignite id (like 123 in IGNITE-123). + */ + public int igniteId() { + return Integer.valueOf(key.substring("IGNITE-".length())); + } + + /** + * @return Ticket status (open, resolved, etc); + */ + public String status() { + return fields.status.name; + } +} \ No newline at end of file diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java new file mode 100644 index 00000000..f265b375 --- /dev/null +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/Tickets.java @@ -0,0 +1,58 @@ +/* + * 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.jira; + +import java.util.Collection; +import java.util.Collections; + +/** + * See example of GSON here + * https://issues.apache.org/jira/rest/api/2/search?jql=project%20=%20IGNITE%20order%20by%20updated%20DESC&fields=status + */ +public class Tickets { + /** Start at. */ + public int startAt; + + /** Max amount of tickets on the page. */ + public int maxResults; + + /** Total tickets. */ + public int total; + + /** Jira tickets. */ + public Collection<Ticket> issues; + + /** + * @return Start index for next page. Return -1 if it is last page. + */ + public int nextStart() { + int next = startAt + maxResults; + + if (next < total) + return next; + + return -1; + } + + /** + * @return Jira tickets. + */ + public Collection<Ticket> issuesNotNull() { + return issues == null ? Collections.emptyList() : issues; + } +} \ No newline at end of file diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java new file mode 100644 index 00000000..4a6e4142 --- /dev/null +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketDao.java @@ -0,0 +1,113 @@ +/* + * 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.jira.ignited; + +import com.google.common.base.Preconditions; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import javax.cache.Cache; +import javax.inject.Inject; +import javax.inject.Provider; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.ci.db.TcHelperDb; +import org.apache.ignite.ci.di.AutoProfiling; +import org.apache.ignite.ci.jira.Ticket; +import org.apache.ignite.ci.teamcity.ignited.IStringCompactor; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.internal.util.typedef.internal.U; + +/** + * + */ +public class JiraTicketDao { + /** Cache name. */ + public static final String TEAMCITY_JIRA_TICKET_CACHE_NAME = "jiraTickets"; + + /** Ignite provider. */ + @Inject private Provider<Ignite> igniteProvider; + + /** Builds cache. */ + private IgniteCache<Long, TicketCompacted> jiraCache; + + /** Compactor. */ + @Inject private IStringCompactor compactor; + + /** + * + */ + public void init() { + jiraCache = igniteProvider.get().getOrCreateCache(TcHelperDb.getCache8PartsConfig(TEAMCITY_JIRA_TICKET_CACHE_NAME)); + } + + /** + * @param srvIdMaskHigh Server id mask high. + * @return Jira tickets. + */ + public Set<Ticket> getTickets(int srvIdMaskHigh) { + Preconditions.checkNotNull(jiraCache, "init() was not called"); + long srvId = (long) srvIdMaskHigh << 32; + + Set<Ticket> res = new HashSet<>(); + + for (Cache.Entry<Long, TicketCompacted> entry : jiraCache) { + if ((entry.getKey() & srvId) == srvId) + res.add(entry.getValue().toTicket(compactor)); + } + + return res; + } + + /** + * Combine server and project into key for storage. + * + * @param srvIdMaskHigh Server id mask high. + * @param igniteId Ticket. + * @return Key from server-project pair. + */ + public static long ticketToCacheKey(int srvIdMaskHigh, int igniteId) { + return (long) igniteId | (long) srvIdMaskHigh << 32; + } + + /** + * Save small part of loaded mutes. + * + * @param srvIdMaskHigh Server id mask high. + * @param chunk Chunk. + */ + @AutoProfiling + public void saveChunk(int srvIdMaskHigh, Collection<Ticket> chunk) { + Preconditions.checkNotNull(jiraCache, "init() was not called"); + + if (F.isEmpty(chunk)) + return; + + HashMap<Long, TicketCompacted> compactedTickets = new HashMap<>(U.capacity(chunk.size())); + + for (Ticket ticket : chunk) { + long key = ticketToCacheKey(srvIdMaskHigh, ticket.igniteId()); + TicketCompacted val = new TicketCompacted(ticket, compactor); + + compactedTickets.put(key, val); + } + + jiraCache.putAll(compactedTickets); + } +} diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.java new file mode 100644 index 00000000..c5dabbcc --- /dev/null +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/JiraTicketSync.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.jira.ignited; + +import java.util.Collection; +import java.util.concurrent.TimeUnit; +import javax.inject.Inject; +import org.apache.ignite.ci.di.MonitoredTask; +import org.apache.ignite.ci.di.scheduler.IScheduler; +import org.apache.ignite.ci.jira.IJiraIntegration; +import org.apache.ignite.ci.jira.IJiraIntegrationProvider; +import org.apache.ignite.ci.jira.Ticket; +import org.apache.ignite.ci.jira.Tickets; +import org.apache.ignite.ci.teamcity.pure.ITeamcityConn; +import org.apache.ignite.ci.user.ICredentialsProv; +import org.apache.ignite.internal.util.typedef.F; + +/** + * + */ +public class JiraTicketSync { + /** Scheduler. */ + @Inject private IScheduler scheduler; + + /** Mute DAO. */ + @Inject private JiraTicketDao jiraDao; + + /** Jira integration provider. */ + @Inject IJiraIntegrationProvider jiraIntegrationProvider; + + /** + * @param taskName Task name. + * @param srvIdMaskHigh Server id mask high. + * @param creds Credentials. + * @param conn Connection. + */ + public void ensureActualizeJiraTickets(String taskName, int srvIdMaskHigh, ICredentialsProv creds, ITeamcityConn conn) { + scheduler.sheduleNamed(taskName, () -> actualizeJiraTickets(srvIdMaskHigh, conn, creds), 15, TimeUnit.MINUTES); + } + + /** + * @param srvIdMaskHigh Server id mask high. + * @param conn Connection. + * @param creds Credentials. + */ + @MonitoredTask(name = "Actualize Jira", nameExtArgsIndexes = {0}) + private String actualizeJiraTickets(int srvIdMaskHigh, ITeamcityConn conn, ICredentialsProv creds) { + String srvId = conn.serverId(); + IJiraIntegration jira = jiraIntegrationProvider.server(srvId); + String url = "search?jql=project%20=%20IGNITE%20order%20by%20updated%20DESC&fields=status&maxResults=100"; + Tickets tickets = jira.getTickets(srvId, creds, url); + Collection<Ticket> page = tickets.issuesNotNull(); + + if (F.isEmpty(page)) + return "Something went wrong - no tickets found. Check jira availability."; + + jiraDao.saveChunk(srvIdMaskHigh, page); + + int ticketsSaved = page.size(); + + while (tickets.nextStart() > 0) { + url = "search?jql=project%20=%20IGNITE%20order%20by%20updated%20DESC&fields=status&maxResults=100&startAt=" + + tickets.nextStart(); + + tickets = jira.getTickets(srvId, creds, url); + + page = tickets.issuesNotNull(); + + if (F.isEmpty(page)) + break; + + jiraDao.saveChunk(srvIdMaskHigh, page); + + ticketsSaved += page.size(); + } + + return "Jira tickets saved " + ticketsSaved + " for " + srvId; + } +} diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java new file mode 100644 index 00000000..8989994f --- /dev/null +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/jira/ignited/TicketCompacted.java @@ -0,0 +1,61 @@ +/* + * 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.jira.ignited; + +import org.apache.ignite.ci.jira.Fields; +import org.apache.ignite.ci.jira.Status; +import org.apache.ignite.ci.jira.Ticket; +import org.apache.ignite.ci.teamcity.ignited.IStringCompactor; + +/** + * + */ +public class TicketCompacted { + /** Id. */ + public long id; + + /** Ticket full name like "IGNITE-123". */ + public int igniteId; + + /** Fields. */ + public int status; + + /** + * @param ticket Jira ticket. + * @param comp Compactor. + */ + public TicketCompacted(Ticket ticket, IStringCompactor comp) { + id = ticket.id; + igniteId = Integer.valueOf(ticket.key.substring("IGNITE-".length())); + status = comp.getStringId(ticket.fields.status.name); + } + + /** + * @param comp Compactor. + */ + public Ticket toTicket(IStringCompactor comp) { + Ticket ticket = new Ticket(); + + ticket.id = id; + ticket.key = "IGNITE-" + igniteId; + ticket.fields = new Fields(); + ticket.fields.status = new Status(comp.getStringFromId(status)); + + return ticket; + } +} 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 e45b3534..aecc4d16 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 @@ -182,7 +182,7 @@ else if (RUNNING_STATUS.equals(buildsStatus)) public Set<MuteInfo> getMutes(String srvId, String projectId, ICredentialsProv creds) { ITeamcityIgnited ignited = teamcityIgnitedProvider.server(srvId, creds); - Set<MuteInfo> infos = ignited.getMutes(projectId); + Set<MuteInfo> infos = ignited.getMutes(projectId, creds); for (MuteInfo info : infos) info.assignment.muteDate = THREAD_FORMATTER.get().format(new Date(info.assignment.timestamp())); diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteAssignment.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteAssignment.java index 0c1c3ff4..d70f894c 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteAssignment.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteAssignment.java @@ -22,7 +22,7 @@ import org.apache.ignite.ci.util.TimeUtil; /** - * + * Mute additional information. Contains mute date and it's comment. */ @XmlRootElement(name = "assignment") public class MuteAssignment { diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteInfo.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteInfo.java index 87925f89..61a153b9 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteInfo.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteInfo.java @@ -26,7 +26,10 @@ import org.jetbrains.annotations.NotNull; /** - * + * TeamCity mute. + * <p> + * See example of XML here + * https://ci.ignite.apache.org/app/rest/mutes/ */ @XmlRootElement(name = "mute") @XmlAccessorType(XmlAccessType.FIELD) @@ -43,6 +46,9 @@ /** Target. */ @XmlElement public MuteTarget target; + /** Jira ticket status. TeamCity don't send it, we fill it when send mutes.html. */ + @XmlElement public String ticketStatus; + /** {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteScope.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteScope.java index ac2ae28d..e2137d62 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteScope.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteScope.java @@ -26,7 +26,7 @@ import org.apache.ignite.ci.tcmodel.conf.Project; /** - * + * Mute additional information. Contains project or build types - scope affected by mute. */ @XmlAccessorType(XmlAccessType.FIELD) public class MuteScope { diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteTarget.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteTarget.java index 2d437de3..cd52735d 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteTarget.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/MuteTarget.java @@ -25,7 +25,7 @@ import org.apache.ignite.ci.tcmodel.result.tests.TestRef; /** - * Mute target (e.g. muted test). + * Mute additional information. Contains what was muted (tests, problems). */ @XmlAccessorType(XmlAccessType.FIELD) public class MuteTarget { diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/Mutes.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/Mutes.java index 9b7fe407..c8177b48 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/Mutes.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/tcmodel/mute/Mutes.java @@ -31,9 +31,8 @@ /** * Mute entities from TeamCity. On TeamCity this object represent page with several mutes. * <p> - * But we unite mutes into single object to store in mute cache. - * <p> - * See https://ci.ignite.apache.org/app/rest/mutes/ + * See example of XML here + * https://ci.ignite.apache.org/app/rest/mutes/ */ @XmlRootElement(name = "mutes") @XmlAccessorType(XmlAccessType.FIELD) 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 36a54e98..ead6dd71 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 @@ -30,6 +30,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.fatbuild.FatBuildCompacted; +import org.apache.ignite.ci.user.ICredentialsProv; import org.jetbrains.annotations.NotNull; /** @@ -59,9 +60,10 @@ /** * @param projectId Project id. + * @param creds Credentials. * @return Mutes for associated server and given project pair. */ - Set<MuteInfo> getMutes(String projectId); + public Set<MuteInfo> getMutes(String projectId, ICredentialsProv creds); /** * Return all builds for branch and suite with finish status. 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 d305d5b4..4a4e19f3 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 @@ -27,6 +27,9 @@ 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.jira.ignited.JiraTicketDao; +import org.apache.ignite.ci.jira.ignited.JiraTicketSync; +import org.apache.ignite.ci.jira.Ticket; import org.apache.ignite.ci.tcbot.trends.MasterTrendsService; import org.apache.ignite.ci.tcmodel.mute.MuteInfo; import org.apache.ignite.ci.teamcity.ignited.mute.MuteDao; @@ -50,6 +53,8 @@ import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistCompactedDao; import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistSync; import org.apache.ignite.ci.teamcity.pure.ITeamcityConn; +import org.apache.ignite.ci.user.ICredentialsProv; +import org.apache.ignite.internal.util.typedef.F; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -108,6 +113,12 @@ /** Mute Sync. */ @Inject private MuteSync muteSync; + /** Jira ticket DAO. */ + @Inject private JiraTicketDao jiraTicketDao; + + /** Jira ticket Sync. */ + @Inject private JiraTicketSync jiraTicketSync; + /** Changes DAO. */ @Inject private ChangeDao changesDao; @@ -146,6 +157,7 @@ public void init(String srvId, ITeamcityConn conn) { changesDao.init(); runHistCompactedDao.init(); muteDao.init(); + jiraTicketDao.init(); } /** @@ -326,10 +338,45 @@ else if (midValStartDate.before(key)) } /** {@inheritDoc} */ - @Override public Set<MuteInfo> getMutes(String projectId) { + @Override public Set<MuteInfo> getMutes(String projectId, ICredentialsProv creds) { muteSync.ensureActualizeMutes(taskName("actualizeMutes"), projectId, srvIdMaskHigh, conn); + jiraTicketSync.ensureActualizeJiraTickets(taskName("actualizeJiraTickets"), srvIdMaskHigh, creds, conn); + + SortedSet<MuteInfo> mutes = muteDao.getMutes(srvIdMaskHigh); + Collection<Ticket> tickets = jiraTicketDao.getTickets(srvIdMaskHigh); - return muteDao.getMutes(srvIdMaskHigh); + insertTicketStatus(mutes, tickets); + + return mutes; + } + + /** + * Insert ticket status for all mutes, if they have ticket in description. + * + * @param mutes Mutes. + * @param tickets Tickets. + */ + private void insertTicketStatus(SortedSet<MuteInfo> mutes, Collection<Ticket> tickets) { + for (MuteInfo mute : mutes) { + if (F.isEmpty(mute.assignment.text)) + continue; + + int pos = mute.assignment.text.indexOf("https://issues.apache.org/jira/browse/"); + + if (pos == -1) + continue; + + for (Ticket ticket : tickets) { + String muteTicket = mute.assignment.text.substring(pos + + "https://issues.apache.org/jira/browse/".length()); + + if (ticket.key.equals(muteTicket)) { + mute.ticketStatus = ticket.status(); + + break; + } + } + } } /** {@inheritDoc} */ diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedModule.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedModule.java index a6d76f28..1dd0fe55 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedModule.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/TeamcityIgnitedModule.java @@ -18,6 +18,8 @@ import com.google.inject.AbstractModule; import com.google.inject.internal.SingletonScope; +import org.apache.ignite.ci.jira.ignited.JiraTicketDao; +import org.apache.ignite.ci.jira.ignited.JiraTicketSync; import org.apache.ignite.ci.teamcity.ignited.buildcondition.BuildConditionDao; import org.apache.ignite.ci.teamcity.ignited.buildref.BuildRefDao; import org.apache.ignite.ci.teamcity.ignited.buildref.BuildRefSync; @@ -29,6 +31,7 @@ import org.apache.ignite.ci.teamcity.ignited.fatbuild.FatBuildDao; import org.apache.ignite.ci.teamcity.ignited.fatbuild.ProactiveFatBuildSync; import org.apache.ignite.ci.teamcity.ignited.mute.MuteDao; +import org.apache.ignite.ci.teamcity.ignited.mute.MuteSync; import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistCompactedDao; import org.apache.ignite.ci.teamcity.ignited.runhist.RunHistSync; import org.apache.ignite.ci.teamcity.pure.ITeamcityHttpConnection; @@ -58,6 +61,9 @@ bind(RunHistCompactedDao.class).in(new SingletonScope()); bind(RunHistSync.class).in(new SingletonScope()); bind(MuteDao.class).in(new SingletonScope()); + bind(MuteSync.class).in(new SingletonScope()); + bind(JiraTicketDao.class).in(new SingletonScope()); + bind(JiraTicketSync.class).in(new SingletonScope()); bind(IStringCompactor.class).to(IgniteStringCompactor.class).in(new SingletonScope()); diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/mute/MuteDao.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/mute/MuteDao.java index a955701d..7dfb0178 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/mute/MuteDao.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/mute/MuteDao.java @@ -62,9 +62,9 @@ public void init() { * @return Server mutes. */ @AutoProfiling - public SortedSet<MuteInfo> getMutes(long srvIdMaskHigh) { + public SortedSet<MuteInfo> getMutes(int srvIdMaskHigh) { Preconditions.checkNotNull(muteCache, "init() was not called"); - long srvId = srvIdMaskHigh << 32; + long srvId = (long) srvIdMaskHigh << 32; TreeSet<MuteInfo> res = new TreeSet<>(); diff --git a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/mute/MuteSync.java b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/mute/MuteSync.java index 53f5a573..ee118e45 100644 --- a/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/mute/MuteSync.java +++ b/ignite-tc-helper-web/src/main/java/org/apache/ignite/ci/teamcity/ignited/mute/MuteSync.java @@ -23,8 +23,10 @@ import javax.inject.Inject; import org.apache.ignite.ci.di.MonitoredTask; import org.apache.ignite.ci.di.scheduler.IScheduler; +import org.apache.ignite.ci.jira.IJiraIntegrationProvider; import org.apache.ignite.ci.tcmodel.mute.MuteInfo; import org.apache.ignite.ci.teamcity.pure.ITeamcityConn; +import org.apache.ignite.ci.user.ICredentialsProv; import org.apache.ignite.internal.util.typedef.F; /** @@ -48,6 +50,8 @@ public void ensureActualizeMutes(String taskName, String projectId, int srvIdMas * Refresh mutes for given project. * * @param projectId Project id. + * @param srvIdMaskHigh Server id mask high. + * @param conn TeamCity connection. * @return Message with loading result. */ @MonitoredTask(name = "Actualize Mute", nameExtArgsIndexes = {0}) 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 817fa047..24181899 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 @@ -228,7 +228,7 @@ public static String sendPostAsStringToGit(String githubAuthTok, String url, Str } /** - * Send POST request to the GitHub url. + * Send POST request to the JIRA url. * * @param jiraAuthTok Authorization Base64 token. * @param url URL. @@ -257,7 +257,37 @@ public static String sendPostAsStringToJira(String jiraAuthTok, String url, Stri logger.info("\nSending 'POST' request to URL : " + url + "\n" + body); - try (InputStream inputStream = getInputStream(con)){ + try (InputStream inputStream = getInputStream(con)) { + return readIsToString(inputStream); + } + } + + /** + * Send GET request to the JIRA url. + * + * @param jiraAuthTok Jira auth token. + * @param url Url. + */ + public static String sendGetToJira(String jiraAuthTok, String url) throws IOException { + Stopwatch started = Stopwatch.createStarted(); + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection)obj.openConnection(); + Charset charset = StandardCharsets.UTF_8; + + con.setRequestProperty("accept-charset", charset.toString()); + con.setRequestProperty("Authorization", "Basic " + jiraAuthTok); + con.setRequestProperty("content-type", "application/json"); + con.setRequestProperty("Connection", "Keep-Alive"); + con.setRequestProperty("Keep-Alive", "header"); + + con.setRequestMethod("GET"); + + int resCode = con.getResponseCode(); + + logger.info(Thread.currentThread().getName() + ": Required: " + started.elapsed(TimeUnit.MILLISECONDS) + + "ms : Sending 'GET' request to : " + url + " Response: " + resCode); + + try (InputStream inputStream = getInputStream(con)) { return readIsToString(inputStream); } } diff --git a/ignite-tc-helper-web/src/main/webapp/mutes.html b/ignite-tc-helper-web/src/main/webapp/mutes.html index b714b8cb..ee8e7675 100644 --- a/ignite-tc-helper-web/src/main/webapp/mutes.html +++ b/ignite-tc-helper-web/src/main/webapp/mutes.html @@ -54,30 +54,30 @@ $.ajax({ url: "rest/tracked/mutes?serverId=apache", success: function (result) { - showVisasTable(result); + showTable(result); }, error: showErrInLoadStatus } ); } - function showVisasTable(result) { + function showTable(result) { // Debug info // if (isDefinedAndFilled(result)) { // result.sort((a, b) => (a.id < b.id) ? -1 : ((a.id > b.id) ? 1 : 0)); // console.log(result); // } - let visasTable = $('#visasTable'); + let table = $('#table'); let testNameMatcher = new RegExp("\\.(\\w+\\d*):.*\\.([a-z][$\\w]+\\w+\\d*)"); let testNameMatcher2 = new RegExp("(\\w+\.Test\\w+\\d*)$"); let suiteNameMatcher2 = new RegExp("(.*):"); let ticketMatcher = new RegExp("https:\\/\\/issues.apache.org\\/jira\\/browse\\/(IGNITE-\\d+)"); - visasTable.dataTable().fnDestroy(); + table.dataTable().fnDestroy(); - visasTable.DataTable({ + table.DataTable({ data: result, "iDisplayLength": 30, //rows to be shown by default stateSave: true, @@ -166,6 +166,13 @@ + ticket[1] + "</a>"; } }, + { + title: "Status", + width: 50, + "data": function (data, type, row, meta) { + return data.ticketStatus; + } + }, { title: "Mute Date", "data": function (data, type, row, meta) { @@ -195,7 +202,7 @@ <br> <div id="loadStatus"></div> <br> -<table id="visasTable" class="row-border" style="width:100%"> +<table id="table" class="row-border" style="width:100%"> <thead> <tr class="ui-widget-header "> <th>.</th> @@ -204,6 +211,7 @@ <th>.</th> <th>.</th> <th>.</th> + <th>.</th> </tr> </thead> </table> ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services