Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -e/--eol-config-path support to schedule-builder #3550

Merged
merged 1 commit into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 51 additions & 10 deletions cmd/schedule-builder/cmd/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,22 +167,34 @@ func processFile(fileName string, vars interface{}) string {
return process(tmpl, vars)
}

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

for _, schedule := range schedule.Schedules {
removeSchedules := []int{}
for i, sched := range schedule.Schedules {
for {
eolDate, err := time.Parse(refDate, schedule.EndOfLifeDate)
eolDate, err := time.Parse(refDate, sched.EndOfLifeDate)
if err != nil {
return fmt.Errorf("parse end of life date: %w", err)
}

if refTime.After(eolDate) {
logrus.Infof("Skipping end of life release: %s", schedule.Release)
if eolFilePath == "" {
logrus.Infof("Skipping end of life release: %s", sched.Release)
break
}

logrus.Infof("Moving %s to end of life", sched.Release)
eolBranches.Branches = append([]*EolBranch{{
Release: sched.Release,
FinalPatchRelease: sched.Next.Release,
EndOfLifeDate: sched.Next.TargetDate,
}}, eolBranches.Branches...)
removeSchedules = append(removeSchedules, i)
break
}

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

// Copy the release to the previousPatches section
schedule.PreviousPatches = append([]*PatchRelease{schedule.Next}, schedule.PreviousPatches...)
sched.PreviousPatches = append([]*PatchRelease{sched.Next}, sched.PreviousPatches...)

// Create a new next release
nextReleaseVersion, err := util.TagStringToSemver(schedule.Next.Release)
nextReleaseVersion, err := util.TagStringToSemver(sched.Next.Release)
if err != nil {
return fmt.Errorf("parse semver version: %w", err)
}
if err := nextReleaseVersion.IncrementPatch(); err != nil {
return fmt.Errorf("increment patch version: %w", err)
}

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

schedule.Next = &PatchRelease{
sched.Next = &PatchRelease{
Release: nextReleaseVersion.String(),
CherryPickDeadline: newCherryPickDeadline.Format(refDate),
TargetDate: newTargetDate.Format(refDate),
}

logrus.Infof("Adding release schedule: %+v", schedule.Next)
logrus.Infof("Adding release schedule: %+v", sched.Next)
}
}

newSchedules := []*Schedule{}
for i, sched := range schedule.Schedules {
appendItem := true
for _, k := range removeSchedules {
if i == k {
appendItem = false
break
}
}
if appendItem {
newSchedules = append(newSchedules, sched)
}
}
schedule.Schedules = newSchedules

newUpcomingReleases := []*PatchRelease{}
latestDate := refTime
for _, upcomingRelease := range schedule.UpcomingReleases {
Expand Down Expand Up @@ -275,6 +302,20 @@ func updatePatchSchedule(refTime time.Time, schedule PatchSchedule, filePath str
return fmt.Errorf("write schedule YAML: %w", err)
}

if eolFilePath != "" {
logrus.Infof("Writing end of life branches: %s", eolFilePath)

yamlBytes, err := yaml.Marshal(eolBranches)
if err != nil {
return fmt.Errorf("marshal end of life YAML: %w", err)
}

//nolint:gocritic,gosec
if err := os.WriteFile(eolFilePath, yamlBytes, 0o644); err != nil {
return fmt.Errorf("write end of life YAML: %w", err)
}
}

logrus.Infof("Wrote schedule YAML to: %v", filePath)
return nil
}
Expand Down
44 changes: 33 additions & 11 deletions cmd/schedule-builder/cmd/markdown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ func TestUpdatePatchSchedule(t *testing.T) {
name string
refTime time.Time
givenSchedule, expectedSchedule PatchSchedule
expectedEolBranches EolBranches
}{
{
name: "succeed to update the schedule",
Expand All @@ -368,6 +369,11 @@ func TestUpdatePatchSchedule(t *testing.T) {
{ // EOL
Release: "1.20",
EndOfLifeDate: "2023-01-01",
Next: &PatchRelease{
Release: "1.20.10",
CherryPickDeadline: "2023-12-08",
TargetDate: "2023-12-12",
},
},
},
UpcomingReleases: []*PatchRelease{
Expand Down Expand Up @@ -417,10 +423,6 @@ func TestUpdatePatchSchedule(t *testing.T) {
},
},
},
{
Release: "1.20",
EndOfLifeDate: "2023-01-01",
},
},
UpcomingReleases: []*PatchRelease{
{
Expand All @@ -440,21 +442,41 @@ func TestUpdatePatchSchedule(t *testing.T) {
},
},
},
expectedEolBranches: EolBranches{
Branches: []*EolBranch{
{
Release: "1.20",
FinalPatchRelease: "1.20.10",
EndOfLifeDate: "2023-12-12",
},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
file, err := os.CreateTemp("", "schedule-")
scheduleFile, err := os.CreateTemp("", "schedule-")
require.NoError(t, err)
require.NoError(t, scheduleFile.Close())

eolFile, err := os.CreateTemp("", "eol-")
require.NoError(t, err)
require.NoError(t, eolFile.Close())

require.NoError(t, updatePatchSchedule(tc.refTime, tc.givenSchedule, EolBranches{}, scheduleFile.Name(), eolFile.Name()))

scheduleYamlBytes, err := os.ReadFile(scheduleFile.Name())
require.NoError(t, err)
require.NoError(t, file.Close())
patchRes := PatchSchedule{}
require.NoError(t, yaml.UnmarshalStrict(scheduleYamlBytes, &patchRes))

require.NoError(t, updatePatchSchedule(tc.refTime, tc.givenSchedule, file.Name()))
assert.Equal(t, tc.expectedSchedule, patchRes)

yamlBytes, err := os.ReadFile(file.Name())
eolYamlBytes, err := os.ReadFile(eolFile.Name())
require.NoError(t, err)
res := PatchSchedule{}
require.NoError(t, yaml.UnmarshalStrict(yamlBytes, &res))
eolRes := EolBranches{}
require.NoError(t, yaml.UnmarshalStrict(eolYamlBytes, &eolRes))

assert.Equal(t, tc.expectedSchedule, res)
assert.Equal(t, tc.expectedEolBranches, eolRes)
})
}
}
13 changes: 13 additions & 0 deletions cmd/schedule-builder/cmd/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ type Schedule struct {
PreviousPatches []*PatchRelease `json:"previousPatches,omitempty" yaml:"previousPatches,omitempty"`
}

// EolBranches is main struct to hold the end of life branches.
type EolBranches struct {
Branches []*EolBranch `json:"branches,omitempty" yaml:"branches,omitempty"`
}

// EolBranch struct to define the end of life release branches.
type EolBranch struct {
Release string `json:"release,omitempty" yaml:"release,omitempty"`
FinalPatchRelease string `json:"finalPatchRelease,omitempty" yaml:"finalPatchRelease,omitempty"`
EndOfLifeDate string `json:"endOfLifeDate,omitempty" yaml:"endOfLifeDate,omitempty"`
Note string `json:"note,omitempty" yaml:"note,omitempty"`
}

type ReleaseSchedule struct {
Releases []Release `yaml:"releases"`
}
Expand Down
58 changes: 43 additions & 15 deletions cmd/schedule-builder/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,26 @@ var rootCmd = &cobra.Command{
}

type options struct {
configPath string
outputFile string
logLevel string
typeFile string
update bool
version bool
configPath string
eolConfigPath string
outputFile string
logLevel string
typeFile string
update bool
version bool
}

var opts = &options{}

const (
configPathFlag = "config-path"
outputFileFlag = "output-file"
typeFlag = "type"
updateFlag = "update"
versionFlag = "version"
typePatch = "patch"
typeRelease = "release"
configPathFlag = "config-path"
eolConfigPathFlag = "eol-config-path"
outputFileFlag = "output-file"
typeFlag = "type"
updateFlag = "update"
versionFlag = "version"
typePatch = "patch"
typeRelease = "release"
)

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

rootCmd.PersistentFlags().StringVarP(
&opts.eolConfigPath,
eolConfigPathFlag,
"e",
"",
"path where can find the eol.yaml file for updating end of life releases",
)

rootCmd.PersistentFlags().StringVarP(
&opts.outputFile,
outputFileFlag,
Expand Down Expand Up @@ -145,6 +155,7 @@ func run(opts *options) error {
var (
patchSchedule PatchSchedule
releaseSchedule ReleaseSchedule
eolBranches EolBranches
scheduleOut string
)

Expand All @@ -153,12 +164,29 @@ func run(opts *options) error {
switch opts.typeFile {
case typePatch:
if err := yaml.UnmarshalStrict(data, &patchSchedule); err != nil {
return fmt.Errorf("failed to decode the file: %w", err)
return fmt.Errorf("failed to decode patch schedule: %w", err)
}

if opts.eolConfigPath != "" {
data, err := os.ReadFile(opts.eolConfigPath)
if err != nil {
return fmt.Errorf("failed to read end of life config path: %w", err)
}

if err := yaml.UnmarshalStrict(data, &eolBranches); err != nil {
return fmt.Errorf("failed to decode end of life branches: %w", err)
}
}

if opts.update {
logrus.Info("Updating schedule")
if err := updatePatchSchedule(time.Now(), patchSchedule, opts.configPath); err != nil {
if err := updatePatchSchedule(
time.Now(),
patchSchedule,
eolBranches,
opts.configPath,
opts.eolConfigPath,
); err != nil {
return fmt.Errorf("update patch schedule: %w", err)
}
} else {
Expand Down