Skip to content

Commit 576f2a3

Browse files
committed
Provide SimRel dates in machine-readable form and add details generator
Provide SimRel dates as JSON because it's a commonly used and well supported format, especially in the web area. Add a generator for the Wiki details page for a release, that requires the dates JSON file for the targeted release (i.e. '<SimRel-name>_dates.json') to exist and can then be invoked from CLI: java scripts/generateReleaseDetails.java <SimRel-name> where <SimRel-name> is for example '2025-12', requiring to use Java-25 or later.
1 parent 1fb1992 commit 576f2a3

16 files changed

+241
-4
lines changed

scripts/.classpath

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<classpath>
3+
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-25"/>
4+
<classpathentry kind="src" path="."/>
5+
<classpathentry kind="output" path="bin"/>
6+
</classpath>

scripts/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/bin/

scripts/.project

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>eclipse.simrel.scripts</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.jdt.core.javabuilder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.jdt.core.javanature</nature>
16+
</natures>
17+
</projectDescription>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
eclipse.preferences.version=1
2+
encoding/<project>=UTF-8
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
eclipse.preferences.version=1
2+
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
3+
org.eclipse.jdt.core.compiler.codegen.targetPlatform=25
4+
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5+
org.eclipse.jdt.core.compiler.compliance=25
6+
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7+
org.eclipse.jdt.core.compiler.debug.localVariable=generate
8+
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9+
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
10+
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
11+
org.eclipse.jdt.core.compiler.release=enabled
12+
org.eclipse.jdt.core.compiler.source=25
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025, 2025 Hannes Wellmann and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Hannes Wellmann - initial API and implementation
13+
*******************************************************************************/
14+
15+
final Locale LOCAL = Locale.ENGLISH;
16+
final DateTimeFormatter LONG = DateTimeFormatter.ofPattern("EEEE, MMMM d, yyyy", LOCAL);
17+
final DateTimeFormatter SHORT = DateTimeFormatter.ofPattern("MM/dd", LOCAL);
18+
19+
private record SimRelDates(LocalDate M1, LocalDate M2, LocalDate M3, LocalDate RC1, LocalDate RC2, LocalDate GA) {
20+
}
21+
22+
void main(String[] args) throws IOException {
23+
String simRelName = readSimRelName(args);
24+
Path templateFile = Path.of("wiki/SimRel/releaseDetails.template_md");
25+
Path overviewFile = templateFile.resolveSibling(simRelName + ".md");
26+
27+
SimRelDates dates = parseDatesJSON(Path.of("wiki/SimRel/" + simRelName + "_dates.json"));
28+
performSanityChecks(simRelName, dates);
29+
30+
String simRelMonthYear = DateTimeFormatter.ofPattern("MMMM yyyy", LOCAL).format(dates.GA);
31+
String previousSimRelName = DateTimeFormatter.ofPattern("yyyy-MM", LOCAL).format(dates.GA.minusMonths(3));
32+
if (!Files.isRegularFile(overviewFile.resolveSibling(previousSimRelName + ".md"))) {
33+
throw new IllegalStateException("Previous SimRel " + previousSimRelName + " not found.");
34+
}
35+
var calendarDate = DateTimeFormatter.ofPattern("yyyyMMdd", LOCAL);
36+
String calendarPeriodStart = calendarDate.format(dates.M1.minusWeeks(2));
37+
String calendarPeriodEnd = calendarDate.format(dates.GA.plusDays(1));
38+
39+
String content = Files.readString(templateFile);
40+
content = content.replace("${SIMREL_NAME}", simRelName) //
41+
.replace("${PREVIOUS_SIMREL_NAME}", previousSimRelName) //
42+
.replace("${SIMREL_FULL_MONTH_YEAR}", simRelMonthYear)
43+
.replace("${QUIET_PERIOD_START_SHORT}", SHORT.format(dates.RC2))
44+
.replace("${QUIET_PERIOD_END_SHORT}", SHORT.format(dates.GA.minusDays(1)))
45+
.replace("${CALENDAR_PERIOD}", calendarPeriodStart + "%2F" + calendarPeriodEnd);
46+
content = resolveDateVariables(content, "M1", dates.M1);
47+
content = resolveDateVariables(content, "M2", dates.M2);
48+
content = resolveDateVariables(content, "M3", dates.M3);
49+
content = resolveDateVariables(content, "RC1", dates.RC1);
50+
content = resolveDateVariables(content, "RC2", dates.RC2);
51+
content = resolveDateVariables(content, "GA", dates.GA);
52+
53+
Files.writeString(overviewFile, content);
54+
55+
IO.println("Overview for " + simRelName + " generated successfully: " + overviewFile);
56+
}
57+
58+
String readSimRelName(String[] args) {
59+
if (args.length < 1) {
60+
throw new IllegalArgumentException("Expected SimRel name argument is missing");
61+
}
62+
String simRelName = args[0];
63+
if (!Pattern.compile("(?<year>\\d{4})-(?<month>\\d{2})").matcher(simRelName).matches()) {
64+
throw new IllegalArgumentException("SimRel name has unexpected format: " + simRelName);
65+
}
66+
return simRelName;
67+
}
68+
69+
SimRelDates parseDatesJSON(Path file) throws IOException {
70+
// Use built-in JSON parser once the JDK provides one
71+
String content = Files.readString(file).trim();
72+
if (!content.startsWith("{") || !content.endsWith("}")) {
73+
throw new IllegalArgumentException("Unexpected content of" + file.getFileName());
74+
}
75+
var jsonDateObject = Pattern.compile("\"(?<name>\\w+)\"\\s*:\\s*\"(?<date>[^\"]+)\"\\s*(,|})");
76+
var dates = jsonDateObject.matcher(content).results()
77+
.collect(Collectors.toMap(m -> m.group("name"), m -> LocalDate.parse(m.group("date"))));
78+
return new SimRelDates(getDate(dates, "M1"), getDate(dates, "M2"), getDate(dates, "M3"), //
79+
getDate(dates, "RC1"), getDate(dates, "RC2"), getDate(dates, "GA"));
80+
}
81+
82+
LocalDate getDate(Map<String, LocalDate> dates, String key) {
83+
return Objects.requireNonNull(dates.get(key), key + " date not specified");
84+
}
85+
86+
void performSanityChecks(String simRelName, SimRelDates dates) {
87+
var allDates = Arrays.stream(SimRelDates.class.getRecordComponents()).map(RecordComponent::getAccessor).map(m -> {
88+
try {
89+
return m.invoke(dates);
90+
} catch (IllegalAccessException | InvocationTargetException e) {
91+
throw new IllegalStateException(e);
92+
}
93+
}).map(LocalDate.class::cast).toList();
94+
for (int i = 1; i < allDates.size(); i++) {
95+
if (allDates.get(i - 1).compareTo(allDates.get(i)) >= 0) {
96+
throw new IllegalArgumentException("Dates are not in strictly ascending order: " + allDates);
97+
}
98+
}
99+
if (!allDates.subList(0, allDates.size() - 1).stream().allMatch(d -> d.getDayOfWeek() == DayOfWeek.FRIDAY)) {
100+
throw new IllegalArgumentException("Not all milestones and RCs are Fridays: " + dates);
101+
}
102+
if (dates.GA.getDayOfWeek() != DayOfWeek.WEDNESDAY) {
103+
throw new IllegalArgumentException("GA release day is not a Wednesday: " + dates.GA);
104+
}
105+
if (!simRelName.equals(String.format("%d-%02d", dates.GA.getYear(), dates.GA.getMonthValue()))) {
106+
throw new IllegalArgumentException("GA date does not match the SimRel name (" + simRelName + "): " + dates.GA);
107+
}
108+
var milestoneLengths = Set.of(Period.ofWeeks(2), Period.ofWeeks(3), Period.ofWeeks(4));
109+
if (!milestoneLengths.contains(dates.M1.until(dates.M2)) || !milestoneLengths.contains(dates.M2.until(dates.M3))) {
110+
// The number of weeks between M1 and M2 may be subject to adjustments in order
111+
// to adapt to years not having exactly 52 years and correspondingly increase or
112+
// decrease the offset of M1 from M2 as necessary. Usually both are three weeks
113+
// apart, just like M2 and M3 (which is usually not adapted).
114+
throw new IllegalArgumentException(
115+
"M1, M2 and M3 are further apart than usual: " + dates.M1 + ", " + dates.M2 + ", " + dates.M3);
116+
}
117+
if (dates.M3.until(dates.RC1, ChronoUnit.DAYS) != 7 || dates.RC1.until(dates.RC2, ChronoUnit.DAYS) != 7) {
118+
throw new IllegalArgumentException("M3, RC1 and RC2 are not in strictly one week apart: " + dates.M3 + ", "
119+
+ dates.RC1 + ", " + dates.RC2);
120+
}
121+
if (dates.RC2.until(dates.GA, ChronoUnit.DAYS) >= 7) {
122+
throw new IllegalArgumentException(
123+
"RC2 and GA are not in strictly within one week: " + dates.RC2 + ", " + dates.GA);
124+
}
125+
}
126+
127+
String resolveDateVariables(String str, String name, LocalDate date) {
128+
return str.replace("${" + name + "_DATE_LONG}", LONG.format(date))
129+
.replace("${" + name + "_START_SHORT}", SHORT.format(date.minusDays(7)))
130+
.replace("${" + name + "_END_SHORT}", SHORT.format(date));
131+
}

wiki/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,19 @@ This folder also provides provides details about the processes involved in produ
3030
- [SimRel FAQ](SimRel/Simultaneous_Release_Cycle_FAQ.md)
3131
- [SimRel Checklist](SimRel/Release_Checklist.md)
3232

33+
#### Adding a new SimRel and its dates
34+
35+
When adding a new simultaneous release and its dates, first add the JSON file containing the agreed dates for `M1`, `M2`, `M3`, `RC1`, `RC2` and `GA` in a JSON file named
36+
```
37+
wiki/SimRel/<SimRel-Name>_dates.json
38+
```
39+
where `<SimRel-Name>` is for example `2025-12`.
40+
41+
To generate the wiki details page for that release, the following command can be run from the root of this repository (requiring Java-25 or later):
42+
```
43+
java scripts/generateReleaseDetails.java <SimRel-name>
44+
```
45+
3346
---
3447

3548
#### Why this format?

wiki/SimRel/2025-03.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ This documents related to 2025-03, the Eclipse Foundation's multi-project [Simul
1616
| **Quiet period** | | 03/07 to 03/11 | | No builds. It is assumed all code is done by end of RC2. |
1717
| **2025-03 GA** | Wednesday, March 12, 2025 | | <ul><li>Release reviews conclude on this date</ul> | 5 days from RC2 |
1818

19-
[Google Calendar Link](https://calendar.google.com/calendar/embed?src=gchs7nm4nvpm837469ddj9tjlk@group.calendar.google.com&dates=20241201%2F20250331&hl=en&mode=AGENDA)
19+
[Google Calendar Link](https://calendar.google.com/calendar/embed?src=gchs7nm4nvpm837469ddj9tjlk@group.calendar.google.com&dates=20241227%2F20250313&hl=en&mode=AGENDA)
2020

2121
## Non-wiki pages related to the release
2222

wiki/SimRel/2025-03_dates.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"M1": "2025-01-10",
3+
"M2": "2025-01-31",
4+
"M3": "2025-02-21",
5+
"RC1": "2025-02-28",
6+
"RC2": "2025-03-07",
7+
"GA": "2025-03-12"
8+
}

wiki/SimRel/2025-06.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ This documents related to 2025-06, the Eclipse Foundation's multi-project [Simul
1919
| **Quiet period** | | 06/06 to 06/10 | | No builds. It is assumed all code is done by end of RC2. |
2020
| **2025-06 GA** | Wednesday, June 11, 2025 | | | 5 days from RC2 |
2121

22-
[Google Calendar Link](https://calendar.google.com/calendar/embed?src=gchs7nm4nvpm837469ddj9tjlk@group.calendar.google.com&dates=20241201%2F20250331&hl=en&mode=AGENDA)
22+
[Google Calendar Link](https://calendar.google.com/calendar/embed?src=gchs7nm4nvpm837469ddj9tjlk@group.calendar.google.com&dates=20250328%2F20250612&hl=en&mode=AGENDA)
2323

2424
## Non-wiki pages related to the release
2525

0 commit comments

Comments
 (0)