├── .gitignore ├── LICENSE ├── README.md ├── action └── upgrade.go ├── common └── batch │ ├── batch.go │ └── batch_test.go ├── executor └── executor.go ├── go.mod ├── go.sum └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dreamacro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-check 2 | 3 | Check for outdated go module. 4 | 5 | ### Getting Started 6 | 7 | ```sh 8 | $ go install github.com/Dreamacro/go-check@latest 9 | ``` 10 | 11 | ### Use Case 12 | 13 | 14 | 15 | ### About 16 | 17 | Inspired by [npm-check](https://github.com/dylang/npm-check) 18 | -------------------------------------------------------------------------------- /action/upgrade.go: -------------------------------------------------------------------------------- 1 | package action 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | 10 | "github.com/Dreamacro/go-check/common/batch" 11 | "github.com/Dreamacro/go-check/executor" 12 | 13 | "github.com/avast/retry-go/v4" 14 | "github.com/charmbracelet/huh" 15 | "github.com/charmbracelet/huh/spinner" 16 | "github.com/charmbracelet/lipgloss" 17 | "github.com/spf13/cobra" 18 | "golang.org/x/mod/modfile" 19 | "golang.org/x/mod/module" 20 | ) 21 | 22 | type mod module.Version 23 | 24 | func (m mod) String() string { 25 | return m.Path + "@" + m.Version 26 | } 27 | 28 | func Contains[S ~[]E, E comparable](s S, v E) bool { 29 | for _, item := range s { 30 | if item == v { 31 | return true 32 | } 33 | } 34 | return false 35 | } 36 | 37 | func Upgrade(cmd *cobra.Command, args []string) { 38 | pwd, err := os.Getwd() 39 | if err != nil { 40 | println(err.Error()) 41 | return 42 | } 43 | 44 | modFile := filepath.Join(pwd, "go.mod") 45 | modBuf, err := os.ReadFile(modFile) 46 | if err != nil { 47 | println("❌ get go.mod failed:", err.Error()) 48 | return 49 | } 50 | f, err := modfile.Parse(modFile, modBuf, nil) 51 | if err != nil { 52 | println(err.Error()) 53 | return 54 | } 55 | 56 | directoryModulePath := []string{} 57 | for _, require := range f.Replace { 58 | if modfile.IsDirectoryPath(require.New.Path) { 59 | directoryModulePath = append(directoryModulePath, require.Old.Path) 60 | } 61 | } 62 | 63 | mainModule := []mod{} 64 | for _, require := range f.Require { 65 | if require.Indirect { 66 | continue 67 | } 68 | 69 | if Contains(directoryModulePath, require.Mod.Path) { 70 | println("🚧", require.Mod.Path, "is replace as a directory path, skip it.") 71 | continue 72 | } 73 | 74 | mainModule = append(mainModule, mod(require.Mod)) 75 | } 76 | 77 | println("🔍 find main module:\n") 78 | for _, m := range mainModule { 79 | println(m.String()) 80 | } 81 | println("") 82 | 83 | yellowStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("227")) 84 | cyanStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("39")) 85 | 86 | b, ctx := batch.New(context.Background(), batch.WithConcurrencyNum[*executor.Module](10)) 87 | 88 | var ( 89 | result map[string]batch.Result[*executor.Module] 90 | bErr *batch.Error 91 | ) 92 | 93 | go func() { 94 | for _, module := range mainModule { 95 | m := module 96 | b.Go(m.Path, func() (ret *executor.Module, err error) { 97 | err = retry.Do( 98 | func() error { 99 | info, err := executor.GetModuleUpdate(pwd, m.Path) 100 | if err == nil { 101 | ret = info 102 | } 103 | return err 104 | }, 105 | ) 106 | return 107 | }) 108 | } 109 | 110 | result, bErr = b.WaitAndGetResult() 111 | }() 112 | 113 | spinner.New(). 114 | Type(spinner.Jump). 115 | Title(yellowStyle.Render(" Find module information...")). 116 | Context(ctx). 117 | Run() 118 | 119 | if bErr != nil { 120 | println(bErr.Err.Error()) 121 | return 122 | } 123 | 124 | texts := []huh.Option[string]{} 125 | mapping := map[string]*executor.Module{} 126 | for _, require := range f.Require { 127 | if require.Indirect { 128 | continue 129 | } 130 | 131 | value, exist := result[require.Mod.Path] 132 | if !exist { 133 | continue 134 | } 135 | 136 | pkg := value.Value 137 | if pkg.Update == nil { 138 | continue 139 | } 140 | 141 | if pkg.Update.Version != require.Mod.Version { 142 | key := fmt.Sprintf("%s (%s --> %s)", pkg.Path, require.Mod.Version, pkg.Update.Version) 143 | texts = append(texts, huh.NewOption(key, key)) 144 | mapping[key] = pkg 145 | } 146 | } 147 | 148 | if len(texts) == 0 { 149 | println("🎉 Your modules look amazing. Keep up the great work.") 150 | return 151 | } 152 | 153 | lipgloss.DefaultRenderer().Output().ClearScreen() 154 | 155 | selected := []string{} 156 | err = huh.NewMultiSelect[string](). 157 | Options(texts...). 158 | Title(cyanStyle.Render("Select the packages you want to upgrade")). 159 | Value(&selected). 160 | WithTheme(huh.ThemeBase16()). 161 | Run() 162 | 163 | if err != nil { 164 | return 165 | } 166 | 167 | if len(selected) == 0 { 168 | return 169 | } 170 | 171 | lipgloss.DefaultRenderer().Output().ClearScreen() 172 | 173 | answer := strings.Join(selected, "\n") + "\n" 174 | println(cyanStyle.Render(answer)) 175 | 176 | shouldUpgrade := []*executor.Module{} 177 | for _, item := range selected { 178 | shouldUpgrade = append(shouldUpgrade, mapping[item]) 179 | } 180 | 181 | spinner.New(). 182 | Type(spinner.Jump). 183 | Title(yellowStyle.Render(" Installing using `go get`...")). 184 | Action(func() { 185 | _, err = executor.Upgrade(pwd, shouldUpgrade) 186 | }). 187 | Run() 188 | 189 | if err != nil { 190 | println(err.Error()) 191 | return 192 | } 193 | 194 | spinner.New(). 195 | Type(spinner.Jump). 196 | Title(yellowStyle.Render(" Running `go mod tidy`")). 197 | Action(func() { 198 | _, err = executor.Tidy(pwd) 199 | }). 200 | Run() 201 | 202 | if err != nil { 203 | println(err.Error()) 204 | return 205 | } 206 | 207 | println("🎉 Update complete!") 208 | } 209 | -------------------------------------------------------------------------------- /common/batch/batch.go: -------------------------------------------------------------------------------- 1 | package batch 2 | 3 | import ( 4 | "context" 5 | "sync" 6 | ) 7 | 8 | type Option[T any] func(b *Batch[T]) 9 | 10 | type Result[T any] struct { 11 | Value T 12 | Err error 13 | } 14 | 15 | type Error struct { 16 | Key string 17 | Err error 18 | } 19 | 20 | func WithConcurrencyNum[T any](n int) Option[T] { 21 | return func(b *Batch[T]) { 22 | q := make(chan struct{}, n) 23 | for i := 0; i < n; i++ { 24 | q <- struct{}{} 25 | } 26 | b.queue = q 27 | } 28 | } 29 | 30 | // Batch similar to errgroup, but can control the maximum number of concurrent 31 | type Batch[T any] struct { 32 | result map[string]Result[T] 33 | queue chan struct{} 34 | wg sync.WaitGroup 35 | mux sync.Mutex 36 | err *Error 37 | once sync.Once 38 | cancel func() 39 | } 40 | 41 | func (b *Batch[T]) Go(key string, fn func() (T, error)) { 42 | b.wg.Add(1) 43 | go func() { 44 | defer b.wg.Done() 45 | if b.queue != nil { 46 | <-b.queue 47 | defer func() { 48 | b.queue <- struct{}{} 49 | }() 50 | } 51 | 52 | value, err := fn() 53 | if err != nil { 54 | b.once.Do(func() { 55 | b.err = &Error{key, err} 56 | if b.cancel != nil { 57 | b.cancel() 58 | } 59 | }) 60 | } 61 | 62 | ret := Result[T]{value, err} 63 | b.mux.Lock() 64 | defer b.mux.Unlock() 65 | b.result[key] = ret 66 | }() 67 | } 68 | 69 | func (b *Batch[T]) Wait() *Error { 70 | b.wg.Wait() 71 | if b.cancel != nil { 72 | b.cancel() 73 | } 74 | return b.err 75 | } 76 | 77 | func (b *Batch[T]) WaitAndGetResult() (map[string]Result[T], *Error) { 78 | err := b.Wait() 79 | return b.Result(), err 80 | } 81 | 82 | func (b *Batch[T]) Result() map[string]Result[T] { 83 | b.mux.Lock() 84 | defer b.mux.Unlock() 85 | copy := map[string]Result[T]{} 86 | for k, v := range b.result { 87 | copy[k] = v 88 | } 89 | return copy 90 | } 91 | 92 | func New[T any](ctx context.Context, opts ...Option[T]) (*Batch[T], context.Context) { 93 | ctx, cancel := context.WithCancel(ctx) 94 | 95 | b := &Batch[T]{ 96 | result: map[string]Result[T]{}, 97 | } 98 | 99 | for _, o := range opts { 100 | o(b) 101 | } 102 | 103 | b.cancel = cancel 104 | return b, ctx 105 | } 106 | -------------------------------------------------------------------------------- /common/batch/batch_test.go: -------------------------------------------------------------------------------- 1 | package batch 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "strconv" 7 | "testing" 8 | "time" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestBatch(t *testing.T) { 14 | b, _ := New[string](context.Background()) 15 | 16 | now := time.Now() 17 | b.Go("foo", func() (string, error) { 18 | time.Sleep(time.Millisecond * 100) 19 | return "foo", nil 20 | }) 21 | b.Go("bar", func() (string, error) { 22 | time.Sleep(time.Millisecond * 150) 23 | return "bar", nil 24 | }) 25 | result, err := b.WaitAndGetResult() 26 | 27 | assert.Nil(t, err) 28 | 29 | duration := time.Since(now) 30 | assert.Less(t, duration, time.Millisecond*200) 31 | assert.Equal(t, 2, len(result)) 32 | 33 | for k, v := range result { 34 | assert.NoError(t, v.Err) 35 | assert.Equal(t, k, v.Value) 36 | } 37 | } 38 | 39 | func TestBatchWithConcurrencyNum(t *testing.T) { 40 | b, _ := New( 41 | context.Background(), 42 | WithConcurrencyNum[string](3), 43 | ) 44 | 45 | now := time.Now() 46 | for i := 0; i < 7; i++ { 47 | idx := i 48 | b.Go(strconv.Itoa(idx), func() (string, error) { 49 | time.Sleep(time.Millisecond * 100) 50 | return strconv.Itoa(idx), nil 51 | }) 52 | } 53 | result, _ := b.WaitAndGetResult() 54 | duration := time.Since(now) 55 | assert.Greater(t, duration, time.Millisecond*260) 56 | assert.Equal(t, 7, len(result)) 57 | 58 | for k, v := range result { 59 | assert.NoError(t, v.Err) 60 | assert.Equal(t, k, v.Value) 61 | } 62 | } 63 | 64 | func TestBatchContext(t *testing.T) { 65 | b, ctx := New[any](context.Background()) 66 | 67 | b.Go("error", func() (any, error) { 68 | time.Sleep(time.Millisecond * 100) 69 | return nil, errors.New("test error") 70 | }) 71 | 72 | b.Go("ctx", func() (any, error) { 73 | <-ctx.Done() 74 | return nil, ctx.Err() 75 | }) 76 | 77 | result, err := b.WaitAndGetResult() 78 | 79 | assert.NotNil(t, err) 80 | assert.Equal(t, "error", err.Key) 81 | 82 | assert.Equal(t, ctx.Err(), result["ctx"].Err) 83 | } 84 | -------------------------------------------------------------------------------- /executor/executor.go: -------------------------------------------------------------------------------- 1 | package executor 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "os/exec" 10 | "time" 11 | 12 | "golang.org/x/tools/go/packages" 13 | ) 14 | 15 | // Module provides module information for a package. 16 | type Module struct { 17 | Path string // module path 18 | Version string // module version 19 | Replace *Module // replaced by this module 20 | Time *time.Time // time version was created 21 | Update *Module // available update, if any (with -u) 22 | Main bool // is this the main module? 23 | Indirect bool // is this module only an indirect dependency of main module? 24 | Dir string // directory holding files for this module, if any 25 | GoMod string // path to go.mod file used when loading this module, if any 26 | GoVersion string // go version used in module 27 | Error *packages.ModuleError // error loading module 28 | } 29 | 30 | func execSync(pwd string, command string, args ...string) ([]byte, error) { 31 | cmd := exec.Command(command, args...) 32 | cmd.Dir = pwd 33 | 34 | buf := &bytes.Buffer{} 35 | bufErr := &bytes.Buffer{} 36 | stdout, _ := cmd.StdoutPipe() 37 | stderr, _ := cmd.StderrPipe() 38 | 39 | go io.Copy(buf, stdout) 40 | go io.Copy(bufErr, stderr) 41 | if err := cmd.Run(); err != nil { 42 | return nil, errors.New(bufErr.String()) 43 | } 44 | return buf.Bytes(), nil 45 | } 46 | 47 | func GetModuleUpdate(pwd, module string) (*Module, error) { 48 | buf, err := execSync(pwd, "go", "list", "-u", "-m", "-mod=mod", "-json", module) 49 | if err != nil { 50 | return nil, err 51 | } 52 | 53 | pkg := Module{} 54 | if err := json.Unmarshal(buf, &pkg); err != nil { 55 | return nil, err 56 | } 57 | 58 | return &pkg, nil 59 | } 60 | 61 | func Upgrade(pwd string, pkgs []*Module) ([]byte, error) { 62 | args := []string{"get"} 63 | for _, pkg := range pkgs { 64 | args = append(args, fmt.Sprintf("%s@%s", pkg.Path, pkg.Update.Version)) 65 | } 66 | 67 | return execSync(pwd, "go", args...) 68 | } 69 | 70 | func Tidy(pwd string) ([]byte, error) { 71 | return execSync(pwd, "go", "mod", "tidy") 72 | } 73 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Dreamacro/go-check 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/avast/retry-go/v4 v4.6.0 7 | github.com/charmbracelet/huh v0.6.0 8 | github.com/charmbracelet/huh/spinner v0.0.0-20240906163306-a9285a0ef8a3 9 | github.com/charmbracelet/lipgloss v0.13.0 10 | github.com/spf13/cobra v1.8.1 11 | github.com/stretchr/testify v1.9.0 12 | golang.org/x/mod v0.21.0 13 | golang.org/x/tools v0.25.0 14 | ) 15 | 16 | require ( 17 | github.com/atotto/clipboard v0.1.4 // indirect 18 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 19 | github.com/catppuccin/go v0.2.0 // indirect 20 | github.com/charmbracelet/bubbles v0.20.0 // indirect 21 | github.com/charmbracelet/bubbletea v1.1.0 // indirect 22 | github.com/charmbracelet/x/ansi v0.2.3 // indirect 23 | github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect 24 | github.com/charmbracelet/x/term v0.2.0 // indirect 25 | github.com/davecgh/go-spew v1.1.1 // indirect 26 | github.com/dustin/go-humanize v1.0.1 // indirect 27 | github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect 28 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 29 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 30 | github.com/mattn/go-isatty v0.0.20 // indirect 31 | github.com/mattn/go-localereader v0.0.1 // indirect 32 | github.com/mattn/go-runewidth v0.0.16 // indirect 33 | github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect 34 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 35 | github.com/muesli/cancelreader v0.2.2 // indirect 36 | github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect 37 | github.com/pmezard/go-difflib v1.0.0 // indirect 38 | github.com/rivo/uniseg v0.4.7 // indirect 39 | github.com/spf13/pflag v1.0.5 // indirect 40 | golang.org/x/sync v0.8.0 // indirect 41 | golang.org/x/sys v0.25.0 // indirect 42 | golang.org/x/text v0.18.0 // indirect 43 | gopkg.in/yaml.v3 v3.0.1 // indirect 44 | ) 45 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= 2 | github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= 3 | github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= 4 | github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= 5 | github.com/avast/retry-go/v4 v4.6.0 h1:K9xNA+KeB8HHc2aWFuLb25Offp+0iVRXEvFx8IinRJA= 6 | github.com/avast/retry-go/v4 v4.6.0/go.mod h1:gvWlPhBVsvBbLkVGDg/KwvBv0bEkCOLRRSHKIr2PyOE= 7 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 8 | github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= 9 | github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= 10 | github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= 11 | github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE= 12 | github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU= 13 | github.com/charmbracelet/bubbletea v1.1.0 h1:FjAl9eAL3HBCHenhz/ZPjkKdScmaS5SK69JAK2YJK9c= 14 | github.com/charmbracelet/bubbletea v1.1.0/go.mod h1:9Ogk0HrdbHolIKHdjfFpyXJmiCzGwy+FesYkZr7hYU4= 15 | github.com/charmbracelet/huh v0.6.0 h1:mZM8VvZGuE0hoDXq6XLxRtgfWyTI3b2jZNKh0xWmax8= 16 | github.com/charmbracelet/huh v0.6.0/go.mod h1:GGNKeWCeNzKpEOh/OJD8WBwTQjV3prFAtQPpLv+AVwU= 17 | github.com/charmbracelet/huh/spinner v0.0.0-20240906163306-a9285a0ef8a3 h1:fP1Lr+Q8rWGLCifueSnqW/2QFtZUswA3YsNOx9OesZ0= 18 | github.com/charmbracelet/huh/spinner v0.0.0-20240906163306-a9285a0ef8a3/go.mod h1:/dHGy3eS2ikDSO71IhslBdBGvrknQ+ze/VDiNdIxocw= 19 | github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw= 20 | github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY= 21 | github.com/charmbracelet/x/ansi v0.2.3 h1:VfFN0NUpcjBRd4DnKfRaIRo53KRgey/nhOoEqosGDEY= 22 | github.com/charmbracelet/x/ansi v0.2.3/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw= 23 | github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4= 24 | github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ= 25 | github.com/charmbracelet/x/term v0.2.0 h1:cNB9Ot9q8I711MyZ7myUR5HFWL/lc3OpU8jZ4hwm0x0= 26 | github.com/charmbracelet/x/term v0.2.0/go.mod h1:GVxgxAbjUrmpvIINHIQnJJKpMlHiZ4cktEQCN6GWyF0= 27 | github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 28 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 29 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 30 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 31 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 32 | github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= 33 | github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= 34 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= 35 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 36 | github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 37 | github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 38 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 39 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 40 | github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= 41 | github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= 42 | github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 43 | github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 44 | github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= 45 | github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= 46 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= 47 | github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= 48 | github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= 49 | github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= 50 | github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg= 51 | github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= 52 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 53 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 54 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 55 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 56 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 57 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 58 | github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= 59 | github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 60 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 61 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 62 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 63 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 64 | golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= 65 | golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 66 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 67 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 68 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 69 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 70 | golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= 71 | golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 72 | golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= 73 | golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 74 | golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= 75 | golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 76 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 77 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 78 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 79 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 80 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/Dreamacro/go-check/action" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | var rootCmd = &cobra.Command{ 10 | Short: "go-check is a go module updater", 11 | Run: action.Upgrade, 12 | } 13 | 14 | func main() { 15 | rootCmd.Execute() 16 | } 17 | --------------------------------------------------------------------------------