feat: support goctl --module to set go module (#5135)

This commit is contained in:
Kevin Wan
2025-08-31 16:40:49 +08:00
committed by GitHub
parent d728a3b2d9
commit 955b8016aa
14 changed files with 944 additions and 6 deletions

View File

@@ -9,17 +9,30 @@ import (
)
func GetParentPackage(dir string) (string, string, error) {
return GetParentPackageWithModule(dir, "")
}
func GetParentPackageWithModule(dir, moduleName string) (string, string, error) {
abs, err := filepath.Abs(dir)
if err != nil {
return "", "", err
}
projectCtx, err := ctx.Prepare(abs)
var projectCtx *ctx.ProjectContext
if len(moduleName) > 0 {
projectCtx, err = ctx.PrepareWithModule(abs, moduleName)
} else {
projectCtx, err = ctx.Prepare(abs)
}
if err != nil {
return "", "", err
}
// fix https://github.com/zeromicro/go-zero/issues/1058
return buildParentPackage(projectCtx)
}
// buildParentPackage extracts the common logic for building parent package paths
func buildParentPackage(projectCtx *ctx.ProjectContext) (string, string, error) {
wd := projectCtx.WorkDir
d := projectCtx.Dir
same, err := pathx.SameFile(wd, d)

View File

@@ -0,0 +1,223 @@
package golang
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetParentPackage(t *testing.T) {
// Create a temporary directory for testing
tempDir, err := os.MkdirTemp("", "goctl-test-*")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
// Test with a directory (should create go.mod with directory name)
testDir := filepath.Join(tempDir, "testproject")
err = os.MkdirAll(testDir, 0755)
require.NoError(t, err)
parentPkg, rootPkg, err := GetParentPackage(testDir)
assert.NoError(t, err)
assert.Equal(t, "testproject", parentPkg)
assert.Equal(t, "testproject", rootPkg)
// Verify go.mod was created with directory name
goModPath := filepath.Join(testDir, "go.mod")
assert.FileExists(t, goModPath)
content, err := os.ReadFile(goModPath)
require.NoError(t, err)
assert.Contains(t, string(content), "module testproject")
}
func TestGetParentPackageWithModule(t *testing.T) {
tests := []struct {
name string
moduleName string
expectedModule string
expectedPkg string
}{
{
name: "custom module name",
moduleName: "github.com/example/myproject",
expectedModule: "github.com/example/myproject",
expectedPkg: "github.com/example/myproject",
},
{
name: "simple module name",
moduleName: "myservice",
expectedModule: "myservice",
expectedPkg: "myservice",
},
{
name: "empty module name falls back to directory",
moduleName: "",
expectedModule: "fallback",
expectedPkg: "fallback",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a temporary directory for testing
tempDir, err := os.MkdirTemp("", "goctl-test-*")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
// Create test directory - use "fallback" name for empty module test
testDirName := "fallback"
if tt.name != "empty module name falls back to directory" {
testDirName = "testdir"
}
testDir := filepath.Join(tempDir, testDirName)
err = os.MkdirAll(testDir, 0755)
require.NoError(t, err)
parentPkg, rootPkg, err := GetParentPackageWithModule(testDir, tt.moduleName)
assert.NoError(t, err)
assert.Equal(t, tt.expectedPkg, parentPkg)
assert.Equal(t, tt.expectedModule, rootPkg)
// Verify go.mod was created with correct module name
goModPath := filepath.Join(testDir, "go.mod")
assert.FileExists(t, goModPath)
content, err := os.ReadFile(goModPath)
require.NoError(t, err)
assert.Contains(t, string(content), "module "+tt.expectedModule)
})
}
}
func TestGetParentPackageWithModule_InvalidDir(t *testing.T) {
// Test with non-existent directory
_, _, err := GetParentPackageWithModule("/non/existent/path", "github.com/example/test")
assert.Error(t, err)
}
func TestGetParentPackage_InvalidDir(t *testing.T) {
// Test with non-existent directory
_, _, err := GetParentPackage("/non/existent/path")
assert.Error(t, err)
}
func TestGetParentPackage_UsesGetParentPackageWithModule(t *testing.T) {
// Create a temporary directory for testing
tempDir, err := os.MkdirTemp("", "goctl-test-*")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
testDir := filepath.Join(tempDir, "testproject")
err = os.MkdirAll(testDir, 0755)
require.NoError(t, err)
// Test that GetParentPackage calls GetParentPackageWithModule with empty string
parentPkg1, rootPkg1, err1 := GetParentPackage(testDir)
require.NoError(t, err1)
// Clean up go.mod to test again
os.Remove(filepath.Join(testDir, "go.mod"))
parentPkg2, rootPkg2, err2 := GetParentPackageWithModule(testDir, "")
require.NoError(t, err2)
// Should produce identical results
assert.Equal(t, parentPkg1, parentPkg2)
assert.Equal(t, rootPkg1, rootPkg2)
}
func TestBuildParentPackage(t *testing.T) {
// This tests the internal buildParentPackage function indirectly
// through the public API, as it's a private function
// Create a temporary directory with subdirectory structure
tempDir, err := os.MkdirTemp("", "goctl-test-*")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
// Create a nested directory structure
projectDir := filepath.Join(tempDir, "myproject")
subDir := filepath.Join(projectDir, "internal", "logic")
err = os.MkdirAll(subDir, 0755)
require.NoError(t, err)
// Test from root directory
parentPkg, rootPkg, err := GetParentPackageWithModule(projectDir, "github.com/example/myproject")
assert.NoError(t, err)
assert.Equal(t, "github.com/example/myproject", parentPkg)
assert.Equal(t, "github.com/example/myproject", rootPkg)
// Test from subdirectory
parentPkg2, rootPkg2, err := GetParentPackageWithModule(subDir, "github.com/example/myproject")
assert.NoError(t, err)
assert.Equal(t, "github.com/example/myproject/internal/logic", parentPkg2)
assert.Equal(t, "github.com/example/myproject", rootPkg2)
}
func TestGetParentPackageWithModule_SpecialCharacters(t *testing.T) {
tests := []struct {
name string
moduleName string
valid bool
}{
{
name: "domain with path",
moduleName: "github.com/user/repo",
valid: true,
},
{
name: "domain with version",
moduleName: "github.com/user/repo/v2",
valid: true,
},
{
name: "private repo",
moduleName: "private.example.com/team/project",
valid: true,
},
{
name: "simple name with underscore",
moduleName: "my_project",
valid: true,
},
{
name: "simple name with hyphen",
moduleName: "my-project",
valid: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Create a temporary directory for testing
tempDir, err := os.MkdirTemp("", "goctl-test-*")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
testDir := filepath.Join(tempDir, "testdir")
err = os.MkdirAll(testDir, 0755)
require.NoError(t, err)
parentPkg, rootPkg, err := GetParentPackageWithModule(testDir, tt.moduleName)
if tt.valid {
assert.NoError(t, err)
assert.Equal(t, tt.moduleName, parentPkg)
assert.Equal(t, tt.moduleName, rootPkg)
// Verify go.mod contains the module name
goModPath := filepath.Join(testDir, "go.mod")
content, err := os.ReadFile(goModPath)
require.NoError(t, err)
assert.Contains(t, string(content), "module "+tt.moduleName)
} else {
assert.Error(t, err)
}
})
}
}