Skip to content

Commit 4917b8c

Browse files
committed
Add -e/--eol-config-path support to schedule-builder
It's not possible to specify an optional EOL config path. This file will be updated when a patch release goes end of life when specified. Signed-off-by: Sascha Grunert <[email protected]>
1 parent 7fc79f9 commit 4917b8c

File tree

4 files changed

+140
-36
lines changed

4 files changed

+140
-36
lines changed

cmd/schedule-builder/cmd/markdown.go

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,22 +167,34 @@ func processFile(fileName string, vars interface{}) string {
167167
return process(tmpl, vars)
168168
}
169169

170-
func updatePatchSchedule(refTime time.Time, schedule PatchSchedule, filePath string) error {
170+
func updatePatchSchedule(refTime time.Time, schedule PatchSchedule, eolBranches EolBranches, filePath, eolFilePath string) error {
171171
const refDate = "2006-01-02"
172172

173-
for _, schedule := range schedule.Schedules {
173+
removeSchedules := []int{}
174+
for i, sched := range schedule.Schedules {
174175
for {
175-
eolDate, err := time.Parse(refDate, schedule.EndOfLifeDate)
176+
eolDate, err := time.Parse(refDate, sched.EndOfLifeDate)
176177
if err != nil {
177178
return fmt.Errorf("parse end of life date: %w", err)
178179
}
179180

180181
if refTime.After(eolDate) {
181-
logrus.Infof("Skipping end of life release: %s", schedule.Release)
182+
if eolFilePath == "" {
183+
logrus.Infof("Skipping end of life release: %s", sched.Release)
184+
break
185+
}
186+
187+
logrus.Infof("Moving %s to end of life", sched.Release)
188+
eolBranches.Branches = append([]*EolBranch{{
189+
Release: sched.Release,
190+
FinalPatchRelease: sched.Next.Release,
191+
EndOfLifeDate: sched.Next.TargetDate,
192+
}}, eolBranches.Branches...)
193+
removeSchedules = append(removeSchedules, i)
182194
break
183195
}
184196

185-
targetDate, err := time.Parse(refDate, schedule.Next.TargetDate)
197+
targetDate, err := time.Parse(refDate, sched.Next.TargetDate)
186198
if err != nil {
187199
return fmt.Errorf("parse target date: %w", err)
188200
}
@@ -192,18 +204,18 @@ func updatePatchSchedule(refTime time.Time, schedule PatchSchedule, filePath str
192204
}
193205

194206
// Copy the release to the previousPatches section
195-
schedule.PreviousPatches = append([]*PatchRelease{schedule.Next}, schedule.PreviousPatches...)
207+
sched.PreviousPatches = append([]*PatchRelease{sched.Next}, sched.PreviousPatches...)
196208

197209
// Create a new next release
198-
nextReleaseVersion, err := util.TagStringToSemver(schedule.Next.Release)
210+
nextReleaseVersion, err := util.TagStringToSemver(sched.Next.Release)
199211
if err != nil {
200212
return fmt.Errorf("parse semver version: %w", err)
201213
}
202214
if err := nextReleaseVersion.IncrementPatch(); err != nil {
203215
return fmt.Errorf("increment patch version: %w", err)
204216
}
205217

206-
cherryPickDeadline, err := time.Parse(refDate, schedule.Next.CherryPickDeadline)
218+
cherryPickDeadline, err := time.Parse(refDate, sched.Next.CherryPickDeadline)
207219
if err != nil {
208220
return fmt.Errorf("parse cherry pick deadline: %w", err)
209221
}
@@ -215,16 +227,31 @@ func updatePatchSchedule(refTime time.Time, schedule PatchSchedule, filePath str
215227
targetDateDay := secondTuesday(targetDatePlusOneMonth)
216228
newTargetDate := time.Date(targetDatePlusOneMonth.Year(), targetDatePlusOneMonth.Month(), targetDateDay, 0, 0, 0, 0, time.UTC)
217229

218-
schedule.Next = &PatchRelease{
230+
sched.Next = &PatchRelease{
219231
Release: nextReleaseVersion.String(),
220232
CherryPickDeadline: newCherryPickDeadline.Format(refDate),
221233
TargetDate: newTargetDate.Format(refDate),
222234
}
223235

224-
logrus.Infof("Adding release schedule: %+v", schedule.Next)
236+
logrus.Infof("Adding release schedule: %+v", sched.Next)
225237
}
226238
}
227239

240+
newSchedules := []*Schedule{}
241+
for i, sched := range schedule.Schedules {
242+
appendItem := true
243+
for _, k := range removeSchedules {
244+
if i == k {
245+
appendItem = false
246+
break
247+
}
248+
}
249+
if appendItem {
250+
newSchedules = append(newSchedules, sched)
251+
}
252+
}
253+
schedule.Schedules = newSchedules
254+
228255
newUpcomingReleases := []*PatchRelease{}
229256
latestDate := refTime
230257
for _, upcomingRelease := range schedule.UpcomingReleases {
@@ -275,6 +302,20 @@ func updatePatchSchedule(refTime time.Time, schedule PatchSchedule, filePath str
275302
return fmt.Errorf("write schedule YAML: %w", err)
276303
}
277304

305+
if eolFilePath != "" {
306+
logrus.Infof("Writing end of life branches: %s", eolFilePath)
307+
308+
yamlBytes, err := yaml.Marshal(eolBranches)
309+
if err != nil {
310+
return fmt.Errorf("marshal end of life YAML: %w", err)
311+
}
312+
313+
//nolint:gocritic,gosec
314+
if err := os.WriteFile(eolFilePath, yamlBytes, 0o644); err != nil {
315+
return fmt.Errorf("write end of life YAML: %w", err)
316+
}
317+
}
318+
278319
logrus.Infof("Wrote schedule YAML to: %v", filePath)
279320
return nil
280321
}

cmd/schedule-builder/cmd/markdown_test.go

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ func TestUpdatePatchSchedule(t *testing.T) {
349349
name string
350350
refTime time.Time
351351
givenSchedule, expectedSchedule PatchSchedule
352+
expectedEolBranches EolBranches
352353
}{
353354
{
354355
name: "succeed to update the schedule",
@@ -368,6 +369,11 @@ func TestUpdatePatchSchedule(t *testing.T) {
368369
{ // EOL
369370
Release: "1.20",
370371
EndOfLifeDate: "2023-01-01",
372+
Next: &PatchRelease{
373+
Release: "1.20.10",
374+
CherryPickDeadline: "2023-12-08",
375+
TargetDate: "2023-12-12",
376+
},
371377
},
372378
},
373379
UpcomingReleases: []*PatchRelease{
@@ -417,10 +423,6 @@ func TestUpdatePatchSchedule(t *testing.T) {
417423
},
418424
},
419425
},
420-
{
421-
Release: "1.20",
422-
EndOfLifeDate: "2023-01-01",
423-
},
424426
},
425427
UpcomingReleases: []*PatchRelease{
426428
{
@@ -440,21 +442,41 @@ func TestUpdatePatchSchedule(t *testing.T) {
440442
},
441443
},
442444
},
445+
expectedEolBranches: EolBranches{
446+
Branches: []*EolBranch{
447+
{
448+
Release: "1.20",
449+
FinalPatchRelease: "1.20.10",
450+
EndOfLifeDate: "2023-12-12",
451+
},
452+
},
453+
},
443454
},
444455
} {
445456
t.Run(tc.name, func(t *testing.T) {
446-
file, err := os.CreateTemp("", "schedule-")
457+
scheduleFile, err := os.CreateTemp("", "schedule-")
458+
require.NoError(t, err)
459+
require.NoError(t, scheduleFile.Close())
460+
461+
eolFile, err := os.CreateTemp("", "eol-")
462+
require.NoError(t, err)
463+
require.NoError(t, eolFile.Close())
464+
465+
require.NoError(t, updatePatchSchedule(tc.refTime, tc.givenSchedule, EolBranches{}, scheduleFile.Name(), eolFile.Name()))
466+
467+
scheduleYamlBytes, err := os.ReadFile(scheduleFile.Name())
447468
require.NoError(t, err)
448-
require.NoError(t, file.Close())
469+
patchRes := PatchSchedule{}
470+
require.NoError(t, yaml.UnmarshalStrict(scheduleYamlBytes, &patchRes))
449471

450-
require.NoError(t, updatePatchSchedule(tc.refTime, tc.givenSchedule, file.Name()))
472+
assert.Equal(t, tc.expectedSchedule, patchRes)
451473

452-
yamlBytes, err := os.ReadFile(file.Name())
474+
eolYamlBytes, err := os.ReadFile(eolFile.Name())
453475
require.NoError(t, err)
454-
res := PatchSchedule{}
455-
require.NoError(t, yaml.UnmarshalStrict(yamlBytes, &res))
476+
eolRes := EolBranches{}
477+
require.NoError(t, yaml.UnmarshalStrict(eolYamlBytes, &eolRes))
456478

457-
assert.Equal(t, tc.expectedSchedule, res)
479+
assert.Equal(t, tc.expectedEolBranches, eolRes)
458480
})
459481
}
460482
}

cmd/schedule-builder/cmd/model.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ type Schedule struct {
4040
PreviousPatches []*PatchRelease `json:"previousPatches,omitempty" yaml:"previousPatches,omitempty"`
4141
}
4242

43+
// EolBranches is main struct to hold the end of life branches.
44+
type EolBranches struct {
45+
Branches []*EolBranch `json:"branches,omitempty" yaml:"branches,omitempty"`
46+
}
47+
48+
// EolBranch struct to define the end of life release branches.
49+
type EolBranch struct {
50+
Release string `json:"release,omitempty" yaml:"release,omitempty"`
51+
FinalPatchRelease string `json:"finalPatchRelease,omitempty" yaml:"finalPatchRelease,omitempty"`
52+
EndOfLifeDate string `json:"endOfLifeDate,omitempty" yaml:"endOfLifeDate,omitempty"`
53+
Note string `json:"note,omitempty" yaml:"note,omitempty"`
54+
}
55+
4356
type ReleaseSchedule struct {
4457
Releases []Release `yaml:"releases"`
4558
}

cmd/schedule-builder/cmd/root.go

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,24 +43,26 @@ var rootCmd = &cobra.Command{
4343
}
4444

4545
type options struct {
46-
configPath string
47-
outputFile string
48-
logLevel string
49-
typeFile string
50-
update bool
51-
version bool
46+
configPath string
47+
eolConfigPath string
48+
outputFile string
49+
logLevel string
50+
typeFile string
51+
update bool
52+
version bool
5253
}
5354

5455
var opts = &options{}
5556

5657
const (
57-
configPathFlag = "config-path"
58-
outputFileFlag = "output-file"
59-
typeFlag = "type"
60-
updateFlag = "update"
61-
versionFlag = "version"
62-
typePatch = "patch"
63-
typeRelease = "release"
58+
configPathFlag = "config-path"
59+
eolConfigPathFlag = "eol-config-path"
60+
outputFileFlag = "output-file"
61+
typeFlag = "type"
62+
updateFlag = "update"
63+
versionFlag = "version"
64+
typePatch = "patch"
65+
typeRelease = "release"
6466
)
6567

6668
// Execute adds all child commands to the root command and sets flags appropriately.
@@ -80,6 +82,14 @@ func init() {
8082
"path where can find the schedule.yaml file",
8183
)
8284

85+
rootCmd.PersistentFlags().StringVarP(
86+
&opts.eolConfigPath,
87+
eolConfigPathFlag,
88+
"e",
89+
"",
90+
"path where can find the eol.yaml file for updating end of life releases",
91+
)
92+
8393
rootCmd.PersistentFlags().StringVarP(
8494
&opts.outputFile,
8595
outputFileFlag,
@@ -145,6 +155,7 @@ func run(opts *options) error {
145155
var (
146156
patchSchedule PatchSchedule
147157
releaseSchedule ReleaseSchedule
158+
eolBranches EolBranches
148159
scheduleOut string
149160
)
150161

@@ -153,12 +164,29 @@ func run(opts *options) error {
153164
switch opts.typeFile {
154165
case typePatch:
155166
if err := yaml.UnmarshalStrict(data, &patchSchedule); err != nil {
156-
return fmt.Errorf("failed to decode the file: %w", err)
167+
return fmt.Errorf("failed to decode patch schedule: %w", err)
168+
}
169+
170+
if opts.eolConfigPath != "" {
171+
data, err := os.ReadFile(opts.eolConfigPath)
172+
if err != nil {
173+
return fmt.Errorf("failed to read end of life config path: %w", err)
174+
}
175+
176+
if err := yaml.UnmarshalStrict(data, &eolBranches); err != nil {
177+
return fmt.Errorf("failed to decode end of life branches: %w", err)
178+
}
157179
}
158180

159181
if opts.update {
160182
logrus.Info("Updating schedule")
161-
if err := updatePatchSchedule(time.Now(), patchSchedule, opts.configPath); err != nil {
183+
if err := updatePatchSchedule(
184+
time.Now(),
185+
patchSchedule,
186+
eolBranches,
187+
opts.configPath,
188+
opts.eolConfigPath,
189+
); err != nil {
162190
return fmt.Errorf("update patch schedule: %w", err)
163191
}
164192
} else {

0 commit comments

Comments
 (0)