hertz icon indicating copy to clipboard operation
hertz copied to clipboard

自定义模板中使用 update_behavior: type: "skip" 不生效

Open storious opened this issue 4 months ago • 8 comments

Describe the Question

我的目标是为每个 handler.go 添加一个单测文件,但是当使用 hz update 更新时,我希望忽略单测文件,以便于保存我对测试函数的修改 按用户文档描述,我在自定义模板 package.yaml 生成单测文件的部分添加 update_behavior: type: "skip" 来达到这个目的。 但是结果依然覆盖了单测文件。

Reproducible Code

问题复现如下: 首先我的目录如下所示

├── Makefile
├── api
│   └── hello.proto
├── app
├── template
│   └── package.yaml
└── third_party
    └── api.proto // hz 提供的注解文件

package.yaml如下

layouts:
  - path: "{{.HandlerDir}}/{{.GenPackage}}/{{ToSnakeCase .ServiceName}}_test.go"
    loop_service: true
    update_behavior:
      type: "skip" # 用于在 hz update 时跳过
    body: |-
      package {{.FilePackage}}
      import (
        "bytes"
        "testing"

        "github.com/cloudwego/hertz/pkg/app/server"
        "github.com/cloudwego/hertz/pkg/common/test/assert"
        "github.com/cloudwego/hertz/pkg/common/ut"
      )
      {{range $_, $MethodInfo := $.Methods}}
        func Test{{$MethodInfo.Name}}(t *testing.T) {
        h := server.Default()
        h.{{$MethodInfo.HTTPMethod}}("{{$MethodInfo.Path}}", {{$MethodInfo.Name}})
        w := ut.PerformRequest(h.Engine, "{{$MethodInfo.HTTPMethod}}", "{{$MethodInfo.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1},
        ut.Header{})
        resp := w.Result()
        assert.DeepEqual(t, 201, resp.StatusCode())
        assert.DeepEqual(t, "", string(resp.Body()))
        // todo edit your unit test.
        }
      {{end}}

hello.proto如下

syntax = "proto3";

package hello;

import "api.proto";
service hello {
  rpc echo(Req) returns (Resp) { option (api.get) = "/echo"; };
}

message Req {}

message Resp {}

Makefile 如下

new:
	hz new --idl api/hello.proto --mod issue -I "third_party;." --out_dir app/hello \
	--customize_package=template/package.yaml --force
.PHONY: new

update:
	hz update --idl api/hello.proto --mod issue -I "third_party;." --out_dir app/hello \
	--customize_package=template/package.yaml
.PHONY: update

此时在根目录执行

make new

得到app/hello/biz/handler/hello/hello_test.go

//hello_test.go
package hello

import (
	"bytes"
	"testing"

	"github.com/cloudwego/hertz/pkg/app/server"
	"github.com/cloudwego/hertz/pkg/common/test/assert"
	"github.com/cloudwego/hertz/pkg/common/ut"
)

func TestEcho(t *testing.T) {
	h := server.Default()
	h.GET("/echo", Echo)
	w := ut.PerformRequest(h.Engine, "GET", "/echo", &ut.Body{Body: bytes.NewBufferString(""), Len: 1},
		ut.Header{})
	resp := w.Result()
	assert.DeepEqual(t, 201, resp.StatusCode())
	assert.DeepEqual(t, "", string(resp.Body()))
	// todo edit your unit test.
}

将其略作修改如下

// hello_test.go
package hello

import (
	"testing"
)

func TestEcho(t *testing.T) {
	// todo edit your unit test.
}

执行

make update

hello_test.go 的修改被覆盖了,没有达到预期

Hertz version:

# hz -v                                                                                                                                                                                                                             
hz version v0.9.7 

github.com/cloudwego/hertz v0.10.2

Environment:

The output of go env.

set AR=ar                                                                                                                                                                                                                           
set CC=gcc                                                                                                                                                                                                                          
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_ENABLED=1
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set CXX=g++
set GCCGO=gccgo
set GO111MODULE=on
set GOAMD64=v1
set GOARCH=amd64
set GOAUTH=netrc
set GOBIN=
set GOCACHE=C:\Users\xxx\AppData\Local\go-build
set GOCACHEPROG=
set GODEBUG=
set GOENV=C:\Users\xxx\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFIPS140=off
set GOFLAGS=
set GOGCCFLAGS=-m64 -mthreads -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\xxx\AppData\Local\Temp\go-build1522494292=/tmp/go-build -gno-record-gcc-switches
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMOD=NUL
set GOMODCACHE=C:\Users\xxx\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=C:\Users\xxx\go
set GOPRIVATE=
set GOPROXY=https://goproxy.cn,direct
set GOROOT=C:/Users/xxx/scoop/apps/go/current
set GOSUMDB=sum.golang.org
set GOTELEMETRY=on
set GOTELEMETRYDIR=C:\Users\xxx\AppData\Roaming\go\telemetry
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=C:\Users\xxx\scoop\apps\go\current\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.25.0
set GOWORK=
set PKG_CONFIG=pkg-config

storious avatar Aug 28 '25 12:08 storious

试下把 update_behavior 调整成 append 模式呢

HeyJavaBean avatar Sep 08 '25 06:09 HeyJavaBean

修改为 append 模式也没有效果

我修改后的package.yaml如下所示

layouts:
  - path: "{{.HandlerDir}}/{{.GenPackage}}/{{ToSnakeCase .ServiceName}}_test.go"
    loop_service: true
    update_behavior:
      type: "append" # 用于在 hz update 时跳过
      append_key: "method"
      insert_key: "Test{{$.Name}}"
      append_tpl: |-
        func Test{{.Name}}(t *testing.T) {
          h := server.Default()
          h.{{.HTTPMethod}}("{{.Path}}", {{.Name}})
          w := ut.PerformRequest(h.Engine, "{{.HTTPMethod}}", "{{.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1},
          ut.Header{})
          resp := w.Result()
          assert.DeepEqual(t, 201, resp.StatusCode())
          assert.DeepEqual(t, "", string(resp.Body()))
          // todo edit your unit test.
        }
    body: |-
      package {{.FilePackage}}
      import (
        "bytes"
        "testing"

        "github.com/cloudwego/hertz/pkg/app/server"
        "github.com/cloudwego/hertz/pkg/common/test/assert"
        "github.com/cloudwego/hertz/pkg/common/ut"
      )
      {{range $_, $MethodInfo := $.Methods}}
        func Test{{$MethodInfo.Name}}(t *testing.T) {
        h := server.Default()
        h.{{$MethodInfo.HTTPMethod}}("{{$MethodInfo.Path}}", {{$MethodInfo.Name}})
        w := ut.PerformRequest(h.Engine, "{{$MethodInfo.HTTPMethod}}", "{{$MethodInfo.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1},
        ut.Header{})
        resp := w.Result()
        assert.DeepEqual(t, 201, resp.StatusCode())
        assert.DeepEqual(t, "", string(resp.Body()))
        // todo edit your unit test.
        }
      {{end}}

storious avatar Sep 08 '25 11:09 storious

可能是 --out_dir app/hello 和自定义模板有冲突,去掉之后试试呢

HeyJavaBean avatar Sep 09 '25 09:09 HeyJavaBean

去掉之后可以实现期望的效果,但是如果不能使用--out_dir 指定输出目录,该如何以 monorepo 方式组织项目呢?

storious avatar Sep 09 '25 11:09 storious

可能先试试手动调整路径吧。工具自定义路径和模板可能有冲突,后面我们会看下原因。

HeyJavaBean avatar Sep 10 '25 03:09 HeyJavaBean

把 package.yaml 的 - path: "{{.HandlerDir}}/{{.GenPackage}}/{{ToSnakeCase .ServiceName}}_test.go" 改成 - path: "{{.ProjectDir}}/{{.HandlerDir}}/{{.GenPackage}}/{{ToSnakeCase .ServiceName}}_test.go" 可以在update时保持正确skip,因为在默认的情况下HandlerDir是 “biz/handler",而在加上out_dir 后实际目录多了一层 “/path/to/app/hello”绝对路径前缀。

hz在“biz/handler"没找到已存在的文件就重新生成覆盖了文件,而加上 {{.ProjectDir}} 后相当于指定了 out_dir,hz 就能够找到文件并识别进行 skip 操作跳过重新生成。

但是这会使得在new时产生错误路径,出现绝对路径嵌套绝对路径的问题。我认为这是不符合预期的,指定 {{.ProjectDir}} 作为绝对路径时不应该按相对路径拼接生成,为此我发起了一个 PR,希望能修复该问题。

nnothing1 avatar Sep 19 '25 19:09 nnothing1

原来如此,的确如你所说👍

storious avatar Sep 20 '25 06:09 storious

@nnothing1 感谢~

HeyJavaBean avatar Sep 22 '25 09:09 HeyJavaBean