diff --git a/.gitignore b/.gitignore index edd2caf..feee9f7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -/gomodinit* +/gomodinit +/gomodinit.exe .idea/ \ No newline at end of file diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..da8139b --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,25 @@ +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + ldflags: + - "-s -w -X go.jolheiser.com/gomodinit.Version={{.Version}}" +archives: + - replacements: + 386: i386 + amd64: x86_64 + format_overrides: + - goos: windows + format: zip +checksum: + name_template: 'checksums.txt' +release: + gitea: + owner: jolheiser + name: gomodinit +gitea_urls: + api: https://git.jojodev.com/api/v1/ + download: https://git.jojodev.com diff --git a/.woodpecker/goreleaser.yml b/.woodpecker/goreleaser.yml new file mode 100644 index 0000000..da85098 --- /dev/null +++ b/.woodpecker/goreleaser.yml @@ -0,0 +1,39 @@ +clone: + git: + image: woodpeckerci/plugin-git + settings: + tags: true + +pipeline: + compliance: + image: golang:1.18 + commands: + - go test -race ./... + - go vet ./... + - go run github.com/rs/zerolog/cmd/lint@latest go.jolheiser.com/gomodinit + when: + event: pull_request + + build: + image: goreleaser/goreleaser + commands: + - goreleaser build --snapshot + when: + event: pull_request + + release: + image: goreleaser/goreleaser + commands: + - goreleaser release + secrets: [ gitea_token ] + when: + event: tag + + prune: + image: jolheiser/drone-gitea-prune + settings: + base: https://git.jojodev.com + token: + from_secret: gitea_token + when: + event: tag diff --git a/README.md b/README.md index 7fcba9c..7eb06bc 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ `go mod init` -1. Set your base URL prefix via flag or env variable -2. `gomodinit` will default to the current directory name as the module, otherwise the first command argument +`gomodinit` walks up the current dir path until it finds something vaguely resembling a URI (i.e. a path part with at least one `.`) +and constructs a `go mod init ` call from it. ## This seems like a trivial thing diff --git a/go.mod b/go.mod index 00896c0..1473f2c 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,8 @@ module go.jolheiser.com/gomodinit -go 1.17 +go 1.18 -require github.com/peterbourgon/ff/v3 v3.1.0 +require ( + github.com/matryer/is v1.4.0 + github.com/peterbourgon/ff/v3 v3.1.2 +) diff --git a/go.sum b/go.sum index 5dc37d8..7706950 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,9 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= -github.com/peterbourgon/ff/v3 v3.1.0 h1:5JAeDK5j/zhKFjyHEZQXwXBoDijERaos10RE+xamOsY= -github.com/peterbourgon/ff/v3 v3.1.0/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE= +github.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM= +github.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/gomodinit_test.go b/gomodinit_test.go new file mode 100644 index 0000000..bb5bb02 --- /dev/null +++ b/gomodinit_test.go @@ -0,0 +1,61 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/matryer/is" +) + +func TestModule(t *testing.T) { + tmp := t.TempDir() + + tt := []struct { + Name string + Path string + Expected string + }{ + { + Name: "gitea", + Path: "gitea.com/user1/repo", + Expected: "gitea.com/user1/repo", + }, + { + Name: "gitea_sub", + Path: "gitea.com/user2/repo/subpkg", + Expected: "gitea.com/user2/repo/subpkg", + }, + { + Name: "no_uri", + Path: "giteacom/user3/repo", + Expected: "%s/giteacom/user3/repo", + }, + } + + for _, tc := range tt { + t.Run(tc.Name, func(t *testing.T) { + assert := is.New(t) + + dir := filepath.Join(tmp, tc.Path) + + err := os.MkdirAll(dir, os.ModePerm) + assert.NoErr(err) // Should create temp dir + + err = os.Chdir(dir) + assert.NoErr(err) // Should chdir to temp dir + + name, err := module() + assert.NoErr(err) // Should get module name + + expected := tc.Expected + if strings.Contains(expected, "%s") { + expected = fmt.Sprintf(expected, tmp) + } + + assert.Equal(name, expected) // Module name should match expected name + }) + } +} diff --git a/main.go b/main.go index 1e74a63..e903f4b 100644 --- a/main.go +++ b/main.go @@ -11,35 +11,54 @@ import ( "github.com/peterbourgon/ff/v3" ) +var Version = "develop" + func main() { fs := flag.NewFlagSet("gomodinit", flag.ExitOnError) - base := fs.String("base", "", "Base URL prefix for module") + versionFlag := fs.Bool("version", false, "Print version and exit") if err := ff.Parse(fs, os.Args[1:], ff.WithEnvVarPrefix("GMI")); err != nil { fmt.Println(err) return } - if *base == "" { - fmt.Println("Base URL is required") + if *versionFlag { + fmt.Printf("gomodinit %s\n", Version) return } - dir, err := os.Getwd() - if err != nil { - fmt.Println(err) - return - } - - name := filepath.Base(dir) + var name string if fs.NArg() > 0 { name = fs.Arg(0) + } else { + n, err := module() + if err != nil { + fmt.Println(err) + return + } + name = n } - *base = strings.TrimSuffix(*base, "/") - - cmd := exec.Command("go", "mod", "init", fmt.Sprintf("%s/%s", *base, name)) + cmd := exec.Command("go", "mod", "init", name) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr _ = cmd.Run() } + +func module() (string, error) { + dir, err := os.Getwd() + if err != nil { + return "", err + } + + list := strings.Split(dir, string(filepath.Separator)) + name := list[len(list)-1] + for idx := len(list) - 2; idx >= 0; idx-- { + part := list[idx] + name = fmt.Sprintf("%s/%s", part, name) + if strings.Contains(part, ".") { + break + } + } + return name, nil +}