Repository: go-kratos/kratos (go)

Issue:
kratos run目录问题
kratos run运行之后，如果代码里有生成文件或者目录等操作，会被创建到相对于main.go的目录，而不是相对于项目根目录。
比如我的项目根目录叫testProject
main文件在testProject/cmd/server/main.go
如果执行kratos run运行后
我现在使用os.OpenFile()创建一个文件test.log
这个文件就会生成在 testProject/cmd/server/ 目录
而不是 testProject/ 目录

Pull request:
fix: change the working directory of the command
Refs #2519

<!--
🎉 Thanks for sending a pull request to Kratos! Here are some tips for you:

1. If this is your first time contributing to Kratos, please read our contribution guide: https://go-kratos.dev/en/docs/community/contribution/
2. Ensure you have added or ran the appropriate tests and lint for your PR, please use `make lint` and `make test` before filing your PR, use `make clean` to tidy your go mod.
3. If the PR is unfinished, you may need to mark it as a WIP(Work In Progress) PR or draft PR
4. Please use a semantic commits format title, such as `<type>[optional scope]: <description>`, see: https://go-kratos.dev/docs/community/contribution#type
5. at the same time, please note that similar work should be submitted in one PR as far as possible to reduce the workload of reviewers. Do not split a work into multiple PR unless it should.
-->

<!--
🎉 感谢您向 Kratos 发送 PR 请求！以下是一些提示：
如果这是你第一次为 Kratos 贡献，请阅读我们的贡献指南：https://go-kratos.dev/en/docs/community/contribution/
2、确保您已经为您的 PR 添加或运行了适当的测试和lint，请在提交PR之前使用“make lint”和“make test”，使用“make clean”整理您的 go.mod。
3、如果请购单未完成，您可能需要将其标记为 WIP（在制品）PR 或 draft PR
4、请使用语义提交格式标题，如“<类型>[可选范围]：<说明>`，请参阅：https://go-kratos.dev/docs/community/contribution#type
5. 同时请注意，同类的工作请尽量在一个PR中提交，以减轻 review 者的工作负担，不要把一项工作拆分成很多个PR，除非它应该这样做。
-->

<!--
-->

#### Description (what this PR does / why we need it):
<!--
* The description should include the motivation for this PR or contrast this with previous behavior
-->
This pr changes the working directory of the command run, so that the file creation operation is relative to the project root directory.

#### Which issue(s) this PR fixes (resolves / be part of):
<!--
* Automatically closes linked issue when PR is merged.
* If your PR is not fully resolved the issue, please use `part of #<issue number>` instead.

Usage: `fixes/resolves #<issue number>`, or `fixes/resolves (paste link of issue)`.
-->
fixes #2519

#### Other special notes for the reviewers:
<!--
* Somethings that need extra attention for the reviewers
* Some additional notes, TODO list, etc.
-->


Patch:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 9d94238a..83ac2c39 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -44,7 +44,7 @@ jobs:
     steps:
       - uses: actions/checkout@v3
       - name: Set up Go
-        uses: actions/setup-go@v3.5.0
+        uses: actions/setup-go@v4.0.0
         with:
           go-version: ${{ matrix.go }}
 
diff --git a/Makefile b/Makefile
index 77ee21a8..7825a11c 100644
--- a/Makefile
+++ b/Makefile
@@ -89,7 +89,7 @@ test:
 .PHONY: test-coverage
 test-coverage:
 	@${TOOLS_SHELL} test_coverage
-	@echo "go test with coverage finished"	
+	@echo "go test with coverage finished"
 
 .PHONY: lint
 lint: $(LINTER)
@@ -99,4 +99,4 @@ lint: $(LINTER)
 .PHONY: proto
 proto:
 	protoc --proto_path=./api --proto_path=./third_party --go_out=paths=source_relative:./api --go-grpc_out=paths=source_relative:./api --go-http_out=paths=source_relative:./api metadata/metadata.proto
-	protoc --proto_path=./third_party --go_out=paths=source_relative:./ errors/errors.proto
+	protoc --proto_path=./third_party --go_out=paths=source_relative:./errors/errors.proto
diff --git a/SECURITY.md b/SECURITY.md
index d7fb3ffe..6e28dd41 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -5,10 +5,10 @@
 Use this section to tell people about which versions of your project are
 currently being supported with security updates.
 
-| Version | Supported          |
-| ------- | ------------------ |
-| 2.0.rc1   | :white_check_mark: |
-| < 2.0.beta3  | :x:                |
+| Version     | Supported          |
+|-------------|--------------------|
+| 2.0.rc1     | :white_check_mark: |
+| < 2.0.beta3 | :x:                |
 
 ## Reporting a Vulnerability
 
diff --git a/cmd/kratos/internal/base/path.go b/cmd/kratos/internal/base/path.go
index f0a505ce..7456ba67 100644
--- a/cmd/kratos/internal/base/path.go
+++ b/cmd/kratos/internal/base/path.go
@@ -37,7 +37,6 @@ func kratosHomeWithDir(dir string) string {
 }
 
 func copyFile(src, dst string, replaces []string) error {
-	var err error
 	srcinfo, err := os.Stat(src)
 	if err != nil {
 		return err
@@ -58,19 +57,18 @@ func copyFile(src, dst string, replaces []string) error {
 }
 
 func copyDir(src, dst string, replaces, ignores []string) error {
-	var err error
-	var fds []os.DirEntry
-	var srcinfo os.FileInfo
-
-	if srcinfo, err = os.Stat(src); err != nil {
+	srcinfo, err := os.Stat(src)
+	if err != nil {
 		return err
 	}
 
-	if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
+	err = os.MkdirAll(dst, srcinfo.Mode())
+	if err != nil {
 		return err
 	}
 
-	if fds, err = os.ReadDir(src); err != nil {
+	fds, err := os.ReadDir(src)
+	if err != nil {
 		return err
 	}
 	for _, fd := range fds {
diff --git a/cmd/kratos/internal/base/repo.go b/cmd/kratos/internal/base/repo.go
index bdcb3f01..4ad241c8 100644
--- a/cmd/kratos/internal/base/repo.go
+++ b/cmd/kratos/internal/base/repo.go
@@ -68,7 +68,7 @@ func (r *Repo) Pull(ctx context.Context) error {
 	cmd.Dir = r.Path()
 	_, err := cmd.CombinedOutput()
 	if err != nil {
-		return nil
+		return err
 	}
 	cmd = exec.CommandContext(ctx, "git", "pull")
 	cmd.Dir = r.Path()
diff --git a/cmd/kratos/internal/project/new.go b/cmd/kratos/internal/project/new.go
index f98552b0..c084e7f0 100644
--- a/cmd/kratos/internal/project/new.go
+++ b/cmd/kratos/internal/project/new.go
@@ -6,10 +6,10 @@ import (
 	"os"
 	"path"
 
-	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
-
 	"github.com/AlecAivazis/survey/v2"
 	"github.com/fatih/color"
+
+	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
 )
 
 // Project is a project template.
@@ -23,11 +23,11 @@ func (p *Project) New(ctx context.Context, dir string, layout string, branch str
 	to := path.Join(dir, p.Name)
 	if _, err := os.Stat(to); !os.IsNotExist(err) {
 		fmt.Printf("🚫 %s already exists\n", p.Name)
-		override := false
 		prompt := &survey.Confirm{
 			Message: "📂 Do you want to override the folder ?",
 			Help:    "Delete the existing folder and create the project.",
 		}
+		var override bool
 		e := survey.AskOne(prompt, &override)
 		if e != nil {
 			return e
diff --git a/cmd/kratos/internal/project/project.go b/cmd/kratos/internal/project/project.go
index 9abc98b7..ce0e1ed4 100644
--- a/cmd/kratos/internal/project/project.go
+++ b/cmd/kratos/internal/project/project.go
@@ -66,15 +66,15 @@ func run(cmd *cobra.Command, args []string) {
 	} else {
 		name = args[0]
 	}
-	wd = getProjectPlaceDir(name, wd)
-	p := &Project{Name: filepath.Base(name), Path: name}
+	projectName, workingDir := processProjectParams(name, wd)
+	p := &Project{Name: projectName, Path: projectName}
 	done := make(chan error, 1)
 	go func() {
 		if !nomod {
-			done <- p.New(ctx, wd, repoURL, branch)
+			done <- p.New(ctx, workingDir, repoURL, branch)
 			return
 		}
-		projectRoot := getgomodProjectRoot(wd)
+		projectRoot := getgomodProjectRoot(workingDir)
 		if gomodIsNotExistIn(projectRoot) {
 			done <- fmt.Errorf("🚫 go.mod don't exists in %s", projectRoot)
 			return
@@ -84,7 +84,7 @@ func run(cmd *cobra.Command, args []string) {
 		if e != nil {
 			panic(e)
 		}
-		done <- p.Add(ctx, wd, repoURL, branch, mod)
+		done <- p.Add(ctx, workingDir, repoURL, branch, mod)
 	}()
 	select {
 	case <-ctx.Done():
@@ -100,29 +100,29 @@ func run(cmd *cobra.Command, args []string) {
 	}
 }
 
-func getProjectPlaceDir(projectName string, fallbackPlaceDir string) string {
-	projectFullPath := projectName
-
-	wd := filepath.Dir(projectName)
-	// check for home dir
-	if strings.HasPrefix(wd, "~") {
+func processProjectParams(projectName string, workingDir string) (projectNameResult, workingDirResult string) {
+	_projectDir := projectName
+	_workingDir := workingDir
+	// Process ProjectName with system variable
+	if strings.HasPrefix(projectName, "~") {
 		homeDir, err := os.UserHomeDir()
 		if err != nil {
 			// cannot get user home return fallback place dir
-			return fallbackPlaceDir
+			return _projectDir, _workingDir
 		}
-		projectFullPath = filepath.Join(homeDir, projectName[2:])
+		_projectDir = filepath.Join(homeDir, projectName[2:])
 	}
+
 	// check path is relative
-	if !filepath.IsAbs(projectFullPath) {
-		absPath, err := filepath.Abs(projectFullPath)
+	if !filepath.IsAbs(projectName) {
+		absPath, err := filepath.Abs(projectName)
 		if err != nil {
-			return fallbackPlaceDir
+			return _projectDir, _workingDir
 		}
-		projectFullPath = absPath
+		_projectDir = absPath
 	}
-	// create project logic will check stat,so not check path stat here
-	return filepath.Dir(projectFullPath)
+
+	return filepath.Base(_projectDir), filepath.Dir(_projectDir)
 }
 
 func getgomodProjectRoot(dir string) string {
diff --git a/cmd/kratos/internal/proto/client/client.go b/cmd/kratos/internal/proto/client/client.go
index 8bc00633..013f9f72 100644
--- a/cmd/kratos/internal/proto/client/client.go
+++ b/cmd/kratos/internal/proto/client/client.go
@@ -8,9 +8,9 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
-
 	"github.com/spf13/cobra"
+
+	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
 )
 
 // CmdClient represents the source command.
diff --git a/cmd/kratos/internal/proto/proto.go b/cmd/kratos/internal/proto/proto.go
index 4b9c858b..b176d5de 100644
--- a/cmd/kratos/internal/proto/proto.go
+++ b/cmd/kratos/internal/proto/proto.go
@@ -1,11 +1,11 @@
 package proto
 
 import (
+	"github.com/spf13/cobra"
+
 	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/add"
 	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/client"
 	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/server"
-
-	"github.com/spf13/cobra"
 )
 
 // CmdProto represents the proto command.
diff --git a/cmd/kratos/internal/proto/server/server.go b/cmd/kratos/internal/proto/server/server.go
index 3b8a8196..e9af0c71 100644
--- a/cmd/kratos/internal/proto/server/server.go
+++ b/cmd/kratos/internal/proto/server/server.go
@@ -17,7 +17,7 @@ import (
 var CmdServer = &cobra.Command{
 	Use:   "server",
 	Short: "Generate the proto Server implementations",
-	Long:  "Generate the proto Server implementations. Example: kratos proto server api/xxx.proto -target-dir=internal/service",
+	Long:  "Generate the proto Server implementations. Example: kratos proto server api/xxx.proto --target-dir=internal/service",
 	Run:   run,
 }
 var targetDir string
diff --git a/cmd/kratos/internal/run/run.go b/cmd/kratos/internal/run/run.go
index ac229bab..005c832a 100644
--- a/cmd/kratos/internal/run/run.go
+++ b/cmd/kratos/internal/run/run.go
@@ -19,6 +19,11 @@ var CmdRun = &cobra.Command{
 	Long:  "Run project. Example: kratos run",
 	Run:   Run,
 }
+var targetDir string
+
+func init() {
+	CmdRun.Flags().StringVarP(&targetDir, "work", "w", "", "target working directory")
+}
 
 // Run run project.
 func Run(cmd *cobra.Command, args []string) {
@@ -64,10 +69,11 @@ func Run(cmd *cobra.Command, args []string) {
 			dir = cmdPath[dir]
 		}
 	}
-	fd := exec.Command("go", append([]string{"run", "."}, programArgs...)...)
+	fd := exec.Command("go", append([]string{"run", dir}, programArgs...)...)
 	fd.Stdout = os.Stdout
 	fd.Stderr = os.Stderr
 	fd.Dir = dir
+	changeWorkingDirectory(fd, targetDir)
 	if err := fd.Run(); err != nil {
 		fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", err.Error())
 		return
@@ -131,3 +137,10 @@ func findCMD(base string) (map[string]string, error) {
 	}
 	return map[string]string{"": base}, nil
 }
+
+func changeWorkingDirectory(cmd *exec.Cmd, targetDir string) {
+	targetDir = strings.TrimSpace(targetDir)
+	if targetDir != "" {
+		cmd.Dir = targetDir
+	}
+}
diff --git a/cmd/kratos/internal/upgrade/upgrade.go b/cmd/kratos/internal/upgrade/upgrade.go
index a8825dcc..79e53e3c 100644
--- a/cmd/kratos/internal/upgrade/upgrade.go
+++ b/cmd/kratos/internal/upgrade/upgrade.go
@@ -3,9 +3,9 @@ package upgrade
 import (
 	"fmt"
 
-	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
-
 	"github.com/spf13/cobra"
+
+	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
 )
 
 // CmdUpgrade represents the upgrade command.
diff --git a/cmd/kratos/main.go b/cmd/kratos/main.go
index 2ae05e31..a227a215 100644
--- a/cmd/kratos/main.go
+++ b/cmd/kratos/main.go
@@ -3,13 +3,13 @@ package main
 import (
 	"log"
 
+	"github.com/spf13/cobra"
+
 	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/change"
 	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/project"
 	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto"
 	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/run"
 	"github.com/go-kratos/kratos/cmd/kratos/v2/internal/upgrade"
-
-	"github.com/spf13/cobra"
 )
 
 var rootCmd = &cobra.Command{
diff --git a/selector/node/ewma/node.go b/selector/node/ewma/node.go
index 3b8d2a02..c718f252 100644
--- a/selector/node/ewma/node.go
+++ b/selector/node/ewma/node.go
@@ -10,7 +10,6 @@ import (
 	"time"
 
 	"github.com/go-kratos/kratos/v2/errors"
-
 	"github.com/go-kratos/kratos/v2/selector"
 )
 
diff --git a/transport/grpc/client.go b/transport/grpc/client.go
index b2b5c0c2..2d614cb0 100644
--- a/transport/grpc/client.go
+++ b/transport/grpc/client.go
@@ -109,19 +109,26 @@ func WithLogger(log log.Logger) ClientOption {
 	return func(o *clientOptions) {}
 }
 
+func WithPrintDiscoveryDebugLog(p bool) ClientOption {
+	return func(o *clientOptions) {
+		o.printDiscoveryDebugLog = p
+	}
+}
+
 // clientOptions is gRPC Client
 type clientOptions struct {
-	endpoint     string
-	subsetSize   int
-	tlsConf      *tls.Config
-	timeout      time.Duration
-	discovery    registry.Discovery
-	middleware   []middleware.Middleware
-	ints         []grpc.UnaryClientInterceptor
-	streamInts   []grpc.StreamClientInterceptor
-	grpcOpts     []grpc.DialOption
-	balancerName string
-	filters      []selector.NodeFilter
+	endpoint               string
+	subsetSize             int
+	tlsConf                *tls.Config
+	timeout                time.Duration
+	discovery              registry.Discovery
+	middleware             []middleware.Middleware
+	ints                   []grpc.UnaryClientInterceptor
+	streamInts             []grpc.StreamClientInterceptor
+	grpcOpts               []grpc.DialOption
+	balancerName           string
+	filters                []selector.NodeFilter
+	printDiscoveryDebugLog bool
 }
 
 // Dial returns a GRPC connection.
@@ -136,9 +143,10 @@ func DialInsecure(ctx context.Context, opts ...ClientOption) (*grpc.ClientConn,
 
 func dial(ctx context.Context, insecure bool, opts ...ClientOption) (*grpc.ClientConn, error) {
 	options := clientOptions{
-		timeout:      2000 * time.Millisecond,
-		balancerName: balancerName,
-		subsetSize:   25,
+		timeout:                2000 * time.Millisecond,
+		balancerName:           balancerName,
+		subsetSize:             25,
+		printDiscoveryDebugLog: true,
 	}
 	for _, o := range opts {
 		o(&options)
@@ -157,7 +165,7 @@ func dial(ctx context.Context, insecure bool, opts ...ClientOption) (*grpc.Clien
 		sints = append(sints, options.streamInts...)
 	}
 	grpcOpts := []grpc.DialOption{
-		grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"loadBalancingConfig": [{"%s":{}}]}`, options.balancerName)),
+		grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"loadBalancingConfig": [{"%s":{}}],"healthCheckConfig":{"serviceName":""}}`, options.balancerName)),
 		grpc.WithChainUnaryInterceptor(ints...),
 		grpc.WithChainStreamInterceptor(sints...),
 	}
@@ -169,6 +177,7 @@ func dial(ctx context.Context, insecure bool, opts ...ClientOption) (*grpc.Clien
 					options.discovery,
 					discovery.WithInsecure(insecure),
 					discovery.WithSubset(options.subsetSize),
+					discovery.PrintDebugLog(options.printDiscoveryDebugLog),
 				)))
 	}
 	if insecure {
diff --git a/transport/grpc/resolver/discovery/builder.go b/transport/grpc/resolver/discovery/builder.go
index 6186cdf1..37a9b560 100644
--- a/transport/grpc/resolver/discovery/builder.go
+++ b/transport/grpc/resolver/discovery/builder.go
@@ -38,29 +38,37 @@ func WithSubset(size int) Option {
 	}
 }
 
+// Deprecated: please use PrintDebugLog
 // DisableDebugLog disables update instances log.
 func DisableDebugLog() Option {
 	return func(b *builder) {
-		b.debugLogDisabled = true
+		b.debugLog = false
+	}
+}
+
+// PrintDebugLog print grpc resolver watch service log
+func PrintDebugLog(p bool) Option {
+	return func(b *builder) {
+		b.debugLog = p
 	}
 }
 
 type builder struct {
-	discoverer       registry.Discovery
-	timeout          time.Duration
-	insecure         bool
-	subsetSize       int
-	debugLogDisabled bool
+	discoverer registry.Discovery
+	timeout    time.Duration
+	insecure   bool
+	subsetSize int
+	debugLog   bool
 }
 
 // NewBuilder creates a builder which is used to factory registry resolvers.
 func NewBuilder(d registry.Discovery, opts ...Option) resolver.Builder {
 	b := &builder{
-		discoverer:       d,
-		timeout:          time.Second * 10,
-		insecure:         false,
-		debugLogDisabled: false,
-		subsetSize:       25,
+		discoverer: d,
+		timeout:    time.Second * 10,
+		insecure:   false,
+		debugLog:   true,
+		subsetSize: 25,
 	}
 	for _, o := range opts {
 		o(b)
@@ -96,14 +104,14 @@ func (b *builder) Build(target resolver.Target, cc resolver.ClientConn, opts res
 	}
 
 	r := &discoveryResolver{
-		w:                watchRes.w,
-		cc:               cc,
-		ctx:              ctx,
-		cancel:           cancel,
-		insecure:         b.insecure,
-		debugLogDisabled: b.debugLogDisabled,
-		subsetSize:       b.subsetSize,
-		selecterKey:      uuid.New().String(),
+		w:           watchRes.w,
+		cc:          cc,
+		ctx:         ctx,
+		cancel:      cancel,
+		insecure:    b.insecure,
+		debugLog:    b.debugLog,
+		subsetSize:  b.subsetSize,
+		selecterKey: uuid.New().String(),
 	}
 	go r.watch()
 	return r, nil
diff --git a/transport/grpc/resolver/discovery/resolver.go b/transport/grpc/resolver/discovery/resolver.go
index a66a9b4e..a4bd05d5 100644
--- a/transport/grpc/resolver/discovery/resolver.go
+++ b/transport/grpc/resolver/discovery/resolver.go
@@ -22,10 +22,10 @@ type discoveryResolver struct {
 	ctx    context.Context
 	cancel context.CancelFunc
 
-	insecure         bool
-	debugLogDisabled bool
-	selecterKey      string
-	subsetSize       int
+	insecure    bool
+	debugLog    bool
+	selecterKey string
+	subsetSize  int
 }
 
 func (r *discoveryResolver) watch() {
@@ -90,7 +90,7 @@ func (r *discoveryResolver) update(ins []*registry.ServiceInstance) {
 		log.Errorf("[resolver] failed to update state: %s", err)
 	}
 
-	if !r.debugLogDisabled {
+	if r.debugLog {
 		b, _ := json.Marshal(filtered)
 		log.Infof("[resolver] update instances: %s", b)
 	}


Test patch:
diff --git a/cmd/kratos/internal/project/project_linux_test.go b/cmd/kratos/internal/project/project_linux_test.go
index 271e1353..868cdf02 100644
--- a/cmd/kratos/internal/project/project_linux_test.go
+++ b/cmd/kratos/internal/project/project_linux_test.go
@@ -7,7 +7,7 @@ import (
 	"testing"
 )
 
-func Test_getProjectPlaceDir(t *testing.T) {
+func Test_processProjectParams(t *testing.T) {
 	type args struct {
 		projectName      string
 		fallbackPlaceDir string
@@ -21,8 +21,8 @@ func Test_getProjectPlaceDir(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			if got := getProjectPlaceDir(tt.args.projectName, tt.args.fallbackPlaceDir); got != tt.want {
-				t.Errorf("getProjectPlaceDir() = %v, want %v", got, tt.want)
+			if _, got := processProjectParams(tt.args.projectName, tt.args.fallbackPlaceDir); got != tt.want {
+				t.Errorf("processProjectParams() = %v, want %v", got, tt.want)
 			}
 		})
 	}
diff --git a/cmd/kratos/internal/project/project_windows_test.go b/cmd/kratos/internal/project/project_windows_test.go
index ea60473a..c86baf37 100644
--- a/cmd/kratos/internal/project/project_windows_test.go
+++ b/cmd/kratos/internal/project/project_windows_test.go
@@ -7,7 +7,7 @@ import (
 	"testing"
 )
 
-func Test_getProjectPlaceDir(t *testing.T) {
+func Test_processProjectParams(t *testing.T) {
 	type args struct {
 		projectName      string
 		fallbackPlaceDir string
@@ -22,7 +22,7 @@ func Test_getProjectPlaceDir(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			if got := getProjectPlaceDir(tt.args.projectName, tt.args.fallbackPlaceDir); got != tt.want {
+			if _, got := processProjectParams(tt.args.projectName, tt.args.fallbackPlaceDir); got != tt.want {
 				t.Errorf("getProjectPlaceDir() = %v, want %v", got, tt.want)
 			}
 		})
diff --git a/transport/grpc/resolver/discovery/builder_test.go b/transport/grpc/resolver/discovery/builder_test.go
index 664b5d44..21d5585c 100644
--- a/transport/grpc/resolver/discovery/builder_test.go
+++ b/transport/grpc/resolver/discovery/builder_test.go
@@ -33,8 +33,8 @@ func TestWithTimeout(t *testing.T) {
 func TestDisableDebugLog(t *testing.T) {
 	o := &builder{}
 	DisableDebugLog()(o)
-	if !o.debugLogDisabled {
-		t.Errorf("expected debugLogDisabled true, got %v", o.debugLogDisabled)
+	if o.debugLog {
+		t.Errorf("expected debugLog true, got %v", o.debugLog)
 	}
 }
 
diff --git a/transport/http/client_test.go b/transport/http/client_test.go
index 9a0dd782..119c8c0b 100644
--- a/transport/http/client_test.go
+++ b/transport/http/client_test.go
@@ -10,13 +10,12 @@ import (
 	"io"
 	"log"
 	"net/http"
-	nethttp "net/http"
 	"reflect"
 	"strconv"
 	"testing"
 	"time"
 
-	kratosErrors "github.com/go-kratos/kratos/v2/errors"
+	kratoserrors "github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/go-kratos/kratos/v2/selector"
@@ -24,7 +23,7 @@ import (
 
 type mockRoundTripper struct{}
 
-func (rt *mockRoundTripper) RoundTrip(req *nethttp.Request) (resp *nethttp.Response, err error) {
+func (rt *mockRoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
 	return
 }
 
@@ -129,7 +128,7 @@ func TestWithRequestEncoder(t *testing.T) {
 
 func TestWithResponseDecoder(t *testing.T) {
 	o := &clientOptions{}
-	v := func(ctx context.Context, res *nethttp.Response, out interface{}) error { return nil }
+	v := func(ctx context.Context, res *http.Response, out interface{}) error { return nil }
 	WithResponseDecoder(v)(o)
 	if o.decoder == nil {
 		t.Errorf("expected encoder to be not nil")
@@ -138,7 +137,7 @@ func TestWithResponseDecoder(t *testing.T) {
 
 func TestWithErrorDecoder(t *testing.T) {
 	o := &clientOptions{}
-	v := func(ctx context.Context, res *nethttp.Response) error { return nil }
+	v := func(ctx context.Context, res *http.Response) error { return nil }
 	WithErrorDecoder(v)(o)
 	if o.errorDecoder == nil {
 		t.Errorf("expected encoder to be not nil")
@@ -199,27 +198,24 @@ func TestWithNodeFilter(t *testing.T) {
 }
 
 func TestDefaultRequestEncoder(t *testing.T) {
-	req1 := &nethttp.Request{
-		Header: make(nethttp.Header),
-		Body:   io.NopCloser(bytes.NewBufferString("{\"a\":\"1\", \"b\": 2}")),
-	}
-	req1.Header.Set("Content-Type", "application/xml")
+	r, _ := http.NewRequest(http.MethodPost, "", io.NopCloser(bytes.NewBufferString(`{"a":"1", "b": 2}`)))
+	r.Header.Set("Content-Type", "application/xml")
 
 	v1 := &struct {
 		A string `json:"a"`
 		B int64  `json:"b"`
 	}{"a", 1}
-	b, err1 := DefaultRequestEncoder(context.TODO(), "application/json", v1)
-	if err1 != nil {
-		t.Errorf("expected no error, got %v", err1)
+	b, err := DefaultRequestEncoder(context.TODO(), "application/json", v1)
+	if err != nil {
+		t.Fatal(err)
 	}
 	v1b := &struct {
 		A string `json:"a"`
 		B int64  `json:"b"`
 	}{}
-	err1 = json.Unmarshal(b, v1b)
-	if err1 != nil {
-		t.Errorf("expected no error, got %v", err1)
+	err = json.Unmarshal(b, v1b)
+	if err != nil {
+		t.Fatal(err)
 	}
 	if !reflect.DeepEqual(v1b, v1) {
 		t.Errorf("expected %v, got %v", v1, v1b)
@@ -227,8 +223,8 @@ func TestDefaultRequestEncoder(t *testing.T) {
 }
 
 func TestDefaultResponseDecoder(t *testing.T) {
-	resp1 := &nethttp.Response{
-		Header:     make(nethttp.Header),
+	resp1 := &http.Response{
+		Header:     make(http.Header),
 		StatusCode: 200,
 		Body:       io.NopCloser(bytes.NewBufferString("{\"a\":\"1\", \"b\": 2}")),
 	}
@@ -236,19 +232,19 @@ func TestDefaultResponseDecoder(t *testing.T) {
 		A string `json:"a"`
 		B int64  `json:"b"`
 	}{}
-	err1 := DefaultResponseDecoder(context.TODO(), resp1, &v1)
-	if err1 != nil {
-		t.Errorf("expected no error, got %v", err1)
+	err := DefaultResponseDecoder(context.TODO(), resp1, &v1)
+	if err != nil {
+		t.Fatal(err)
 	}
-	if !reflect.DeepEqual("1", v1.A) {
+	if v1.A != "1" {
 		t.Errorf("expected %v, got %v", "1", v1.A)
 	}
-	if !reflect.DeepEqual(int64(2), v1.B) {
+	if v1.B != int64(2) {
 		t.Errorf("expected %v, got %v", 2, v1.B)
 	}
 
-	resp2 := &nethttp.Response{
-		Header:     make(nethttp.Header),
+	resp2 := &http.Response{
+		Header:     make(http.Header),
 		StatusCode: 200,
 		Body:       io.NopCloser(bytes.NewBufferString("{badjson}")),
 	}
@@ -256,22 +252,22 @@ func TestDefaultResponseDecoder(t *testing.T) {
 		A string `json:"a"`
 		B int64  `json:"b"`
 	}{}
-	err2 := DefaultResponseDecoder(context.TODO(), resp2, &v2)
-	terr1 := &json.SyntaxError{}
-	if !errors.As(err2, &terr1) {
-		t.Errorf("expected %v, got %v", terr1, err2)
+	err = DefaultResponseDecoder(context.TODO(), resp2, &v2)
+	syntaxErr := &json.SyntaxError{}
+	if !errors.As(err, &syntaxErr) {
+		t.Errorf("expected %v, got %v", syntaxErr, err)
 	}
 }
 
 func TestDefaultErrorDecoder(t *testing.T) {
 	for i := 200; i < 300; i++ {
-		resp := &nethttp.Response{Header: make(nethttp.Header), StatusCode: i}
+		resp := &http.Response{Header: make(http.Header), StatusCode: i}
 		if DefaultErrorDecoder(context.TODO(), resp) != nil {
 			t.Errorf("expected no error, got %v", DefaultErrorDecoder(context.TODO(), resp))
 		}
 	}
-	resp1 := &nethttp.Response{
-		Header:     make(nethttp.Header),
+	resp1 := &http.Response{
+		Header:     make(http.Header),
 		StatusCode: 300,
 		Body:       io.NopCloser(bytes.NewBufferString("{\"foo\":\"bar\"}")),
 	}
@@ -279,28 +275,28 @@ func TestDefaultErrorDecoder(t *testing.T) {
 		t.Errorf("expected error, got nil")
 	}
 
-	resp2 := &nethttp.Response{
-		Header:     make(nethttp.Header),
+	resp2 := &http.Response{
+		Header:     make(http.Header),
 		StatusCode: 500,
 		Body:       io.NopCloser(bytes.NewBufferString("{\"code\":54321, \"message\": \"hi\", \"reason\": \"FOO\"}")),
 	}
-	err2 := DefaultErrorDecoder(context.TODO(), resp2)
-	if err2 == nil {
+	err := DefaultErrorDecoder(context.TODO(), resp2)
+	if err == nil {
 		t.Errorf("expected error, got nil")
 	}
-	if !reflect.DeepEqual(int32(500), err2.(*kratosErrors.Error).Code) {
-		t.Errorf("expected %v, got %v", 500, err2.(*kratosErrors.Error).Code)
+	if err.(*kratoserrors.Error).Code != int32(500) {
+		t.Errorf("expected %v, got %v", 500, err.(*kratoserrors.Error).Code)
 	}
-	if !reflect.DeepEqual("hi", err2.(*kratosErrors.Error).Message) {
-		t.Errorf("expected %v, got %v", "hi", err2.(*kratosErrors.Error).Message)
+	if err.(*kratoserrors.Error).Message != "hi" {
+		t.Errorf("expected %v, got %v", "hi", err.(*kratoserrors.Error).Message)
 	}
-	if !reflect.DeepEqual("FOO", err2.(*kratosErrors.Error).Reason) {
-		t.Errorf("expected %v, got %v", "FOO", err2.(*kratosErrors.Error).Reason)
+	if err.(*kratoserrors.Error).Reason != "FOO" {
+		t.Errorf("expected %v, got %v", "FOO", err.(*kratoserrors.Error).Reason)
 	}
 }
 
 func TestCodecForResponse(t *testing.T) {
-	resp := &nethttp.Response{Header: make(nethttp.Header)}
+	resp := &http.Response{Header: make(http.Header)}
 	resp.Header.Set("Content-Type", "application/xml")
 	c := CodecForResponse(resp)
 	if !reflect.DeepEqual("xml", c.Name()) {
@@ -346,7 +342,7 @@ func TestNewClient(t *testing.T) {
 		}),
 	)
 	if err != nil {
-		t.Error(err)
+		t.Fatal(err)
 	}
 
 	err = client.Invoke(context.Background(), http.MethodPost, "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{}, &mockCallOption{})
diff --git a/transport/http/codec_test.go b/transport/http/codec_test.go
index b701b70f..8efd2332 100644
--- a/transport/http/codec_test.go
+++ b/transport/http/codec_test.go
@@ -3,53 +3,50 @@ package http
 import (
 	"bytes"
 	"io"
-	nethttp "net/http"
-	"reflect"
+	"net/http"
 	"testing"
 
 	"github.com/go-kratos/kratos/v2/errors"
 )
 
 func TestDefaultRequestDecoder(t *testing.T) {
-	bodyString := "{\"a\":\"1\", \"b\": 2}"
-
-	req1 := &nethttp.Request{
-		Header: make(nethttp.Header),
-		Body:   io.NopCloser(bytes.NewBufferString(bodyString)),
-	}
-	req1.Header.Set("Content-Type", "application/json")
+	var (
+		bodyStr = `{"a":"1", "b": 2}`
+		r, _    = http.NewRequest(http.MethodPost, "", io.NopCloser(bytes.NewBufferString(bodyStr)))
+	)
+	r.Header.Set("Content-Type", "application/json")
 
 	v1 := &struct {
 		A string `json:"a"`
 		B int64  `json:"b"`
 	}{}
-	err1 := DefaultRequestDecoder(req1, &v1)
-	if err1 != nil {
-		t.Errorf("expected no error, got %v", err1)
+	err := DefaultRequestDecoder(r, &v1)
+	if err != nil {
+		t.Fatal(err)
 	}
-	if !reflect.DeepEqual("1", v1.A) {
+	if v1.A != "1" {
 		t.Errorf("expected %v, got %v", "1", v1.A)
 	}
-	if !reflect.DeepEqual(int64(2), v1.B) {
+	if v1.B != int64(2) {
 		t.Errorf("expected %v, got %v", 2, v1.B)
 	}
 
-	data, err := io.ReadAll(req1.Body)
+	data, err := io.ReadAll(r.Body)
 	if err != nil {
-		t.Errorf("expected no error, got %v", err1)
+		t.Fatal(err)
 	}
-	if !reflect.DeepEqual([]byte(bodyString), data) {
-		t.Errorf("expected %v, got %v", bodyString, data)
+	if bodyStr != string(data) {
+		t.Errorf("expected %v, got %v", bodyStr, string(data))
 	}
 }
 
 type mockResponseWriter struct {
 	StatusCode int
 	Data       []byte
-	header     nethttp.Header
+	header     http.Header
 }
 
-func (w *mockResponseWriter) Header() nethttp.Header {
+func (w *mockResponseWriter) Header() http.Header {
 	return w.header
 }
 
@@ -62,27 +59,28 @@ func (w *mockResponseWriter) WriteHeader(statusCode int) {
 	w.StatusCode = statusCode
 }
 
-type dataWithStatusCode struct {
-	A string `json:"a"`
-	B int64  `json:"b"`
-}
-
 func TestDefaultResponseEncoder(t *testing.T) {
-	w := &mockResponseWriter{StatusCode: 200, header: make(nethttp.Header)}
-	req1 := &nethttp.Request{
-		Header: make(nethttp.Header),
-	}
-	req1.Header.Set("Content-Type", "application/json")
-
-	v1 := &dataWithStatusCode{A: "1", B: 2}
-	err := DefaultResponseEncoder(w, req1, v1)
+	var (
+		w    = &mockResponseWriter{StatusCode: 200, header: make(http.Header)}
+		r, _ = http.NewRequest(http.MethodPost, "", nil)
+		v    = &struct {
+			A string `json:"a"`
+			B int64  `json:"b"`
+		}{
+			A: "1",
+			B: 2,
+		}
+	)
+	r.Header.Set("Content-Type", "application/json")
+
+	err := DefaultResponseEncoder(w, r, v)
 	if err != nil {
-		t.Errorf("expected no error, got %v", err)
+		t.Fatal(err)
 	}
-	if !reflect.DeepEqual("application/json", w.Header().Get("Content-Type")) {
+	if w.Header().Get("Content-Type") != "application/json" {
 		t.Errorf("expected %v, got %v", "application/json", w.Header().Get("Content-Type"))
 	}
-	if !reflect.DeepEqual(200, w.StatusCode) {
+	if w.StatusCode != 200 {
 		t.Errorf("expected %v, got %v", 200, w.StatusCode)
 	}
 	if w.Data == nil {
@@ -90,19 +88,19 @@ func TestDefaultResponseEncoder(t *testing.T) {
 	}
 }
 
-func TestDefaultResponseEncoderWithError(t *testing.T) {
-	w := &mockResponseWriter{header: make(nethttp.Header)}
-	req := &nethttp.Request{
-		Header: make(nethttp.Header),
-	}
-	req.Header.Set("Content-Type", "application/json")
+func TestDefaultErrorEncoder(t *testing.T) {
+	var (
+		w    = &mockResponseWriter{header: make(http.Header)}
+		r, _ = http.NewRequest(http.MethodPost, "", nil)
+		err  = errors.New(511, "", "")
+	)
+	r.Header.Set("Content-Type", "application/json")
 
-	se := errors.New(511, "", "")
-	DefaultErrorEncoder(w, req, se)
-	if !reflect.DeepEqual("application/json", w.Header().Get("Content-Type")) {
+	DefaultErrorEncoder(w, r, err)
+	if w.Header().Get("Content-Type") != "application/json" {
 		t.Errorf("expected %v, got %v", "application/json", w.Header().Get("Content-Type"))
 	}
-	if !reflect.DeepEqual(511, w.StatusCode) {
+	if w.StatusCode != 511 {
 		t.Errorf("expected %v, got %v", 511, w.StatusCode)
 	}
 	if w.Data == nil {
@@ -111,20 +109,20 @@ func TestDefaultResponseEncoderWithError(t *testing.T) {
 }
 
 func TestDefaultResponseEncoderEncodeNil(t *testing.T) {
-	w := &mockResponseWriter{StatusCode: 204, header: make(nethttp.Header)}
-	req1 := &nethttp.Request{
-		Header: make(nethttp.Header),
-	}
-	req1.Header.Set("Content-Type", "application/json")
+	var (
+		w    = &mockResponseWriter{StatusCode: 204, header: make(http.Header)}
+		r, _ = http.NewRequest(http.MethodPost, "", io.NopCloser(bytes.NewBufferString("<xml></xml>")))
+	)
+	r.Header.Set("Content-Type", "application/json")
 
-	err := DefaultResponseEncoder(w, req1, nil)
+	err := DefaultResponseEncoder(w, r, nil)
 	if err != nil {
-		t.Errorf("expected no error, got %v", err)
+		t.Fatal(err)
 	}
-	if !reflect.DeepEqual("", w.Header().Get("Content-Type")) {
+	if w.Header().Get("Content-Type") != "" {
 		t.Errorf("expected empty string, got %v", w.Header().Get("Content-Type"))
 	}
-	if !reflect.DeepEqual(204, w.StatusCode) {
+	if w.StatusCode != 204 {
 		t.Errorf("expected %v, got %v", 204, w.StatusCode)
 	}
 	if w.Data != nil {
@@ -133,31 +131,23 @@ func TestDefaultResponseEncoderEncodeNil(t *testing.T) {
 }
 
 func TestCodecForRequest(t *testing.T) {
-	req1 := &nethttp.Request{
-		Header: make(nethttp.Header),
-		Body:   io.NopCloser(bytes.NewBufferString("<xml></xml>")),
-	}
-	req1.Header.Set("Content-Type", "application/xml")
-
-	c, ok := CodecForRequest(req1, "Content-Type")
+	r, _ := http.NewRequest(http.MethodPost, "", io.NopCloser(bytes.NewBufferString("<xml></xml>")))
+	r.Header.Set("Content-Type", "application/xml")
+	c, ok := CodecForRequest(r, "Content-Type")
 	if !ok {
-		t.Errorf("expected true, got %v", ok)
+		t.Fatalf("expected true, got %v", ok)
 	}
-	if !reflect.DeepEqual("xml", c.Name()) {
+	if c.Name() != "xml" {
 		t.Errorf("expected %v, got %v", "xml", c.Name())
 	}
 
-	req2 := &nethttp.Request{
-		Header: make(nethttp.Header),
-		Body:   io.NopCloser(bytes.NewBufferString("{\"a\":\"1\", \"b\": 2}")),
-	}
-	req2.Header.Set("Content-Type", "blablablabla")
-
-	c, ok = CodecForRequest(req2, "Content-Type")
+	r, _ = http.NewRequest(http.MethodPost, "", io.NopCloser(bytes.NewBufferString(`{"a":"1", "b": 2}`)))
+	r.Header.Set("Content-Type", "blablablabla")
+	c, ok = CodecForRequest(r, "Content-Type")
 	if ok {
-		t.Errorf("expected false, got %v", ok)
+		t.Fatalf("expected false, got %v", ok)
 	}
-	if !reflect.DeepEqual("json", c.Name()) {
+	if c.Name() != "json" {
 		t.Errorf("expected %v, got %v", "json", c.Name())
 	}
 }