diff --git a/tools/goctl/api/gogen/config.tpl b/tools/goctl/api/gogen/config.tpl index 55127efba..5fa7ad602 100644 --- a/tools/goctl/api/gogen/config.tpl +++ b/tools/goctl/api/gogen/config.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package config import {{.authImport}} diff --git a/tools/goctl/api/gogen/gencomment_test.go b/tools/goctl/api/gogen/gencomment_test.go new file mode 100644 index 000000000..12e78af4c --- /dev/null +++ b/tools/goctl/api/gogen/gencomment_test.go @@ -0,0 +1,181 @@ +package gogen + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zeromicro/go-zero/tools/goctl/internal/version" +) + +// TestGenerationComments verifies that all generated files have appropriate generation comments +func TestGenerationComments(t *testing.T) { + // Create a temporary directory for our test + tempDir, err := os.MkdirTemp("", "goctl_test_") + require.NoError(t, err) + defer os.RemoveAll(tempDir) + + // Create a simple API spec for testing + apiContent := ` +syntax = "v1" + +type HelloRequest { + Name string ` + "`json:\"name\"`" + ` +} + +type HelloResponse { + Message string ` + "`json:\"message\"`" + ` +} + +service hello-api { + @handler helloHandler + post /hello (HelloRequest) returns (HelloResponse) +}` + + // Write the API spec to a temporary file + apiFile := filepath.Join(tempDir, "test.api") + err = os.WriteFile(apiFile, []byte(apiContent), 0644) + require.NoError(t, err) + + // Parse and generate the API files using the correct function signature + err = DoGenProject(apiFile, tempDir, "gozero", false) + require.NoError(t, err) + + // Define expected files and their comment types + expectedFiles := map[string]string{ + // Files that should have "DO NOT EDIT" comments (regenerated files) + "internal/types/types.go": "DO NOT EDIT", + + // Files that should have "Safe to edit" comments (scaffolded files) + "internal/handler/hellohandler.go": "Safe to edit", + "internal/config/config.go": "Safe to edit", + "hello.go": "Safe to edit", // main file + "internal/svc/servicecontext.go": "Safe to edit", + "internal/logic/hellologic.go": "Safe to edit", + } + + // Check each file for the correct generation comment + for filePath, expectedCommentType := range expectedFiles { + fullPath := filepath.Join(tempDir, filePath) + + // Skip if file doesn't exist (some files might not be generated in all cases) + if _, err := os.Stat(fullPath); os.IsNotExist(err) { + t.Logf("File %s does not exist, skipping", filePath) + continue + } + + content, err := os.ReadFile(fullPath) + require.NoError(t, err, "Failed to read file: %s", filePath) + + contentStr := string(content) + lines := strings.Split(contentStr, "\n") + + // Check that the file starts with proper generation comments + require.GreaterOrEqual(t, len(lines), 2, "File %s should have at least 2 lines", filePath) + + if expectedCommentType == "DO NOT EDIT" { + assert.Contains(t, lines[0], "// Code generated by goctl. DO NOT EDIT.", + "File %s should have 'DO NOT EDIT' comment as first line", filePath) + } else if expectedCommentType == "Safe to edit" { + assert.Contains(t, lines[0], "// Code scaffolded by goctl. Safe to edit.", + "File %s should have 'Safe to edit' comment as first line", filePath) + } + + // Check that the second line contains the version + assert.Contains(t, lines[1], "// goctl", + "File %s should have version comment as second line", filePath) + assert.Contains(t, lines[1], version.BuildVersion, + "File %s should contain version %s in second line", filePath, version.BuildVersion) + } +} + +// TestRoutesGenerationComment verifies routes files have "DO NOT EDIT" comment +func TestRoutesGenerationComment(t *testing.T) { + // Create a temporary directory for our test + tempDir, err := os.MkdirTemp("", "goctl_routes_test_") + require.NoError(t, err) + defer os.RemoveAll(tempDir) + + // Create an API spec with multiple handlers to ensure routes file is generated + apiContent := ` +syntax = "v1" + +type HelloRequest { + Name string ` + "`json:\"name\"`" + ` +} + +type HelloResponse { + Message string ` + "`json:\"message\"`" + ` +} + +service hello-api { + @handler helloHandler + post /hello (HelloRequest) returns (HelloResponse) + + @handler worldHandler + get /world returns (HelloResponse) +}` + + // Write the API spec to a temporary file + apiFile := filepath.Join(tempDir, "test.api") + err = os.WriteFile(apiFile, []byte(apiContent), 0644) + require.NoError(t, err) + + // Generate the API files using the correct function signature + err = DoGenProject(apiFile, tempDir, "gozero", false) + require.NoError(t, err) + + // Check the routes file specifically + routesFile := filepath.Join(tempDir, "internal/handler/routes.go") + if _, err := os.Stat(routesFile); os.IsNotExist(err) { + t.Skip("Routes file not generated, skipping test") + return + } + + content, err := os.ReadFile(routesFile) + require.NoError(t, err, "Failed to read routes.go") + + contentStr := string(content) + lines := strings.Split(contentStr, "\n") + + // Check that routes.go has "DO NOT EDIT" comment + require.GreaterOrEqual(t, len(lines), 2, "Routes file should have at least 2 lines") + assert.Contains(t, lines[0], "// Code generated by goctl. DO NOT EDIT.", + "Routes file should have 'DO NOT EDIT' comment") + assert.Contains(t, lines[1], "// goctl", + "Routes file should have version comment") + assert.Contains(t, lines[1], version.BuildVersion, + "Routes file should contain version %s", version.BuildVersion) +} + +// TestVersionInTemplateData verifies that version is correctly passed to templates +func TestVersionInTemplateData(t *testing.T) { + // Test that BuildVersion is available + assert.NotEmpty(t, version.BuildVersion, "BuildVersion should not be empty") +} + +// TestCommentsFollowGoStandards verifies our comments follow Go community standards +func TestCommentsFollowGoStandards(t *testing.T) { + // Test the format of our generation comments + doNotEditComment := "// Code generated by goctl. DO NOT EDIT." + safeToEditComment := "// Code scaffolded by goctl. Safe to edit." + + // Both should be valid Go comments + assert.True(t, strings.HasPrefix(doNotEditComment, "//"), + "DO NOT EDIT comment should start with //") + assert.True(t, strings.HasPrefix(safeToEditComment, "//"), + "Safe to edit comment should start with //") + + // Should contain key information + assert.Contains(t, doNotEditComment, "goctl", + "DO NOT EDIT comment should mention goctl") + assert.Contains(t, safeToEditComment, "goctl", + "Safe to edit comment should mention goctl") + assert.Contains(t, doNotEditComment, "DO NOT EDIT", + "Should clearly state DO NOT EDIT") + assert.Contains(t, safeToEditComment, "Safe to edit", + "Should clearly state Safe to edit") +} diff --git a/tools/goctl/api/gogen/genconfig.go b/tools/goctl/api/gogen/genconfig.go index 423b3283f..465dcfc64 100644 --- a/tools/goctl/api/gogen/genconfig.go +++ b/tools/goctl/api/gogen/genconfig.go @@ -7,6 +7,7 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/config" + "github.com/zeromicro/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/vars" ) @@ -61,6 +62,7 @@ func genConfig(dir, projectPkg string, cfg *config.Config, api *spec.ApiSpec) er "auth": strings.Join(auths, "\n"), "jwtTrans": strings.Join(jwtTransList, "\n"), "projectPkg": projectPkg, + "version": version.BuildVersion, }, }) } diff --git a/tools/goctl/api/gogen/genhandlers.go b/tools/goctl/api/gogen/genhandlers.go index 52d5d9eaf..54d918b72 100644 --- a/tools/goctl/api/gogen/genhandlers.go +++ b/tools/goctl/api/gogen/genhandlers.go @@ -8,6 +8,7 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/config" + "github.com/zeromicro/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/pathx" @@ -64,6 +65,7 @@ func genHandler(dir, rootPkg, projectPkg string, cfg *config.Config, group spec. "HasDoc": len(route.JoinedDoc()) > 0, "Doc": getDoc(route.JoinedDoc()), "projectPkg": projectPkg, + "version": version.BuildVersion, }, }) } diff --git a/tools/goctl/api/gogen/genhandlerstest.go b/tools/goctl/api/gogen/genhandlerstest.go index e066af385..51603ddd4 100644 --- a/tools/goctl/api/gogen/genhandlerstest.go +++ b/tools/goctl/api/gogen/genhandlerstest.go @@ -7,6 +7,7 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/config" + "github.com/zeromicro/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/pathx" @@ -51,6 +52,7 @@ func genHandlerTest(dir, rootPkg, projectPkg string, cfg *config.Config, group s "HasDoc": len(route.JoinedDoc()) > 0, "Doc": getDoc(route.JoinedDoc()), "projectPkg": projectPkg, + "version": version.BuildVersion, }, }) } diff --git a/tools/goctl/api/gogen/genlogic.go b/tools/goctl/api/gogen/genlogic.go index de08742a4..39aeef75f 100644 --- a/tools/goctl/api/gogen/genlogic.go +++ b/tools/goctl/api/gogen/genlogic.go @@ -10,6 +10,7 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/api/parser/g4/gen/api" "github.com/zeromicro/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/config" + "github.com/zeromicro/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/vars" @@ -92,6 +93,7 @@ func genLogicByRoute(dir, rootPkg, projectPkg string, cfg *config.Config, group "hasDoc": len(route.JoinedDoc()) > 0, "doc": getDoc(route.JoinedDoc()), "projectPkg": projectPkg, + "version": version.BuildVersion, }, }) } diff --git a/tools/goctl/api/gogen/genlogictest.go b/tools/goctl/api/gogen/genlogictest.go index c831561e3..e0c5b6b46 100644 --- a/tools/goctl/api/gogen/genlogictest.go +++ b/tools/goctl/api/gogen/genlogictest.go @@ -7,6 +7,7 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/config" + "github.com/zeromicro/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/pathx" ) @@ -74,6 +75,7 @@ func genLogicTestByRoute(dir, rootPkg, projectPkg string, cfg *config.Config, gr "hasDoc": len(route.JoinedDoc()) > 0, "doc": getDoc(route.JoinedDoc()), "projectPkg": projectPkg, + "version": version.BuildVersion, }, }) } diff --git a/tools/goctl/api/gogen/genmain.go b/tools/goctl/api/gogen/genmain.go index b6828ceed..c0e36f03a 100644 --- a/tools/goctl/api/gogen/genmain.go +++ b/tools/goctl/api/gogen/genmain.go @@ -7,6 +7,7 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/config" + "github.com/zeromicro/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/vars" @@ -39,6 +40,7 @@ func genMain(dir, rootPkg, projectPkg string, cfg *config.Config, api *spec.ApiS "importPackages": genMainImports(rootPkg), "serviceName": configName, "projectPkg": projectPkg, + "version": version.BuildVersion, }, }) } diff --git a/tools/goctl/api/gogen/genmiddleware.go b/tools/goctl/api/gogen/genmiddleware.go index d302b51cc..35d811724 100644 --- a/tools/goctl/api/gogen/genmiddleware.go +++ b/tools/goctl/api/gogen/genmiddleware.go @@ -6,6 +6,7 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/config" + "github.com/zeromicro/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/util/format" ) @@ -31,7 +32,8 @@ func genMiddleware(dir string, cfg *config.Config, api *spec.ApiSpec) error { templateFile: middlewareImplementCodeFile, builtinTemplate: middlewareImplementCode, data: map[string]string{ - "name": strings.Title(name), + "name": strings.Title(name), + "version": version.BuildVersion, }, }) if err != nil { diff --git a/tools/goctl/api/gogen/gensvc.go b/tools/goctl/api/gogen/gensvc.go index cbe9a96c6..fefbb71dd 100644 --- a/tools/goctl/api/gogen/gensvc.go +++ b/tools/goctl/api/gogen/gensvc.go @@ -7,6 +7,7 @@ import ( "github.com/zeromicro/go-zero/tools/goctl/api/spec" "github.com/zeromicro/go-zero/tools/goctl/config" + "github.com/zeromicro/go-zero/tools/goctl/internal/version" "github.com/zeromicro/go-zero/tools/goctl/util/format" "github.com/zeromicro/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/vars" @@ -54,6 +55,7 @@ func genServiceContext(dir, rootPkg, projectPkg string, cfg *config.Config, api "middleware": middlewareStr, "middlewareAssignment": middlewareAssignment, "projectPkg": projectPkg, + "version": version.BuildVersion, }, }) } diff --git a/tools/goctl/api/gogen/handler.tpl b/tools/goctl/api/gogen/handler.tpl index fce5acc2d..eba1f7abc 100644 --- a/tools/goctl/api/gogen/handler.tpl +++ b/tools/goctl/api/gogen/handler.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package {{.PkgName}} import ( diff --git a/tools/goctl/api/gogen/handler_test.tpl b/tools/goctl/api/gogen/handler_test.tpl index a07716350..d1976ea08 100644 --- a/tools/goctl/api/gogen/handler_test.tpl +++ b/tools/goctl/api/gogen/handler_test.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package {{.PkgName}} import ( diff --git a/tools/goctl/api/gogen/logic.tpl b/tools/goctl/api/gogen/logic.tpl index 94611c577..d89dc1514 100644 --- a/tools/goctl/api/gogen/logic.tpl +++ b/tools/goctl/api/gogen/logic.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package {{.pkgName}} import ( diff --git a/tools/goctl/api/gogen/logic_test.tpl b/tools/goctl/api/gogen/logic_test.tpl index a63cd2a21..9a211df9b 100644 --- a/tools/goctl/api/gogen/logic_test.tpl +++ b/tools/goctl/api/gogen/logic_test.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package {{.pkgName}} import ( diff --git a/tools/goctl/api/gogen/main.tpl b/tools/goctl/api/gogen/main.tpl index ad1a46d0b..88c6fd987 100644 --- a/tools/goctl/api/gogen/main.tpl +++ b/tools/goctl/api/gogen/main.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package main import ( diff --git a/tools/goctl/api/gogen/middleware.tpl b/tools/goctl/api/gogen/middleware.tpl index 3a9f8e91a..260e98dc0 100644 --- a/tools/goctl/api/gogen/middleware.tpl +++ b/tools/goctl/api/gogen/middleware.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package middleware import "net/http" diff --git a/tools/goctl/api/gogen/sse_handler.tpl b/tools/goctl/api/gogen/sse_handler.tpl index 2ed4cf322..722167095 100644 --- a/tools/goctl/api/gogen/sse_handler.tpl +++ b/tools/goctl/api/gogen/sse_handler.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package {{.PkgName}} import ( diff --git a/tools/goctl/api/gogen/sse_logic.tpl b/tools/goctl/api/gogen/sse_logic.tpl index b29fbd303..676cdf322 100644 --- a/tools/goctl/api/gogen/sse_logic.tpl +++ b/tools/goctl/api/gogen/sse_logic.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package {{.pkgName}} import ( diff --git a/tools/goctl/api/gogen/svc.tpl b/tools/goctl/api/gogen/svc.tpl index c15c1e452..c85dfb0a9 100644 --- a/tools/goctl/api/gogen/svc.tpl +++ b/tools/goctl/api/gogen/svc.tpl @@ -1,3 +1,6 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + package svc import (