From 6eaf515e91227675f46a63967211e7b7b1d99488 Mon Sep 17 00:00:00 2001 From: Son Luong Ngoc Date: Fri, 5 Jul 2024 20:08:23 +0200 Subject: [PATCH] update-repos: add -parse_only flag --- cmd/gazelle/update-repos.go | 11 +- language/go/modules.go | 98 ++++++++ language/go/update.go | 3 + language/go/update_import_test.go | 374 ++++++++++++++++++++++++++++++ language/update.go | 4 + 5 files changed, 486 insertions(+), 4 deletions(-) diff --git a/cmd/gazelle/update-repos.go b/cmd/gazelle/update-repos.go index 9d33977a1..6f1ef6613 100644 --- a/cmd/gazelle/update-repos.go +++ b/cmd/gazelle/update-repos.go @@ -40,6 +40,7 @@ type updateReposConfig struct { macroFileName string macroDefName string pruneRules bool + parseOnly bool workspace *rule.File repoFileMap map[string]*rule.File } @@ -80,6 +81,7 @@ func (*updateReposConfigurer) RegisterFlags(fs *flag.FlagSet, cmd string, c *con fs.StringVar(&uc.repoFilePath, "from_file", "", "Gazelle will translate repositories listed in this file into repository rules in WORKSPACE or a .bzl macro function. Gopkg.lock and go.mod files are supported") fs.Var(macroFlag{macroFileName: &uc.macroFileName, macroDefName: &uc.macroDefName}, "to_macro", "Tells Gazelle to write repository rules into a .bzl macro function rather than the WORKSPACE file. . The expected format is: macroFile%defName") fs.BoolVar(&uc.pruneRules, "prune", false, "When enabled, Gazelle will remove rules that no longer have equivalent repos in the go.mod file. Can only used with -from_file.") + fs.BoolVar(&uc.parseOnly, "parse_only", false, "When enabled, Gazelle will derive the repository rules from parsing the given config file (i.e. go.mod) and lock file (i.e. go.sum) without making any additional network calls.") } func (*updateReposConfigurer) CheckFlags(fs *flag.FlagSet, c *config.Config) error { @@ -425,10 +427,11 @@ func importRepos(c *config.Config, rc *repo.RemoteCache) (gen, empty []*rule.Rul } } res := importer.ImportRepos(language.ImportReposArgs{ - Config: c, - Path: uc.repoFilePath, - Prune: uc.pruneRules, - Cache: rc, + Config: c, + Path: uc.repoFilePath, + Prune: uc.pruneRules, + ParseOnly: uc.parseOnly, + Cache: rc, }) return res.Gen, res.Empty, res.Error } diff --git a/language/go/modules.go b/language/go/modules.go index 828cb8da7..7ed24aa4b 100644 --- a/language/go/modules.go +++ b/language/go/modules.go @@ -16,6 +16,7 @@ limitations under the License. package golang import ( + "bufio" "bytes" "fmt" "os" @@ -23,9 +24,106 @@ import ( "strings" "github.com/bazelbuild/bazel-gazelle/language" + "golang.org/x/mod/modfile" + "golang.org/x/mod/module" + "golang.org/x/tools/go/packages" ) +func importReposFromParse(args language.ImportReposArgs) language.ImportReposResult { + // Parse go.sum for checksum + checksumIdx := make(map[string]string) + goSumPath := filepath.Join(filepath.Dir(args.Path), "go.sum") + goSumFile, err := os.Open(goSumPath) + if err != nil { + return language.ImportReposResult{ + Error: fmt.Errorf("failed to open go.sum file at %s: %v", goSumPath, err), + } + } + scanner := bufio.NewScanner(goSumFile) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + fields := strings.Fields(line) + if len(fields) != 3 { + continue + } + path, version, sum := fields[0], fields[1], fields[2] + if strings.HasSuffix(version, "/go.mod") { + continue + } + checksumIdx[path+"@"+version] = sum + } + if scanner.Err() != nil { + return language.ImportReposResult{ + Error: fmt.Errorf("failed to parse go.sum file at %s: %v", goSumPath, scanner.Err()), + } + } + + // Parse go.mod for modules information + b, err := os.ReadFile(args.Path) + if err != nil { + return language.ImportReposResult{ + Error: fmt.Errorf("failed to read go.mod file at %s: %v", args.Path, err), + } + } + modFile, err := modfile.Parse(filepath.Base(args.Path), b, nil) + if err != nil { + return language.ImportReposResult{ + Error: fmt.Errorf("failed to parse go.mod file at %s: %v", args.Path, err), + } + } + + // Build an index of 'replace' directives + replaceIdx := make(map[string]module.Version, len(modFile.Replace)) + for _, replace := range modFile.Replace { + replaceIdx[replace.Old.String()] = replace.New + } + + pathToModule := make(map[string]*moduleFromList, len(modFile.Require)) + for _, require := range modFile.Require { + modKey := require.Mod.String() + pathToModule[modKey] = &moduleFromList{ + Module: packages.Module{ + Path: require.Mod.Path, + Version: require.Mod.Version, + }, + } + + // If there is a match replacement, add .Replace and change .Sum to the checksum of the new module + replace, foundReplace := replaceIdx[modKey] + if !foundReplace { + replace, foundReplace = replaceIdx[require.Mod.Path] + } + if foundReplace { + replaceChecksum, foundReplaceChecksum := checksumIdx[replace.String()] + if !foundReplaceChecksum { + return language.ImportReposResult{ + Error: fmt.Errorf("module %s is missing from go.sum. Run 'go mod tidy' to fix.", replace.String()), + } + } + pathToModule[modKey].Replace = &packages.Module{ + Path: replace.Path, + Version: replace.Version, + } + pathToModule[modKey].Sum = replaceChecksum + continue + } + + checksum, ok := checksumIdx[modKey] + if !ok { + return language.ImportReposResult{ + Error: fmt.Errorf("module %s is missing from go.sum. Run 'go mod tidy' to fix.", modKey), + } + } + pathToModule[modKey].Sum = checksum + } + + return language.ImportReposResult{Gen: toRepositoryRules(pathToModule)} +} + func importReposFromModules(args language.ImportReposArgs) language.ImportReposResult { + if args.ParseOnly { + return importReposFromParse(args) + } // run go list in the dir where go.mod is located data, err := goListModules(filepath.Dir(args.Path)) if err != nil { diff --git a/language/go/update.go b/language/go/update.go index d1be928f4..23280c5b9 100644 --- a/language/go/update.go +++ b/language/go/update.go @@ -69,6 +69,9 @@ func (*goLang) CanImport(path string) bool { func (*goLang) ImportRepos(args language.ImportReposArgs) language.ImportReposResult { res := repoImportFuncs[filepath.Base(args.Path)](args) + if res.Error != nil { + return res + } for _, r := range res.Gen { setBuildAttrs(getGoConfig(args.Config), r) } diff --git a/language/go/update_import_test.go b/language/go/update_import_test.go index 86ac4d7b6..4db42ceb5 100644 --- a/language/go/update_import_test.go +++ b/language/go/update_import_test.go @@ -645,3 +645,377 @@ go_repository( }) } } + +func TestImportsParseOnly(t *testing.T) { + for _, tc := range []struct { + desc string + want string + wantErr string + files []testtools.FileSpec + }{ + { + desc: "base_case", + files: []testtools.FileSpec{ + { + Path: "go.mod", + Content: ` +module foo + +go 1.22.5 + +require github.com/BurntSushi/toml v0.3.1`, + }, + { + Path: "go.sum", + Content: ` +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=`, + }, + { + Path: "main.go", + Content: ` +package main + +import ( + _ "github.com/BurntSushi/toml" +)`, + }, + }, + want: ` +go_repository( + name = "com_github_burntsushi_toml", + importpath = "github.com/BurntSushi/toml", + sum = "h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=", + version = "v0.3.1", +)`, + }, + { + desc: "with_replace", + files: []testtools.FileSpec{ + { + Path: "go.mod", + Content: ` +module foo + +go 1.22.5 + +replace github.com/throttled/throttled/v2 => github.com/buildbuddy-io/throttled/v2 v2.9.1-rc2 + +require github.com/throttled/throttled/v2 v2.12.0 + +require github.com/stretchr/testify v1.8.0 // indirect`, + }, + { + Path: "go.sum", + Content: ` +github.com/buildbuddy-io/throttled/v2 v2.9.1-rc2 h1:l9PGL9DJwcCgQcVt/zFzVjJbSzb+BmpU8NBeo6leHKU= +github.com/buildbuddy-io/throttled/v2 v2.9.1-rc2/go.mod h1:LSVJkC18NVPon/lADUB4AabAylh2dnsZbk4SkMCk4KQ= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-redis/redis/v8 v8.4.2/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= +github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=`, + }, + { + Path: "main.go", + Content: ` +package main + +import ( + _ "github.com/throttled/throttled/v2" +)`, + }, + }, + want: ` +go_repository( + name = "com_github_stretchr_testify", + importpath = "github.com/stretchr/testify", + sum = "h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=", + version = "v1.8.0", +) + +go_repository( + name = "com_github_throttled_throttled_v2", + importpath = "github.com/throttled/throttled/v2", + replace = "github.com/buildbuddy-io/throttled/v2", + sum = "h1:l9PGL9DJwcCgQcVt/zFzVjJbSzb+BmpU8NBeo6leHKU=", + version = "v2.9.1-rc2", +)`, + }, + { + desc: "with_version_in_replace", + files: []testtools.FileSpec{ + { + Path: "go.mod", + Content: ` +module foo + +go 1.22.5 + +replace github.com/crewjam/saml v0.4.14 => github.com/grafana/saml v0.4.15-0.20240523142256-cc370b98af7c + +require github.com/crewjam/saml v0.4.14 + +require ( + github.com/beevik/etree v1.2.0 // indirect + github.com/jonboulle/clockwork v0.2.2 // indirect + github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect + github.com/russellhaering/goxmldsig v1.4.0 // indirect + golang.org/x/crypto v0.14.0 // indirect +)`, + }, + { + Path: "go.sum", + Content: ` +github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= +github.com/beevik/etree v1.2.0 h1:l7WETslUG/T+xOPs47dtd6jov2Ii/8/OjCldk5fYfQw= +github.com/beevik/etree v1.2.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/grafana/saml v0.4.15-0.20240523142256-cc370b98af7c h1:SWmG1QLZ36Ay0htq4Wt3dzlNIhWvQ3GUf7mk19dR8nI= +github.com/grafana/saml v0.4.15-0.20240523142256-cc370b98af7c/go.mod h1:S4+611dxnKt8z/ulbvaJzcgSHsuhjVc1QHNTcr1R7Fw= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= +github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= +github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=`, + }, + { + Path: "main.go", + Content: ` +package main + +import ( + _ "github.com/crewjam/saml" +)`, + }, + }, + want: ` +go_repository( + name = "com_github_beevik_etree", + importpath = "github.com/beevik/etree", + sum = "h1:l7WETslUG/T+xOPs47dtd6jov2Ii/8/OjCldk5fYfQw=", + version = "v1.2.0", +) + +go_repository( + name = "com_github_crewjam_saml", + importpath = "github.com/crewjam/saml", + replace = "github.com/grafana/saml", + sum = "h1:SWmG1QLZ36Ay0htq4Wt3dzlNIhWvQ3GUf7mk19dR8nI=", + version = "v0.4.15-0.20240523142256-cc370b98af7c", +) + +go_repository( + name = "com_github_jonboulle_clockwork", + importpath = "github.com/jonboulle/clockwork", + sum = "h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=", + version = "v0.2.2", +) + +go_repository( + name = "com_github_mattermost_xml_roundtrip_validator", + importpath = "github.com/mattermost/xml-roundtrip-validator", + sum = "h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=", + version = "v0.1.0", +) + +go_repository( + name = "com_github_russellhaering_goxmldsig", + importpath = "github.com/russellhaering/goxmldsig", + sum = "h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys=", + version = "v1.4.0", +) + +go_repository( + name = "org_golang_x_crypto", + importpath = "golang.org/x/crypto", + sum = "h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=", + version = "v0.14.0", +)`, + }, + { + desc: "missing_sum", + files: []testtools.FileSpec{ + { + Path: "go.mod", + Content: ` +module foo + +go 1.22.5 + +require github.com/BurntSushi/toml v0.3.1`, + }, + { + Path: "go.sum", + Content: ``, + }, + { + Path: "main.go", + Content: ` +package main + +import ( + _ "github.com/BurntSushi/toml" +)`, + }, + }, + wantErr: "module github.com/BurntSushi/toml@v0.3.1 is missing from go.sum. Run 'go mod tidy' to fix.", + }, + } { + t.Run(tc.desc, func(t *testing.T) { + dir, cleanup := testtools.CreateFiles(t, tc.files) + defer cleanup() + filename := filepath.Join(dir, tc.files[0].Path) + c := &config.Config{Exts: map[string]interface{}{}} + rc, rcCleanup := repo.NewRemoteCache(nil) + defer func() { + if err := rcCleanup(); err != nil { + t.Fatal(err) + } + }() + gl := NewLanguage() + gl.Configure(c, "", nil) + importer := gl.(language.RepoImporter) + result := importer.ImportRepos(language.ImportReposArgs{ + Config: c, + Path: filename, + ParseOnly: true, + Cache: rc, + }) + if tc.wantErr != "" { + if result.Error == nil { + t.Fatalf("Want error %v but got %v", tc.wantErr, result) + } + if result.Error.Error() != tc.wantErr { + t.Fatalf("Want error %v but got %v", tc.wantErr, result.Error) + } + return + } + if result.Error != nil { + t.Fatal(result.Error) + } + f := rule.EmptyFile("test", "") + for _, r := range result.Gen { + r.Insert(f) + } + got := strings.TrimSpace(string(f.Format())) + want := strings.TrimSpace(tc.want) + if got != want { + t.Errorf("got:\n%s\n\nwant:\n%s\n", got, want) + } + }) + } +} diff --git a/language/update.go b/language/update.go index cebf73a27..3b588fdf2 100644 --- a/language/update.go +++ b/language/update.go @@ -97,6 +97,10 @@ type ImportReposArgs struct { // filled in. Prune bool + // Solely rely on config file (and coupled lock file) to generate + // repository rules without making any additional network calls. + ParseOnly bool + // Cache stores information fetched from the network and ensures that // the same request isn't made multiple times. Cache *repo.RemoteCache