Add method that retrieve links for specific EiffelEvent key Solves: Jira GER-1545 Change-Id: Ia2cc9f065773a49bed01158334bd16f96a037d73
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHub.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHub.java index 8d6cab9..8e58fbb 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHub.java +++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHub.java
@@ -91,6 +91,20 @@ */ public Optional<UUID> getScsForCommit(String repo, String commit, List<String> branches) throws EiffelEventIdLookupException; + + /** + * If an event exists, already published or awaiting publish in this EiffelEventHub, such that: + * + * <p>{@code EventKey.fromEvent(this).equals(EventKey.fromEvent(existing)} + * + * <p>is true, links.target for all links of type PREVIOUS_VERSION of this event is returned, + * otherwise Optional.empty() + * + * @param key EventKey + * @return Optional<List<UUID>> event.links[].target + * @throws EiffelEventIdLookupException when failing to lookup event from Eiffel. + */ + public Optional<List<UUID>> getParentLinks(EventKey key) throws EiffelEventIdLookupException; /** Start publishing events to Eiffel. */ public void startPublishing(); /** Stop publishing events to Eiffel. */
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubImpl.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubImpl.java index 841aa4f..2138164 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubImpl.java +++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubImpl.java
@@ -15,6 +15,7 @@ package com.googlesource.gerrit.plugins.eventseiffel; import static com.google.common.base.Preconditions.checkState; +import static com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkType.PREVIOUS_VERSION; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -26,6 +27,7 @@ import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey; import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey; import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEvent; +import java.util.Arrays; import java.util.Deque; import java.util.List; import java.util.Map; @@ -173,6 +175,29 @@ } @Override + public Optional<List<UUID>> getParentLinks(EventKey key) throws EiffelEventIdLookupException { + final ReentrantLock idLookupLock = this.idLookupLock; + idLookupLock.lock(); + try { + EiffelEvent fromHub = eventsInQueue.getOrDefault(key, null); + if (fromHub != null) { + if (key.matches(fromHub)) { + return Optional.of( + Arrays.stream(fromHub.links) + .filter(link -> link.type == PREVIOUS_VERSION) + .map(link -> link.target) + .collect(Collectors.toList())); + } + throw new EiffelEventIdLookupException( + "Key: %s does not match found event: %s.", key, EventKey.fromEvent(fromHub)); + } + } finally { + idLookupLock.unlock(); + } + return idCache.getParentLinks(key); + } + + @Override public boolean isOpen() { return open; }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCache.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCache.java index 1299a7e..59775e0 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCache.java +++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCache.java
@@ -36,6 +36,19 @@ Optional<UUID> getEventId(EventKey key) throws EiffelEventIdLookupException; /** + * Returns the ids that is linked with PREVIOUS_VERSION by event that matches: + * + * <p>{@code EventKey.fromEvent(event).equals(key)} + * + * <p>Optional.Empty if no such event exists. + * + * @param key + * @return Optional<List<UUID>> + * @throws EiffelEventIdLookupException if value failed to load. + */ + Optional<List<UUID>> getParentLinks(EventKey key) throws EiffelEventIdLookupException; + + /** * Returns the id of an event that matches the repo and the commit: * * <p>Optional.Empty if no such event exists.
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCacheImpl.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCacheImpl.java index fa7d622..923039b 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCacheImpl.java +++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/cache/EiffelEventIdCacheImpl.java
@@ -131,6 +131,18 @@ return !ids.isEmpty() ? Optional.of(ids.get(0)) : Optional.empty(); } + @Override + public Optional<List<UUID>> getParentLinks(EventKey key) throws EiffelEventIdLookupException { + try { + return eventStorage.getParentLinks(key); + } catch (EventStorageException e) { + throw new EiffelEventIdLookupException( + e, + key.type(), + String.format("failed to lookup Eiffel event links for %s from GraphQl", key)); + } + } + /* (non-Javadoc) * @see com.googlesource.gerrit.plugins.eventseiffel.EiffelEventIdCache#putId(com.googlesource.gerrit.plugins.eventseiffel.eiffel.EiffelEvent) */
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelClient.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelClient.java index 5bf5c75..002f6bc 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelClient.java +++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelClient.java
@@ -60,6 +60,11 @@ } @Override + public Optional<List<UUID>> getParentLinks(EventKey key) throws EventStorageException { + return restClient.getParentLinks(key); + } + + @Override public List<UUID> getScsIds(String repo, String commit) throws EventStorageException { return graphQlClient.getScsIds(repo, commit); }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGoRestClient.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGoRestClient.java index 1cece64..1936110 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGoRestClient.java +++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGoRestClient.java
@@ -14,6 +14,8 @@ package com.googlesource.gerrit.plugins.eventseiffel.eiffel.api; +import static com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkType.PREVIOUS_VERSION; + import com.github.rholder.retry.RetryException; import com.github.rholder.retry.Retryer; import com.github.rholder.retry.RetryerBuilder; @@ -23,16 +25,24 @@ import com.google.common.flogger.FluentLogger; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; +import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey; +import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey; import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkInfo; +import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkType; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandlers; +import java.util.Arrays; import java.util.List; +import java.util.Optional; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class EiffelGoRestClient { public static FluentLogger logger = FluentLogger.forEnclosingClass(); @@ -49,6 +59,43 @@ this.goRestUrl = goRestUrl; } + public Optional<List<UUID>> getParentLinks(EventKey key) throws EventStorageException { + String query; + switch (key.type()) { + case SCC: + SourceChangeEventKey sccKey = (SourceChangeEventKey) key; + query = + String.format( + LINKS_ID_URL, + sccKey.type().getType(), + sccKey.repo(), + sccKey.branch(), + sccKey.commit()); + break; + case SCS: + SourceChangeEventKey scsKey = (SourceChangeEventKey) key; + query = + String.format( + LINKS_ID_URL, + scsKey.type().getType(), + scsKey.repo(), + scsKey.branch(), + scsKey.commit()); + break; + default: + return Optional.empty(); + } + QueryResult qr = restQuery(query); + if (qr == null || qr.isEmpty()) { + return Optional.empty(); + } + + if (qr.nbrOfFoundEvents() > 1) { + logger.atWarning().log("More than one event found (using first) for query:\"%s\"", query); + } + return Optional.of(qr.getParentLinks()); + } + private QueryResult restQuery(String query) throws EventStorageException { HttpResponse<String> response; try { @@ -95,5 +142,23 @@ class Data { EiffelLinkInfo[] links; } + + int nbrOfFoundEvents() { + return items != null ? items.size() : 0; + } + + boolean isEmpty() { + return items == null || items.isEmpty(); + } + + List<UUID> getParentLinks() { + return getLinks(PREVIOUS_VERSION).collect(Collectors.toList()); + } + + private Stream<UUID> getLinks(EiffelLinkType linkType) { + return Arrays.stream(items.get(0).links) + .filter(link -> link.type == linkType) + .map(link -> link.target); + } } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGraphQlClient.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGraphQlClient.java index 468d030..2b0a79a 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGraphQlClient.java +++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EiffelGraphQlClient.java
@@ -180,18 +180,22 @@ Data data; List<Error> errors; - List<UUID> getIds() { + List<Data.Field.Edge> getEdges() { if (data != null) { if (data.sourceChangeCreated != null) { - return toIds(data.sourceChangeCreated.edges); + return data.sourceChangeCreated.edges; } if (data.sourceChangeSubmitted != null) { - return toIds(data.sourceChangeSubmitted.edges); + return data.sourceChangeSubmitted.edges; } } return Lists.newArrayList(); } + List<UUID> getIds() { + return toIds(getEdges()); + } + List<String> getErrorMessages() { return errors.stream().map(e -> e.message).collect(Collectors.toList()); } @@ -208,18 +212,20 @@ class Field { List<Edge> edges; + Meta meta; class Edge { Node node; class Node { + List<Data> links; Meta meta; - - class Meta { - UUID id; - } } } + + class Meta { + UUID id; + } } }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EventStorage.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EventStorage.java index 399cc5b..56be459 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EventStorage.java +++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/api/EventStorage.java
@@ -34,6 +34,16 @@ public Optional<UUID> getEventId(EventKey key) throws EventStorageException; /** + * Returns the links.target for links where links.type is PREVIOUS_VERSION for the event that + * matches EventKey key. Optional.empty() if there exists no such event. + * + * @param key + * @return {@link Optional} of {@link List} of {@link UUID} ids of the linked events. + * @throws EventStorageException + */ + public Optional<List<UUID>> getParentLinks(EventKey key) throws EventStorageException; + + /** * Returns the meta.ids of the SCS events that match the repo and the commitid. * * @param repo the repo of the SCS events. @@ -52,6 +62,11 @@ } @Override + public Optional<List<UUID>> getParentLinks(EventKey key) throws EventStorageException { + throw new NotImplementedException(); + } + + @Override public List<UUID> getScsIds(String repo, String commit) throws EventStorageException { throw new NotImplementedException(); }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventHub.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventHub.java index ddbb055..9957d69 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventHub.java +++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventHub.java
@@ -22,6 +22,8 @@ import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey; import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey; import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEvent; +import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkType; +import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.Set; @@ -70,6 +72,17 @@ return idCache.getScsForCommit(repo, commit, branches); } + @Override + public Optional<List<UUID>> getParentLinks(EventKey key) throws EiffelEventIdLookupException { + return findEvent(key) + .map( + event -> + Arrays.stream(event.links) + .filter(link -> link.type.equals(EiffelLinkType.PREVIOUS_VERSION)) + .map(link -> link.target) + .collect(Collectors.toList())); + } + private Optional<EiffelEvent> findEvent(EventKey key) { for (EiffelEvent event : EVENTS) { if (key.equals(EventKey.fromEvent(event))) {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventStorage.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventStorage.java index b257679..74196c8 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventStorage.java +++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventStorage.java
@@ -16,6 +16,7 @@ import static com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType.SCS; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.inject.Singleton; import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey; @@ -64,6 +65,11 @@ .collect(Collectors.toList()); } + @Override + public Optional<List<UUID>> getParentLinks(EventKey key) throws EventStorageException { + return Optional.of(Lists.newArrayList()); + } + private boolean equalsSCSWithRepoAndCommit(EventKey key, String repo, String commit) { if (!key.type().equals(SCS)) return false; SourceChangeEventKey scsKey = (SourceChangeEventKey) key;