mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-11 00:40:00 +08:00
feat: support goctl --module to set go module (#5135)
This commit is contained in:
@@ -90,6 +90,7 @@ func init() {
|
||||
newCmdFlags.StringVar(&new.VarStringHome, "home")
|
||||
newCmdFlags.StringVar(&new.VarStringRemote, "remote")
|
||||
newCmdFlags.StringVar(&new.VarStringBranch, "branch")
|
||||
newCmdFlags.StringVar(&new.VarStringModule, "module")
|
||||
newCmdFlags.StringVarWithDefaultValue(&new.VarStringStyle, "style", config.DefaultFormat)
|
||||
|
||||
pluginCmdFlags.StringVarP(&plugin.VarStringPlugin, "plugin", "p")
|
||||
|
||||
@@ -75,6 +75,11 @@ func GoCommand(_ *cobra.Command, _ []string) error {
|
||||
|
||||
// DoGenProject gen go project files with api file
|
||||
func DoGenProject(apiFile, dir, style string, withTest bool) error {
|
||||
return DoGenProjectWithModule(apiFile, dir, "", style, withTest)
|
||||
}
|
||||
|
||||
// DoGenProjectWithModule gen go project files with api file using custom module name
|
||||
func DoGenProjectWithModule(apiFile, dir, moduleName, style string, withTest bool) error {
|
||||
api, err := parser.Parse(apiFile)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -90,7 +95,13 @@ func DoGenProject(apiFile, dir, style string, withTest bool) error {
|
||||
}
|
||||
|
||||
logx.Must(pathx.MkdirIfNotExist(dir))
|
||||
rootPkg, projectPkg, err := golang.GetParentPackage(dir)
|
||||
|
||||
var rootPkg, projectPkg string
|
||||
if len(moduleName) > 0 {
|
||||
rootPkg, projectPkg, err = golang.GetParentPackageWithModule(dir, moduleName)
|
||||
} else {
|
||||
rootPkg, projectPkg, err = golang.GetParentPackage(dir)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ var (
|
||||
VarStringBranch string
|
||||
// VarStringStyle describes the style of output files.
|
||||
VarStringStyle string
|
||||
// VarStringModule describes the module name for go.mod.
|
||||
VarStringModule string
|
||||
)
|
||||
|
||||
// CreateServiceCommand fast create service
|
||||
@@ -83,6 +85,6 @@ func CreateServiceCommand(_ *cobra.Command, args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = gogen.DoGenProject(apiFilePath, abs, VarStringStyle, false)
|
||||
err = gogen.DoGenProjectWithModule(apiFilePath, abs, VarStringModule, VarStringStyle, false)
|
||||
return err
|
||||
}
|
||||
|
||||
205
tools/goctl/api/new/newservice_test.go
Normal file
205
tools/goctl/api/new/newservice_test.go
Normal file
@@ -0,0 +1,205 @@
|
||||
package new
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
|
||||
"github.com/zeromicro/go-zero/tools/goctl/config"
|
||||
)
|
||||
|
||||
func TestDoGenProjectWithModule_Integration(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
moduleName string
|
||||
serviceName string
|
||||
expectedMod string
|
||||
}{
|
||||
{
|
||||
name: "with custom module",
|
||||
moduleName: "github.com/test/customapi",
|
||||
serviceName: "myservice",
|
||||
expectedMod: "github.com/test/customapi",
|
||||
},
|
||||
{
|
||||
name: "with empty module",
|
||||
moduleName: "",
|
||||
serviceName: "myservice",
|
||||
expectedMod: "myservice",
|
||||
},
|
||||
{
|
||||
name: "with simple module",
|
||||
moduleName: "simpleapi",
|
||||
serviceName: "testapi",
|
||||
expectedMod: "simpleapi",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Create temporary directory
|
||||
tempDir, err := os.MkdirTemp("", "goctl-api-module-test-*")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Create service directory
|
||||
serviceDir := filepath.Join(tempDir, tt.serviceName)
|
||||
err = os.MkdirAll(serviceDir, 0755)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a simple API file for testing
|
||||
apiContent := `syntax = "v1"
|
||||
|
||||
type Request {
|
||||
Name string ` + "`" + `path:"name,options=you|me"` + "`" + `
|
||||
}
|
||||
|
||||
type Response {
|
||||
Message string ` + "`" + `json:"message"` + "`" + `
|
||||
}
|
||||
|
||||
service ` + tt.serviceName + `-api {
|
||||
@handler ` + tt.serviceName + `Handler
|
||||
get /from/:name(Request) returns (Response)
|
||||
}
|
||||
`
|
||||
apiFile := filepath.Join(serviceDir, tt.serviceName+".api")
|
||||
err = os.WriteFile(apiFile, []byte(apiContent), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Call the module-aware service creation function
|
||||
err = gogen.DoGenProjectWithModule(apiFile, serviceDir, tt.moduleName, config.DefaultFormat, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check go.mod file
|
||||
goModPath := filepath.Join(serviceDir, "go.mod")
|
||||
assert.FileExists(t, goModPath)
|
||||
|
||||
// Verify module name in go.mod
|
||||
content, err := os.ReadFile(goModPath)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, string(content), "module "+tt.expectedMod)
|
||||
|
||||
// Check basic directory structure was created
|
||||
assert.DirExists(t, filepath.Join(serviceDir, "etc"))
|
||||
assert.DirExists(t, filepath.Join(serviceDir, "internal"))
|
||||
assert.DirExists(t, filepath.Join(serviceDir, "internal", "handler"))
|
||||
assert.DirExists(t, filepath.Join(serviceDir, "internal", "logic"))
|
||||
assert.DirExists(t, filepath.Join(serviceDir, "internal", "svc"))
|
||||
assert.DirExists(t, filepath.Join(serviceDir, "internal", "types"))
|
||||
assert.DirExists(t, filepath.Join(serviceDir, "internal", "config"))
|
||||
|
||||
// Check that main.go imports use correct module
|
||||
mainGoPath := filepath.Join(serviceDir, tt.serviceName+".go")
|
||||
if _, err := os.Stat(mainGoPath); err == nil {
|
||||
mainContent, err := os.ReadFile(mainGoPath)
|
||||
require.NoError(t, err)
|
||||
// Check for import of internal packages with correct module path
|
||||
assert.Contains(t, string(mainContent), `"`+tt.expectedMod+"/internal/")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateServiceCommand_Integration(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
moduleName string
|
||||
serviceName string
|
||||
expectedMod string
|
||||
shouldError bool
|
||||
}{
|
||||
{
|
||||
name: "valid service with custom module",
|
||||
moduleName: "github.com/example/testapi",
|
||||
serviceName: "myapi",
|
||||
expectedMod: "github.com/example/testapi",
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "valid service with no module",
|
||||
moduleName: "",
|
||||
serviceName: "simpleapi",
|
||||
expectedMod: "simpleapi",
|
||||
shouldError: false,
|
||||
},
|
||||
{
|
||||
name: "invalid service name with hyphens",
|
||||
moduleName: "github.com/test/api",
|
||||
serviceName: "my-api",
|
||||
expectedMod: "",
|
||||
shouldError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.shouldError && tt.serviceName == "my-api" {
|
||||
// Test that service names with hyphens are rejected
|
||||
// This is tested in the actual command function, not the generate function
|
||||
assert.Contains(t, tt.serviceName, "-")
|
||||
return
|
||||
}
|
||||
|
||||
// Create temporary directory
|
||||
tempDir, err := os.MkdirTemp("", "goctl-create-service-test-*")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
// Change to temp directory
|
||||
oldDir, _ := os.Getwd()
|
||||
defer os.Chdir(oldDir)
|
||||
os.Chdir(tempDir)
|
||||
|
||||
// Set the module variable as the command would
|
||||
VarStringModule = tt.moduleName
|
||||
VarStringStyle = config.DefaultFormat
|
||||
|
||||
// Create the service directory manually since we're testing the core functionality
|
||||
serviceDir := filepath.Join(tempDir, tt.serviceName)
|
||||
|
||||
// Simulate what CreateServiceCommand does - create API file and call DoGenProjectWithModule
|
||||
err = os.MkdirAll(serviceDir, 0755)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create API file
|
||||
apiContent := `syntax = "v1"
|
||||
|
||||
type Request {
|
||||
Name string ` + "`" + `path:"name,options=you|me"` + "`" + `
|
||||
}
|
||||
|
||||
type Response {
|
||||
Message string ` + "`" + `json:"message"` + "`" + `
|
||||
}
|
||||
|
||||
service ` + tt.serviceName + `-api {
|
||||
@handler ` + tt.serviceName + `Handler
|
||||
get /from/:name(Request) returns (Response)
|
||||
}
|
||||
`
|
||||
apiFile := filepath.Join(serviceDir, tt.serviceName+".api")
|
||||
err = os.WriteFile(apiFile, []byte(apiContent), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Call DoGenProjectWithModule as CreateServiceCommand does
|
||||
err = gogen.DoGenProjectWithModule(apiFile, serviceDir, VarStringModule, VarStringStyle, false)
|
||||
|
||||
if tt.shouldError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Verify go.mod
|
||||
goModPath := filepath.Join(serviceDir, "go.mod")
|
||||
assert.FileExists(t, goModPath)
|
||||
content, err := os.ReadFile(goModPath)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, string(content), "module "+tt.expectedMod)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user