Skip to content

Commit 8d29b36

Browse files
committed
[RelEng] Create RelEng calendar entries in preparation pipeline
1 parent 75acc90 commit 8d29b36

3 files changed

Lines changed: 148 additions & 9 deletions

File tree

JenkinsJobs/Releng/prepareNextDevCycle.jenkinsfile

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ pipeline {
4040
utilities.setDryRun(params.DRY_RUN)
4141
githubAPI = load "JenkinsJobs/shared/githubAPI.groovy"
4242
githubAPI.setDryRun(params.DRY_RUN)
43+
calendarAPI = load "JenkinsJobs/shared/calendarAPI.groovy"
44+
calendarAPI.setDryRun(params.DRY_RUN)
4345

4446
echo "NEXT_RELEASE_VERSION: ${NEXT_RELEASE_VERSION}"
4547
def nextVersion = utilities.matchPattern('NEXT_RELEASE_VERSION', "${NEXT_RELEASE_VERSION}", [ /(?<major>\d+)\.(?<minor>\d+)/ ])
@@ -380,7 +382,6 @@ pipeline {
380382
- [ ] Review and submit the new N&N pages created for the [eclipse website](https://github.com/eclipse-platform/www.eclipse.org-eclipse/pulls) repository.
381383
- [ ] Submit this PR.
382384
Before the preparation PRs in all submodules have been submitted the build of this change cannot complete (this can still submit it before).
383-
- [ ] Update build calendar for platform ${NEXT_RELEASE_VERSION} release cycle.
384385

385386
After this and all submodule PRs are submitted:
386387
- [ ] Run the [`Create Jobs`](https://ci.eclipse.org/releng/job/CreateJobs/) seed job to create the Jenkins jobs of the new stream
@@ -432,13 +433,44 @@ pipeline {
432433
}
433434
}
434435
}
436+
stage('Create build calendar') {
437+
environment {
438+
GCLOULD_KEY_FILE = credentials('gclould-service-account-key') // Secret file
439+
}
440+
steps {
441+
script {
442+
calendarAPI.initialize(utilities)
443+
def rc2 = utilities.parseDate("${RC2_DATE}")
444+
def ga = utilities.parseDate("${GA_DATE}")
445+
def eclipsePrefix = "Eclipse ${NEXT_RELEASE_VERSION}" //TODO: Or keep Eclipse Platform
446+
// I-build events
447+
def iBuildStart = java.time.LocalDate.now().plusDays(1).atTime(18, 0).atZone(java.time.ZoneId.of('America/Toronto'))
448+
def iBuildUntil = rc2.minusDays(1) // exclusive
449+
calendarAPI.createEvent("Eclipse ${NEXT_RELEASE_VERSION} I-build", iBuildStart, iBuildStart.plusHours(1),
450+
[ calendarAPI.createRecurrenceRRule('DAILY', iBuildUntil) ])
451+
// Release events
452+
utilities.releaseEvents().each{ name, description ->
453+
def date = utilities.parseDate(env["${name}_DATE"])
454+
if (name.startsWith('RC')) {
455+
calendarAPI.createEvent("${eclipsePrefix} ${name} Stabilization", date.minusDays(3), date.minusDays(1))
456+
calendarAPI.createEvent("${eclipsePrefix} ${name} Sign-off", date.minusDays(1))
457+
}
458+
def title = eclipsePrefix + (name != 'GA' ? " ${name} Promotion" : " (${NEXT_SIMREL_NAME}) GA")
459+
calendarAPI.createEvent(title, date, date)
460+
}
461+
calendarAPI.createEvent("${eclipsePrefix} Quiet period", rc2.plusDays(1), ga)
462+
}
463+
}
464+
}
435465
}
436466
}
437467

438468
@groovy.transform.Field
439469
def utilities = null
440470
@groovy.transform.Field
441471
def githubAPI = null
472+
@groovy.transform.Field
473+
def calendarAPI = null
442474

443475
// --- utility methods
444476

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 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+
import java.time.LocalDate
16+
import java.time.ZonedDateTime
17+
18+
@groovy.transform.Field
19+
def boolean _CALENDAR_API_IS_DRY_RUN = true
20+
21+
def setDryRun(boolean isDryRun) {
22+
_CALENDAR_API_IS_DRY_RUN = isDryRun
23+
}
24+
25+
def initialize(Object utilities) {
26+
def gcloudInstall = utilities.installDownloadableTool('gcloud', 'https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-cli-linux-x86_64.tar.gz')
27+
env.GCLOUD = "${gcloudInstall}/bin/gcloud"
28+
// https://docs.cloud.google.com/sdk/docs/configurations
29+
env.CLOUDSDK_CONFIG = "${gcloudInstall}/../config"
30+
// https://docs.cloud.google.com/sdk/docs/initializing
31+
sh '''#!/bin/bash -xe
32+
# Skip default initialization since this is a non-interactive session
33+
$GCLOUD config set disable_prompts true
34+
$GCLOUD auth activate-service-account --key-file=${GCLOULD_KEY_FILE}
35+
'''
36+
}
37+
38+
// Calendar events: https://developers.google.com/workspace/calendar/api/v3/reference/events#resource
39+
40+
def createEvent(String title, LocalDate start, LocalDate end = null) {
41+
if (end == null) {
42+
end = start.plusDays(1) // Assume one day event
43+
}
44+
def parameters = [summary: title, start: [date: formatDate(start)], end: [date: formatDate(end)] ]
45+
insertEvent(parameters)
46+
}
47+
48+
// Recurrence Rules: https://datatracker.ietf.org/doc/html/rfc5545#section-3.3.10
49+
50+
def createRecurrenceRRule(String frequency, LocalDate until) {
51+
// See https://datatracker.ietf.org/doc/html/rfc5545#section-3.8.5.3
52+
return "RRULE:FREQ=${frequency.toUpperCase()};UNTIL=${java.time.format.DateTimeFormatter.BASIC_ISO_DATE.format(until)}"
53+
}
54+
// createRecurrenceExRule(), createRecurrenceRDate() and createRecurrenceExDate() currently not needed
55+
56+
def createEvent(String title, ZonedDateTime start, ZonedDateTime end, recurrenceRules = null) {
57+
def parameters = [summary: title]
58+
parameters.start = [dateTime: formatDateTime(start), timeZone: start.zone.id]
59+
parameters.end = [dateTime: formatDateTime(end), timeZone: end.zone.id]
60+
parameters.recurrence = recurrenceRules
61+
insertEvent(parameters)
62+
}
63+
64+
private String formatDate(LocalDate date) {
65+
return java.time.format.DateTimeFormatter.ISO_LOCAL_DATE.format(date)
66+
}
67+
68+
private String formatDateTime(ZonedDateTime dateTime) {
69+
return java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(dateTime)
70+
}
71+
72+
// https://developers.google.com/workspace/calendar/api/v3/reference/events/insert
73+
private void insertEvent(Map<String, Object> parameters) {
74+
def response = queryGoogleCalendarAPI('-X POST', 'events', parameters)
75+
if (response != null && !isConfirmedEvent(response)) {
76+
error "Response contains errors:\n${response}"
77+
}
78+
}
79+
80+
private boolean isConfirmedEvent(Map response) {
81+
return response.kind == 'calendar#event' && response.status == 'confirmed'
82+
}
83+
84+
// See documentation of the Google Calendar API
85+
// - https://developers.google.com/workspace/calendar/api/guides/overview
86+
87+
private Map<String, String> queryGoogleCalendarAPI(String method, String endpoint, Map<String, Object> parameters = null) {
88+
def calendarId = 'prfk26fdmpru1mptlb06p0jh4s@group.calendar.google.com'
89+
def query = """\
90+
GC_API_TOKEN=\$(\$GCLOUD auth print-access-token --scopes=https://www.googleapis.com/auth/calendar)
91+
curl -L ${method} \
92+
'https://www.googleapis.com/calendar/v3/calendars/${calendarId}/${endpoint}' \
93+
-H "Authorization: Bearer \${GC_API_TOKEN}" \
94+
-H 'Accept: application/json' \
95+
-H 'Content-Type: application/json'
96+
""".replace('\t','').trim()
97+
if (parameters) {
98+
def data = writeJSON(json: parameters, returnText: true)
99+
data = data.replace("'", "'\\''") // Escape single quotes by '\''
100+
query += " --data '${data}'"
101+
}
102+
if (_CALENDAR_API_IS_DRY_RUN && !method.isEmpty()) {
103+
echo "Query (not send):\n${query}"
104+
return null
105+
}
106+
echo "Execute:\n${query}"
107+
// Ensure the commands are not printed to prevent exposure of (temporary credentials)
108+
def response = sh(script: "#!/bin/bash -e\n${query}", returnStdout: true)
109+
if (response == null || response.isEmpty()) {
110+
error 'Response is null or empty. This commonly indicates: HTTP/1.1 500 Internal Server Error'
111+
}
112+
return readJSON(text: response)
113+
}
114+
115+
return this

RELEASE.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,6 @@ The release is scheduled for 10:00 UTC.
118118
- After RC2 is promoted/published run the [`Prepare Next Development Cycle`](https://ci.eclipse.org/releng/job/Releng/job/prepareNextDevCycle/) job
119119
- Review the Pull-Requests created by it in this `eclipse.platform.releng.aggregator` repository and all its submodules and complete the listed tasks.
120120

121-
#### **Update the Build Calendar:**
122-
- Create an [issue](https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/289) and update the [build calendar](https://calendar.google.com/calendar/u/0?cid=cHJmazI2ZmRtcHJ1MW1wdGxiMDZwMGpoNHNAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ) for the next GA release based on the [Simultaneous Release schedule](https://wiki.eclipse.org/Simultaneous_Release).
123-
- Each stream has its own [page](https://github.com/eclipse-simrel/.github/blob/main/wiki/SimRel/2026-06.md) with a more detailed schedule.
124-
- List of people who can edit the calendar
125-
- Alexander Kurtakov(@akurtakov)
126-
- Gireesh Punathil
127-
- Rahul Mohanan
128-
129121
#### **Update Splash Screen:**
130122
- Future spash screens are kept in a subfolder of [eclipse.platform/platform/org.eclipse.platform](https://github.com/eclipse-platform/eclipse.platform/tree/master/platform/org.eclipse.platform/futureSplashScreens).
131123
- NOTE: Splash screens are created 4 at a time, for 4 consequtive quarterly releases, so they need to be requested once a year before the 20XX-06 release (the cycle is 2022-06 -> 2023-03, etc). Create an issue in the [Eclipse Help Desk](https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/issues) similar to [Bug 575781](https://bugs.eclipse.org/bugs/show_bug.cgi?id=575781). It is customary to do this by the previous -09 (September) release so that there's plenty of time for discussion before the -06 (June) release is opened.

0 commit comments

Comments
 (0)