diff --git a/git-ls-remote.go b/git-ls-remote.go new file mode 100644 index 0000000..f6a8b01 --- /dev/null +++ b/git-ls-remote.go @@ -0,0 +1,68 @@ +package gomod + +import ( + "fmt" + "os/exec" + "regexp" + "strings" +) + +var ( + lsRemote _lsRemote + + tagRegexp = regexp.MustCompile(`refs/tags/(.*)`) + headRegexp = regexp.MustCompile(`refs/heads/(master|main)`) +) + +type _lsRemote struct { + url string + output string +} + +func (lr *_lsRemote) setUrl(url string) *_lsRemote { + if !strings.HasPrefix(url, "https") { + url = "https://" + url + } + lr.url = url + return lr +} + +func (lr *_lsRemote) command() error { + cmd := exec.Command("git", "ls-remote", "--heads", "--tags", lr.url) + output, err := cmd.CombinedOutput() + if err != nil { + return err + } + lr.output = string(output) + return nil +} + +func (lr *_lsRemote) getLatestTagOrCommitID() (string, error) { + if err := lr.command(); err != nil { + return "", err + } + lr.output = strings.Trim(lr.output, "\n ") + commits := strings.Split(lr.output, "\n") + if len(commits) == 0 { + return "", fmt.Errorf("get commit log empty") + } + commit := commits[len(commits)-1] + + if strings.Contains(commit, "refs/heads/") { + matches := headRegexp.FindStringSubmatch(commit) + if len(matches) != 2 { + return "", fmt.Errorf("%s no match rule: %s", commit, headRegexp.String()) + } + return strings.Trim(strings.ReplaceAll(commit, matches[0], ""), " \n\t\r"), nil + } + + if strings.Contains(commit, "refs/tags/") { + matches := tagRegexp.FindStringSubmatch(commit) + if len(matches) != 2 { + return "", fmt.Errorf("%s no match rule: %s", commit, tagRegexp.String()) + } + return matches[1], nil + } + + return "", fmt.Errorf("%s no match heads and tags rule", commit) +} diff --git a/git-ls-remote_test.go b/git-ls-remote_test.go new file mode 100644 index 0000000..c99919c --- /dev/null +++ b/git-ls-remote_test.go @@ -0,0 +1,17 @@ +package gomod + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNormalUrlGetTag(t *testing.T) { + output, err := lsRemote.setUrl("https://gitter.top/coco/bootstrap").getLatestTagOrCommitID() + assert.NoError(t, err) + t.Log(output) + + output, err = lsRemote.setUrl("https://github.com/spf13/cobra").getLatestTagOrCommitID() + assert.NoError(t, err) + t.Log(output) +} diff --git a/go.mod b/go.mod index 0424902..378d90f 100644 --- a/go.mod +++ b/go.mod @@ -3,24 +3,28 @@ module gitter.top/apps/gomod go 1.20 require ( - github.com/google/go-github/v53 v53.0.0 + github.com/google/go-github/v53 v53.2.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 - gitter.top/common/lormatter v0.0.0-20230630185243-1bb8638cf785 + github.com/stretchr/testify v1.7.0 + gitter.top/common/lormatter v0.0.0-20230722045844-3f2987f9dd0e golang.org/x/mod v0.10.0 ) require ( github.com/ProtonMail/go-crypto v0.0.0-20230528122434-6f98819771a1 // indirect github.com/cloudflare/circl v1.3.3 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/crypto v0.7.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.9.0 // indirect + golang.org/x/sys v0.10.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8aa449d..7049973 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-github/v53 v53.0.0 h1:T1RyHbSnpHYnoF0ZYKiIPSgPtuJ8G6vgc0MKodXsQDQ= -github.com/google/go-github/v53 v53.0.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao= +github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI= +github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -39,8 +39,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -gitter.top/common/lormatter v0.0.0-20230630185243-1bb8638cf785 h1:hgeKDXRze6Cew4Wu/6PdNkTS/XYFeaNQNiT/Sjo4/Z4= -gitter.top/common/lormatter v0.0.0-20230630185243-1bb8638cf785/go.mod h1:/Zue/gLVDDSvCCRJKytEfpX0LP/JHkIeDzwVE5cA254= +gitter.top/common/lormatter v0.0.0-20230722045844-3f2987f9dd0e h1:R/PQxgliGNSKBKIXReaZWShyiPqUjwRbd+1j0+H7APo= +gitter.top/common/lormatter v0.0.0-20230722045844-3f2987f9dd0e/go.mod h1:/Zue/gLVDDSvCCRJKytEfpX0LP/JHkIeDzwVE5cA254= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -75,8 +75,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= diff --git a/gomod.go b/gomod.go index 5df8873..a745e30 100644 --- a/gomod.go +++ b/gomod.go @@ -3,24 +3,48 @@ package gomod import ( "context" "fmt" - "github.com/sirupsen/logrus" "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 command(url string) error { - cmd := exec.Command("go", "get", "-u", url) - if _, err := cmd.CombinedOutput(); err != nil { - return err +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 + } } - return nil + + 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() { @@ -34,33 +58,26 @@ func AllModUpgrade() { logrus.Errorf("parse go.mod file failed: %v", err) return } - for _, mod := range modFile.Require { if mod.Indirect { continue } - logrus.Infof("go get -u %s", mod.Mod.String()) - if err := command(mod.Mod.String()); err != nil { - logrus.Errorf("upgrade %s failed: %v", mod.Mod.String(), err) + versionUrl, err := upgrade(mod.Mod.String()) + if err != nil { + logrus.WithField("url", mod.Mod.String()).Errorf("upgrade failed: %v", err) continue } - logrus.Infof("upgrade %s success", mod.Mod.String()) + logrus.WithField("url", versionUrl).Infof("upgrade success") } } func SingleModUpgrade(url string) { - version := url + "@latest" - if strings.Contains(url, "github.com") { - commitID, err := getCommitID(url) - if err == nil { - version = url + "@" + commitID[:8] - } - } - if err := command(version); err != nil { - logrus.Errorf("upgrade %s failed: %v", version, err) + versionUrl, err := upgrade(url) + if err != nil { + logrus.WithField("url", url).Errorf("upgrade failed: %v", err) return } - logrus.Infof("upgrade %s success", version) + logrus.WithField("url", versionUrl).Infof("upgrade success") } func parseUrl(url string) (owner, repo string) { @@ -82,9 +99,13 @@ func getCommitID(url string) (string, error) { Page: 0, PerPage: 1, }) - if len(tags) == 0 && err != nil { - logrus.Warnf("get tag info failed: %v, start get commit id", err) + 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, @@ -92,6 +113,7 @@ func getCommitID(url string) (string, error) { }, }) if err != nil { + logrus.WithField("url", url).Errorf("get latest commit failed: %v", err) return "", err } if len(commits) == 0 { diff --git a/gomod_test.go b/gomod_test.go new file mode 100644 index 0000000..f1aade5 --- /dev/null +++ b/gomod_test.go @@ -0,0 +1,13 @@ +package gomod + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetTag(t *testing.T) { + value, err := getCommitID("https://github.com/spf13/cobra") + assert.NoError(t, err) + t.Log(value) +}