Merge "docs/config-themes: clarify and link to JavaScript plugin dev"
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index 33e7804..58a3724 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -6520,7 +6520,14 @@
|`topic` |optional|The topic to which this change belongs.
|`attention_set` |optional|
The map that maps link:rest-api-accounts.html#account-id[account IDs]
-to link:#attention-set-info[AttentionSetInfo] of that account.
+to link:#attention-set-info[AttentionSetInfo] of that account. Those are all
+accounts that are currently in the attention set.
+|`removed_from_attention_set` |optional|
+The map that maps link:rest-api-accounts.html#account-id[account IDs]
+to link:#attention-set-info[AttentionSetInfo] of that account. Those are all
+accounts that were in the attention set but were removed. The
+link:#attention-set-info[AttentionSetInfo] is the latest and most recent removal
+ of the account from the attention set.
|`assignee` |optional|
The assignee of the change as an link:rest-api-accounts.html#account-info[
AccountInfo] entity.
diff --git a/java/com/google/gerrit/extensions/common/ChangeInfo.java b/java/com/google/gerrit/extensions/common/ChangeInfo.java
index 2bb3dd7..55e4670 100644
--- a/java/com/google/gerrit/extensions/common/ChangeInfo.java
+++ b/java/com/google/gerrit/extensions/common/ChangeInfo.java
@@ -46,6 +46,8 @@
*/
public Map<Integer, AttentionSetInfo> attentionSet;
+ public Map<Integer, AttentionSetInfo> removedFromAttentionSet;
+
public AccountInfo assignee;
public Collection<String> hashtags;
public String changeId;
diff --git a/java/com/google/gerrit/server/change/ActionJson.java b/java/com/google/gerrit/server/change/ActionJson.java
index 54ebf40..ffbd30b 100644
--- a/java/com/google/gerrit/server/change/ActionJson.java
+++ b/java/com/google/gerrit/server/change/ActionJson.java
@@ -118,6 +118,10 @@
copy.topic = changeInfo.topic;
copy.attentionSet =
changeInfo.attentionSet == null ? null : ImmutableMap.copyOf(changeInfo.attentionSet);
+ copy.removedFromAttentionSet =
+ changeInfo.removedFromAttentionSet == null
+ ? null
+ : ImmutableMap.copyOf(changeInfo.removedFromAttentionSet);
copy.assignee = changeInfo.assignee;
copy.hashtags = changeInfo.hashtags;
copy.changeId = changeInfo.changeId;
diff --git a/java/com/google/gerrit/server/change/ChangeJson.java b/java/com/google/gerrit/server/change/ChangeJson.java
index 328c5de..e57238b 100644
--- a/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/java/com/google/gerrit/server/change/ChangeJson.java
@@ -35,6 +35,7 @@
import static com.google.gerrit.extensions.client.ListChangesOption.TRACKING_IDS;
import static com.google.gerrit.server.ChangeMessagesUtil.createChangeMessageInfo;
import static com.google.gerrit.server.util.AttentionSetUtil.additionsOnly;
+import static com.google.gerrit.server.util.AttentionSetUtil.removalsOnly;
import static java.util.stream.Collectors.toList;
import com.google.common.base.Joiner;
@@ -603,6 +604,12 @@
out.branch = in.getDest().shortName();
out.topic = in.getTopic();
if (!cd.attentionSet().isEmpty()) {
+ out.removedFromAttentionSet =
+ removalsOnly(cd.attentionSet()).stream()
+ .collect(
+ toImmutableMap(
+ a -> a.account().get(),
+ a -> AttentionSetUtil.createAttentionSetInfo(a, accountLoader)));
out.attentionSet =
// This filtering should match GetAttentionSet.
additionsOnly(cd.attentionSet()).stream()
diff --git a/java/com/google/gerrit/server/util/AttentionSetUtil.java b/java/com/google/gerrit/server/util/AttentionSetUtil.java
index 9238b44..98200fd 100644
--- a/java/com/google/gerrit/server/util/AttentionSetUtil.java
+++ b/java/com/google/gerrit/server/util/AttentionSetUtil.java
@@ -43,6 +43,14 @@
.collect(ImmutableSet.toImmutableSet());
}
+ /** Returns only updates where the user was removed. */
+ public static ImmutableSet<AttentionSetUpdate> removalsOnly(
+ Collection<AttentionSetUpdate> updates) {
+ return updates.stream()
+ .filter(u -> u.operation() == Operation.REMOVE)
+ .collect(ImmutableSet.toImmutableSet());
+ }
+
/**
* Validates the input for AttentionSetInput. This must be called for all inputs that relate to
* adding or removing attention set entries, except for {@link
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java b/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java
index 0a11b15..4bce5d8 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java
@@ -261,6 +261,12 @@
fakeClock.now(), user.id(), AttentionSetUpdate.Operation.REMOVE, "removed");
assertThat(r.getChange().attentionSet()).containsExactly(expectedAttentionSetUpdate);
+ // The removal also shows up in AttentionSetInfo.
+ AttentionSetInfo attentionSetInfo =
+ Iterables.getOnlyElement(change(r).get().removedFromAttentionSet.values());
+ assertThat(attentionSetInfo.reason).isEqualTo("removed");
+ assertThat(attentionSetInfo.account).isEqualTo(getAccountInfo(user.id()));
+
// Second removal is ignored.
fakeClock.advance(Duration.ofSeconds(42));
change(r).attention(user.id().toString()).remove(new AttentionSetInput("removed again"));