From 470287397571f59f14bdd0f4107bdd2926a08c1e Mon Sep 17 00:00:00 2001 From: Rogee Date: Thu, 19 Dec 2024 17:34:12 +0800 Subject: [PATCH] feat: add gen_provider.go and gomod package --- cmd/gen.go | 1 + cmd/gen_enum.go | 3 +- cmd/gen_provider.go | 436 ++++++++++++++++++++++++++++++++++++ go.mod | 7 +- go.sum | 10 + pkg/utils/gomod/mod.go | 142 ++++++++++++ pkg/utils/gomod/mod_test.go | 32 +++ 7 files changed, 629 insertions(+), 2 deletions(-) create mode 100644 cmd/gen_provider.go create mode 100644 pkg/utils/gomod/mod.go create mode 100644 pkg/utils/gomod/mod_test.go diff --git a/cmd/gen.go b/cmd/gen.go index b4d7c31..633a652 100644 --- a/cmd/gen.go +++ b/cmd/gen.go @@ -10,6 +10,7 @@ func CommandGen(root *cobra.Command) { cmd.PersistentFlags().StringP("config", "c", "config.toml", "database config file") cmds := []func(*cobra.Command){ + CommandGenProvider, CommandGenModel, CommandGenEnum, } diff --git a/cmd/gen_enum.go b/cmd/gen_enum.go index 837bce1..6cf3fcf 100644 --- a/cmd/gen_enum.go +++ b/cmd/gen_enum.go @@ -44,7 +44,8 @@ func commandGenEnumE(cmd *cobra.Command, args []string) error { return nil } - content, err := os.ReadFile(path) + var content []byte + content, err = os.ReadFile(path) if err != nil { return err } diff --git a/cmd/gen_provider.go b/cmd/gen_provider.go new file mode 100644 index 0000000..3b304b1 --- /dev/null +++ b/cmd/gen_provider.go @@ -0,0 +1,436 @@ +package cmd + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "io/fs" + "math/rand" + "os" + "path/filepath" + "strings" + "text/template" + + "git.ipao.vip/rogeecn/atomctl/pkg/utils/gomod" + "github.com/samber/lo" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "golang.org/x/tools/imports" +) + +func getTypePkgName(typ string) string { + if strings.Contains(typ, ".") { + return strings.Split(typ, ".")[0] + } + return "" +} + +func CommandGenProvider(root *cobra.Command) { + cmd := &cobra.Command{ + Use: "provider", + Short: "Generate providers", + Long: ` +// @provider +// @provider:[except|only] [returnType] [group] +// when except add tag: inject:"false" +// when only add tag: inject:"true" + `, + RunE: commandGenProviderE, + } + + root.AddCommand(cmd) +} + +var scalarTypes = []string{ + "float32", + "float64", + "int", + "int8", + "int16", + "int32", + "int64", + "uint", + "uint8", + "uint16", + "uint32", + "uint64", + "bool", + "uintptr", + "complex64", + "complex128", +} + +func commandGenProviderE(cmd *cobra.Command, args []string) error { + var err error + var path string + if len(args) > 0 { + path = args[0] + } else { + path, err = os.Getwd() + if err != nil { + return err + } + } + + path, _ = filepath.Abs(path) + + err = gomod.Parse(filepath.Join(path, "go.mod")) + if err != nil { + return err + } + + providers := []Provider{} + + // if path is file, then get the dir + log.Infof("generate providers for dir: %s", path) + // travel controller to find all controller objects + _ = filepath.WalkDir(path, func(filepath string, d fs.DirEntry, err error) error { + if d.IsDir() { + return nil + } + + if !strings.HasSuffix(filepath, ".go") { + return nil + } + + if strings.HasSuffix(filepath, "_test.go") { + return nil + } + + providers = append(providers, astParseProviders(filepath)...) + return nil + }) + + // generate files + groups := lo.GroupBy(providers, func(item Provider) string { + return item.ProviderFile + }) + + for file, conf := range groups { + if err := renderFile(file, conf); err != nil { + return err + } + } + return nil +} + +type InjectParam struct { + Star string + Type string + Package string + PackageAlias string +} +type Provider struct { + StructName string + ReturnType string + ProviderGroup string + NeedPrepareFunc bool + InjectParams map[string]InjectParam + Imports map[string]string + PkgName string + ProviderFile string +} + +func astParseProviders(source string) []Provider { + if strings.HasSuffix(source, "_test.go") { + return []Provider{} + } + + if strings.HasSuffix(source, "/provider.go") { + return []Provider{} + } + + providers := []Provider{} + + fset := token.NewFileSet() + node, err := parser.ParseFile(fset, source, nil, parser.ParseComments) + if err != nil { + log.Error("ERR: ", err) + return nil + } + imports := make(map[string]string) + for _, imp := range node.Imports { + name := "" + pkgPath := strings.Trim(imp.Path.Value, "\"") + + if imp.Name != nil { + // 如果有显式指定包名,直接使用 + name = imp.Name.Name + } else { + // 尝试从go.mod中获取真实包名 + name = gomod.GetPackageModuleName(pkgPath) + } + + // 处理匿名导入的情况 + if name == "_" { + name = gomod.GetPackageModuleName(pkgPath) + + // 处理重名 + if _, ok := imports[name]; ok { + name = fmt.Sprintf("%s%d", name, rand.Intn(100)) + } + } + + imports[name] = pkgPath + } + + // 再去遍历 struct 的方法去 + for _, decl := range node.Decls { + provider := Provider{ + InjectParams: make(map[string]InjectParam), + Imports: make(map[string]string), + } + + decl, ok := decl.(*ast.GenDecl) + if !ok { + continue + } + + if len(decl.Specs) == 0 { + continue + } + + declType, ok := decl.Specs[0].(*ast.TypeSpec) + if !ok { + continue + } + + // 必须包含注释 // @provider:only/except + if decl.Doc == nil { + continue + } + + if len(decl.Doc.List) == 0 { + continue + } + + structType, ok := declType.Type.(*ast.StructType) + if !ok { + continue + } + provider.StructName = declType.Name.Name + + docMark := strings.TrimLeft(decl.Doc.List[len(decl.Doc.List)-1].Text, "/ \t") + if !strings.HasPrefix(docMark, "@provider") { + continue + } + mode, returnType, group := parseDoc(docMark) + if group != "" { + provider.ProviderGroup = group + } + // log.Infof("mode: %s, returnType: %s, group: %s", mode, returnType, group) + + if returnType == "#" { + provider.ReturnType = "*" + provider.StructName + } else { + provider.ReturnType = returnType + } + onlyMode := mode == "only" + exceptMode := mode == "except" + log.Infof("[%s] %s => ONLY: %+v, EXCEPT: %+v, Type: %s, Group: %s", source, declType.Name.Name, onlyMode, exceptMode, provider.ReturnType, provider.ProviderGroup) + + for _, field := range structType.Fields.List { + if field.Names == nil { + continue + } + + if field.Tag != nil { + provider.NeedPrepareFunc = true + } + + if onlyMode { + if field.Tag == nil || !strings.Contains(field.Tag.Value, `inject:"true"`) { + continue + } + } + + if exceptMode { + if field.Tag != nil && strings.Contains(field.Tag.Value, `inject:"false"`) { + continue + } + } + + var star string + var pkg string + var pkgAlias string + var typ string + switch field.Type.(type) { + case *ast.Ident: + typ = field.Type.(*ast.Ident).Name + case *ast.StarExpr: + star = "*" + paramsType := field.Type.(*ast.StarExpr) + switch paramsType.X.(type) { + case *ast.SelectorExpr: + X := paramsType.X.(*ast.SelectorExpr) + + pkgAlias = X.X.(*ast.Ident).Name + p, ok := imports[pkgAlias] + if !ok { + continue + } + pkg = p + + typ = X.Sel.Name + default: + typ = paramsType.X.(*ast.Ident).Name + } + case *ast.SelectorExpr: + pkgAlias = field.Type.(*ast.SelectorExpr).X.(*ast.Ident).Name + p, ok := imports[pkgAlias] + if !ok { + continue + } + pkg = p + typ = field.Type.(*ast.SelectorExpr).Sel.Name + } + + if lo.Contains(scalarTypes, typ) { + continue + } + + for _, name := range field.Names { + provider.InjectParams[name.Name] = InjectParam{ + Star: star, + Type: typ, + Package: pkg, + PackageAlias: pkgAlias, + } + } + + if importPkg, ok := imports[pkgAlias]; ok { + provider.Imports[importPkg] = pkgAlias + } + } + + if pkgAlias := getTypePkgName(provider.ReturnType); pkgAlias != "" { + if importPkg, ok := imports[pkgAlias]; ok { + provider.Imports[importPkg] = pkgAlias + } + } + + if pkgAlias := getTypePkgName(provider.ProviderGroup); pkgAlias != "" { + if importPkg, ok := imports[pkgAlias]; ok { + provider.Imports[importPkg] = pkgAlias + } + } + + provider.PkgName = node.Name.Name + provider.ProviderFile = filepath.Join(filepath.Dir(source), "provider.gen.go") + + providers = append(providers, provider) + + } + + return providers +} + +func parseDoc(doc string) (string, string, string) { + // @provider:[except|only] [returnType] [group] + doc = strings.TrimLeft(doc[len("@provider"):], ":") + if !strings.HasPrefix(doc, "except") && !strings.HasPrefix(doc, "only") { + doc = "except " + doc + } + + doc = strings.ReplaceAll(doc, "\t", " ") + cmds := strings.Split(doc, " ") + cmds = lo.Filter(cmds, func(item string, idx int) bool { + return strings.TrimSpace(item) != "" + }) + + if len(cmds) == 0 { + return "except", "#", "" + } + + if len(cmds) == 1 { + return cmds[0], "#", "" + } + + if len(cmds) == 2 { + return cmds[0], cmds[1], "" + } + + return cmds[0], cmds[1], cmds[2] +} + +func renderFile(filename string, conf []Provider) error { + defer func() { + result, err := imports.Process(filename, nil, nil) + if err == nil { + os.WriteFile(filename, result, os.ModePerm) + } + }() + + imports := map[string]string{ + "git.ipao.vip/rogeecn/atom/container": "", + "git.ipao.vip/rogeecn/atom/utils/opt": "", + } + lo.ForEach(conf, func(item Provider, _ int) { + for k, v := range item.Imports { + // 如果是当前包的引用,直接使用包名 + if strings.HasSuffix(k, "/"+v) { + v = "" + } + imports[k] = v + } + }) + + tmpl := `package {{.PkgName}} + +import ( +{{- range $pkg, $alias := .Imports }} + {{- if eq $alias "" }} + "{{$pkg}}" + {{- else }} + {{$alias}} "{{$pkg}}" + {{- end }} +{{- end }} +) + +func Provide(opts ...opt.Option) error { +{{- range .Providers }} + if err := container.Container.Provide(func( + {{- range $key, $param := .InjectParams }} + {{$key}} {{$param.Star}}{{if eq $param.Package ""}}{{$param.Type}}{{else}}{{$param.PackageAlias}}.{{$param.Type}}{{end}}, + {{- end }} + ) ({{.ReturnType}}, error) { + obj := &{{.StructName}}{ + {{- range $key, $param := .InjectParams }} + {{$key}}: {{$key}}, + {{- end }} + } + {{- if .NeedPrepareFunc }} + if err := obj.Prepare(); err != nil { + return nil, err + } + {{- end }} + return obj, nil + }{{if .ProviderGroup}}, {{.ProviderGroup}}{{end}}); err != nil { + return err + } +{{- end }} + return nil +} +` + + t := template.Must(template.New("provider").Parse(tmpl)) + + data := struct { + PkgName string + Imports map[string]string + Providers []Provider + }{ + PkgName: conf[0].PkgName, + Imports: imports, + Providers: conf, + } + + fd, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_RDWR, os.ModePerm) + if err != nil { + return err + } + defer fd.Close() + + return t.Execute(fd, data) +} diff --git a/go.mod b/go.mod index 6bf32f4..2652632 100644 --- a/go.mod +++ b/go.mod @@ -9,11 +9,14 @@ require ( github.com/lib/pq v1.10.9 github.com/pkg/errors v0.9.1 github.com/pressly/goose/v3 v3.23.1 + github.com/rogeecn/fabfile v1.4.0 github.com/samber/lo v1.47.0 github.com/sirupsen/logrus v1.9.3 + github.com/smartystreets/goconvey v1.8.1 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 + golang.org/x/mod v0.17.0 golang.org/x/text v0.21.0 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d ) @@ -25,6 +28,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -35,6 +39,7 @@ require ( github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgtype v1.14.4 // indirect + github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mfridman/interpolate v0.0.2 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect @@ -46,6 +51,7 @@ require ( github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect + github.com/smarty/assertions v1.15.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.7.0 // indirect @@ -54,7 +60,6 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect - golang.org/x/mod v0.17.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index c48067d..2d3bc48 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= @@ -96,6 +98,8 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -144,6 +148,8 @@ github.com/pressly/goose/v3 v3.23.1 h1:bwjOXvep4HtuiiIqtrXmCkQu0IW9O9JAqA6UQNY9n github.com/pressly/goose/v3 v3.23.1/go.mod h1:0oK0zcK7cmNqJSVwMIOiUUW0ox2nDIz+UfPMSOaw2zY= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogeecn/fabfile v1.4.0 h1:Rw7/7OH8cV4aRPw79Oa4hHHFKaC/ol+sNmGcB/usHaQ= +github.com/rogeecn/fabfile v1.4.0/go.mod h1:EPwX7TtVcIWSLJkJAqxSzYjM/aV1Q0wymcaXqnMgzas= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -168,6 +174,10 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= +github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= +github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= +github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= diff --git a/pkg/utils/gomod/mod.go b/pkg/utils/gomod/mod.go new file mode 100644 index 0000000..317f226 --- /dev/null +++ b/pkg/utils/gomod/mod.go @@ -0,0 +1,142 @@ +package gomod + +import ( + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + + "golang.org/x/mod/modfile" +) + +var goMod *GoMod + +type GoMod struct { + file *modfile.File + modules map[string]ModuleInfo +} + +type ModuleInfo struct { + Name string + Version string + Path string +} + +// ParseGoMod 解析当前目录下的go.mod文件 +func Parse(modPath string) error { + // 查找当前目录下的go.mod文件 + // 读取文件内容 + content, err := os.ReadFile(modPath) + if err != nil { + return err + } + + // 使用官方包解析go.mod + f, err := modfile.Parse(modPath, content, nil) + if err != nil { + return err + } + goMod = &GoMod{file: f, modules: make(map[string]ModuleInfo)} + + for _, require := range f.Require { + if !require.Indirect { + continue + } + + name, err := getPackageName(require.Mod.Path, require.Mod.Version) + if err != nil { + continue + } + + goMod.modules[require.Mod.Path] = ModuleInfo{ + Name: name, + Version: require.Mod.Version, + Path: require.Mod.Path, + } + } + + return nil +} + +// GetModuleName 获取模块名 +func GetModuleName() string { + return goMod.file.Module.Mod.Path +} + +// GetModuleVersion 获取模块版本 +func GetModuleVersion() string { + return goMod.file.Module.Mod.Version +} + +func GetPackageModuleName(pkg string) string { + if module, ok := goMod.modules[pkg]; ok { + return module.Name + } + + return filepath.Base(pkg) +} + +// GetPackageModuleName 获取包的真实包名 +func getPackageName(pkg, version string) (string, error) { + gopath := os.Getenv("GOPATH") + if gopath == "" { + gopath = filepath.Join(os.Getenv("HOME"), "go") + } + + pkgPath := fmt.Sprintf("%s@%s", pkg, version) + // 构建包的本地路径 + pkgLocalPath := filepath.Join(gopath, "pkg", "mod", pkgPath) + + // 获取目录下任意一个非_test.go文件,读取他的package name + files, err := filepath.Glob(filepath.Join(pkgLocalPath, "*.go")) + if err != nil { + return "", err + } + + packagePattern := regexp.MustCompile(`package\s+(\w+)`) + if len(files) > 0 { + for _, file := range files { + if strings.HasSuffix(file, "_test.go") { + continue + } + // 读取文件内容 + + content, err := os.ReadFile(file) + if err != nil { + return "", err + } + + packageName := packagePattern.FindStringSubmatch(string(content)) + if len(packageName) == 2 { + return packageName[1], nil + } + } + } + // 读取go.mod 文件内容 + modFile := filepath.Join(pkgLocalPath, "go.mod") + content, err := os.ReadFile(modFile) + if err != nil { + return "", err + } + + f, err := modfile.Parse(modFile, content, nil) + if err != nil { + return "", err + } + + path := f.Module.Mod.Path + + // 获取包名 + path, name := filepath.Split(path) + versionPattern := regexp.MustCompile(`^v\d+$`) + if versionPattern.MatchString(name) { + _, name = filepath.Split(strings.TrimSuffix(path, "/")) + } + + if strings.Contains(name, "-") { + name = strings.ReplaceAll(name, "-", "") + } + + return name, nil +} diff --git a/pkg/utils/gomod/mod_test.go b/pkg/utils/gomod/mod_test.go new file mode 100644 index 0000000..9a3f710 --- /dev/null +++ b/pkg/utils/gomod/mod_test.go @@ -0,0 +1,32 @@ +package gomod + +import ( + "testing" + + "github.com/rogeecn/fabfile" + . "github.com/smartystreets/goconvey/convey" +) + +func Test_ParseGoMod(t *testing.T) { + Convey("Test ParseGoMod", t, func() { + Convey("parse go.mod", func() { + modFile := fabfile.MustFind("go.mod") + err := Parse(modFile) + So(err, ShouldBeNil) + + t.Logf("%+v", goMod) + }) + }) +} + +func Test_getPackageName(t *testing.T) { + Convey("Test getPackageName", t, func() { + Convey("", func() { + Convey("github.com/redis/go-redis/v9@v9.7.0", func() { + name, err := getPackageName("github.com/redis/go-redis/v9", "v9.7.0") + So(err, ShouldBeNil) + So(name, ShouldEqual, "redis") + }) + }) + }) +}