Skip to content

Commit 7b01ed5

Browse files
committed
feat: find tree root via a user-specified command
Signed-off-by: Brian McGee <[email protected]>
1 parent 9399cd6 commit 7b01ed5

File tree

6 files changed

+111
-75
lines changed

6 files changed

+111
-75
lines changed

cmd/root.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,12 @@ func NewRoot() (*cobra.Command, *stats.Stats) {
4646
// add our config flags to the command's flag set
4747
config.SetFlags(fs)
4848

49-
// xor tree-root and tree-root-file flags
50-
cmd.MarkFlagsMutuallyExclusive("tree-root", "tree-root-file")
49+
// xor tree-root, tree-root-cmd and tree-root-file flags
50+
cmd.MarkFlagsMutuallyExclusive(
51+
"tree-root",
52+
"tree-root-cmd",
53+
"tree-root-file",
54+
)
5155

5256
cmd.HelpTemplate()
5357

config/config.go

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package config
22

33
import (
4+
"context"
45
"fmt"
56
"os"
7+
"os/exec"
68
"path/filepath"
79
"regexp"
810
"strings"
11+
"time"
912

13+
"github.com/charmbracelet/log"
14+
"github.com/google/shlex"
1015
"github.com/numtide/treefmt/v2/walk"
1116
"github.com/spf13/pflag"
1217
"github.com/spf13/viper"
@@ -25,6 +30,7 @@ type Config struct {
2530
OnUnmatched string `mapstructure:"on-unmatched" toml:"on-unmatched,omitempty"`
2631
Quiet bool `mapstructure:"quiet" toml:"-"` // not allowed in config
2732
TreeRoot string `mapstructure:"tree-root" toml:"tree-root,omitempty"`
33+
TreeRootCmd string `mapstructure:"tree-root-cmd" toml:"tree-root-cmd,omitempty"`
2834
TreeRootFile string `mapstructure:"tree-root-file" toml:"tree-root-file,omitempty"`
2935
Verbose uint8 `mapstructure:"verbose" toml:"verbose,omitempty"`
3036
Walk string `mapstructure:"walk" toml:"walk,omitempty"`
@@ -104,9 +110,13 @@ func SetFlags(fs *pflag.FlagSet) {
104110
"The root directory from which treefmt will start walking the filesystem (defaults to the directory "+
105111
"containing the config file). (env $TREEFMT_TREE_ROOT)",
106112
)
113+
fs.String(
114+
"tree-root-cmd", "",
115+
"Command to run to find the tree root. (env $TREEFMT_TREE_ROOT_CMD)",
116+
)
107117
fs.String(
108118
"tree-root-file", "",
109-
"File to search for to find the tree root (if --tree-root is not passed). (env $TREEFMT_TREE_ROOT_FILE)",
119+
"File to search for to find the tree root. (env $TREEFMT_TREE_ROOT_FILE)",
110120
)
111121
fs.CountP(
112122
"verbose", "v",
@@ -186,19 +196,50 @@ func FromViper(v *viper.Viper) (*Config, error) {
186196
cfg.Walk = walk.Stdin.String()
187197
}
188198

199+
// set git-based tree root command if the walker is Git
200+
if cfg.Walk == walk.Git.String() {
201+
cfg.TreeRootCmd = "git rev-parse --show-toplevel"
202+
}
203+
189204
// determine the tree root
190-
if cfg.TreeRoot == "" {
191-
// if none was specified, we first try with tree-root-file
192-
if cfg.TreeRootFile != "" {
193-
// search the tree root using the --tree-root-file if specified
194-
_, cfg.TreeRoot, err = FindUp(cfg.WorkingDirectory, cfg.TreeRootFile)
195-
if err != nil {
196-
return nil, fmt.Errorf("failed to find tree-root based on tree-root-file: %w", err)
197-
}
198-
} else {
199-
// otherwise fallback to the directory containing the config file
200-
cfg.TreeRoot = filepath.Dir(v.ConfigFileUsed())
205+
// NOTE: at the treefmt command level we ensure that `--tree-root`, `--tree-root-cmd` and `--tree-root-file` are
206+
// mutually exclusive
207+
switch {
208+
case cfg.TreeRoot == "" && cfg.TreeRootFile != "":
209+
// search the tree root using the --tree-root-file if specified
210+
_, cfg.TreeRoot, err = FindUp(cfg.WorkingDirectory, cfg.TreeRootFile)
211+
if err != nil {
212+
return nil, fmt.Errorf("failed to find tree-root based on tree-root-file: %w", err)
213+
}
214+
215+
case cfg.TreeRoot == "" && cfg.TreeRootCmd != "":
216+
// use the output of the tree root command as the tree root
217+
parts, splitErr := shlex.Split(cfg.TreeRootCmd)
218+
if splitErr != nil {
219+
return nil, fmt.Errorf("failed to parse tree-root-cmd: %w", splitErr)
201220
}
221+
222+
// set a reasonable timeout of 2 seconds to wait for the command to return
223+
// it shouldn't take anywhere near this amount of time unless there's a problem
224+
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
225+
defer cancel()
226+
227+
//nolint:gosec
228+
cmd := exec.CommandContext(ctx, parts[0], parts[1:]...)
229+
cmd.Dir = cfg.WorkingDirectory
230+
231+
out, cmdErr := cmd.CombinedOutput()
232+
if cmdErr != nil {
233+
log.Errorf("tree-root-cmd output: \n%s", out)
234+
235+
return nil, fmt.Errorf("failed to run tree-root-cmd: %w", cmdErr)
236+
}
237+
238+
cfg.TreeRoot = strings.TrimSpace(string(out))
239+
240+
case cfg.TreeRoot == "":
241+
// no tree root was specified, so we fall back to the directory containing the config file
242+
cfg.TreeRoot = filepath.Dir(v.ConfigFileUsed())
202243
}
203244

204245
// resolve tree root to an absolute path
@@ -212,7 +253,6 @@ func FromViper(v *viper.Viper) (*Config, error) {
212253
}
213254

214255
// validate formatter names do not contain invalid characters
215-
216256
nameRegex := regexp.MustCompile("^[a-zA-Z0-9_-]+$")
217257

218258
for name := range cfg.FormatterConfigs {

config/config_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"bytes"
66
"fmt"
77
"os"
8+
"os/exec"
89
"path/filepath"
910
"testing"
1011

@@ -26,6 +27,17 @@ func newViper(t *testing.T) (*viper.Viper, *pflag.FlagSet) {
2627
tempDir := t.TempDir()
2728
v.SetConfigFile(filepath.Join(tempDir, "treefmt.toml"))
2829

30+
// initialise a git repo to help with tree-root-cmd testing
31+
cmd := exec.Command("git", "init")
32+
cmd.Dir = tempDir
33+
34+
if err = cmd.Run(); err != nil {
35+
t.Fatal(err)
36+
}
37+
38+
// change working directory to the temp dir
39+
t.Chdir(tempDir)
40+
2941
flags := pflag.NewFlagSet("test", pflag.ContinueOnError)
3042
config.SetFlags(flags)
3143

@@ -457,6 +469,41 @@ func TestTreeRootFile(t *testing.T) {
457469
checkValue(tempDir, ".git/config")
458470
}
459471

472+
func TestTreeRootCmd(t *testing.T) {
473+
as := require.New(t)
474+
475+
cfg := &config.Config{}
476+
v, flags := newViper(t)
477+
478+
checkValue := func(treeRoot string) {
479+
readValue(t, v, cfg, func(cfg *config.Config) {
480+
as.Equal(treeRoot, cfg.TreeRoot)
481+
})
482+
}
483+
484+
tempDir := t.TempDir()
485+
as.NoError(os.MkdirAll(filepath.Join(tempDir, "foo"), 0o755))
486+
as.NoError(os.MkdirAll(filepath.Join(tempDir, "bar"), 0o755))
487+
488+
// default with no flag, env or config
489+
// should match the absolute path of the directory in which the config file is located
490+
checkValue(filepath.Dir(v.ConfigFileUsed()))
491+
492+
// set config value
493+
cfg.TreeRootCmd = "echo " + tempDir
494+
checkValue(tempDir)
495+
496+
// env override
497+
// should match the directory above
498+
t.Setenv("TREEFMT_TREE_ROOT_CMD", fmt.Sprintf("echo \"%s/foo\"", tempDir))
499+
checkValue(filepath.Join(tempDir, "foo"))
500+
501+
// flag override
502+
// should match the root of the temp directory structure
503+
as.NoError(flags.Set("tree-root-cmd", fmt.Sprintf("echo '%s/bar'", tempDir)))
504+
checkValue(filepath.Join(tempDir, "bar"))
505+
}
506+
460507
func TestVerbosity(t *testing.T) {
461508
as := require.New(t)
462509

go.mod

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ require (
77
github.com/adrg/xdg v0.5.3
88
github.com/charmbracelet/log v0.4.1
99
github.com/gobwas/glob v0.2.3
10+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
1011
github.com/otiai10/copy v1.14.1
1112
github.com/spf13/cobra v1.9.1
1213
github.com/spf13/pflag v1.0.6
@@ -26,21 +27,15 @@ require (
2627
github.com/fsnotify/fsnotify v1.8.0 // indirect
2728
github.com/go-logfmt/logfmt v0.6.0 // indirect
2829
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
29-
github.com/hashicorp/hcl v1.0.0 // indirect
3030
github.com/inconshreveable/mousetrap v1.1.0 // indirect
3131
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
32-
github.com/magiconair/properties v1.8.7 // indirect
3332
github.com/mattn/go-isatty v0.0.20 // indirect
34-
github.com/mattn/go-runewidth v0.0.15 // indirect
35-
github.com/mitchellh/mapstructure v1.5.0 // indirect
36-
github.com/muesli/reflow v0.3.0 // indirect
3733
github.com/muesli/termenv v0.16.0 // indirect
3834
github.com/otiai10/mint v1.6.3 // indirect
3935
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
4036
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
4137
github.com/rivo/uniseg v0.4.7 // indirect
4238
github.com/sagikazarmark/locafero v0.7.0 // indirect
43-
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
4439
github.com/sourcegraph/conc v0.3.0 // indirect
4540
github.com/spf13/afero v1.12.0 // indirect
4641
github.com/spf13/cast v1.7.1 // indirect
@@ -51,6 +46,5 @@ require (
5146
golang.org/x/term v0.29.0 // indirect
5247
golang.org/x/text v0.21.0 // indirect
5348
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
54-
gopkg.in/ini.v1 v1.67.0 // indirect
5549
gopkg.in/yaml.v3 v3.0.1 // indirect
5650
)

go.sum

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
1-
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
2-
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
31
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
42
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
53
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
64
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
75
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
86
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
9-
github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
10-
github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
117
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
128
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
13-
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
14-
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
159
github.com/charmbracelet/log v0.4.1 h1:6AYnoHKADkghm/vt4neaNEXkxcXLSV2g1rdyFDOpTyk=
1610
github.com/charmbracelet/log v0.4.1/go.mod h1:pXgyTsqsVu4N9hGdHmQ0xEA4RsXof402LX9ZgiITn2I=
1711
github.com/charmbracelet/x/ansi v0.4.2 h1:0JM6Aj/g/KC154/gOP4vfxun0ff6itogDYk41kof+qk=
@@ -25,8 +19,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
2519
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2620
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
2721
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
28-
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
29-
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
3022
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
3123
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
3224
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
@@ -39,8 +31,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
3931
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
4032
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
4133
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
42-
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
43-
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
34+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
35+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
4436
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
4537
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
4638
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -52,72 +44,40 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
5244
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
5345
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
5446
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
55-
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
56-
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
5747
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
5848
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
59-
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
60-
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
61-
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
62-
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
63-
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
64-
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
65-
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
6649
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
6750
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
6851
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
6952
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
7053
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
7154
github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
72-
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
73-
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
7455
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
7556
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
7657
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7758
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
7859
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
79-
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
80-
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
8160
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
8261
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
8362
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
8463
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
8564
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
86-
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
87-
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
8865
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
8966
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
90-
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
91-
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
9267
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
9368
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
94-
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
95-
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
9669
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
9770
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
98-
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
99-
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
10071
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
10172
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
10273
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
10374
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
10475
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
10576
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
106-
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
107-
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
108-
github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY=
109-
github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
11077
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
11178
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
11279
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
113-
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
114-
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
115-
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
11680
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
117-
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
118-
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
119-
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
120-
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
12181
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
12282
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
12383
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
@@ -130,27 +90,18 @@ go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
13090
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
13191
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
13292
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
133-
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
134-
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
13593
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
13694
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
13795
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
138-
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
139-
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
14096
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
14197
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
14298
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
14399
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
144-
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
145-
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
146100
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
147101
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
148102
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
149103
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
150104
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
151-
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
152-
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
153-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
154105
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
155106
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
156107
mvdan.cc/sh/v3 v3.11.0 h1:q5h+XMDRfUGUedCqFFsjoFjrhwf2Mvtt1rkMvVz0blw=

0 commit comments

Comments
 (0)