From 694c357005621a586cc689bfe1adef4af4a2da7b Mon Sep 17 00:00:00 2001 From: debasishbsws Date: Mon, 27 May 2024 00:35:29 +0530 Subject: [PATCH] add gitlab update Signed-off-by: debasishbsws --- go.mod | 1 + go.sum | 2 + pkg/update/gitlabRelease.go | 215 ++++++++++++++++++++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 pkg/update/gitlabRelease.go diff --git a/go.mod b/go.mod index 125a6950..90013661 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/texttheater/golang-levenshtein/levenshtein v0.0.0-20200805054039-cae8b0eaed6c github.com/tmc/dot v0.0.0-20210901225022-f9bc17da75c0 + github.com/xanzy/go-gitlab v0.105.0 go.lsp.dev/uri v0.3.0 go.opentelemetry.io/otel v1.27.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.27.0 diff --git a/go.sum b/go.sum index 553c7c44..400b70d8 100644 --- a/go.sum +++ b/go.sum @@ -1150,6 +1150,8 @@ github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIq github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20= github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 h1:0KGbf+0SMg+UFy4e1A/CPVvXn21f1qtWdeJwxZFoQG8= github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA= +github.com/xanzy/go-gitlab v0.105.0 h1:3nyLq0ESez0crcaM19o5S//SvezOQguuIHZ3wgX64hM= +github.com/xanzy/go-gitlab v0.105.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= diff --git a/pkg/update/gitlabRelease.go b/pkg/update/gitlabRelease.go new file mode 100644 index 00000000..191dbe60 --- /dev/null +++ b/pkg/update/gitlabRelease.go @@ -0,0 +1,215 @@ +package update + +import ( + "errors" + "fmt" + "log" + "os" + "regexp" + "strings" + + "chainguard.dev/melange/pkg/config" + "github.com/wolfi-dev/wolfictl/pkg/melange" + "github.com/xanzy/go-gitlab" +) + +const ( + gitlabBaseURL = "https://gitlab.com" +) + +type GitLabReleaseOptions struct { + PackageConfigs map[string]*melange.Packages + gitlabClient *gitlab.Client + Logger *log.Logger + + ErrorMessages map[string]string +} +type VersionComit struct { + Version string + Commit string +} + +func NewGitlabReleaseOptions(packageConfigs map[string]*melange.Packages) GitLabReleaseOptions { + + token := os.Getenv("GITLAB_TOKEN") + if token == "" { + log.Fatalf("GITLAB_TOKEN environment variable not set") + } + + client, err := gitlab.NewClient(token, gitlab.WithBaseURL(gitlabBaseURL)) + if err != nil { + log.Fatalf("Failed to create gitlab client: %v", err) + } + + o := GitLabReleaseOptions{ + PackageConfigs: packageConfigs, + gitlabClient: client, + Logger: log.New(log.Writer(), "wolfictl check update: ", log.LstdFlags|log.Lmsgprefix), + ErrorMessages: make(map[string]string), + } + + return o +} + +func (o GitLabReleaseOptions) getLatestGitLabVersions() (map[string]NewVersionResults, map[string]string, error) { + if len(o.PackageConfigs) == 0 { + return nil, o.ErrorMessages, errors.New("No package configs provided") + } + + releaseRepoList, tagRepoList := o.getSeparateRepoLists() + + latestVersionResults := make(map[string]NewVersionResults) + + if len(releaseRepoList) > 0 { + o.Logger.Println("Checking for latest new releases") + for packageName, identifier := range releaseRepoList { + o.Logger.Printf("Checking for latest release on %s using identifier %s\n", packageName, identifier) + listReleaseOption := &gitlab.ListReleasesOptions{ + ListOptions: gitlab.ListOptions{ + PerPage: 20, + Page: 1, + }, + } + releases, resp, err := o.gitlabClient.Releases.ListReleases(identifier, listReleaseOption) + if err != nil || resp.StatusCode != 200 { + o.ErrorMessages[packageName] = fmt.Sprintf("Failed to list releases for %s: %v", packageName, err) + continue + } + if len(releases) == 0 { + o.ErrorMessages[packageName] = fmt.Sprintf("No releases found for %s", packageName) + continue + } + + // filter out releases that match the ignore regex patterns and other filters + allReleaseList := []VersionComit{} + for _, release := range releases { + allReleaseList = append(allReleaseList, VersionComit{ + Version: release.TagName, + Commit: release.Commit.ID, + }) + } + properVersionList, err := prepareVersion(allReleaseList, &o.PackageConfigs[packageName].Config) + if err != nil { + o.ErrorMessages[packageName] = fmt.Sprintf("Failed to prepare version for %s: %v", packageName, err) + continue + } + if len(properVersionList) > 0 { + latestVersionResults[packageName] = NewVersionResults{ + Version: properVersionList[0].Version, + Commit: properVersionList[0].Commit, + } + } + } + } + + if len(tagRepoList) > 0 { + o.Logger.Println("Checking for latest new tags") + listTagsOption := &gitlab.ListTagsOptions{ + ListOptions: gitlab.ListOptions{ + PerPage: 50, + Page: 1, + OrderBy: "version", + }, + } + for packageName, identifier := range tagRepoList { + o.Logger.Printf("Checking for latest tag on %s using projectID %s\n", packageName, identifier) + tags, resp, err := o.gitlabClient.Tags.ListTags(identifier, listTagsOption) + if err != nil || resp.StatusCode != 200 { + o.ErrorMessages[packageName] = fmt.Sprintf("Failed to list tags for %s: %v", packageName, err) + continue + } + if len(tags) == 0 { + o.ErrorMessages[packageName] = fmt.Sprintf("No tags found for %s", packageName) + continue + } + + // filter out releases that match the ignore regex patterns and other filters + allTagsList := []VersionComit{} + for _, tag := range tags { + allTagsList = append(allTagsList, VersionComit{ + Version: tag.Name, + Commit: tag.Commit.ID, + }) + } + properVersionList, err := prepareVersion(allTagsList, &o.PackageConfigs[packageName].Config) + if err != nil { + o.ErrorMessages[packageName] = fmt.Sprintf("Failed to prepare version for %s: %v", packageName, err) + continue + } + if len(properVersionList) > 0 { + latestVersionResults[packageName] = NewVersionResults{ + Version: properVersionList[0].Version, + Commit: properVersionList[0].Commit, + } + } + } + } + + return latestVersionResults, o.ErrorMessages, nil +} + +func prepareVersion(versionList []VersionComit, packageConfig *config.Configuration) ([]VersionComit, error) { + properVersionList := []VersionComit{} + if len(versionList) == 0 { + return properVersionList, errors.New("No versions found, empty list") + } + + glm := packageConfig.Update.GitLabMonitor + if glm == nil { + return properVersionList, errors.New("No GitLab update configuration found for package") + } + + for _, vc := range versionList { + if len(packageConfig.Update.IgnoreRegexPatterns) > 0 { + for _, pattern := range packageConfig.Update.IgnoreRegexPatterns { + regex, err := regexp.Compile(pattern) + if err != nil { + return properVersionList, fmt.Errorf("Failed to compile regex %s", pattern) + } + if regex.MatchString(vc.Version) { + continue + } + } + } + if glm.TagFilterPrefix != "" { + if !strings.HasPrefix(vc.Version, glm.TagFilterPrefix) { + continue + } + } + if glm.TagFilterContains != "" { + if !strings.Contains(vc.Version, glm.TagFilterContains) { + continue + } + } + + version := vc.Version + if glm.StripPrefix != "" { + version = strings.TrimPrefix(version, glm.StripPrefix) + } + if glm.StripSuffix != "" { + version = strings.TrimSuffix(version, glm.StripSuffix) + } + properVersionList = append(properVersionList, VersionComit{ + Version: version, + Commit: vc.Commit, + }) + } + + return properVersionList, nil +} +func (o GitLabReleaseOptions) getSeparateRepoLists() (releaseRepoList, tagRepoList map[string]string) { + tagRepoList = make(map[string]string) + releaseRepoList = make(map[string]string) + for _, pc := range o.PackageConfigs { + if monitor := pc.Config.Update.GitLabMonitor; monitor != nil { + identifire := monitor.Identifier + if monitor.UseTags { + tagRepoList[pc.Config.Package.Name] = identifire + } else { + releaseRepoList[pc.Config.Package.Name] = identifire + } + } + } + + return releaseRepoList, tagRepoList +}