12 changed files with 883 additions and 415 deletions
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
package org.springframework.gradle.github.milestones; |
||||
|
||||
import java.io.IOException; |
||||
import java.time.LocalDate; |
||||
|
||||
import com.google.gson.TypeAdapter; |
||||
import com.google.gson.stream.JsonReader; |
||||
import com.google.gson.stream.JsonWriter; |
||||
|
||||
/** |
||||
* @author Steve Riesenberg |
||||
*/ |
||||
class LocalDateAdapter extends TypeAdapter<LocalDate> { |
||||
@Override |
||||
public void write(JsonWriter jsonWriter, LocalDate localDate) throws IOException { |
||||
jsonWriter.value(localDate.toString()); |
||||
} |
||||
|
||||
@Override |
||||
public LocalDate read(JsonReader jsonReader) throws IOException { |
||||
return LocalDate.parse(jsonReader.nextString()); |
||||
} |
||||
} |
||||
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
package org.springframework.gradle.github.milestones; |
||||
|
||||
import java.io.IOException; |
||||
import java.time.LocalDateTime; |
||||
import java.time.ZoneOffset; |
||||
import java.time.format.DateTimeFormatter; |
||||
|
||||
import com.google.gson.TypeAdapter; |
||||
import com.google.gson.stream.JsonReader; |
||||
import com.google.gson.stream.JsonWriter; |
||||
|
||||
/** |
||||
* @author Steve Riesenberg |
||||
*/ |
||||
class LocalDateTimeAdapter extends TypeAdapter<LocalDateTime> { |
||||
@Override |
||||
public void write(JsonWriter jsonWriter, LocalDateTime localDateTime) throws IOException { |
||||
jsonWriter.value(localDateTime.atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_ZONED_DATE_TIME)); |
||||
} |
||||
|
||||
@Override |
||||
public LocalDateTime read(JsonReader jsonReader) throws IOException { |
||||
return LocalDateTime.parse(jsonReader.nextString(), DateTimeFormatter.ISO_ZONED_DATE_TIME); |
||||
} |
||||
} |
||||
@ -0,0 +1,142 @@
@@ -0,0 +1,142 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* Licensed 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 |
||||
* |
||||
* https://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.springframework.gradle.github.milestones; |
||||
|
||||
import java.time.LocalDate; |
||||
import java.time.LocalTime; |
||||
|
||||
import org.gradle.api.DefaultTask; |
||||
import org.gradle.api.tasks.Input; |
||||
import org.gradle.api.tasks.TaskAction; |
||||
|
||||
import org.springframework.gradle.github.RepositoryRef; |
||||
|
||||
/** |
||||
* @author Steve Riesenberg |
||||
*/ |
||||
public class ScheduleNextReleaseTask extends DefaultTask { |
||||
@Input |
||||
private RepositoryRef repository = new RepositoryRef(); |
||||
|
||||
@Input |
||||
private String gitHubAccessToken; |
||||
|
||||
@Input |
||||
private String version; |
||||
|
||||
@Input |
||||
private Integer weekOfMonth; |
||||
|
||||
@Input |
||||
private Integer dayOfWeek; |
||||
|
||||
@TaskAction |
||||
public void scheduleNextRelease() { |
||||
GitHubMilestoneApi gitHubMilestoneApi = new GitHubMilestoneApi(this.gitHubAccessToken); |
||||
String nextReleaseMilestone = gitHubMilestoneApi.getNextReleaseMilestone(this.repository, this.version); |
||||
|
||||
// If the next release contains a dash (e.g. 5.6.0-RC1), it is already scheduled
|
||||
if (nextReleaseMilestone.contains("-")) { |
||||
return; |
||||
} |
||||
|
||||
// Check to see if a scheduled GA version already exists
|
||||
boolean hasExistingMilestone = gitHubMilestoneApi.getMilestones(this.repository).stream() |
||||
.anyMatch(milestone -> nextReleaseMilestone.equals(milestone.getTitle())); |
||||
if (hasExistingMilestone) { |
||||
return; |
||||
} |
||||
|
||||
// Next milestone is either a patch version or minor version
|
||||
// Note: Major versions will be handled like minor and get a release
|
||||
// train which can be manually updated to match the desired schedule.
|
||||
if (nextReleaseMilestone.endsWith(".0")) { |
||||
// Create M1, M2, M3, RC1 and GA milestones for release train
|
||||
getReleaseTrain(nextReleaseMilestone).getTrainDates().forEach((milestoneTitle, dueOn) -> { |
||||
Milestone milestone = new Milestone(); |
||||
milestone.setTitle(milestoneTitle); |
||||
// Note: GitHub seems to store full date/time as UTC then displays
|
||||
// as a date (no time) in your timezone, which means the date will
|
||||
// not always be the same date as we intend.
|
||||
// Using 12pm/noon UTC allows GitHub to schedule and display the
|
||||
// correct date.
|
||||
milestone.setDueOn(dueOn.atTime(LocalTime.NOON)); |
||||
gitHubMilestoneApi.createMilestone(this.repository, milestone); |
||||
}); |
||||
} else { |
||||
// Create GA milestone for patch release on the next even month
|
||||
LocalDate startDate = LocalDate.now(); |
||||
LocalDate dueOn = getReleaseTrain(nextReleaseMilestone).getNextReleaseDate(startDate); |
||||
Milestone milestone = new Milestone(); |
||||
milestone.setTitle(nextReleaseMilestone); |
||||
milestone.setDueOn(dueOn.atTime(LocalTime.NOON)); |
||||
gitHubMilestoneApi.createMilestone(this.repository, milestone); |
||||
} |
||||
} |
||||
|
||||
private SpringReleaseTrain getReleaseTrain(String nextReleaseMilestone) { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.nextTrain() |
||||
.version(nextReleaseMilestone) |
||||
.weekOfMonth(this.weekOfMonth) |
||||
.dayOfWeek(this.dayOfWeek) |
||||
.build(); |
||||
|
||||
return new SpringReleaseTrain(releaseTrainSpec); |
||||
} |
||||
|
||||
public RepositoryRef getRepository() { |
||||
return this.repository; |
||||
} |
||||
|
||||
public void setRepository(RepositoryRef repository) { |
||||
this.repository = repository; |
||||
} |
||||
|
||||
public String getGitHubAccessToken() { |
||||
return this.gitHubAccessToken; |
||||
} |
||||
|
||||
public void setGitHubAccessToken(String gitHubAccessToken) { |
||||
this.gitHubAccessToken = gitHubAccessToken; |
||||
} |
||||
|
||||
public String getVersion() { |
||||
return this.version; |
||||
} |
||||
|
||||
public void setVersion(String version) { |
||||
this.version = version; |
||||
} |
||||
|
||||
public Integer getWeekOfMonth() { |
||||
return weekOfMonth; |
||||
} |
||||
|
||||
public void setWeekOfMonth(Integer weekOfMonth) { |
||||
this.weekOfMonth = weekOfMonth; |
||||
} |
||||
|
||||
public Integer getDayOfWeek() { |
||||
return dayOfWeek; |
||||
} |
||||
|
||||
public void setDayOfWeek(Integer dayOfWeek) { |
||||
this.dayOfWeek = dayOfWeek; |
||||
} |
||||
} |
||||
@ -0,0 +1,134 @@
@@ -0,0 +1,134 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* Licensed 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 |
||||
* |
||||
* https://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.springframework.gradle.github.milestones; |
||||
|
||||
import java.time.DayOfWeek; |
||||
import java.time.LocalDate; |
||||
import java.time.Month; |
||||
import java.time.Year; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Spring release train generator based on rules contained in a specification. |
||||
* <p> |
||||
* The rules are: |
||||
* <ol> |
||||
* <li>Train 1 (January-May) or 2 (July-November)</li> |
||||
* <li>Version number (e.g. 0.1.2, 1.0.0, etc.)</li> |
||||
* <li>Week of month (1st, 2nd, 3rd, 4th)</li> |
||||
* <li>Day of week (Monday-Friday)</li> |
||||
* <li>Year (e.g. 2020, 2021, etc.)</li> |
||||
* </ol> |
||||
* |
||||
* The release train generated will contain M1, M2, M3, RC1 and GA versions |
||||
* mapped to their respective dates in the train. |
||||
* |
||||
* @author Steve Riesenberg |
||||
*/ |
||||
public final class SpringReleaseTrain { |
||||
private final SpringReleaseTrainSpec releaseTrainSpec; |
||||
|
||||
public SpringReleaseTrain(SpringReleaseTrainSpec releaseTrainSpec) { |
||||
this.releaseTrainSpec = releaseTrainSpec; |
||||
} |
||||
|
||||
/** |
||||
* Calculate release train dates based on the release train specification. |
||||
* |
||||
* @return A mapping of release milestones to scheduled release dates |
||||
*/ |
||||
public Map<String, LocalDate> getTrainDates() { |
||||
Map<String, LocalDate> releaseDates = new LinkedHashMap<>(); |
||||
switch (this.releaseTrainSpec.getTrain()) { |
||||
case ONE: |
||||
addTrainDate(releaseDates, "M1", Month.JANUARY); |
||||
addTrainDate(releaseDates, "M2", Month.FEBRUARY); |
||||
addTrainDate(releaseDates, "M3", Month.MARCH); |
||||
addTrainDate(releaseDates, "RC1", Month.APRIL); |
||||
addTrainDate(releaseDates, null, Month.MAY); |
||||
break; |
||||
case TWO: |
||||
addTrainDate(releaseDates, "M1", Month.JULY); |
||||
addTrainDate(releaseDates, "M2", Month.AUGUST); |
||||
addTrainDate(releaseDates, "M3", Month.SEPTEMBER); |
||||
addTrainDate(releaseDates, "RC1", Month.OCTOBER); |
||||
addTrainDate(releaseDates, null, Month.NOVEMBER); |
||||
break; |
||||
} |
||||
|
||||
return releaseDates; |
||||
} |
||||
|
||||
/** |
||||
* Determine if a given date matches the due date of given version. |
||||
* |
||||
* @param version The version number (e.g. 5.6.0-M1, 5.6.0, etc.) |
||||
* @param expectedDate The expected date |
||||
* @return true if the given date matches the due date of the given version, false otherwise |
||||
*/ |
||||
public boolean isTrainDate(String version, LocalDate expectedDate) { |
||||
return expectedDate.isEqual(getTrainDates().get(version)); |
||||
} |
||||
|
||||
/** |
||||
* Calculate the next release date following the given date. |
||||
* <p> |
||||
* The next release date is always on an even month so that a patch release |
||||
* is the month after the GA version of a release train. This method does |
||||
* not consider the year of the release train, only the given start date. |
||||
* |
||||
* @param startDate The start date |
||||
* @return The next release date following the given date |
||||
*/ |
||||
public LocalDate getNextReleaseDate(LocalDate startDate) { |
||||
LocalDate trainDate; |
||||
LocalDate currentDate = startDate; |
||||
do { |
||||
trainDate = calculateReleaseDate( |
||||
Year.of(currentDate.getYear()), |
||||
currentDate.getMonth(), |
||||
this.releaseTrainSpec.getDayOfWeek().getDayOfWeek(), |
||||
this.releaseTrainSpec.getWeekOfMonth().getDayOffset() |
||||
); |
||||
currentDate = currentDate.plusMonths(1); |
||||
} while (!trainDate.isAfter(startDate) || trainDate.getMonthValue() % 2 != 0); |
||||
|
||||
return trainDate; |
||||
} |
||||
|
||||
private void addTrainDate(Map<String, LocalDate> releaseDates, String milestone, Month month) { |
||||
LocalDate releaseDate = calculateReleaseDate( |
||||
this.releaseTrainSpec.getYear(), |
||||
month, |
||||
this.releaseTrainSpec.getDayOfWeek().getDayOfWeek(), |
||||
this.releaseTrainSpec.getWeekOfMonth().getDayOffset() |
||||
); |
||||
String suffix = (milestone == null) ? "" : "-" + milestone; |
||||
releaseDates.put(this.releaseTrainSpec.getVersion() + suffix, releaseDate); |
||||
} |
||||
|
||||
private static LocalDate calculateReleaseDate(Year year, Month month, DayOfWeek dayOfWeek, int dayOffset) { |
||||
LocalDate firstDayOfMonth = year.atMonth(month).atDay(1); |
||||
int dayOfWeekOffset = dayOfWeek.getValue() - firstDayOfMonth.getDayOfWeek().getValue(); |
||||
if (dayOfWeekOffset < 0) { |
||||
dayOfWeekOffset += 7; |
||||
} |
||||
|
||||
return firstDayOfMonth.plusDays(dayOfWeekOffset).plusDays(dayOffset); |
||||
} |
||||
} |
||||
@ -0,0 +1,205 @@
@@ -0,0 +1,205 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* Licensed 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 |
||||
* |
||||
* https://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.springframework.gradle.github.milestones; |
||||
|
||||
import java.time.LocalDate; |
||||
import java.time.Month; |
||||
import java.time.Year; |
||||
|
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* A specification for a release train. |
||||
* |
||||
* @author Steve Riesenberg |
||||
* @see SpringReleaseTrain |
||||
*/ |
||||
public final class SpringReleaseTrainSpec { |
||||
private final Train train; |
||||
private final String version; |
||||
private final WeekOfMonth weekOfMonth; |
||||
private final DayOfWeek dayOfWeek; |
||||
private final Year year; |
||||
|
||||
public SpringReleaseTrainSpec(Train train, String version, WeekOfMonth weekOfMonth, DayOfWeek dayOfWeek, Year year) { |
||||
this.train = train; |
||||
this.version = version; |
||||
this.weekOfMonth = weekOfMonth; |
||||
this.dayOfWeek = dayOfWeek; |
||||
this.year = year; |
||||
} |
||||
|
||||
public Train getTrain() { |
||||
return train; |
||||
} |
||||
|
||||
public String getVersion() { |
||||
return version; |
||||
} |
||||
|
||||
public WeekOfMonth getWeekOfMonth() { |
||||
return weekOfMonth; |
||||
} |
||||
|
||||
public DayOfWeek getDayOfWeek() { |
||||
return dayOfWeek; |
||||
} |
||||
|
||||
public Year getYear() { |
||||
return year; |
||||
} |
||||
|
||||
public static Builder builder() { |
||||
return new Builder(); |
||||
} |
||||
|
||||
public enum WeekOfMonth { |
||||
FIRST(0), SECOND(7), THIRD(14), FOURTH(21); |
||||
|
||||
private final int dayOffset; |
||||
|
||||
WeekOfMonth(int dayOffset) { |
||||
this.dayOffset = dayOffset; |
||||
} |
||||
|
||||
public int getDayOffset() { |
||||
return dayOffset; |
||||
} |
||||
} |
||||
|
||||
public enum DayOfWeek { |
||||
MONDAY(java.time.DayOfWeek.MONDAY), |
||||
TUESDAY(java.time.DayOfWeek.TUESDAY), |
||||
WEDNESDAY(java.time.DayOfWeek.WEDNESDAY), |
||||
THURSDAY(java.time.DayOfWeek.THURSDAY), |
||||
FRIDAY(java.time.DayOfWeek.FRIDAY); |
||||
|
||||
private final java.time.DayOfWeek dayOfWeek; |
||||
|
||||
DayOfWeek(java.time.DayOfWeek dayOfWeek) { |
||||
this.dayOfWeek = dayOfWeek; |
||||
} |
||||
|
||||
public java.time.DayOfWeek getDayOfWeek() { |
||||
return dayOfWeek; |
||||
} |
||||
} |
||||
|
||||
public enum Train { |
||||
ONE, TWO |
||||
} |
||||
|
||||
public static class Builder { |
||||
private Train train; |
||||
private String version; |
||||
private WeekOfMonth weekOfMonth; |
||||
private DayOfWeek dayOfWeek; |
||||
private Year year; |
||||
|
||||
private Builder() { |
||||
} |
||||
|
||||
public Builder train(int train) { |
||||
switch (train) { |
||||
case 1: this.train = Train.ONE; break; |
||||
case 2: this.train = Train.TWO; break; |
||||
default: throw new IllegalArgumentException("Invalid train: " + train); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public Builder train(Train train) { |
||||
this.train = train; |
||||
return this; |
||||
} |
||||
|
||||
public Builder nextTrain() { |
||||
// Search for next train starting with this month
|
||||
return nextTrain(LocalDate.now().withDayOfMonth(1)); |
||||
} |
||||
|
||||
public Builder nextTrain(LocalDate startDate) { |
||||
Train nextTrain = null; |
||||
|
||||
// Search for next train from a given start date
|
||||
LocalDate currentDate = startDate; |
||||
while (nextTrain == null) { |
||||
if (currentDate.getMonth() == Month.JANUARY) { |
||||
nextTrain = Train.ONE; |
||||
} else if (currentDate.getMonth() == Month.JULY) { |
||||
nextTrain = Train.TWO; |
||||
} |
||||
|
||||
currentDate = currentDate.plusMonths(1); |
||||
} |
||||
|
||||
return train(nextTrain).year(currentDate.getYear()); |
||||
} |
||||
|
||||
public Builder version(String version) { |
||||
this.version = version; |
||||
return this; |
||||
} |
||||
|
||||
public Builder weekOfMonth(int weekOfMonth) { |
||||
switch (weekOfMonth) { |
||||
case 1: this.weekOfMonth = WeekOfMonth.FIRST; break; |
||||
case 2: this.weekOfMonth = WeekOfMonth.SECOND; break; |
||||
case 3: this.weekOfMonth = WeekOfMonth.THIRD; break; |
||||
case 4: this.weekOfMonth = WeekOfMonth.FOURTH; break; |
||||
default: throw new IllegalArgumentException("Invalid weekOfMonth: " + weekOfMonth); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public Builder weekOfMonth(WeekOfMonth weekOfMonth) { |
||||
this.weekOfMonth = weekOfMonth; |
||||
return this; |
||||
} |
||||
|
||||
public Builder dayOfWeek(int dayOfWeek) { |
||||
switch (dayOfWeek) { |
||||
case 1: this.dayOfWeek = DayOfWeek.MONDAY; break; |
||||
case 2: this.dayOfWeek = DayOfWeek.TUESDAY; break; |
||||
case 3: this.dayOfWeek = DayOfWeek.WEDNESDAY; break; |
||||
case 4: this.dayOfWeek = DayOfWeek.THURSDAY; break; |
||||
case 5: this.dayOfWeek = DayOfWeek.FRIDAY; break; |
||||
default: throw new IllegalArgumentException("Invalid dayOfWeek: " + dayOfWeek); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
public Builder dayOfWeek(DayOfWeek dayOfWeek) { |
||||
this.dayOfWeek = dayOfWeek; |
||||
return this; |
||||
} |
||||
|
||||
public Builder year(int year) { |
||||
this.year = Year.of(year); |
||||
return this; |
||||
} |
||||
|
||||
public SpringReleaseTrainSpec build() { |
||||
Assert.notNull(train, "train cannot be null"); |
||||
Assert.notNull(version, "version cannot be null"); |
||||
Assert.notNull(weekOfMonth, "weekOfMonth cannot be null"); |
||||
Assert.notNull(dayOfWeek, "dayOfWeek cannot be null"); |
||||
Assert.notNull(year, "year cannot be null"); |
||||
return new SpringReleaseTrainSpec(train, version, weekOfMonth, dayOfWeek, year); |
||||
} |
||||
} |
||||
} |
||||
@ -1,389 +0,0 @@
@@ -1,389 +0,0 @@
|
||||
package io.spring.gradle.github.milestones; |
||||
|
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import okhttp3.mockwebserver.MockResponse; |
||||
import okhttp3.mockwebserver.MockWebServer; |
||||
import okhttp3.mockwebserver.RecordedRequest; |
||||
import org.junit.jupiter.api.AfterEach; |
||||
import org.junit.jupiter.api.BeforeEach; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.gradle.github.RepositoryRef; |
||||
import org.springframework.gradle.github.milestones.GitHubMilestoneApi; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
||||
|
||||
|
||||
public class GitHubMilestoneApiTests { |
||||
private GitHubMilestoneApi github; |
||||
|
||||
private RepositoryRef repositoryRef = RepositoryRef.owner("spring-projects").repository("spring-security").build(); |
||||
|
||||
private MockWebServer server; |
||||
|
||||
private String baseUrl; |
||||
|
||||
@BeforeEach |
||||
public void setup() throws Exception { |
||||
this.server = new MockWebServer(); |
||||
this.server.start(); |
||||
this.github = new GitHubMilestoneApi("mock-oauth-token"); |
||||
this.baseUrl = this.server.url("/api").toString(); |
||||
this.github.setBaseUrl(this.baseUrl); |
||||
} |
||||
|
||||
@AfterEach |
||||
public void cleanup() throws Exception { |
||||
this.server.shutdown(); |
||||
} |
||||
|
||||
@Test |
||||
public void findMilestoneNumberByTitleWhenFoundThenSuccess() throws Exception { |
||||
String responseJson = "[\n" + |
||||
" {\n" + |
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + |
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + |
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + |
||||
" \"id\":6611880,\n" + |
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + |
||||
" \"number\":207,\n" + |
||||
" \"title\":\"5.6.x\",\n" + |
||||
" \"description\":\"\",\n" + |
||||
" \"creator\":{\n" + |
||||
" \"login\":\"jgrandja\",\n" + |
||||
" \"id\":10884212,\n" + |
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + |
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + |
||||
" \"gravatar_id\":\"\",\n" + |
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" + |
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" + |
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + |
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + |
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + |
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + |
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + |
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + |
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + |
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + |
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + |
||||
" \"type\":\"User\",\n" + |
||||
" \"site_admin\":false\n" + |
||||
" },\n" + |
||||
" \"open_issues\":1,\n" + |
||||
" \"closed_issues\":0,\n" + |
||||
" \"state\":\"open\",\n" + |
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" + |
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + |
||||
" \"due_on\":null,\n" + |
||||
" \"closed_at\":null\n" + |
||||
" },\n" + |
||||
" {\n" + |
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + |
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + |
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + |
||||
" \"id\":5884208,\n" + |
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + |
||||
" \"number\":191,\n" + |
||||
" \"title\":\"5.5.0-RC1\",\n" + |
||||
" \"description\":\"\",\n" + |
||||
" \"creator\":{\n" + |
||||
" \"login\":\"jzheaux\",\n" + |
||||
" \"id\":3627351,\n" + |
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + |
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + |
||||
" \"gravatar_id\":\"\",\n" + |
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" + |
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" + |
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + |
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + |
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + |
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + |
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + |
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + |
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + |
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + |
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + |
||||
" \"type\":\"User\",\n" + |
||||
" \"site_admin\":false\n" + |
||||
" },\n" + |
||||
" \"open_issues\":21,\n" + |
||||
" \"closed_issues\":23,\n" + |
||||
" \"state\":\"open\",\n" + |
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" + |
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + |
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" + |
||||
" \"closed_at\":null\n" + |
||||
" }\n" + |
||||
"]"; |
||||
this.server.enqueue(new MockResponse().setBody(responseJson)); |
||||
|
||||
long milestoneNumberByTitle = this.github.findMilestoneNumberByTitle(this.repositoryRef, "5.5.0-RC1"); |
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); |
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); |
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/milestones?per_page=100"); |
||||
|
||||
assertThat(milestoneNumberByTitle).isEqualTo(191); |
||||
} |
||||
|
||||
@Test |
||||
public void findMilestoneNumberByTitleWhenNotFoundThenException() throws Exception { |
||||
String responseJson = "[\n" + |
||||
" {\n" + |
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207\",\n" + |
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/207\",\n" + |
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/207/labels\",\n" + |
||||
" \"id\":6611880,\n" + |
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNjYxMTg4MA==\",\n" + |
||||
" \"number\":207,\n" + |
||||
" \"title\":\"5.6.x\",\n" + |
||||
" \"description\":\"\",\n" + |
||||
" \"creator\":{\n" + |
||||
" \"login\":\"jgrandja\",\n" + |
||||
" \"id\":10884212,\n" + |
||||
" \"node_id\":\"MDQ6VXNlcjEwODg0MjEy\",\n" + |
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/10884212?v=4\",\n" + |
||||
" \"gravatar_id\":\"\",\n" + |
||||
" \"url\":\"https://api.github.com/users/jgrandja\",\n" + |
||||
" \"html_url\":\"https://github.com/jgrandja\",\n" + |
||||
" \"followers_url\":\"https://api.github.com/users/jgrandja/followers\",\n" + |
||||
" \"following_url\":\"https://api.github.com/users/jgrandja/following{/other_user}\",\n" + |
||||
" \"gists_url\":\"https://api.github.com/users/jgrandja/gists{/gist_id}\",\n" + |
||||
" \"starred_url\":\"https://api.github.com/users/jgrandja/starred{/owner}{/repo}\",\n" + |
||||
" \"subscriptions_url\":\"https://api.github.com/users/jgrandja/subscriptions\",\n" + |
||||
" \"organizations_url\":\"https://api.github.com/users/jgrandja/orgs\",\n" + |
||||
" \"repos_url\":\"https://api.github.com/users/jgrandja/repos\",\n" + |
||||
" \"events_url\":\"https://api.github.com/users/jgrandja/events{/privacy}\",\n" + |
||||
" \"received_events_url\":\"https://api.github.com/users/jgrandja/received_events\",\n" + |
||||
" \"type\":\"User\",\n" + |
||||
" \"site_admin\":false\n" + |
||||
" },\n" + |
||||
" \"open_issues\":1,\n" + |
||||
" \"closed_issues\":0,\n" + |
||||
" \"state\":\"open\",\n" + |
||||
" \"created_at\":\"2021-03-31T11:29:17Z\",\n" + |
||||
" \"updated_at\":\"2021-03-31T11:30:47Z\",\n" + |
||||
" \"due_on\":null,\n" + |
||||
" \"closed_at\":null\n" + |
||||
" },\n" + |
||||
" {\n" + |
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + |
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + |
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + |
||||
" \"id\":5884208,\n" + |
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + |
||||
" \"number\":191,\n" + |
||||
" \"title\":\"5.5.0-RC1\",\n" + |
||||
" \"description\":\"\",\n" + |
||||
" \"creator\":{\n" + |
||||
" \"login\":\"jzheaux\",\n" + |
||||
" \"id\":3627351,\n" + |
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + |
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + |
||||
" \"gravatar_id\":\"\",\n" + |
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" + |
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" + |
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + |
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + |
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + |
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + |
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + |
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + |
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + |
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + |
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + |
||||
" \"type\":\"User\",\n" + |
||||
" \"site_admin\":false\n" + |
||||
" },\n" + |
||||
" \"open_issues\":21,\n" + |
||||
" \"closed_issues\":23,\n" + |
||||
" \"state\":\"open\",\n" + |
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" + |
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + |
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" + |
||||
" \"closed_at\":null\n" + |
||||
" }\n" + |
||||
"]"; |
||||
this.server.enqueue(new MockResponse().setBody(responseJson)); |
||||
|
||||
assertThatExceptionOfType(RuntimeException.class) |
||||
.isThrownBy(() -> this.github.findMilestoneNumberByTitle(this.repositoryRef, "missing")); |
||||
} |
||||
|
||||
@Test |
||||
public void isOpenIssuesForMilestoneNumberWhenAllClosedThenFalse() throws Exception { |
||||
String responseJson = "[]"; |
||||
long milestoneNumber = 202; |
||||
this.server.enqueue(new MockResponse().setBody(responseJson)); |
||||
|
||||
assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isFalse(); |
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); |
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); |
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber); |
||||
} |
||||
|
||||
@Test |
||||
public void isOpenIssuesForMilestoneNumberWhenOpenIssuesThenTrue() throws Exception { |
||||
String responseJson = "[\n" + |
||||
" {\n" + |
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562\",\n" + |
||||
" \"repository_url\":\"https://api.github.com/repos/spring-projects/spring-security\",\n" + |
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/labels{/name}\",\n" + |
||||
" \"comments_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/comments\",\n" + |
||||
" \"events_url\":\"https://api.github.com/repos/spring-projects/spring-security/issues/9562/events\",\n" + |
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" + |
||||
" \"id\":851886504,\n" + |
||||
" \"node_id\":\"MDExOlB1bGxSZXF1ZXN0NjEwMjMzMDcw\",\n" + |
||||
" \"number\":9562,\n" + |
||||
" \"title\":\"Add package-list\",\n" + |
||||
" \"user\":{\n" + |
||||
" \"login\":\"jzheaux\",\n" + |
||||
" \"id\":3627351,\n" + |
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + |
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + |
||||
" \"gravatar_id\":\"\",\n" + |
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" + |
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" + |
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + |
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + |
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + |
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + |
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + |
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + |
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + |
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + |
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + |
||||
" \"type\":\"User\",\n" + |
||||
" \"site_admin\":false\n" + |
||||
" },\n" + |
||||
" \"labels\":[\n" + |
||||
" {\n" + |
||||
" \"id\":322225043,\n" + |
||||
" \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNDM=\",\n" + |
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/in:%20build\",\n" + |
||||
" \"name\":\"in: build\",\n" + |
||||
" \"color\":\"e8f9de\",\n" + |
||||
" \"default\":false,\n" + |
||||
" \"description\":\"An issue in the build\"\n" + |
||||
" },\n" + |
||||
" {\n" + |
||||
" \"id\":322225079,\n" + |
||||
" \"node_id\":\"MDU6TGFiZWwzMjIyMjUwNzk=\",\n" + |
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/labels/type:%20bug\",\n" + |
||||
" \"name\":\"type: bug\",\n" + |
||||
" \"color\":\"e3d9fc\",\n" + |
||||
" \"default\":false,\n" + |
||||
" \"description\":\"A general bug\"\n" + |
||||
" }\n" + |
||||
" ],\n" + |
||||
" \"state\":\"open\",\n" + |
||||
" \"locked\":false,\n" + |
||||
" \"assignee\":{\n" + |
||||
" \"login\":\"rwinch\",\n" + |
||||
" \"id\":362503,\n" + |
||||
" \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" + |
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" + |
||||
" \"gravatar_id\":\"\",\n" + |
||||
" \"url\":\"https://api.github.com/users/rwinch\",\n" + |
||||
" \"html_url\":\"https://github.com/rwinch\",\n" + |
||||
" \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" + |
||||
" \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" + |
||||
" \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" + |
||||
" \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" + |
||||
" \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" + |
||||
" \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" + |
||||
" \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" + |
||||
" \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" + |
||||
" \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" + |
||||
" \"type\":\"User\",\n" + |
||||
" \"site_admin\":false\n" + |
||||
" },\n" + |
||||
" \"assignees\":[\n" + |
||||
" {\n" + |
||||
" \"login\":\"rwinch\",\n" + |
||||
" \"id\":362503,\n" + |
||||
" \"node_id\":\"MDQ6VXNlcjM2MjUwMw==\",\n" + |
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/362503?v=4\",\n" + |
||||
" \"gravatar_id\":\"\",\n" + |
||||
" \"url\":\"https://api.github.com/users/rwinch\",\n" + |
||||
" \"html_url\":\"https://github.com/rwinch\",\n" + |
||||
" \"followers_url\":\"https://api.github.com/users/rwinch/followers\",\n" + |
||||
" \"following_url\":\"https://api.github.com/users/rwinch/following{/other_user}\",\n" + |
||||
" \"gists_url\":\"https://api.github.com/users/rwinch/gists{/gist_id}\",\n" + |
||||
" \"starred_url\":\"https://api.github.com/users/rwinch/starred{/owner}{/repo}\",\n" + |
||||
" \"subscriptions_url\":\"https://api.github.com/users/rwinch/subscriptions\",\n" + |
||||
" \"organizations_url\":\"https://api.github.com/users/rwinch/orgs\",\n" + |
||||
" \"repos_url\":\"https://api.github.com/users/rwinch/repos\",\n" + |
||||
" \"events_url\":\"https://api.github.com/users/rwinch/events{/privacy}\",\n" + |
||||
" \"received_events_url\":\"https://api.github.com/users/rwinch/received_events\",\n" + |
||||
" \"type\":\"User\",\n" + |
||||
" \"site_admin\":false\n" + |
||||
" }\n" + |
||||
" ],\n" + |
||||
" \"milestone\":{\n" + |
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191\",\n" + |
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/milestone/191\",\n" + |
||||
" \"labels_url\":\"https://api.github.com/repos/spring-projects/spring-security/milestones/191/labels\",\n" + |
||||
" \"id\":5884208,\n" + |
||||
" \"node_id\":\"MDk6TWlsZXN0b25lNTg4NDIwOA==\",\n" + |
||||
" \"number\":191,\n" + |
||||
" \"title\":\"5.5.0-RC1\",\n" + |
||||
" \"description\":\"\",\n" + |
||||
" \"creator\":{\n" + |
||||
" \"login\":\"jzheaux\",\n" + |
||||
" \"id\":3627351,\n" + |
||||
" \"node_id\":\"MDQ6VXNlcjM2MjczNTE=\",\n" + |
||||
" \"avatar_url\":\"https://avatars.githubusercontent.com/u/3627351?v=4\",\n" + |
||||
" \"gravatar_id\":\"\",\n" + |
||||
" \"url\":\"https://api.github.com/users/jzheaux\",\n" + |
||||
" \"html_url\":\"https://github.com/jzheaux\",\n" + |
||||
" \"followers_url\":\"https://api.github.com/users/jzheaux/followers\",\n" + |
||||
" \"following_url\":\"https://api.github.com/users/jzheaux/following{/other_user}\",\n" + |
||||
" \"gists_url\":\"https://api.github.com/users/jzheaux/gists{/gist_id}\",\n" + |
||||
" \"starred_url\":\"https://api.github.com/users/jzheaux/starred{/owner}{/repo}\",\n" + |
||||
" \"subscriptions_url\":\"https://api.github.com/users/jzheaux/subscriptions\",\n" + |
||||
" \"organizations_url\":\"https://api.github.com/users/jzheaux/orgs\",\n" + |
||||
" \"repos_url\":\"https://api.github.com/users/jzheaux/repos\",\n" + |
||||
" \"events_url\":\"https://api.github.com/users/jzheaux/events{/privacy}\",\n" + |
||||
" \"received_events_url\":\"https://api.github.com/users/jzheaux/received_events\",\n" + |
||||
" \"type\":\"User\",\n" + |
||||
" \"site_admin\":false\n" + |
||||
" },\n" + |
||||
" \"open_issues\":21,\n" + |
||||
" \"closed_issues\":23,\n" + |
||||
" \"state\":\"open\",\n" + |
||||
" \"created_at\":\"2020-09-16T13:28:03Z\",\n" + |
||||
" \"updated_at\":\"2021-04-06T23:47:10Z\",\n" + |
||||
" \"due_on\":\"2021-04-12T07:00:00Z\",\n" + |
||||
" \"closed_at\":null\n" + |
||||
" },\n" + |
||||
" \"comments\":0,\n" + |
||||
" \"created_at\":\"2021-04-06T23:47:10Z\",\n" + |
||||
" \"updated_at\":\"2021-04-07T17:00:00Z\",\n" + |
||||
" \"closed_at\":null,\n" + |
||||
" \"author_association\":\"MEMBER\",\n" + |
||||
" \"active_lock_reason\":null,\n" + |
||||
" \"pull_request\":{\n" + |
||||
" \"url\":\"https://api.github.com/repos/spring-projects/spring-security/pulls/9562\",\n" + |
||||
" \"html_url\":\"https://github.com/spring-projects/spring-security/pull/9562\",\n" + |
||||
" \"diff_url\":\"https://github.com/spring-projects/spring-security/pull/9562.diff\",\n" + |
||||
" \"patch_url\":\"https://github.com/spring-projects/spring-security/pull/9562.patch\"\n" + |
||||
" },\n" + |
||||
" \"body\":\"Closes gh-9528\\r\\n\\r\\n<!--\\r\\nFor Security Vulnerabilities, please use https://pivotal.io/security#reporting\\r\\n-->\\r\\n\\r\\n<!--\\r\\nBefore creating new features, we recommend creating an issue to discuss the feature. This ensures that everyone is on the same page before extensive work is done.\\r\\n\\r\\nThanks for contributing to Spring Security. Please provide a brief description of your pull-request and reference any related issue numbers (prefix references with gh-).\\r\\n-->\\r\\n\",\n" + |
||||
" \"performed_via_github_app\":null\n" + |
||||
" }\n" + |
||||
"]"; |
||||
long milestoneNumber = 191; |
||||
this.server.enqueue(new MockResponse().setBody(responseJson)); |
||||
|
||||
assertThat(this.github.isOpenIssuesForMilestoneNumber(this.repositoryRef, milestoneNumber)).isTrue(); |
||||
|
||||
RecordedRequest recordedRequest = this.server.takeRequest(1, TimeUnit.SECONDS); |
||||
assertThat(recordedRequest.getMethod()).isEqualToIgnoringCase("get"); |
||||
assertThat(recordedRequest.getRequestUrl().toString()).isEqualTo(this.baseUrl + "/repos/spring-projects/spring-security/issues?per_page=1&milestone=" + milestoneNumber); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,245 @@
@@ -0,0 +1,245 @@
|
||||
/* |
||||
* Copyright 2002-2022 the original author or authors. |
||||
* |
||||
* Licensed 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 |
||||
* |
||||
* https://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.springframework.gradle.github.milestones; |
||||
|
||||
import java.time.LocalDate; |
||||
import java.time.Year; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
import org.junit.jupiter.params.ParameterizedTest; |
||||
import org.junit.jupiter.params.provider.CsvSource; |
||||
|
||||
import org.springframework.gradle.github.milestones.SpringReleaseTrainSpec.Train; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* @author Steve Riesenberg |
||||
*/ |
||||
public class SpringReleaseTrainTests { |
||||
@ParameterizedTest |
||||
@CsvSource({ |
||||
"2019-12-31, ONE, 2020", |
||||
"2020-01-01, ONE, 2020", |
||||
"2020-01-31, ONE, 2020", |
||||
"2020-02-01, TWO, 2020", |
||||
"2020-07-31, TWO, 2020", |
||||
"2020-08-01, ONE, 2021" |
||||
}) |
||||
public void nextTrainWhenBoundaryConditionsThenSuccess(LocalDate startDate, Train expectedTrain, Year expectedYear) { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.nextTrain(startDate) |
||||
.version("1.0.0") |
||||
.weekOfMonth(2) |
||||
.dayOfWeek(2) |
||||
.build(); |
||||
assertThat(releaseTrainSpec.getTrain()).isEqualTo(expectedTrain); |
||||
assertThat(releaseTrainSpec.getYear()).isEqualTo(expectedYear); |
||||
} |
||||
|
||||
@Test |
||||
public void getTrainDatesWhenTrainOneIsSecondTuesdayOf2020ThenSuccess() { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.train(1) |
||||
.version("1.0.0") |
||||
.weekOfMonth(2) |
||||
.dayOfWeek(2) |
||||
.year(2020) |
||||
.build(); |
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); |
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates(); |
||||
assertThat(trainDates).hasSize(5); |
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2020, 1, 14)); |
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2020, 2, 11)); |
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2020, 3, 10)); |
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2020, 4, 14)); |
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2020, 5, 12)); |
||||
} |
||||
|
||||
@Test |
||||
public void getTrainDatesWhenTrainTwoIsSecondTuesdayOf2020ThenSuccess() { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.train(2) |
||||
.version("1.0.0") |
||||
.weekOfMonth(2) |
||||
.dayOfWeek(2) |
||||
.year(2020) |
||||
.build(); |
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); |
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates(); |
||||
assertThat(trainDates).hasSize(5); |
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2020, 7, 14)); |
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2020, 8, 11)); |
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2020, 9, 8)); |
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2020, 10, 13)); |
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2020, 11, 10)); |
||||
} |
||||
|
||||
@Test |
||||
public void getTrainDatesWhenTrainOneIsSecondTuesdayOf2022ThenSuccess() { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.train(1) |
||||
.version("1.0.0") |
||||
.weekOfMonth(2) |
||||
.dayOfWeek(2) |
||||
.year(2022) |
||||
.build(); |
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); |
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates(); |
||||
assertThat(trainDates).hasSize(5); |
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 1, 11)); |
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 2, 8)); |
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 3, 8)); |
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 4, 12)); |
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 5, 10)); |
||||
} |
||||
|
||||
@Test |
||||
public void getTrainDatesWhenTrainTwoIsSecondTuesdayOf2022ThenSuccess() { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.train(2) |
||||
.version("1.0.0") |
||||
.weekOfMonth(2) |
||||
.dayOfWeek(2) |
||||
.year(2022) |
||||
.build(); |
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); |
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates(); |
||||
assertThat(trainDates).hasSize(5); |
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 7, 12)); |
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 8, 9)); |
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 9, 13)); |
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 10, 11)); |
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 11, 8)); |
||||
} |
||||
|
||||
@Test |
||||
public void getTrainDatesWhenTrainOneIsThirdMondayOf2022ThenSuccess() { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.train(1) |
||||
.version("1.0.0") |
||||
.weekOfMonth(3) |
||||
.dayOfWeek(1) |
||||
.year(2022) |
||||
.build(); |
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); |
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates(); |
||||
assertThat(trainDates).hasSize(5); |
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 1, 17)); |
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 2, 21)); |
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 3, 21)); |
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 4, 18)); |
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 5, 16)); |
||||
} |
||||
|
||||
@Test |
||||
public void getTrainDatesWhenTrainTwoIsThirdMondayOf2022ThenSuccess() { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.train(2) |
||||
.version("1.0.0") |
||||
.weekOfMonth(3) |
||||
.dayOfWeek(1) |
||||
.year(2022) |
||||
.build(); |
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); |
||||
Map<String, LocalDate> trainDates = releaseTrain.getTrainDates(); |
||||
assertThat(trainDates).hasSize(5); |
||||
assertThat(trainDates.get("1.0.0-M1")).isEqualTo(LocalDate.of(2022, 7, 18)); |
||||
assertThat(trainDates.get("1.0.0-M2")).isEqualTo(LocalDate.of(2022, 8, 15)); |
||||
assertThat(trainDates.get("1.0.0-M3")).isEqualTo(LocalDate.of(2022, 9, 19)); |
||||
assertThat(trainDates.get("1.0.0-RC1")).isEqualTo(LocalDate.of(2022, 10, 17)); |
||||
assertThat(trainDates.get("1.0.0")).isEqualTo(LocalDate.of(2022, 11, 21)); |
||||
} |
||||
|
||||
@Test |
||||
public void isTrainDateWhenTrainOneIsThirdMondayOf2022ThenSuccess() { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.train(1) |
||||
.version("1.0.0") |
||||
.weekOfMonth(3) |
||||
.dayOfWeek(1) |
||||
.year(2022) |
||||
.build(); |
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); |
||||
for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) { |
||||
assertThat(releaseTrain.isTrainDate("1.0.0-M1", LocalDate.of(2022, 1, dayOfMonth))).isEqualTo(dayOfMonth == 17); |
||||
} |
||||
for (int dayOfMonth = 1; dayOfMonth <= 28; dayOfMonth++) { |
||||
assertThat(releaseTrain.isTrainDate("1.0.0-M2", LocalDate.of(2022, 2, dayOfMonth))).isEqualTo(dayOfMonth == 21); |
||||
} |
||||
for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) { |
||||
assertThat(releaseTrain.isTrainDate("1.0.0-M3", LocalDate.of(2022, 3, dayOfMonth))).isEqualTo(dayOfMonth == 21); |
||||
} |
||||
for (int dayOfMonth = 1; dayOfMonth <= 30; dayOfMonth++) { |
||||
assertThat(releaseTrain.isTrainDate("1.0.0-RC1", LocalDate.of(2022, 4, dayOfMonth))).isEqualTo(dayOfMonth == 18); |
||||
} |
||||
for (int dayOfMonth = 1; dayOfMonth <= 31; dayOfMonth++) { |
||||
assertThat(releaseTrain.isTrainDate("1.0.0", LocalDate.of(2022, 5, dayOfMonth))).isEqualTo(dayOfMonth == 16); |
||||
} |
||||
} |
||||
|
||||
@ParameterizedTest |
||||
@CsvSource({ |
||||
"2022-01-01, 2022-02-21", |
||||
"2022-02-01, 2022-02-21", |
||||
"2022-02-21, 2022-04-18", |
||||
"2022-03-01, 2022-04-18", |
||||
"2022-04-01, 2022-04-18", |
||||
"2022-04-18, 2022-06-20", |
||||
"2022-05-01, 2022-06-20", |
||||
"2022-06-01, 2022-06-20", |
||||
"2022-06-20, 2022-08-15", |
||||
"2022-07-01, 2022-08-15", |
||||
"2022-08-01, 2022-08-15", |
||||
"2022-08-15, 2022-10-17", |
||||
"2022-09-01, 2022-10-17", |
||||
"2022-10-01, 2022-10-17", |
||||
"2022-10-17, 2022-12-19", |
||||
"2022-11-01, 2022-12-19", |
||||
"2022-12-01, 2022-12-19", |
||||
"2022-12-19, 2023-02-20" |
||||
}) |
||||
public void getNextReleaseDateWhenBoundaryConditionsThenSuccess(LocalDate startDate, LocalDate expectedDate) { |
||||
SpringReleaseTrainSpec releaseTrainSpec = |
||||
SpringReleaseTrainSpec.builder() |
||||
.train(1) |
||||
.version("1.0.0") |
||||
.weekOfMonth(3) |
||||
.dayOfWeek(1) |
||||
.year(2022) |
||||
.build(); |
||||
|
||||
SpringReleaseTrain releaseTrain = new SpringReleaseTrain(releaseTrainSpec); |
||||
assertThat(releaseTrain.getNextReleaseDate(startDate)).isEqualTo(expectedDate); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue