From ee15e0932a76f75ef5e2ecbe67bf04e4abdc54e6 Mon Sep 17 00:00:00 2001 From: Rogee Date: Fri, 12 Sep 2025 10:33:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E5=B8=AE=E5=8A=A9=E6=96=87=E6=A1=A3=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=AF=A6=E7=BB=86=E8=AF=B4=E6=98=8E=E5=92=8C=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/buf.go | 19 ++++++++++++++----- cmd/fmt.go | 19 ++++++++++++++----- cmd/gen.go | 17 ++++++++++++----- cmd/gen_enum.go | 25 ++++++++++++------------- cmd/gen_model.go | 13 +++++++++++++ cmd/gen_provider.go | 24 ++++++++++++++++++++---- cmd/gen_route.go | 31 +++++++++++++++++++++++++------ cmd/gen_service.go | 9 +++++++++ cmd/migrate.go | 14 ++++++++++++++ cmd/new.go | 8 ++++++++ cmd/new_event.go | 11 +++++++++++ cmd/new_job.go | 18 ++++++++++++++++-- cmd/new_project.go | 13 +++++++++++++ cmd/new_provider.go | 10 ++++++++++ cmd/swag.go | 1 + cmd/swag_fmt.go | 17 +++++++++++------ cmd/swag_init.go | 20 ++++++++++++++------ 17 files changed, 217 insertions(+), 52 deletions(-) diff --git a/cmd/buf.go b/cmd/buf.go index e6741fb..105a71c 100644 --- a/cmd/buf.go +++ b/cmd/buf.go @@ -11,11 +11,20 @@ import ( ) func CommandBuf(root *cobra.Command) { - cmd := &cobra.Command{ - Use: "buf", - Short: "run buf commands", - RunE: commandBufE, - } + cmd := &cobra.Command{ + Use: "buf", + Short: "run buf commands", + Long: `在指定目录执行 buf generate。若本机未安装 buf,将自动 go install github.com/bufbuild/buf/cmd/buf@v1.48.0。 + +Flags: +- --dir 执行目录(默认 .) +- --dry-run 仅打印将要执行的命令 + +说明: +- 运行前会检查 buf.yaml 是否存在,如不存在会给出提示但仍尝试执行 +- 成功后输出生成结果日志`, + RunE: commandBufE, + } cmd.Flags().String("dir", ".", "Directory to run buf from") cmd.Flags().Bool("dry-run", false, "Preview buf command without executing") diff --git a/cmd/fmt.go b/cmd/fmt.go index 8db64f6..2ae6e50 100644 --- a/cmd/fmt.go +++ b/cmd/fmt.go @@ -10,11 +10,20 @@ import ( ) func CommandFmt(root *cobra.Command) { - cmd := &cobra.Command{ - Use: "fmt", - Short: "fmt codes", - RunE: commandFmtE, - } + cmd := &cobra.Command{ + Use: "fmt", + Short: "fmt codes", + Long: `使用 gofumpt -extra 对代码进行格式化;若本机未安装,将自动 go install mvdan.cc/gofumpt@latest。 + +Flags: +- --check 仅检查不写入,输出未格式化文件列表 +- --path 指定格式化路径(默认 .) + +说明: +- 正常格式化等价于:gofumpt -l -extra -w +- 检查模式等价于:gofumpt -l -extra `, + RunE: commandFmtE, + } cmd.Flags().Bool("check", false, "Check formatting without writing changes") cmd.Flags().String("path", ".", "Path to format (default .)") diff --git a/cmd/gen.go b/cmd/gen.go index e95b07c..0bee3ca 100644 --- a/cmd/gen.go +++ b/cmd/gen.go @@ -3,11 +3,18 @@ package cmd import "github.com/spf13/cobra" func CommandGen(root *cobra.Command) { - cmd := &cobra.Command{ - Use: "gen", - Short: "Generate code", - PersistentPostRunE: commandFmtE, - } + cmd := &cobra.Command{ + Use: "gen", + Short: "Generate code", + Long: `代码生成命令组:包含 route、provider、model、enum、service 等。 + +持久化参数: +- -c, --config 数据库配置文件(默认 config.toml),供 gen model 使用 + +说明: +- 子命令执行完成后会自动运行 atomctl fmt 进行格式化`, + PersistentPostRunE: commandFmtE, + } cmd.PersistentFlags().StringP("config", "c", "config.toml", "database config file") cmds := []func(*cobra.Command){ diff --git a/cmd/gen_enum.go b/cmd/gen_enum.go index 8bc774c..2ce8e3f 100644 --- a/cmd/gen_enum.go +++ b/cmd/gen_enum.go @@ -19,23 +19,22 @@ func CommandGenEnum(root *cobra.Command) { Use: "enum", Aliases: []string{"e"}, Short: "Generate enums", - Long: `Generate enums from Go files that contain both ENUM(...) and swagger:enum. + Long: `根据包含 ENUM(...) 且带有 swagger:enum 标记的 Go 文件生成枚举辅助代码。 -Scans the project (recursively) for matching files and writes a corresponding -*.gen.go per file with helpers. +扫描工程(递归)查找匹配文件,并为每个文件生成对应的 *.gen.go。 -Flags: -- -f, --flag Generate flag.Value support (default: true) -- -m, --marshal Generate JSON marshal/unmarshal methods -- -s, --sql Generate database/sql helpers (int, null types) (default: true) +参数(Flags): +- -f, --flag 生成 flag.Value 支持(默认 true) +- -m, --marshal 生成 JSON 编解码方法 +- -s, --sql 生成 database/sql 相关辅助(整型、Null 类型等,默认 true) -Behavior: -- Always generates Names() and Values() -- With --marshal: adds JSON encoding/decoding -- With --flag: adds flag.Value support -- With --sql: adds SQL driver, int, NullInt, NullString helpers +行为说明: +- 始终生成 Names() 与 Values() +- 指定 --marshal:增加 JSON 编解码 +- 指定 --flag:增加 flag.Value 支持 +- 指定 --sql:增加 SQL driver、Int、NullInt、NullString 等辅助 -Examples: +示例: atomctl gen enum -m -s atomctl gen enum --flag=false`, RunE: commandGenEnumE, diff --git a/cmd/gen_model.go b/cmd/gen_model.go index a9a5703..c9aa2e8 100644 --- a/cmd/gen_model.go +++ b/cmd/gen_model.go @@ -18,6 +18,19 @@ func CommandGenModel(root *cobra.Command) { Use: "model", Aliases: []string{"m"}, Short: "Generate models", + Long: `根据数据库连接配置生成模型代码,输出到 ./database,并支持基于 ./database/.transform.yaml 的类型/命名转换。 + +配置:通过 -c/--config 指定配置文件(默认 config.toml),从 [Database] 段读取: + Username, Password, Database, Host, Port, Schema, SslMode, TimeZone + +行为: +- 解析 go.mod 以识别项目模块名 +- 连接 PostgreSQL(gorm + postgres driver),校验连通性 +- 调用 go.ipao.vip/gen 生成模型与相关文件到 ./database +- 根据 .transform.yaml 应用转换规则 + +示例: + atomctl gen -c config.toml model`, RunE: commandGenModelE, } diff --git a/cmd/gen_provider.go b/cmd/gen_provider.go index 13987ed..0080e9e 100644 --- a/cmd/gen_provider.go +++ b/cmd/gen_provider.go @@ -18,10 +18,26 @@ func CommandGenProvider(root *cobra.Command) { Use: "provider", Aliases: []string{"p"}, Short: "Generate providers", - Long: `// @provider -// @provider(cronjob|job|event|grpc|model):[except|only] [returnType] [group] -// when except add tag: inject:"false" -// when only add tag: inject:"true"`, + Long: `扫描源码中带有 @provider 注释的结构体,生成 provider.gen.go 实现依赖注入与分组注册。 + +注释语法: + @provider():[except|only] [returnType] [group] + - mode:grpc|event|job|cronjob|model(可为空) + - :only:仅注入字段 tag 为 inject:"true" 的依赖 + - :except:注入除标注 inject:"false" 之外的非标量依赖 + - returnType:Provide 返回类型(如 contracts.Initial) + - group:分组(如 atom.GroupInitial) + +模式特性: + - grpc:注入 providers/grpc.Grpc,设置 GrpcRegisterFunc + - event:注入 providers/event.PubSub + - job|cronjob:注入 providers/job.Job,并引入 github.com/riverqueue/river + - model:需要 Prepare 钩子 + +行为说明: + - 忽略标量类型字段,自动补全 imports + - 以包为单位生成 provider.gen.go + - 可与 gen route 联动(其 PostRun 会触发本命令)`, RunE: commandGenProviderE, } diff --git a/cmd/gen_route.go b/cmd/gen_route.go index 652d830..64d4cf6 100644 --- a/cmd/gen_route.go +++ b/cmd/gen_route.go @@ -15,12 +15,31 @@ import ( ) func CommandGenRoute(root *cobra.Command) { - cmd := &cobra.Command{ - Use: "route", - Short: "generate routes", - RunE: commandGenRouteE, - PostRunE: commandGenProviderE, - } + cmd := &cobra.Command{ + Use: "route", + Short: "generate routes", + Long: `扫描项目控制器,解析注释生成 routes.gen.go。 + +用法与规则: +- 扫描根目录通过 --path 指定(默认 CWD),会在 /app/http 下递归搜索。 +- 使用注释定义路由与参数绑定: + - @Router [] 例如:@Router /users/:id [get] + - @Bind () key() [model()] + - position 枚举:path|query|body|header|cookie|local|file + - model() 形式:model() 默认 id:int;model(id) 默认 int;model(id:int) 显式类型 + +参数位置与类型建议: +- path:标量,或结合 model() 从路径值加载模型 +- query/header:标量或结构体 +- cookie:标量;string 有快捷写法 +- body:结构体(或标量) +- file:固定 multipart.FileHeader +- local:任意类型(上下文本地值) + +说明:生成完成后会自动运行 gen provider 以补全依赖注入。`, + RunE: commandGenRouteE, + PostRunE: commandGenProviderE, + } cmd.Flags().String("path", ".", "Base path to scan (defaults to CWD)") diff --git a/cmd/gen_service.go b/cmd/gen_service.go index a066554..da743f3 100644 --- a/cmd/gen_service.go +++ b/cmd/gen_service.go @@ -16,6 +16,15 @@ func CommandGenService(root *cobra.Command) { cmd := &cobra.Command{ Use: "service", Short: "generate services", + Long: `扫描 --path 指定目录(默认 ./app/services)下的 Go 文件,汇总服务名并渲染生成 services.gen.go。 + +规则: +- 跳过 *_test.go 与 *.gen.go 文件,仅处理普通 .go 文件 +- 以文件名作为服务名来源: + - PascalCase 作为 CamelName,用于导出类型名 + - camelCase 作为 ServiceName,用于变量/字段名 +- 使用内置模板 services/services.go.tpl 渲染 +- 生成完成后会自动运行 gen provider 以补全注入`, RunE: commandGenServiceE, PostRunE: commandGenProviderE, } diff --git a/cmd/migrate.go b/cmd/migrate.go index ff8e405..b64fd5e 100644 --- a/cmd/migrate.go +++ b/cmd/migrate.go @@ -17,6 +17,20 @@ func CommandMigrate(root *cobra.Command) { Use: "migrate [up|up-by-one|up-to|create|down|down-to|fix|redo|reset|status|version]", Aliases: []string{"m"}, RunE: commandMigrate, + Long: `基于 goose 的数据库迁移工具。 + +action: + up|up-by-one|up-to|create|down|down-to|fix|redo|reset|status|version + +参数: + -c, --config 数据库配置文件(默认 config.toml,读取 [Database]) + --dir 迁移目录(默认 database/migrations) + --table 迁移版本表名(默认 migrations) + +说明: +- 执行 create 时会在缺省情况下追加 sql 类型 +- 使用配置连接数据库,并通过 goose.Run 执行对应 action +- 可在代码中通过 goose.SetTableName 自定义版本表名`, } cmd.Flags().StringP("config", "c", "config.toml", "database config file") cmd.Flags().String("dir", "database/migrations", "migrations directory") diff --git a/cmd/new.go b/cmd/new.go index b7fe0c4..4d4b146 100644 --- a/cmd/new.go +++ b/cmd/new.go @@ -8,6 +8,14 @@ func CommandInit(root *cobra.Command) { cmd := &cobra.Command{ Use: "new [project|module]", Short: "new project/module", + Long: `脚手架命令组:创建项目与常用组件模板。 + +持久化参数(所有子命令通用): +- --force, -f 覆盖已存在文件/目录 +- --dry-run 仅预览渲染与写入,不落盘 +- --dir 指定输出基目录(默认 .) + +子命令:project、provider、event、job(module 已弃用)`, } cmd.PersistentFlags().BoolP("force", "f", false, "Force overwrite existing files or directories") diff --git a/cmd/new_event.go b/cmd/new_event.go index cc78a76..3567481 100644 --- a/cmd/new_event.go +++ b/cmd/new_event.go @@ -20,6 +20,17 @@ func CommandNewEvent(root *cobra.Command) { Use: "event", Aliases: []string{"e"}, Short: "创建新的 event publish & subscriber", + Long: `生成事件的发布者与订阅者模板,并在 app/events/topics.go 中维护事件常量。 + +行为: +- 根据名称转换:驼峰 -> snake 作为 topic,Pascal 作为导出名 +- 生成 publishers/.go 与 subscribers/.go(可通过 --only 选择一侧) +- 若 topics.go 不存在会自动创建,并追加 const Topic{Name}=""(避免重复) +- --dry-run 仅打印渲染与写入动作;--dir 指定输出基目录(默认 .) + +示例: + atomctl new event UserCreated + atomctl new event UserCreated --only=publisher`, Args: cobra.ExactArgs(1), RunE: commandNewEventE, } diff --git a/cmd/new_job.go b/cmd/new_job.go index 37bcc7e..6090ec2 100644 --- a/cmd/new_job.go +++ b/cmd/new_job.go @@ -5,6 +5,7 @@ import ( "io/fs" "os" "path/filepath" + "strings" "text/template" "github.com/samber/lo" @@ -18,8 +19,17 @@ func CommandNewJob(root *cobra.Command) { cmd := &cobra.Command{ Use: "job", Short: "创建新的 job", - Args: cobra.ExactArgs(1), - RunE: commandNewJobE, + Long: `在 app/jobs 下渲染创建任务模板文件。 + +行为: +- 名称转换:输入名的 Snake 与 Pascal 形式分别用于文件名与导出名 +- 输出到 app/jobs/.go +- --dry-run 仅打印渲染与写入动作;--dir 指定输出基目录(默认 .) + +示例: + atomctl new job SendDailyReport`, + Args: cobra.ExactArgs(1), + RunE: commandNewJobE, } root.AddCommand(cmd) @@ -63,6 +73,10 @@ func commandNewJobE(cmd *cobra.Command, args []string) error { return nil } + if strings.HasPrefix(snakeName, "job_") { + snakeName = "job_" + snakeName + } + filePath := filepath.Join(basePath, snakeName+".go") tmpl, err := template.ParseFS(templates.Jobs, path) if err != nil { diff --git a/cmd/new_project.go b/cmd/new_project.go index 625123e..d4d31d5 100644 --- a/cmd/new_project.go +++ b/cmd/new_project.go @@ -29,6 +29,19 @@ func CommandNewProject(root *cobra.Command) { Use: "project", Aliases: []string{"p"}, Short: "new project", + Long: `基于内置模板创建新项目,或在已有 go.mod 的目录中就地初始化。 + +行为: +- 在空目录:需传入模块名(如 github.com/acme/app) +- 在已有 go.mod:可省略模块名,自动解析为就地初始化 +- 模板渲染规则:支持 .tpl/.raw;或通过文件内 atomctl:mode=tpl|raw 指示 +- 隐藏文件占位:模板文件名以 - 开头会渲染为 . 前缀(-.gitignore -> .gitignore) +- --force:可覆盖存在的文件/目录;--dry-run:仅打印渲染与写入动作 + +示例: + atomctl new project github.com/acme/demo + atomctl new -f --dir ./playground project github.com/acme/demo + atomctl new project # 在已有 go.mod 的项目中就地初始化`, RunE: commandNewProjectE, } diff --git a/cmd/new_provider.go b/cmd/new_provider.go index b8f0bf9..12f8b85 100644 --- a/cmd/new_provider.go +++ b/cmd/new_provider.go @@ -19,6 +19,16 @@ func CommandNewProvider(root *cobra.Command) { cmd := &cobra.Command{ Use: "provider", Short: "创建新的 provider", + Long: `在 providers/ 目录下渲染创建 Provider 模板。 + +行为: +- 从内置模板 templates/provider 渲染相关文件 +- 使用 name 的 CamelCase 作为导出名 +- --dry-run 仅打印渲染与写入动作;--dir 指定输出基目录(默认 .) + +示例: + atomctl new provider email + atomctl new --dry-run --dir ./demo provider cache`, Args: cobra.ExactArgs(1), RunE: commandNewProviderE, } diff --git a/cmd/swag.go b/cmd/swag.go index 97457c1..518ef72 100644 --- a/cmd/swag.go +++ b/cmd/swag.go @@ -6,6 +6,7 @@ func CommandSwag(root *cobra.Command) { cmd := &cobra.Command{ Use: "swag", Short: "Generate swag docs", + Long: `Swagger 文档相关命令组:包含 init(生成文档)与 fmt(格式化注释)。`, } cmds := []func(*cobra.Command){ CommandSwagInit, diff --git a/cmd/swag_fmt.go b/cmd/swag_fmt.go index c3e8419..d464bad 100644 --- a/cmd/swag_fmt.go +++ b/cmd/swag_fmt.go @@ -6,12 +6,17 @@ import ( ) func CommandSwagFmt(root *cobra.Command) { - cmd := &cobra.Command{ - Use: "fmt", - Aliases: []string{"f"}, - Short: "swag format", - RunE: commandSwagFmtE, - } + cmd := &cobra.Command{ + Use: "fmt", + Aliases: []string{"f"}, + Short: "swag format", + Long: `格式化接口注释并协助生成更规范的 Swagger 注释。 + +参数: +- --dir 扫描目录(默认 ./app/http) +- --main 主入口文件(默认 main.go)`, + RunE: commandSwagFmtE, + } cmd.Flags().String("dir", "./app/http", "SearchDir for swag format") cmd.Flags().String("main", "main.go", "MainFile for swag format") diff --git a/cmd/swag_init.go b/cmd/swag_init.go index 7c97fe3..403a279 100644 --- a/cmd/swag_init.go +++ b/cmd/swag_init.go @@ -11,12 +11,20 @@ import ( ) func CommandSwagInit(root *cobra.Command) { - cmd := &cobra.Command{ - Use: "init", - Short: "swag init", - Aliases: []string{"i"}, - RunE: commandSwagInitE, - } + cmd := &cobra.Command{ + Use: "init", + Short: "swag init", + Aliases: []string{"i"}, + Long: `生成 Swagger 文档(go/json/yaml)。 + +参数: +- --dir 项目根目录(默认 .) +- --out 输出目录(默认 docs) +- --main 主入口文件(默认 main.go) + +说明:基于 rogeecn/swag 的 gen 构建器,支持模板分隔符定制、依赖解析等配置。`, + RunE: commandSwagInitE, + } cmd.Flags().String("dir", ".", "SearchDir (project root)") cmd.Flags().String("out", "docs", "Output dir for generated docs")