forked from k8sgateway/k8sgateway
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathupgrade_utils.go
93 lines (83 loc) · 3.9 KB
/
upgrade_utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package upgrade
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/google/go-github/v32/github"
errors "github.com/rotisserie/eris"
"github.com/solo-io/gloo/test/testutils/version"
"github.com/solo-io/go-utils/changelogutils"
"github.com/solo-io/go-utils/githubutils"
"github.com/solo-io/go-utils/versionutils"
"github.com/solo-io/skv2/codegen/util"
)
// GetUpgradeVersions returns two semantic versions of a repository:
// - prevLtsRelease: the latest patch release of v1.m-1.x
// - latestRelease: the latest patch release of v1.m.x
//
// Originally intended for use in upgrade testing, it can return any of:
// - (prevLtsRelease, latestRelease, nil): all release versions computable
// - (prevLtsRelease, nil, nil): only prevLtsRelease computable (ie current branch has never been released)
// - (nil, nil, err): unable to fetch versions for upgrade test
func GetUpgradeVersions(ctx context.Context, repoName string) (*versionutils.Version, *versionutils.Version, error) {
// get the latest and upcoming releases of the current branch
files, changelogReadErr := os.ReadDir(filepath.Join(util.GetModuleRoot(), changelogutils.ChangelogDirectory))
if changelogReadErr != nil {
return nil, nil, changelogutils.ReadChangelogDirError(changelogReadErr)
}
latestRelease, upcomingRelease, upcomingReleaseErr := version.ChangelogDirForLatestRelease(files...)
if upcomingReleaseErr != nil && !errors.Is(upcomingReleaseErr, version.FirstReleaseError) {
return nil, nil, upcomingReleaseErr
}
// get latest release of previous LTS branch
// TODO(nfuden): Update goutils to not use a struct but rather interface so we can test this more easily.
client, githubClientErr := githubutils.GetClient(ctx)
if githubClientErr != nil {
return nil, nil, errors.Wrapf(githubClientErr, "unable to create github client")
}
prevLtsRelease, prevLtsReleaseErr := getLatestReleasedPatchVersion(ctx, client, repoName, upcomingRelease.Major, upcomingRelease.Minor-1)
if prevLtsReleaseErr != nil {
return nil, nil, prevLtsReleaseErr
}
if upcomingReleaseErr != nil {
// if we don't yet have a release for the current branch, we can only upgrade from prevLtsRelease
return prevLtsRelease, nil, nil
} else {
// otherwise, we can upgrade from both prevLtsRelease -and- latestRelease
return prevLtsRelease, latestRelease, nil
}
}
type latestPatchForMinorPredicate struct {
versionPrefix string
}
func (s *latestPatchForMinorPredicate) Apply(release *github.RepositoryRelease) bool {
return strings.HasPrefix(*release.Name, s.versionPrefix) &&
!release.GetPrerelease() && // we don't want a prerelease version
!strings.Contains(release.GetBody(), "This release build failed") && // we don't want a failed build
release.GetPublishedAt().Before(time.Now().In(time.UTC).Add(time.Duration(-60)*time.Minute))
}
func newLatestPatchForMinorPredicate(versionPrefix string) *latestPatchForMinorPredicate {
return &latestPatchForMinorPredicate{
versionPrefix: versionPrefix,
}
}
// getLatestReleasedPatchVersion will return the latest released patch version for the given major and minor version
// NOTE: this attempts to reach out to github to get the latest release
func getLatestReleasedPatchVersion(ctx context.Context, client *github.Client, repoName string, majorVersion, minorVersion int) (*versionutils.Version, error) {
versionPrefix := fmt.Sprintf("v%d.%d", majorVersion, minorVersion)
releases, err := githubutils.GetRepoReleasesWithPredicateAndMax(ctx, client, "solo-io", repoName, newLatestPatchForMinorPredicate(versionPrefix), 1)
if err != nil {
return nil, errors.Wrap(err, "unable to get releases")
}
if len(releases) == 0 {
return nil, errors.Errorf("Could not find a recent release with version prefix: %s", versionPrefix)
}
v, err := versionutils.ParseVersion(*releases[0].Name)
if err != nil {
return nil, errors.Wrapf(err, "error parsing release name")
}
return v, nil
}