From 9d0e19856610ee9efbebf6b7d5774f480dc265da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 11 Dec 2024 08:50:02 +0100 Subject: [PATCH] Allow ignoring issues by labels for stale/stewardship --- README.adoc | 14 ++- .../github/lottery/config/LotteryConfig.java | 16 +-- .../quarkus/github/lottery/draw/Lottery.java | 9 +- .../lottery/github/GitHubRepository.java | 27 ++++-- .../lottery/github/GitHubSearchClauses.java | 4 + .../github/lottery/GitHubServiceTest.java | 97 +++++++++++++++++-- .../github/lottery/HistoryServiceTest.java | 4 +- .../lottery/LotterySingleRepositoryTest.java | 26 ++--- 8 files changed, 156 insertions(+), 41 deletions(-) diff --git a/README.adoc b/README.adoc index cd4b419..d279945 100644 --- a/README.adoc +++ b/README.adoc @@ -187,11 +187,12 @@ participants: maxIssues: 2 stale: maxIssues: 5 + ignoreLabels: ["triage/on-ice"] ---- `labels`:: The labels identifying issues you are interested in, as a maintainer. -Issues mentioned in notifications will have at least one of those labels. +Issues mentioned in notifications will have at least one of these labels. + Array of Strings, mandatory, no default. `days`:: @@ -213,6 +214,11 @@ How many issues, at most, you wish to be included in the "Stale" category for each notification. + Integer, mandatory, no default. +`stale.ignoreLabels`:: +The labels identifying issues that should be ignored for the "Stale" category. +Issues mentioned in notifications will never have any one of these labels. ++ +Array of Strings, optional, defaults to an empty array. [[participants-stewardship]] === Stewardship @@ -244,6 +250,7 @@ participants: stewardship: days: ["MONDAY"] maxIssues: 5 + ignoreLabels: ["triage/on-ice"] ---- `days`:: @@ -255,6 +262,11 @@ How many issues, at most, you wish to be included in the "stewardship" category for each notification. + Integer, mandatory, no default. +`ignoreLabels`:: +The labels identifying issues that should be ignored for the "stewardship" category. +Issues mentioned in notifications will never have any one of these labels. ++ +Array of Strings, optional, defaults to an empty array. [[participants-suspending]] === Suspending notifications diff --git a/src/main/java/io/quarkus/github/lottery/config/LotteryConfig.java b/src/main/java/io/quarkus/github/lottery/config/LotteryConfig.java index 2109b2b..4693076 100644 --- a/src/main/java/io/quarkus/github/lottery/config/LotteryConfig.java +++ b/src/main/java/io/quarkus/github/lottery/config/LotteryConfig.java @@ -90,23 +90,27 @@ public Provided(@JsonProperty(required = true) Duration delay, } public record Stale( - @JsonUnwrapped @JsonProperty(access = JsonProperty.Access.READ_ONLY) Notification notification) { + @JsonUnwrapped @JsonProperty(access = JsonProperty.Access.READ_ONLY) Notification notification, + @JsonProperty(required = true) List ignoreLabels) { // https://stackoverflow.com/a/71539100/6692043 // Also gives us a less verbose constructor for tests @JsonCreator - public Stale(@JsonProperty(required = true) Duration delay, @JsonProperty(required = true) Duration timeout) { - this(new Notification(delay, timeout)); + public Stale(@JsonProperty(required = true) Duration delay, @JsonProperty(required = true) Duration timeout, + @JsonProperty(required = false) List ignoreLabels) { + this(new Notification(delay, timeout), ignoreLabels == null ? List.of() : ignoreLabels); } } } public record Stewardship( - @JsonUnwrapped @JsonProperty(access = JsonProperty.Access.READ_ONLY) Notification notification) { + @JsonUnwrapped @JsonProperty(access = JsonProperty.Access.READ_ONLY) Notification notification, + @JsonProperty(required = false) List ignoreLabels) { // https://stackoverflow.com/a/71539100/6692043 // Also gives us a less verbose constructor for tests @JsonCreator - public Stewardship(@JsonProperty(required = true) Duration delay, @JsonProperty(required = true) Duration timeout) { - this(new Notification(delay, timeout)); + public Stewardship(@JsonProperty(required = true) Duration delay, @JsonProperty(required = true) Duration timeout, + @JsonProperty(required = false) List ignoreLabels) { + this(new Notification(delay, timeout), ignoreLabels == null ? List.of() : ignoreLabels); } } diff --git a/src/main/java/io/quarkus/github/lottery/draw/Lottery.java b/src/main/java/io/quarkus/github/lottery/draw/Lottery.java index d2a096c..b5c6e78 100644 --- a/src/main/java/io/quarkus/github/lottery/draw/Lottery.java +++ b/src/main/java/io/quarkus/github/lottery/draw/Lottery.java @@ -95,7 +95,7 @@ void createDraws(GitHubRepository repo, LotteryHistory lotteryHistory, List history.lastNotificationTimedOutForIssueNumber(issue.number())) .iterator(), allWinnings)); @@ -155,9 +155,11 @@ void createDraws(GitHubRepository repo, LotteryHistory lotteryHistory, List(config.maintenance().stale().ignoreLabels()); var history = lotteryHistory.stale(); draws.add(stale.createDraw( - repo.issuesWithLabelLastUpdatedBefore(areaLabel, cutoff) + repo.issuesWithLabelLastUpdatedBefore(areaLabel, ignoreLabels, cutoff) .filter(issue -> history.lastNotificationTimedOutForIssueNumber(issue.number())) .iterator(), allWinnings)); @@ -176,9 +178,10 @@ void createDraws(GitHubRepository repo, LotteryHistory lotteryHistory, List allWinnings) throws IOException { if (stewardship.bucket.hasParticipation()) { var cutoff = now.minus(config.stewardship().notification().delay()); + var ignoreLabels = new LinkedHashSet<>(config.stewardship().ignoreLabels()); var history = lotteryHistory.stewardship(); draws.add(bucket.createDraw( - repo.issuesLastUpdatedBefore(cutoff) + repo.issuesLastUpdatedBefore(ignoreLabels, cutoff) .filter(issue -> history.lastNotificationTimedOutForIssueNumber(issue.number())) .iterator(), allWinnings)); diff --git a/src/main/java/io/quarkus/github/lottery/github/GitHubRepository.java b/src/main/java/io/quarkus/github/lottery/github/GitHubRepository.java index e61d942..ab0c45a 100644 --- a/src/main/java/io/quarkus/github/lottery/github/GitHubRepository.java +++ b/src/main/java/io/quarkus/github/lottery/github/GitHubRepository.java @@ -5,6 +5,7 @@ import static io.quarkus.github.lottery.github.GitHubSearchClauses.author; import static io.quarkus.github.lottery.github.GitHubSearchClauses.isIssue; import static io.quarkus.github.lottery.github.GitHubSearchClauses.label; +import static io.quarkus.github.lottery.github.GitHubSearchClauses.not; import static io.quarkus.github.lottery.github.GitHubSearchClauses.repo; import static io.quarkus.github.lottery.github.GitHubSearchClauses.updatedBefore; import static io.quarkus.github.lottery.util.Streams.toStream; @@ -121,37 +122,43 @@ public Optional fetchLotteryConfig() throws IOException { /** * Lists issues that were last updated before the given instant. * + * @param ignoreLabels GitHub labels. Issues assigned with any of these labels are ignored (not returned). * @param updatedBefore An instant; all returned issues must have been last updated before that instant. * @return A lazily populated stream of matching issues. * @throws java.io.UncheckedIOException In case of I/O failure. */ - public Stream issuesLastUpdatedBefore(Instant updatedBefore) { - return toStream(searchIssues() + public Stream issuesLastUpdatedBefore(Set ignoreLabels, Instant updatedBefore) { + var builder = searchIssues() .isOpen() .q(updatedBefore(updatedBefore)) .sort(GHIssueSearchBuilder.Sort.UPDATED) - .order(GHDirection.DESC) - .list()) - .map(toIssueRecord()); + .order(GHDirection.DESC); + if (!ignoreLabels.isEmpty()) { + builder.q(not(anyLabel(ignoreLabels))); + } + return toStream(builder.list()).map(toIssueRecord()); } /** * Lists issues with the given label that were last updated before the given instant. * * @param label A GitHub label; if non-null, all returned issues must have been assigned that label. + * @param ignoreLabels GitHub labels. Issues assigned with any of these labels are ignored (not returned). * @param updatedBefore An instant; all returned issues must have been last updated before that instant. * @return A lazily populated stream of matching issues. * @throws java.io.UncheckedIOException In case of I/O failure. */ - public Stream issuesWithLabelLastUpdatedBefore(String label, Instant updatedBefore) { - return toStream(searchIssues() + public Stream issuesWithLabelLastUpdatedBefore(String label, Set ignoreLabels, Instant updatedBefore) { + var builder = searchIssues() .isOpen() .q(label(label)) .q(updatedBefore(updatedBefore)) .sort(GHIssueSearchBuilder.Sort.UPDATED) - .order(GHDirection.DESC) - .list()) - .map(toIssueRecord()); + .order(GHDirection.DESC); + if (!ignoreLabels.isEmpty()) { + builder.q(not(anyLabel(ignoreLabels))); + } + return toStream(builder.list()).map(toIssueRecord()); } /** diff --git a/src/main/java/io/quarkus/github/lottery/github/GitHubSearchClauses.java b/src/main/java/io/quarkus/github/lottery/github/GitHubSearchClauses.java index 70ef8b0..abd1007 100644 --- a/src/main/java/io/quarkus/github/lottery/github/GitHubSearchClauses.java +++ b/src/main/java/io/quarkus/github/lottery/github/GitHubSearchClauses.java @@ -9,6 +9,10 @@ public final class GitHubSearchClauses { private GitHubSearchClauses() { } + public static String not(String clause) { + return "-" + clause; + } + public static String repo(GitHubRepositoryRef ref) { return "repo:" + ref.repositoryName(); } diff --git a/src/test/java/io/quarkus/github/lottery/GitHubServiceTest.java b/src/test/java/io/quarkus/github/lottery/GitHubServiceTest.java index 530b690..3a1488c 100644 --- a/src/test/java/io/quarkus/github/lottery/GitHubServiceTest.java +++ b/src/test/java/io/quarkus/github/lottery/GitHubServiceTest.java @@ -163,9 +163,11 @@ void fetchLotteryConfig() throws IOException { stale: delay: P60D timeout: P14D + ignoreLabels: ["triage/on-ice"] stewardship: delay: P60D timeout: P14D + ignoreLabels: ["triage/on-ice"] participants: - username: "yrodiere" triage: @@ -233,9 +235,10 @@ void fetchLotteryConfig() throws IOException { new LotteryConfig.Buckets.Maintenance.Feedback.Provided( Duration.ofDays(7), Duration.ofDays(3))), new LotteryConfig.Buckets.Maintenance.Stale( - Duration.ofDays(60), Duration.ofDays(14))), + Duration.ofDays(60), Duration.ofDays(14), + List.of("triage/on-ice"))), new LotteryConfig.Buckets.Stewardship( - Duration.ofDays(60), Duration.ofDays(14))), + Duration.ofDays(60), Duration.ofDays(14), List.of("triage/on-ice"))), List.of( new LotteryConfig.Participant("yrodiere", Optional.empty(), @@ -324,6 +327,7 @@ void fetchLotteryConfig_minimal() throws IOException { stewardship: delay: P60D timeout: P14D + participants: """); }) .when(() -> { @@ -347,9 +351,9 @@ void fetchLotteryConfig_minimal() throws IOException { new LotteryConfig.Buckets.Maintenance.Feedback.Provided( Duration.ofDays(7), Duration.ofDays(3))), new LotteryConfig.Buckets.Maintenance.Stale( - Duration.ofDays(60), Duration.ofDays(14))), + Duration.ofDays(60), Duration.ofDays(14), List.of())), new LotteryConfig.Buckets.Stewardship( - Duration.ofDays(60), Duration.ofDays(14))), + Duration.ofDays(60), Duration.ofDays(14), List.of())), List.of())); }) .then().github(mocks -> { @@ -381,7 +385,46 @@ void issuesLastUpdatedBefore() throws IOException { .when(() -> { var repo = gitHubService.repository(repoRef); - assertThat(repo.issuesLastUpdatedBefore(cutoff)) + assertThat(repo.issuesLastUpdatedBefore(Set.of(), cutoff)) + .containsExactlyElementsOf(stubIssueList(1, 3, 2, 4)); + }) + .then().github(mocks -> { + verify(searchIssuesBuilderMock).q("repo:" + repoRef.repositoryName()); + verify(searchIssuesBuilderMock).q("is:issue"); + verify(searchIssuesBuilderMock).isOpen(); + verify(searchIssuesBuilderMock).q("updated:<2017-11-05T06:00"); + verify(searchIssuesBuilderMock).sort(GHIssueSearchBuilder.Sort.UPDATED); + verify(searchIssuesBuilderMock).order(GHDirection.DESC); + verifyNoMoreInteractions(searchIssuesBuilderMock); + verifyNoMoreInteractions(mocks.ghObjects()); + }); + } + + @Test + void issuesLastUpdatedBefore_ignoreLabels() throws IOException { + var repoRef = new GitHubRepositoryRef(installationRef, "quarkusio/quarkus"); + + Instant now = LocalDateTime.of(2017, 11, 6, 6, 0).toInstant(ZoneOffset.UTC); + Instant cutoff = now.minus(1, ChronoUnit.DAYS); + + var searchIssuesBuilderMock = Mockito.mock(GHIssueSearchBuilder.class, + withSettings().defaultAnswer(Answers.RETURNS_SELF)); + given() + .github(mocks -> { + var clientMock = mocks.installationClient(installationRef.installationId()); + + when(clientMock.searchIssues()).thenReturn(searchIssuesBuilderMock); + var issue1Mock = mockIssueForLottery(mocks, 1); + var issue2Mock = mockIssueForLottery(mocks, 3); + var issue3Mock = mockIssueForLottery(mocks, 2); + var issue4Mock = mockIssueForLottery(mocks, 4); + var issuesMocks = mockPagedIterable(issue1Mock, issue2Mock, issue3Mock, issue4Mock); + when(searchIssuesBuilderMock.list()).thenReturn(issuesMocks); + }) + .when(() -> { + var repo = gitHubService.repository(repoRef); + + assertThat(repo.issuesLastUpdatedBefore(Set.of("triage/on-ice"), cutoff)) .containsExactlyElementsOf(stubIssueList(1, 3, 2, 4)); }) .then().github(mocks -> { @@ -391,6 +434,7 @@ void issuesLastUpdatedBefore() throws IOException { verify(searchIssuesBuilderMock).q("updated:<2017-11-05T06:00"); verify(searchIssuesBuilderMock).sort(GHIssueSearchBuilder.Sort.UPDATED); verify(searchIssuesBuilderMock).order(GHDirection.DESC); + verify(searchIssuesBuilderMock).q("-label:triage/on-ice"); verifyNoMoreInteractions(searchIssuesBuilderMock); verifyNoMoreInteractions(mocks.ghObjects()); }); @@ -420,7 +464,47 @@ void issuesWithLabelLastUpdatedBefore() throws IOException { .when(() -> { var repo = gitHubService.repository(repoRef); - assertThat(repo.issuesWithLabelLastUpdatedBefore("triage/needs-triage", cutoff)) + assertThat(repo.issuesWithLabelLastUpdatedBefore("triage/needs-triage", Set.of(), cutoff)) + .containsExactlyElementsOf(stubIssueList(1, 3, 2, 4)); + }) + .then().github(mocks -> { + verify(searchIssuesBuilderMock).q("repo:" + repoRef.repositoryName()); + verify(searchIssuesBuilderMock).q("is:issue"); + verify(searchIssuesBuilderMock).isOpen(); + verify(searchIssuesBuilderMock).sort(GHIssueSearchBuilder.Sort.UPDATED); + verify(searchIssuesBuilderMock).order(GHDirection.DESC); + verify(searchIssuesBuilderMock).q("label:triage/needs-triage"); + verify(searchIssuesBuilderMock).q("updated:<2017-11-05T06:00"); + verifyNoMoreInteractions(searchIssuesBuilderMock); + verifyNoMoreInteractions(mocks.ghObjects()); + }); + } + + @Test + void issuesWithLabelLastUpdatedBefore_ignoreLabels() throws IOException { + var repoRef = new GitHubRepositoryRef(installationRef, "quarkusio/quarkus"); + + Instant now = LocalDateTime.of(2017, 11, 6, 6, 0).toInstant(ZoneOffset.UTC); + Instant cutoff = now.minus(1, ChronoUnit.DAYS); + + var searchIssuesBuilderMock = Mockito.mock(GHIssueSearchBuilder.class, + withSettings().defaultAnswer(Answers.RETURNS_SELF)); + given() + .github(mocks -> { + var clientMock = mocks.installationClient(installationRef.installationId()); + + when(clientMock.searchIssues()).thenReturn(searchIssuesBuilderMock); + var issue1Mock = mockIssueForLottery(mocks, 1); + var issue2Mock = mockIssueForLottery(mocks, 3); + var issue3Mock = mockIssueForLottery(mocks, 2); + var issue4Mock = mockIssueForLottery(mocks, 4); + var issuesMocks = mockPagedIterable(issue1Mock, issue2Mock, issue3Mock, issue4Mock); + when(searchIssuesBuilderMock.list()).thenReturn(issuesMocks); + }) + .when(() -> { + var repo = gitHubService.repository(repoRef); + + assertThat(repo.issuesWithLabelLastUpdatedBefore("triage/needs-triage", Set.of("triage/on-ice"), cutoff)) .containsExactlyElementsOf(stubIssueList(1, 3, 2, 4)); }) .then().github(mocks -> { @@ -431,6 +515,7 @@ void issuesWithLabelLastUpdatedBefore() throws IOException { verify(searchIssuesBuilderMock).order(GHDirection.DESC); verify(searchIssuesBuilderMock).q("label:triage/needs-triage"); verify(searchIssuesBuilderMock).q("updated:<2017-11-05T06:00"); + verify(searchIssuesBuilderMock).q("-label:triage/on-ice"); verifyNoMoreInteractions(searchIssuesBuilderMock); verifyNoMoreInteractions(mocks.ghObjects()); }); diff --git a/src/test/java/io/quarkus/github/lottery/HistoryServiceTest.java b/src/test/java/io/quarkus/github/lottery/HistoryServiceTest.java index 1c258ea..657f3c6 100644 --- a/src/test/java/io/quarkus/github/lottery/HistoryServiceTest.java +++ b/src/test/java/io/quarkus/github/lottery/HistoryServiceTest.java @@ -59,9 +59,9 @@ private static LotteryConfig defaultConfig() { new LotteryConfig.Buckets.Maintenance.Feedback.Provided( Duration.ofDays(7), Duration.ofDays(3))), new LotteryConfig.Buckets.Maintenance.Stale( - Duration.ofDays(60), Duration.ofDays(14))), + Duration.ofDays(60), Duration.ofDays(14), List.of("triage/on-ice"))), new LotteryConfig.Buckets.Stewardship( - Duration.ofDays(60), Duration.ofDays(14))), + Duration.ofDays(60), Duration.ofDays(14), List.of("triage/on-ice"))), List.of()); } diff --git a/src/test/java/io/quarkus/github/lottery/LotterySingleRepositoryTest.java b/src/test/java/io/quarkus/github/lottery/LotterySingleRepositoryTest.java index af7f4cd..9afa19c 100644 --- a/src/test/java/io/quarkus/github/lottery/LotterySingleRepositoryTest.java +++ b/src/test/java/io/quarkus/github/lottery/LotterySingleRepositoryTest.java @@ -70,9 +70,9 @@ private static LotteryConfig defaultConfig(List parti new LotteryConfig.Buckets.Maintenance.Feedback.Provided( Duration.ofDays(7), Duration.ofDays(3))), new LotteryConfig.Buckets.Maintenance.Stale( - Duration.ofDays(60), Duration.ofDays(14))), + Duration.ofDays(60), Duration.ofDays(14), List.of("triage/on-ice"))), new LotteryConfig.Buckets.Stewardship( - Duration.ofDays(60), Duration.ofDays(14))), + Duration.ofDays(60), Duration.ofDays(14), List.of("triage/on-ice"))), participants); } @@ -284,7 +284,7 @@ void triage() throws IOException { Optional.empty()))); when(repoMock.fetchLotteryConfig()).thenReturn(Optional.of(config)); - when(repoMock.issuesWithLabelLastUpdatedBefore("needs-triage", now)) + when(repoMock.issuesWithLabelLastUpdatedBefore("needs-triage", Set.of(), now)) .thenAnswer(ignored -> stubIssueList(1, 3, 2, 4).stream()); mockNotifiable("yrodiere", ZoneOffset.UTC); @@ -325,7 +325,7 @@ void triage_issueAlreadyHasNonTimedOutNotification() throws IOException { Optional.empty()))); when(repoMock.fetchLotteryConfig()).thenReturn(Optional.of(config)); - when(repoMock.issuesWithLabelLastUpdatedBefore("needs-triage", now)) + when(repoMock.issuesWithLabelLastUpdatedBefore("needs-triage", Set.of(), now)) .thenAnswer(ignored -> stubIssueList(1, 3, 2, 4).stream()); mockNotifiable("yrodiere", ZoneOffset.UTC); @@ -381,7 +381,7 @@ void maintenance() throws IOException { Set.of("triage/needs-reproducer", "triage/needs-feedback"), "area/hibernate-orm", IssueActionSide.OUTSIDER, feedbackProvidedCutoff)) .thenAnswer(ignored -> stubIssueList(201, 202, 203).stream()); - when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-orm", staleCutoff)) + when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-orm", Set.of("triage/on-ice"), staleCutoff)) .thenAnswer(ignored -> stubIssueList(301, 302, 303, 304, 305, 306).stream()); when(repoMock.issuesLastActedOnByAndLastUpdatedBefore( @@ -392,7 +392,7 @@ void maintenance() throws IOException { Set.of("triage/needs-reproducer", "triage/needs-feedback"), "area/hibernate-search", IssueActionSide.OUTSIDER, feedbackProvidedCutoff)) .thenAnswer(ignored -> stubIssueList(501, 502, 503).stream()); - when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-search", staleCutoff)) + when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-search", Set.of("triage/on-ice"), staleCutoff)) .thenAnswer(ignored -> stubIssueList(601, 602, 603, 604, 605, 606).stream()); mockNotifiable("yrodiere", ZoneOffset.UTC); @@ -455,7 +455,7 @@ void maintenance_issueAlreadyHasTimedOutNotification() throws IOException { Set.of("triage/needs-reproducer", "triage/needs-feedback"), "area/hibernate-orm", IssueActionSide.OUTSIDER, feedbackProvidedCutoff)) .thenAnswer(ignored -> stubIssueList(201, 202, 203).stream()); - when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-orm", staleCutoff)) + when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-orm", Set.of("triage/on-ice"), staleCutoff)) .thenAnswer(ignored -> stubIssueList(301, 302, 303, 304, 305, 306).stream()); when(repoMock.issuesLastActedOnByAndLastUpdatedBefore( @@ -466,7 +466,7 @@ void maintenance_issueAlreadyHasTimedOutNotification() throws IOException { Set.of("triage/needs-reproducer", "triage/needs-feedback"), "area/hibernate-search", IssueActionSide.OUTSIDER, feedbackProvidedCutoff)) .thenAnswer(ignored -> stubIssueList(501, 502, 503).stream()); - when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-search", staleCutoff)) + when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-search", Set.of("triage/on-ice"), staleCutoff)) .thenAnswer(ignored -> stubIssueList(601, 602, 603, 604, 605, 606).stream()); mockNotifiable("yrodiere", ZoneOffset.UTC); @@ -522,7 +522,7 @@ void stewardship() throws IOException { new LotteryConfig.Participant.Participation(3)))))); when(repoMock.fetchLotteryConfig()).thenReturn(Optional.of(config)); - when(repoMock.issuesLastUpdatedBefore(stewardshipCutoff)) + when(repoMock.issuesLastUpdatedBefore(Set.of("triage/on-ice"), stewardshipCutoff)) .thenAnswer(ignored -> stubIssueList(1, 3, 2, 4).stream()); mockNotifiable("geoand", ZoneOffset.UTC); @@ -563,7 +563,7 @@ void stewardship_issueAlreadyHasNonTimedOutNotification() throws IOException { new LotteryConfig.Participant.Participation(3)))))); when(repoMock.fetchLotteryConfig()).thenReturn(Optional.of(config)); - when(repoMock.issuesLastUpdatedBefore(stewardshipCutoff)) + when(repoMock.issuesLastUpdatedBefore(Set.of("triage/on-ice"), stewardshipCutoff)) .thenAnswer(ignored -> stubIssueList(1, 3, 2, 4).stream()); mockNotifiable("geoand", ZoneOffset.UTC); @@ -626,10 +626,10 @@ void stewardship_doesNotAffectMaintenance() throws IOException { Set.of("triage/needs-reproducer", "triage/needs-feedback"), "area/hibernate-search", IssueActionSide.OUTSIDER, feedbackProvidedCutoff)) .thenAnswer(ignored -> stubIssueList(501, 502, 503).stream()); - when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-search", staleCutoff)) + when(repoMock.issuesWithLabelLastUpdatedBefore("area/hibernate-search", Set.of("triage/on-ice"), staleCutoff)) .thenAnswer(ignored -> stubIssueList(601, 602, 603, 604, 605, 606).stream()); - when(repoMock.issuesLastUpdatedBefore(stewardshipCutoff)) + when(repoMock.issuesLastUpdatedBefore(Set.of("triage/on-ice"), stewardshipCutoff)) .thenAnswer(ignored -> stubIssueList(401, 501, 601, 701).stream()); mockNotifiable("yrodiere", ZoneOffset.UTC); @@ -706,7 +706,7 @@ void multiParticipants_evenSpread() throws IOException { Optional.empty()))); when(repoMock.fetchLotteryConfig()).thenReturn(Optional.of(config)); - when(repoMock.issuesWithLabelLastUpdatedBefore("needs-triage", now)) + when(repoMock.issuesWithLabelLastUpdatedBefore("needs-triage", Set.of(), now)) .thenAnswer(ignored -> stubIssueList(1, 3, 2, 4).stream()); mockNotifiable("yrodiere", ZoneOffset.UTC);