package gomod import ( "context" "fmt" "os" "os/exec" "regexp" "strings" "github.com/google/go-github/v53/github" "github.com/sirupsen/logrus" "golang.org/x/mod/modfile" ) const ( defaultVersion = "latest" ) var githubRegexp = regexp.MustCompile(`github.com/(.*?)/(.*)`) func upgrade(url string) (newUrl string, err error) { var version = defaultVersion if strings.Contains(url, "github.com") { commitID, err := getCommitID(url) if err != nil { logrus.WithField("url", url).Warnf("get github commit id failed, use default version: %v", err) } else { version = commitID } } if version == defaultVersion { v, err := lsRemote.setUrl(url).getLatestTagOrCommitID() if err != nil { logrus.WithField("url", url).Warnf("get git ls-remote info failed, use default version: %v", err) } else { version = v } } versionUrl := url + "@" + version cmd := exec.Command("go", "get", "-u", versionUrl) if _, err := cmd.CombinedOutput(); err != nil { return "", err } return versionUrl, nil } func AllModUpgrade() { modFileData, err := os.ReadFile("go.mod") if err != nil { logrus.Errorf("read go.mod file failed: %v", err) return } modFile, err := modfile.Parse("go.mod", modFileData, nil) if err != nil { logrus.Errorf("parse go.mod file failed: %v", err) return } for _, mod := range modFile.Require { if mod.Indirect { continue } versionUrl, err := upgrade(mod.Mod.Path) if err != nil { logrus.WithField("url", mod.Mod.Path).Errorf("upgrade failed: %v", err) continue } logrus.WithField("url", versionUrl).Infof("upgrade success") } } func SingleModUpgrade(url string) { versionUrl, err := upgrade(url) if err != nil { logrus.WithField("url", url).Errorf("upgrade failed: %v", err) return } logrus.WithField("url", versionUrl).Infof("upgrade success") } func parseUrl(url string) (owner, repo string) { res := githubRegexp.FindAllStringSubmatch(url, -1) if len(res) != 1 { logrus.Panicf(fmt.Sprintf("%s url no match github url rule: %s", url, githubRegexp.String())) } if len(res[0]) != 3 { logrus.Panicf(fmt.Sprintf("%s url no match github url rule: %s", url, githubRegexp.String())) } owner = res[0][1] repo = res[0][2] if repoA := strings.Split(repo, "/"); len(repoA) > 1 { repo = repoA[0] } return owner, repo } func getCommitID(url string) (string, error) { owner, repo := parseUrl(url) client := github.NewClient(nil) ctx := context.Background() tags, _, err := client.Repositories.ListTags(ctx, owner, repo, &github.ListOptions{ Page: 0, PerPage: 1, }) if err != nil { logrus.WithField("url", url).Warnf("get tag info failed: %v, start get commit id", err) } if len(tags) != 0 { return tags[0].GetName(), nil } // get latest commit id commits, _, err := client.Repositories.ListCommits(ctx, owner, repo, &github.CommitsListOptions{ ListOptions: github.ListOptions{ Page: 0, PerPage: 1, }, }) if err != nil { logrus.WithField("url", url).Errorf("get latest commit failed: %v", err) return "", err } if len(commits) == 0 { return "", fmt.Errorf("get commit info empty") } return *commits[0].SHA, nil }