Repository: go-kratos/kratos

Issue:
[Feature] Add Chinese Comment Check Workflow to Kratos CI
Please see the FAQ in our main README.md before submitting your issue.

### Requirements description of the feature

I wrote a workflow for our team to check for Chinese comments in the repository when a Pull Request (PR) is opened. The workflow is currently used in our team repo, and you can find it [here](https://github.com/openimsdk/open-im-server/blob/main/.github/workflows/comment-check.yml).

I would like to this workflows is useful to Kratos's workflows. If so, I will submit a PR to integrate this into the repo.
<!--
example:
    The event interface should be added to Kratos. The interface should contain subscribers and publishers, and the message body should contain key value head
-->
### References
[workflows details](https://github.com/openimsdk/open-im-server/blob/main/.github/workflows/comment-check.yml)

[workflows effect](https://github.com/openimsdk/openim-sdk-core/actions/runs/10830099499/job/30049088611)


Discussion:
@mo3et: @shenqidebaozi  @Windfarer @kratos-ci-bot:  
> Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿         
----    
@shenqidebaozi  @Windfarer  
      @shenqidebaozi: This situation should not exist in Kratos. I think you can first check if there are any problems in the current warehouse@mo3et: There are no issues with the current repo. This workflow is triggered when a contributor creates a PR and checks the submitted code, similar to how Go Test ensures that the submitted content can run properly when a PR is initiated.

The check only runs when a PR is opened. If the contributor's code contains Chinese comments, the CI will report an error.@mo3et: If you think this issue is not useful, please close it.@shenqidebaozi: You can submit a PR, add an action, and add a Chinese comment. I would like to see the actual effect@mo3et: > You can submit a PR, add an action, and add a Chinese comment. I would like to see the actual effect

Fine. I will commit to it later today.@dosubot: Hi, @mo3et. I'm [Dosu](https://dosu.dev), and I'm helping the Kratos team manage their backlog. I'm marking this issue as stale.

**Issue Summary**
- You suggested adding a workflow to detect Chinese comments in code during PRs.
- @shenqidebaozi questioned its necessity but later encouraged you to submit a PR.
- You agreed to proceed with a PR to demonstrate the workflow's functionality.
- The team is open to testing the feature before deciding on integration.

**Next Steps**
- Please let me know if this issue is still relevant to the latest version of the Kratos repository by commenting here.
- If there is no further activity, this issue will be automatically closed in 7 days.

Thank you for your understanding and contribution!@mo3et: > Hi, @mo3et. I'm [Dosu](https://dosu.dev), and I'm helping the Kratos team manage their backlog. I'm marking this issue as stale.
> 
> **Issue Summary**
> - You suggested adding a workflow to detect Chinese comments in code during PRs.
> - @shenqidebaozi questioned its necessity but later encouraged you to submit a PR.
> - You agreed to proceed with a PR to demonstrate the workflow's functionality.
> - The team is open to testing the feature before deciding on integration.
> 
> **Next Steps**
> - Please let me know if this issue is still relevant to the latest version of the Kratos repository by commenting here.
> - If there is no further activity, this issue will be automatically closed in 7 days.
> 
> Thank you for your understanding and contribution!

@shenqidebaozi this PR need to solve.@dosubot: @shenqidebaozi, the user @mo3et has indicated that this issue is still relevant and needs your assistance to move forward with the PR for detecting Chinese comments in code. Could you please help them with this?

Solution patch:
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
index 9759c4c7..fc37f824 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.md
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -4,13 +4,13 @@ about: Report something that's broken. Please ensure your kratos version is stil
 title: ''
 labels: bug
 assignees: ''
-
 ---
 
 <!--
 Please answer these questions before submitting your issue. Thanks!
 For questions please use one of our forums: https://go-kratos.dev/docs/getting-started/faq
 -->
+
 #### What happened:
 
 #### What you expected to happen:
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
index eeaf2427..d193e700 100644
--- a/.github/ISSUE_TEMPLATE/feature-request.md
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -45,6 +45,7 @@ example:
 example:
     The event interface should be added to Kratos. The interface should contain subscribers and publishers, and the message body should contain key value head
 -->
+
 ### References
 <!--
 example:
diff --git a/.github/ISSUE_TEMPLATE/proposal.md b/.github/ISSUE_TEMPLATE/proposal.md
index 951953b7..67e09822 100644
--- a/.github/ISSUE_TEMPLATE/proposal.md
+++ b/.github/ISSUE_TEMPLATE/proposal.md
@@ -39,6 +39,7 @@ If the maintainer team members have major differences on a requirement, the fina
 example:
 Add event interface for accessing message oriented middleware
 -->
+
 ### Implementation mode
 <!--
 ```go
@@ -60,8 +61,9 @@ type Event interface {
 }
 ````
 -->
+
 ### Usage demonstration
-<!-- 
+<!--
 example:
 ```go
 msg := kafka.NewMessage("kratos", []byte("hello world"), map[string]string{
@@ -70,4 +72,4 @@ msg := kafka.NewMessage("kratos", []byte("hello world"), map[string]string{
 	})
 err := sender.Send(context.Background(), msg)
 ```
--->
\ No newline at end of file
+-->
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 2bb0cb7e..e7a4f887 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -17,13 +17,11 @@
 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
 -->
 
-
 #### Which issue(s) this PR fixes (resolves / be part of):
 <!--
 * Automatically closes linked issue when PR is merged.
@@ -32,7 +30,6 @@
 Usage: `fixes/resolves #<issue number>`, or `fixes/resolves (paste link of issue)`.
 -->
 
-
 #### Other special notes for the reviewers:
 <!--
 * Some things that need extra attention for the reviewers
diff --git a/.github/stable.yml b/.github/stable.yml
index e6e976bb..43688ffb 100644
--- a/.github/stable.yml
+++ b/.github/stable.yml
@@ -9,4 +9,4 @@ markComment: >
   This issue has been automatically marked as stale because it has not had
   recent activity. It will be closed if no further activity occurs. Thank you
   for your contributions.
-closeComment: true
\ No newline at end of file
+closeComment: true
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index ef40b805..12359610 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -14,9 +14,9 @@ jobs:
       uses: actions/checkout@v4
 
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@v3
+      uses: github/codeql-action/init@v4
       with:
         languages: go
 
     - name: CodeQL Analysis
-      uses: github/codeql-action/analyze@v3
+      uses: github/codeql-action/analyze@v4
diff --git a/.github/workflows/comment-check.yml b/.github/workflows/comment-check.yml
new file mode 100644
index 00000000..699d6aaf
--- /dev/null
+++ b/.github/workflows/comment-check.yml
@@ -0,0 +1,154 @@
+name: Non-English Comments Check
+
+on:
+  pull_request_target:
+    types: [opened, synchronize, reopened]
+    branches:
+      - main
+  # workflow_dispatch:
+
+jobs:
+  non-english-comments-check:
+    runs-on: ubuntu-latest
+    permissions:
+      contents: read
+      pull-requests: write
+
+    env:
+      # Directories to be excluded
+      EXCLUDE_DIRS: ".git docs tests scripts assets node_modules build"
+      # Files to be excluded
+      EXCLUDE_FILES: ".md .txt .html .css .min.js .mdx"
+
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          ref: ${{ github.event.pull_request.head.ref }}
+          repository: ${{ github.event.pull_request.head.repo.full_name }}
+          fetch-depth: 0
+
+      # - name: Search for Non-English comments in the entire repository
+      #   run: |
+      #     set -e
+      #     # Define the regex pattern to match Chinese characters
+      #     pattern='[\p{Han}]'
+      
+      #     # Use find to get all files in the repository
+      #     all_files=$(find . -type f)
+      
+      #     # Loop over each file in the repository
+      #     for file in $all_files; do
+      #       # Skip files in excluded directories
+      #       skip_file=false
+      #       for dir in ${EXCLUDE_DIRS}; do
+      #         if [[ "$file" == ./$dir/* ]]; then
+      #           skip_file=true
+      #           break
+      #         fi
+      #       done
+      
+      #       # Skip files matching excluded patterns
+      #       for file_pattern in ${EXCLUDE_FILES}; do
+      #         if [[ "$file" == *$file_pattern ]]; then
+      #           skip_file=true
+      #           break
+      #         fi
+      #       done
+      
+      #       # If the file matches any exclude pattern, skip it
+      #       if [ "$skip_file" = true ]; then
+      #         continue
+      #       fi
+      
+      #       # Use grep to find all comments containing Non-English characters in filtered files
+      #       grep_output=$(grep -PnH "$pattern" "$file" || true)
+      #       if [ -n "$grep_output" ]; then
+      #         # Insert a tab after the line number, keeping the colon between the file path and line number
+      #         formatted_output=$(echo "$grep_output" | sed 's/^\(.*:[0-9]\+\):/\1\t/')
+      #         echo "$formatted_output" >> non_english_comments.txt  # Save to file
+      #       fi
+      #     done
+
+      - name: Search for Non-English comments in PR diff files
+        run: |
+          set -e
+          # Define the regex pattern to match Chinese characters
+          pattern='[\p{Han}]'
+            
+          # Get the list of files changed in this PR compared to the base branch
+          changed_files=$(git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }})
+            
+          # Loop over each changed file
+          for file in $changed_files; do
+            # Skip files in excluded directories
+            skip_file=false
+            for dir in ${EXCLUDE_DIRS}; do
+              if [[ "$file" == ./$dir/* ]]; then
+                skip_file=true
+                break
+              fi
+            done
+       
+            # Skip files matching excluded patterns
+            for file_pattern in ${EXCLUDE_FILES}; do
+              if [[ "$file" == *$file_pattern ]]; then
+                skip_file=true
+                break
+              fi
+            done
+       
+            # If the file matches any exclude pattern, skip it
+            if [ "$skip_file" = true ]; then
+              continue
+            fi
+       
+            # Use grep to find all comments containing Non-English characters in filtered files
+            grep_output=$(grep -PnH "$pattern" "$file" || true)
+            if [ -n "$grep_output" ]; then
+              # Insert a tab after the line number, keeping the colon between the file path and line number
+              formatted_output=$(echo "$grep_output" | sed 's/^\(.*:[0-9]\+\):/\1\t/')
+              echo "$formatted_output" >> non_english_comments.txt  # Save to file
+            fi
+          done
+
+      - name: Store non-English comments in ENV
+        run: |
+          # Store the entire content of non_english_comments.txt into an environment variable
+          if [ -f non_english_comments.txt ]; then
+            NON_ENGLISH_COMMENTS=$(cat non_english_comments.txt)
+            echo "NON_ENGLISH_COMMENTS<<EOF" >> $GITHUB_ENV
+            echo "$NON_ENGLISH_COMMENTS" >> $GITHUB_ENV
+            echo "EOF" >> $GITHUB_ENV
+          fi
+
+      - name: Output non-English comments if found
+        run: |
+          if [ -s non_english_comments.txt ]; then
+            echo "Non-English comments found in the following locations:"
+            cat non_english_comments.txt
+            exit 1  # terminate the workflow
+          else
+            echo "No Non-English comments found."
+      
+      - name: Find Comment
+        if: failure() && github.event_name != 'workflow_dispatch'
+        uses: peter-evans/find-comment@v3.1.0
+        id: fc
+        with:
+          issue-number: ${{ github.event.pull_request.number }}
+          comment-author: "kratos-ci-bot"
+          body-includes: Non-English comments were found in the following locations
+
+      - name: Comment on PR if errors found
+        if: failure() && github.event_name != 'workflow_dispatch' # This step runs only if the previous step fails
+        uses: peter-evans/create-or-update-comment@v4.0.0
+        with:
+          token: ${{ secrets.BOT_GITHUB_TOKEN }}
+          issue-number: ${{ github.event.pull_request.number }}
+          comment-id: ${{ steps.fc.outputs.comment-id }}
+          edit-mode: replace
+          body: |
+            ⚠️ Non-English comments were found in the following locations:
+            ```
+            ${{ env.NON_ENGLISH_COMMENTS }}
+            ```
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 7979eb96..26c09b31 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -13,7 +13,7 @@ jobs:
   build:
     strategy:
       matrix:
-        go: [1.22.x, 1.23.x, 1.24.x]
+        go: [1.22.x, 1.23.x, 1.24.x, 1.25.x]
     name: build & test
     runs-on: ubuntu-latest
     services:
@@ -42,9 +42,9 @@ jobs:
           - 8091:8091
           - 8093:8093
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
       - name: Set up Go
-        uses: actions/setup-go@v5
+        uses: actions/setup-go@v6
         with:
           go-version: ${{ matrix.go }}
 
@@ -65,9 +65,13 @@ jobs:
 
       - name: Build
         run: go build ./...
+        env:
+          GOTOOLCHAIN: auto
 
       - name: Test
         run: make test-coverage
+        env:
+          GOTOOLCHAIN: auto
 
       - name: Upload coverage to Codecov
         run: bash <(curl -s https://codecov.io/bash)
@@ -77,9 +81,13 @@ jobs:
           cd cmd/kratos
           go build ./...
           go test ./...
+        env:
+          GOTOOLCHAIN: auto
 
       - name: HTTP
         run: |
           cd cmd/protoc-gen-go-http
           go build ./...
           go test ./...
+        env:
+          GOTOOLCHAIN: auto
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 19fd3410..e3eebb79 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
 ### 4. Permanent Ban
 
 **Community Impact**: Demonstrating a pattern of violation of community
-standards, including sustained inappropriate behavior,  harassment of an
+standards, including sustained inappropriate behavior, harassment of an
 individual, or aggression toward or disparagement of classes of individuals.
 
 **Consequence**: A permanent ban from any sort of public interaction within
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b0f9ceca..7603706d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,10 +8,10 @@ When submitting a bug report, use the issue template we provide to clearly descr
 ## Adding new features
 
 In order to accurately distinguish whether the needs put forward by users are the needs or reasonable needs of most users, solicit opinions from the community through the proposal process, and the proposals adopted by the community will be realized as new feature.
-In order to make the proposal process as simple as possible, the process includes three stages: proposal, feature and PR, in which proposal, feature is issue and PR is the specific function implementation. 
-In order to facilitate the community to correctly understand the requirements of the proposal, the proposal issue needs to describe the functional requirements and relevant references or literature in detail. 
+In order to make the proposal process as simple as possible, the process includes three stages: proposal, feature and PR, in which proposal, feature is issue and PR is the specific function implementation.
+In order to facilitate the community to correctly understand the requirements of the proposal, the proposal issue needs to describe the functional requirements and relevant references or literature in detail.
 When most community users agree with this proposal, they will create a feature issue associated with the proposal issue.
-The feature issue needs to describe the implementation method and function demonstration in detail as a reference for the final function implementation. 
+The feature issue needs to describe the implementation method and function demonstration in detail as a reference for the final function implementation.
 After the function is implemented, a merge request will be initiated to associate the proposal issue and feature issue.
 After the merge is completed, Close all issues.
 
@@ -19,7 +19,7 @@ After the merge is completed, Close all issues.
 If you've never submitted code on GitHub, follow these steps:
 
 - First, please fork items to your GitHub account
-- Then create a new feature branch based on the main branch and name it features such as feature-log 
+- Then create a new feature branch based on the main branch and name it features such as feature-log
 - Write code
 - Submit code to the far end branch
 - Submit a PR request in github
@@ -59,7 +59,7 @@ There are the following types of commit:
 - **chore** Daily work, examples, etc.
 - **ci**: Changes to our CI configuration files and scripts
 
-### scope 
+### scope
 
 The following is the list of supported scopes:
 
@@ -88,10 +88,9 @@ The footer should contain any information about **Breaking Changes** and is also
 
 ### examples
 
-
 #### Only commit message
 ```
-fix: The log debug level should be -1  
+fix: The log debug level should be -1
 ```
 
 #### Attention
diff --git a/Makefile b/Makefile
index 5f51d2fb..8756ca05 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 user	:=	$(shell whoami)
-rev 	:= 	$(shell git rev-parse --short HEAD)
+rev		:= 	$(shell git rev-parse --short HEAD)
 os		:=	$(shell uname)
 
 # GOBIN > GOPATH > INSTALLDIR
@@ -20,7 +20,7 @@ ifneq ($(findstring MINGW,$(shell uname -s)),)
 GOBIN := $(shell echo "$(GOBIN)" | sed 's|\\|/|g' | cut -d';' -f1 | sed 's|^\([A-Za-z]\):|/\1|')
 GOPATH := $(shell echo "$(GOPATH)" | sed 's|\\|/|g' | cut -d';' -f1 | sed 's|^\([A-Za-z]\):|/\1|')
 endif
-BIN		:= 	""
+BIN		:= ""
 
 TOOLS_SHELL="./hack/tools.sh"
 # golangci-lint
@@ -36,7 +36,7 @@ else
 	endif
 endif
 
-$(LINTER): 
+$(LINTER):
 	curl -SL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s latest
 
 all:
diff --git a/README.md b/README.md
index 4e2a249b..5852752a 100644
--- a/README.md
+++ b/README.md
@@ -15,11 +15,11 @@
 <a href="https://trendshift.io/repositories/3233" target="_blank"><img src="https://trendshift.io/api/badge/repositories/3233" alt="go-kratos%2Fkratos | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
 <a href="https://www.producthunt.com/posts/go-kratos?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-go-kratos" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=306565&theme=light" alt="Go Kratos - A Go framework for microservices. | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
 </p>
-  
+
 ##### Translate to: [简体中文](README_zh.md)
 
 ## About Kratos
-  
+
 > The name is inspired by the Greek-mythology-based game "God of War". It tells the adventures of Kratos becoming a god of war from a mortal and launching a god-killing slaughter.
 
 Kratos is a microservice-oriented governance framework implemented by golang, which offers convenient capabilities to help you quickly build a bulletproof application from scratch, such as:
@@ -63,23 +63,23 @@ Kratos boosts your productivity. With the integration of excellent resources and
 ## Getting Started
 
 Create a kratos playground through [docker](https://www.docker.com/products/docker-desktop):
-  
+
 ```shell
 docker run -it --rm -p 8000:8000 --workdir /workspace golang
 ```
-  
+
 ```shell
 apt-get update && apt-get -y install protobuf-compiler
 export GOPROXY=https://goproxy.io,direct
 go install github.com/go-kratos/kratos/cmd/kratos/v2@latest && kratos upgrade
 ```
-  
+
 ```shell
 kratos new helloworld
 cd helloworld/ && go mod tidy
 kratos run
 ```
-  
+
 Use a browser to open and visit: `http://localhost:8000/helloworld/kratos`, The kratos program is running!
 
 If you need more, please visit the kratos [documentation](https://go-kratos.dev/en/docs/getting-started/start).
@@ -105,11 +105,11 @@ Thank you for considering contributing to the Kratos framework! The contribution
 ## License
 
 The Kratos framework is open-sourced software licensed under the [MIT license](./LICENSE).
-  
+
 ## Acknowledgments
-  
+
 The following project had particular influence on kratos's design.
-  
+
 - [go-kit/kit](https://github.com/go-kit/kit) is a programming toolkit for building microservices in go.
 - [asim/go-micro](https://github.com/asim/go-micro) a distributed systems development framework.
 - [google/go-cloud](https://github.com/google/go-cloud) is go cloud development kit.
diff --git a/README_zh.md b/README_zh.md
index 3236b568..c9e4e2b4 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -18,7 +18,7 @@ Translations: [English](README.md) | [简体中文](README_zh.md)
 
 # Kratos
 
-Kratos 一套轻量级 Go 微服务框架，包含大量微服务相关功能及工具。  
+Kratos 一套轻量级 Go 微服务框架，包含大量微服务相关功能及工具。
 
 > 名字来源于:《战神》游戏以希腊神话为背景，讲述奎托斯（Kratos）由凡人成为战神并展开弑神屠杀的冒险经历。
 
diff --git a/api/metadata/metadata.proto b/api/metadata/metadata.proto
index d3b9a413..c2199cdb 100644
--- a/api/metadata/metadata.proto
+++ b/api/metadata/metadata.proto
@@ -10,20 +10,19 @@ option java_multiple_files = true;
 option java_package = "com.github.kratos.api";
 option objc_class_prefix = "KratosAPI";
 
-
 // Metadata is api definition metadata service.
 service Metadata {
   // ListServices list the full name of all services.
-  rpc ListServices (ListServicesRequest) returns (ListServicesReply)  {
-      option (google.api.http) = {
-        get: "/services",
-      };
+  rpc ListServices (ListServicesRequest) returns (ListServicesReply) {
+    option (google.api.http) = {
+      get: "/services",
+    };
   }
   // GetServiceDesc get the full fileDescriptorSet of service.
-  rpc GetServiceDesc (GetServiceDescRequest) returns (GetServiceDescReply)  {
-      option (google.api.http) = {
-        get: "/services/{name}",
-      };
+  rpc GetServiceDesc (GetServiceDescRequest) returns (GetServiceDescReply) {
+    option (google.api.http) = {
+      get: "/services/{name}",
+    };
   }
 }
 
@@ -40,4 +39,3 @@ message GetServiceDescRequest {
 message GetServiceDescReply {
   google.protobuf.FileDescriptorSet file_desc_set = 1;
 }
-
diff --git a/cmd/kratos/go.mod b/cmd/kratos/go.mod
index 67de97ac..a202c121 100644
--- a/cmd/kratos/go.mod
+++ b/cmd/kratos/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/cmd/kratos/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/AlecAivazis/survey/v2 v2.3.7
diff --git a/cmd/kratos/internal/base/install.go b/cmd/kratos/internal/base/install.go
index 1563128a..6ec9ac3f 100644
--- a/cmd/kratos/internal/base/install.go
+++ b/cmd/kratos/internal/base/install.go
@@ -1,6 +1,3 @@
-//go:build go1.17
-// +build go1.17
-
 package base
 
 import (
diff --git a/cmd/kratos/internal/base/install_compatible.go b/cmd/kratos/internal/base/install_compatible.go
deleted file mode 100644
index 68480340..00000000
--- a/cmd/kratos/internal/base/install_compatible.go
+++ /dev/null
@@ -1,24 +0,0 @@
-//go:build !go1.17
-// +build !go1.17
-
-package base
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-)
-
-// GoInstall go get path.
-func GoInstall(path ...string) error {
-	for _, p := range path {
-		fmt.Printf("go get -u %s\n", p)
-		cmd := exec.Command("go", "get", "-u", p)
-		cmd.Stdout = os.Stdout
-		cmd.Stderr = os.Stderr
-		if err := cmd.Run(); err != nil {
-			return err
-		}
-	}
-	return nil
-}
diff --git a/cmd/kratos/internal/proto/server/template.go b/cmd/kratos/internal/proto/server/template.go
index 732947ae..32f723a4 100644
--- a/cmd/kratos/internal/proto/server/template.go
+++ b/cmd/kratos/internal/proto/server/template.go
@@ -33,10 +33,11 @@ func New{{ .Service }}Service() *{{ .Service }}Service {
 }
 
 {{- $s1 := "google.protobuf.Empty" }}
+{{- $s2 := "google_protobuf_Empty" }}
 {{ range .Methods }}
 {{- if eq .Type 1 }}
-func (s *{{ .Service }}Service) {{ .Name }}(ctx context.Context, req {{ if eq .Request $s1 }}*emptypb.Empty{{ else }}*pb.{{ .Request }}{{ end }}) ({{ if eq .Reply $s1 }}*emptypb.Empty{{ else }}*pb.{{ .Reply }}{{ end }}, error) {
-	return {{ if eq .Reply $s1 }}&emptypb.Empty{}{{ else }}&pb.{{ .Reply }}{}{{ end }}, nil
+func (s *{{ .Service }}Service) {{ .Name }}(ctx context.Context, req {{ if or (eq .Request $s1) (eq .Request $s2) }}*emptypb.Empty{{ else }}*pb.{{ .Request }}{{ end }}) ({{ if or (eq .Reply $s1) (eq .Reply $s2) }}*emptypb.Empty{{ else }}*pb.{{ .Reply }}{{ end }}, error) {
+    return {{ if or (eq .Reply $s1) (eq .Reply $s2) }}&emptypb.Empty{}{{ else }}&pb.{{ .Reply }}{}{{ end }}, nil
 }
 
 {{- else if eq .Type 2 }}
@@ -49,7 +50,7 @@ func (s *{{ .Service }}Service) {{ .Name }}(conn pb.{{ .Service }}_{{ .Name }}Se
 		if err != nil {
 			return err
 		}
-		
+
 		err = conn.Send(&pb.{{ .Reply }}{})
 		if err != nil {
 			return err
@@ -71,14 +72,13 @@ func (s *{{ .Service }}Service) {{ .Name }}(conn pb.{{ .Service }}_{{ .Name }}Se
 }
 
 {{- else if eq .Type 4 }}
-func (s *{{ .Service }}Service) {{ .Name }}(req {{ if eq .Request $s1 }}*emptypb.Empty
-{{ else }}*pb.{{ .Request }}{{ end }}, conn pb.{{ .Service }}_{{ .Name }}Server) error {
-	for {
-		err := conn.Send(&pb.{{ .Reply }}{})
-		if err != nil {
-			return err
-		}
-	}
+func (s *{{ .Service }}Service) {{ .Name }}(req {{ if or (eq .Request $s1) (eq .Request $s2) }}*emptypb.Empty{{ else }}*pb.{{ .Request }}{{ end }}, conn pb.{{ .Service }}_{{ .Name }}Server) error {
+    for {
+        err := conn.Send(&pb.{{ .Reply }}{})
+        if err != nil {
+            return err
+        }
+    }
 }
 
 {{- end }}
@@ -118,10 +118,15 @@ type Method struct {
 
 func (s *Service) execute() ([]byte, error) {
 	const empty = "google.protobuf.Empty"
+	// another empty style
+	const emptyV2 = "google_protobuf_Empty"
 	buf := new(bytes.Buffer)
 	for _, method := range s.Methods {
-		if (method.Type == unaryType && (method.Request == empty || method.Reply == empty)) ||
-			(method.Type == returnsStreamsType && method.Request == empty) {
+		isReqEmpty := method.Request == empty || method.Request == emptyV2
+		isReplyEmpty := method.Reply == empty || method.Reply == emptyV2
+
+		if (method.Type == unaryType && (isReqEmpty || isReplyEmpty)) ||
+			(method.Type == returnsStreamsType && isReqEmpty) {
 			s.GoogleEmpty = true
 		}
 		if method.Type == twoWayStreamsType || method.Type == requestStreamsType {
diff --git a/cmd/protoc-gen-go-errors/errorsTemplate.tpl b/cmd/protoc-gen-go-errors/errorsTemplate.tpl
index b77a9390..1c322eb8 100644
--- a/cmd/protoc-gen-go-errors/errorsTemplate.tpl
+++ b/cmd/protoc-gen-go-errors/errorsTemplate.tpl
@@ -11,7 +11,7 @@ func Is{{.CamelValue}}(err error) bool {
 
 {{ if .HasComment }}{{ .Comment }}{{ end -}}
 func Error{{ .CamelValue }}(format string, args ...interface{}) *errors.Error {
-	 return errors.New({{ .HTTPCode }}, {{ .Name }}_{{ .Value }}.String(), fmt.Sprintf(format, args...))
+	return errors.New({{ .HTTPCode }}, {{ .Name }}_{{ .Value }}.String(), fmt.Sprintf(format, args...))
 }
 
 {{- end }}
diff --git a/cmd/protoc-gen-go-errors/go.mod b/cmd/protoc-gen-go-errors/go.mod
index 7663c050..a4e5eec7 100644
--- a/cmd/protoc-gen-go-errors/go.mod
+++ b/cmd/protoc-gen-go-errors/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2
 
-go 1.21
+go 1.22
 
 require (
 	golang.org/x/text v0.3.8
diff --git a/cmd/protoc-gen-go-http/go.mod b/cmd/protoc-gen-go-http/go.mod
index 4fe6b849..3a86ef84 100644
--- a/cmd/protoc-gen-go-http/go.mod
+++ b/cmd/protoc-gen-go-http/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2
 
-go 1.21
+go 1.22
 
 require (
 	google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd
diff --git a/cmd/protoc-gen-go-http/httpTemplate.tpl b/cmd/protoc-gen-go-http/httpTemplate.tpl
index c71d148c..3dc9e0b2 100644
--- a/cmd/protoc-gen-go-http/httpTemplate.tpl
+++ b/cmd/protoc-gen-go-http/httpTemplate.tpl
@@ -70,9 +70,9 @@ func New{{.ServiceType}}HTTPClient (client *http.Client) {{.ServiceType}}HTTPCli
 }
 
 {{range .MethodSets}}
-    {{- if ne .Comment ""}}
-    {{.Comment}}
-    {{- end}}
+	{{- if ne .Comment ""}}
+	{{.Comment}}
+	{{- end}}
 func (c *{{$svrType}}HTTPClientImpl) {{.Name}}(ctx context.Context, in *{{.Request}}, opts ...http.CallOption) (*{{.Reply}}, error) {
 	var out {{.Reply}}
 	pattern := "{{.Path}}"
diff --git a/codecov.yml b/codecov.yml
index 302bcfd7..f122b5f4 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -1,3 +1,3 @@
 ignore:
   - "examples"
-  - "**/*.pb.go"
\ No newline at end of file
+  - "**/*.pb.go"
diff --git a/config/README.md b/config/README.md
index 6e6363a0..ff19a885 100644
--- a/config/README.md
+++ b/config/README.md
@@ -22,4 +22,4 @@ go get -u github.com/go-kratos/kratos/contrib/config/etcd/v2
 
 ```shell
 go get -u github.com/go-kratos/kratos/contrib/config/nacos/v2
-```
\ No newline at end of file
+```
diff --git a/contrib/config/apollo/README.md b/contrib/config/apollo/README.md
index 3b10738b..42775b95 100644
--- a/contrib/config/apollo/README.md
+++ b/contrib/config/apollo/README.md
@@ -32,8 +32,8 @@ func main() {
 	if err := c.Load(); err != nil {
 		panic(err)
 	}
-	
-	// use value and watch operations，help yourself. 
+
+	// use value and watch operations，help yourself.
 }
 ```
 
@@ -55,7 +55,7 @@ func WithEnableBackup() Option
 // specify apollo endpoint, such as http://localhost:8080
 func WithEndpoint(endpoint string) Option
 
-// namespaces to load, comma to separate. 
+// namespaces to load, comma to separate.
 func WithNamespace(name string) Option
 
 // secret is the apollo secret key to access application config.
@@ -87,14 +87,14 @@ you got them in kratos config instance maybe look like:
 config := map[string]interface{}{
 	// application be part of the key path.
 	"application": map[string]interface{}{
-        "http": map[string]interface{}{
-            "address": ":8080",
-            "tls": map[string]interface{}{
-                "enable": false,
-                "cert_file": "",
-                "key_file": ""
-            }
-        }
-    }
+		"http": map[string]interface{}{
+			"address": ":8080",
+			"tls": map[string]interface{}{
+				"enable": false,
+				"cert_file": "",
+				"key_file": "",
+			},
+		},
+	},
 }
 ```
diff --git a/contrib/config/apollo/go.mod b/contrib/config/apollo/go.mod
index 7b5dc3ba..fbea5b0d 100644
--- a/contrib/config/apollo/go.mod
+++ b/contrib/config/apollo/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/apollo/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/apolloconfig/agollo/v4 v4.3.1
diff --git a/contrib/config/consul/README.md b/contrib/config/consul/README.md
index 9dc5a066..a5a2cbf4 100644
--- a/contrib/config/consul/README.md
+++ b/contrib/config/consul/README.md
@@ -22,4 +22,4 @@ func main() {
     }
     c := config.New(config.WithSource(cs))
 }
-```
\ No newline at end of file
+```
diff --git a/contrib/config/consul/go.mod b/contrib/config/consul/go.mod
index 3f0d44b9..1952e1ca 100644
--- a/contrib/config/consul/go.mod
+++ b/contrib/config/consul/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/consul/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/config/etcd/go.mod b/contrib/config/etcd/go.mod
index 9fa6fd16..221c06a3 100644
--- a/contrib/config/etcd/go.mod
+++ b/contrib/config/etcd/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/etcd/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/config/kubernetes/README.md b/contrib/config/kubernetes/README.md
index 0739dcba..4adb6696 100644
--- a/contrib/config/kubernetes/README.md
+++ b/contrib/config/kubernetes/README.md
@@ -1,8 +1,8 @@
 # Kubernetes Config
 
 ### Usage in the Kubernetes Cluster
-It is required to 
-> serviceaccount should be set to the actual account of your environment, the default account will be `namespace::default` if the `spec.serviceAccount` is unset. 
+It is required to
+> serviceaccount should be set to the actual account of your environment, the default account will be `namespace::default` if the `spec.serviceAccount` is unset.
 execute this command:
 ```
 kubectl create clusterrolebinding go-kratos:kube --clusterrole=view --serviceaccount=mesh:default
@@ -26,9 +26,9 @@ subjects:
 ### Usage outside the Kubernetes Cluster
 Set the path `~/.kube/config` to KubeConfig
 ```go
-    config.NewSource(SourceOption{
-		Namespace:     "mesh",
-		LabelSelector: "",
-		KubeConfig:    filepath.Join(homedir.HomeDir(), ".kube", "config"),
-	})
-```
\ No newline at end of file
+config.NewSource(SourceOption{
+	Namespace:     "mesh",
+	LabelSelector: "",
+	KubeConfig:    filepath.Join(homedir.HomeDir(), ".kube", "config"),
+})
+```
diff --git a/contrib/config/kubernetes/go.mod b/contrib/config/kubernetes/go.mod
index 48a87f0f..09275ccb 100644
--- a/contrib/config/kubernetes/go.mod
+++ b/contrib/config/kubernetes/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/kubernetes/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/config/nacos/README.md b/contrib/config/nacos/README.md
index fa54caf0..8de21dd2 100644
--- a/contrib/config/nacos/README.md
+++ b/contrib/config/nacos/README.md
@@ -8,7 +8,6 @@ import (
 	kconfig "github.com/go-kratos/kratos/v2/config"
 )
 
-
 sc := []constant.ServerConfig{
 	*constant.NewServerConfig("127.0.0.1", 8848),
 }
@@ -34,4 +33,4 @@ client, err := clients.NewConfigClient(
 if err != nil {
 	log.Panic(err)
 }
-```
\ No newline at end of file
+```
diff --git a/contrib/config/nacos/go.mod b/contrib/config/nacos/go.mod
index 28b179aa..89be44f8 100644
--- a/contrib/config/nacos/go.mod
+++ b/contrib/config/nacos/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/nacos/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/config/polaris/README.md b/contrib/config/polaris/README.md
index b39e78f2..6fb2f1a7 100644
--- a/contrib/config/polaris/README.md
+++ b/contrib/config/polaris/README.md
@@ -3,9 +3,9 @@
 ```go
 import (
 	"log"
-	
+
 	"github.com/polarismesh/polaris-go"
-	
+
 	"github.com/go-kratos/kratos/contrib/config/polaris/v2"
 )
 
diff --git a/contrib/config/polaris/go.mod b/contrib/config/polaris/go.mod
index 357df66d..20c26723 100644
--- a/contrib/config/polaris/go.mod
+++ b/contrib/config/polaris/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/polaris/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/encoding/msgpack/go.mod b/contrib/encoding/msgpack/go.mod
index 28c2a14d..3204234f 100644
--- a/contrib/encoding/msgpack/go.mod
+++ b/contrib/encoding/msgpack/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/encoding/msgpack/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/errortracker/sentry/README.md b/contrib/errortracker/sentry/README.md
index edab5f57..ead5e560 100644
--- a/contrib/errortracker/sentry/README.md
+++ b/contrib/errortracker/sentry/README.md
@@ -4,19 +4,18 @@ This middleware helps you to catch panics and report them to [sentry](https://se
 ## Quick Start
 You could check the full demo in example folder.
 ```go
-// Step 1: 
+// Step 1:
 // init sentry in the entry of your application
 import "github.com/getsentry/sentry-go"
 
 sentry.Init(sentry.ClientOptions{
-		Dsn: "<your dsn>",
-		AttachStacktrace: true, // recommended
+	Dsn: "<your dsn>",
+	AttachStacktrace: true, // recommended
 })
 
-
-// Step 2: 
+// Step 2:
 // set middleware
-import 	ksentry "github.com/go-kratos/kratos/contrib/errortracker/sentry/v2"
+import ksentry "github.com/go-kratos/kratos/contrib/errortracker/sentry/v2"
 
 // for HTTP server, new HTTP server with sentry middleware options
 var opts = []http.ServerOption{
@@ -27,14 +26,13 @@ var opts = []http.ServerOption{
 			"tag": "some-custom-constant-tag",
 			"trace_id": tracing.TraceID(), // If you want to use the TraceID valuer, you need to place it after the A middleware.
 		})), // must after Recovery middleware, because of the exiting order will be reversed
-		
-		logging.Server(logger), 
+		logging.Server(logger),
 	),
 }
 
 // for gRPC server, new gRPC server with sentry middleware options
 var opts = []grpc.ServerOption{
-     grpc.Middleware(
+	grpc.Middleware(
 		recovery.Recovery(),
 		tracing.Server(),
 		ksentry.Server(ksentry.WithTags(map[string]interface{}{
@@ -42,9 +40,8 @@ var opts = []grpc.ServerOption{
 			"trace_id": tracing.TraceID(), // If you want to use the TraceID valuer, you need to place it after the A middleware.
 		})), // must after Recovery middleware, because of the exiting order will be reversed
 		logging.Server(logger),
-     ),
- }
-
+	),
+}
 
 // Then, the framework will report events to Sentry when your trigger panics.
 // Or your can push events to Sentry manually
diff --git a/contrib/errortracker/sentry/go.mod b/contrib/errortracker/sentry/go.mod
index abb43b74..0aefd134 100644
--- a/contrib/errortracker/sentry/go.mod
+++ b/contrib/errortracker/sentry/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/errortracker/sentry/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/getsentry/sentry-go v0.25.0
diff --git a/contrib/log/aliyun/go.mod b/contrib/log/aliyun/go.mod
index ffed8224..38c583a0 100644
--- a/contrib/log/aliyun/go.mod
+++ b/contrib/log/aliyun/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/aliyun/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/aliyun/aliyun-log-go-sdk v0.1.99
diff --git a/contrib/log/fluent/go.mod b/contrib/log/fluent/go.mod
index 98bae279..f96e8727 100644
--- a/contrib/log/fluent/go.mod
+++ b/contrib/log/fluent/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/fluent/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/fluent/fluent-logger-golang v1.9.0
diff --git a/contrib/log/logrus/go.mod b/contrib/log/logrus/go.mod
index 584e6156..ac8f8f70 100644
--- a/contrib/log/logrus/go.mod
+++ b/contrib/log/logrus/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/logrus/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/log/tencent/go.mod b/contrib/log/tencent/go.mod
index d51d024f..c2fcf35f 100644
--- a/contrib/log/tencent/go.mod
+++ b/contrib/log/tencent/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/tencent/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/log/zap/go.mod b/contrib/log/zap/go.mod
index 7d68ea7a..8b02c2e9 100644
--- a/contrib/log/zap/go.mod
+++ b/contrib/log/zap/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/zap/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/log/zerolog/go.mod b/contrib/log/zerolog/go.mod
index a23ff866..455c26d9 100644
--- a/contrib/log/zerolog/go.mod
+++ b/contrib/log/zerolog/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/zerolog/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/middleware/validate/README.md b/contrib/middleware/validate/README.md
index 2f2c4f0d..db61413d 100644
--- a/contrib/middleware/validate/README.md
+++ b/contrib/middleware/validate/README.md
@@ -12,4 +12,4 @@ protovalidate.
 
 protovalidate no longer requires code generation at build time, but for compatibility with existing Kratos
 projects, we enable the legacy mode of protovalidate. For most users, no changes are needed to existing code. **But for
-users who have manually implemented the Validator interface, you need to migrate the relevant implementation yourself**.
\ No newline at end of file
+users who have manually implemented the Validator interface, you need to migrate the relevant implementation yourself**.
diff --git a/contrib/middleware/validate/go.mod b/contrib/middleware/validate/go.mod
index cd5cac5f..dbcb26b9 100644
--- a/contrib/middleware/validate/go.mod
+++ b/contrib/middleware/validate/go.mod
@@ -1,6 +1,8 @@
 module github.com/go-kratos/kratos/contrib/middleware/validate/v2
 
-go 1.24
+go 1.23.0
+
+toolchain go1.24.6
 
 require (
 	buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250717165733-d22d418d82d8.1
diff --git a/contrib/opensergo/README.md b/contrib/opensergo/README.md
index 82cfecce..f356e5ac 100644
--- a/contrib/opensergo/README.md
+++ b/contrib/opensergo/README.md
@@ -3,30 +3,30 @@
 ## Usage
 
 ```go
-	osServer, err := opensergo.New(opensergo.WithEndpoint("localhost:9090"))
-	if err != nil {
-		panic("init opensergo error")
-	}
+osServer, err := opensergo.New(opensergo.WithEndpoint("localhost:9090"))
+if err != nil {
+	panic("init opensergo error")
+}
 
-	s := &server{}
-	grpcSrv := grpc.NewServer(
-		grpc.Address(":9000"),
-		grpc.Middleware(
-			recovery.Recovery(),
-		),
-	)
-	helloworld.RegisterGreeterServer(grpcSrv, s)
+s := &server{}
+grpcSrv := grpc.NewServer(
+	grpc.Address(":9000"),
+	grpc.Middleware(
+		recovery.Recovery(),
+	),
+)
+helloworld.RegisterGreeterServer(grpcSrv, s)
 
-	app := kratos.New(
-		kratos.Name(Name),
-		kratos.Server(
-			grpcSrv,
-		),
-	)
+app := kratos.New(
+	kratos.Name(Name),
+	kratos.Server(
+		grpcSrv,
+	),
+)
 
-	osServer.ReportMetadata(context.Background(), app)
+osServer.ReportMetadata(context.Background(), app)
 
-	if err := app.Run(); err != nil {
-		log.Fatal(err)
-	}
-```
\ No newline at end of file
+if err := app.Run(); err != nil {
+	log.Fatal(err)
+}
+```
diff --git a/contrib/opensergo/go.mod b/contrib/opensergo/go.mod
index 27682013..9b5dfe93 100644
--- a/contrib/opensergo/go.mod
+++ b/contrib/opensergo/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/opensergo/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/polaris/go.mod b/contrib/polaris/go.mod
index 74a03eb3..eb37c78d 100644
--- a/contrib/polaris/go.mod
+++ b/contrib/polaris/go.mod
@@ -2,7 +2,7 @@ module github.com/go-kratos/kratos/contrib/polaris/v2
 
 go 1.23.0
 
-toolchain go1.24.2
+toolchain go1.24.6
 
 require (
 	github.com/go-kratos/aegis v0.2.0
diff --git a/contrib/registry/consul/client.go b/contrib/registry/consul/client.go
index 1e46db09..3bcf877d 100644
--- a/contrib/registry/consul/client.go
+++ b/contrib/registry/consul/client.go
@@ -40,6 +40,8 @@ type Client struct {
 	deregisterCriticalServiceAfter int
 	// serviceChecks  user custom checks
 	serviceChecks api.AgentServiceChecks
+	// tags is service tags
+	tags []string
 
 	// used to control heartbeat
 	lock      sync.RWMutex
@@ -166,11 +168,15 @@ func (c *Client) Register(ctx context.Context, svc *registry.ServiceInstance, en
 		checkAddresses = append(checkAddresses, net.JoinHostPort(addr, strconv.FormatUint(port, 10)))
 		addresses[raw.Scheme] = api.ServiceAddress{Address: endpoint, Port: int(port)}
 	}
+	tags := []string{fmt.Sprintf("version=%s", svc.Version)}
+	if len(c.tags) > 0 {
+		tags = append(tags, c.tags...)
+	}
 	asr := &api.AgentServiceRegistration{
 		ID:              svc.ID,
 		Name:            svc.Name,
 		Meta:            svc.Metadata,
-		Tags:            []string{fmt.Sprintf("version=%s", svc.Version)},
+		Tags:            tags,
 		TaggedAddresses: addresses,
 	}
 	if len(checkAddresses) > 0 {
diff --git a/contrib/registry/consul/go.mod b/contrib/registry/consul/go.mod
index 4c17085b..de9fefec 100644
--- a/contrib/registry/consul/go.mod
+++ b/contrib/registry/consul/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/consul/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/registry/consul/registry.go b/contrib/registry/consul/registry.go
index da9a899f..00c6df0c 100644
--- a/contrib/registry/consul/registry.go
+++ b/contrib/registry/consul/registry.go
@@ -86,6 +86,15 @@ func WithServiceCheck(checks ...*api.AgentServiceCheck) Option {
 	}
 }
 
+// WithTags with service tags.
+func WithTags(tags []string) Option {
+	return func(o *Registry) {
+		if o.cli != nil {
+			o.cli.tags = tags
+		}
+	}
+}
+
 // Config is consul registry config
 type Config struct {
 	*api.Config
diff --git a/contrib/registry/discovery/README.md b/contrib/registry/discovery/README.md
index 46c46e2d..614a264d 100644
--- a/contrib/registry/discovery/README.md
+++ b/contrib/registry/discovery/README.md
@@ -1,4 +1,4 @@
-## Discovery Registry 
+## Discovery Registry
 
 This module implements a `registry.Registrar` and `registry.Discovery` interface in kratos based `bilibili/discovery`.
 
@@ -25,7 +25,7 @@ func main() {
 
 	// construct srv instance
 	// ...
-	
+
 	app := kratos.New(
 		kratos.Name("helloworld"),
 		kratos.Server(
@@ -36,10 +36,10 @@ func main() {
 		// use Registrar
 		kratos.Registrar(r),
 	)
-	
+
 	if err := app.Run(); err != nil {
 		log.NewHelper(logger).Fatal(err)
-	}	
+	}
 }
 ```
 
@@ -71,7 +71,7 @@ func main() {
 		log.Fatal(err)
 	}
 	defer conn.Close()
-	
+
 	// request and log
 }
 ```
@@ -88,7 +88,6 @@ type Config struct {
 }
 ```
 
-### References 
+### References
 
 - [bilibili/discovery](https://github.com/bilibili/discovery)
-
diff --git a/contrib/registry/discovery/discovery.go b/contrib/registry/discovery/discovery.go
index dd3d5e3f..2291ad9a 100644
--- a/contrib/registry/discovery/discovery.go
+++ b/contrib/registry/discovery/discovery.go
@@ -297,7 +297,7 @@ func (d *Discovery) cancel(ins *discoveryInstance) (err error) {
 			return nil
 		}
 
-		log.Warnf("Discovery cancel client.Get(%v)  env(%s) appid(%s) hostname(%s) code(%v)",
+		log.Warnf("Discovery cancel client.Get(%v) env(%s) appid(%s) hostname(%s) code(%v)",
 			uri, config.Env, ins.AppID, config.Host, res.Code)
 		err = fmt.Errorf("ErrorCode: %d", res.Code)
 		return
diff --git a/contrib/registry/discovery/go.mod b/contrib/registry/discovery/go.mod
index 5bc0d471..b620aea5 100644
--- a/contrib/registry/discovery/go.mod
+++ b/contrib/registry/discovery/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/discovery/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/registry/discovery/impl_registrar.go b/contrib/registry/discovery/impl_registrar.go
index c4af66b7..c5f7d1bc 100644
--- a/contrib/registry/discovery/impl_registrar.go
+++ b/contrib/registry/discovery/impl_registrar.go
@@ -103,14 +103,14 @@ func (d *Discovery) register(ctx context.Context, ins *discoveryInstance) (err e
 		SetResult(&res).
 		Post(uri); err != nil {
 		d.switchNode()
-		log.Errorf("Discovery: register client.Get(%s)  zone(%s) env(%s) appid(%s) addrs(%v) error(%v)",
+		log.Errorf("Discovery: register client.Get(%s) zone(%s) env(%s) appid(%s) addrs(%v) error(%v)",
 			uri+"?"+p.Encode(), c.Zone, c.Env, ins.AppID, ins.Addrs, err)
 		return
 	}
 
 	if res.Code != 0 {
 		err = fmt.Errorf("ErrorCode: %d", res.Code)
-		log.Errorf("Discovery: register client.Get(%v)  env(%s) appid(%s) addrs(%v) code(%v)",
+		log.Errorf("Discovery: register client.Get(%v) env(%s) appid(%s) addrs(%v) code(%v)",
 			uri, c.Env, ins.AppID, ins.Addrs, res.Code)
 	}
 
diff --git a/contrib/registry/etcd/go.mod b/contrib/registry/etcd/go.mod
index c05d388c..441199a8 100644
--- a/contrib/registry/etcd/go.mod
+++ b/contrib/registry/etcd/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/etcd/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/registry/eureka/go.mod b/contrib/registry/eureka/go.mod
index c620f481..1d3c0a50 100644
--- a/contrib/registry/eureka/go.mod
+++ b/contrib/registry/eureka/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/eureka/v2
 
-go 1.21
+go 1.22
 
 require github.com/go-kratos/kratos/v2 v2.9.0
 
diff --git a/contrib/registry/kubernetes/go.mod b/contrib/registry/kubernetes/go.mod
index 9fc07273..6ed4f51d 100644
--- a/contrib/registry/kubernetes/go.mod
+++ b/contrib/registry/kubernetes/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/kubernetes/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/registry/kubernetes/registry.go b/contrib/registry/kubernetes/registry.go
index 4d64ed69..dc620d9a 100644
--- a/contrib/registry/kubernetes/registry.go
+++ b/contrib/registry/kubernetes/registry.go
@@ -93,7 +93,7 @@ type Registry struct {
 
 // NewRegistry is used to initialize the Registry
 func NewRegistry(clientSet *kubernetes.Clientset, namespace string) *Registry {
-	if strings.EqualFold(namespace, "") {
+	if namespace == "" {
 		namespace = metav1.NamespaceAll
 	}
 	informerFactory := informers.NewSharedInformerFactoryWithOptions(clientSet, time.Minute*10, informers.WithNamespace(namespace))
diff --git a/contrib/registry/nacos/README.md b/contrib/registry/nacos/README.md
index 1a3e09cb..0672acc4 100644
--- a/contrib/registry/nacos/README.md
+++ b/contrib/registry/nacos/README.md
@@ -20,7 +20,6 @@ func main() {
 	sc := []constant.ServerConfig{
 		*constant.NewServerConfig("127.0.0.1", 8848),
 	}
-	
 
 	client, err := clients.NewNamingClient(
 		vo.NacosClientParam{
@@ -61,7 +60,6 @@ import (
 )
 
 func main() {
-
 	cc := constant.ClientConfig{
 		NamespaceId: "public",
 		TimeoutMs:   5000,
@@ -87,4 +85,4 @@ func main() {
 	)
 	defer conn.Close()
 }
-```
\ No newline at end of file
+```
diff --git a/contrib/registry/nacos/go.mod b/contrib/registry/nacos/go.mod
index 0563ec54..4dc1bbe0 100644
--- a/contrib/registry/nacos/go.mod
+++ b/contrib/registry/nacos/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/nacos/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/registry/polaris/go.mod b/contrib/registry/polaris/go.mod
index 83937b1d..04483784 100644
--- a/contrib/registry/polaris/go.mod
+++ b/contrib/registry/polaris/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/polaris/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/registry/servicecomb/README.md b/contrib/registry/servicecomb/README.md
index ea48cb93..21179c54 100644
--- a/contrib/registry/servicecomb/README.md
+++ b/contrib/registry/servicecomb/README.md
@@ -1,6 +1,7 @@
 # Servicecomb Registry
 
 ## example
+
 ### server
 ```go
 package main
@@ -29,8 +30,8 @@ func main() {
 		log.Fatal(err)
 	}
 }
-
 ```
+
 ### client
 ```go
 package main
@@ -63,5 +64,4 @@ func main() {
 	}
 	defer conn.Close()
 }
-
-```
\ No newline at end of file
+```
diff --git a/contrib/registry/servicecomb/go.mod b/contrib/registry/servicecomb/go.mod
index 83b08da8..4e657b52 100644
--- a/contrib/registry/servicecomb/go.mod
+++ b/contrib/registry/servicecomb/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/servicecomb/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-chassis/cari v0.6.0
diff --git a/contrib/registry/zookeeper/go.mod b/contrib/registry/zookeeper/go.mod
index 1b257437..6f4b20e8 100644
--- a/contrib/registry/zookeeper/go.mod
+++ b/contrib/registry/zookeeper/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/zookeeper/v2
 
-go 1.21
+go 1.22
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/contrib/transport/mcp/go.mod b/contrib/transport/mcp/go.mod
index 4ae294af..53276263 100644
--- a/contrib/transport/mcp/go.mod
+++ b/contrib/transport/mcp/go.mod
@@ -2,7 +2,7 @@ module github.com/go-kratos/kratos/contrib/transport/mcp/v2
 
 go 1.23
 
-toolchain go1.24.2
+toolchain go1.24.6
 
 require (
 	github.com/go-kratos/kratos/v2 v2.9.0
diff --git a/encoding/encoding.go b/encoding/encoding.go
index 55fc93f9..5b28d1e4 100644
--- a/encoding/encoding.go
+++ b/encoding/encoding.go
@@ -4,7 +4,7 @@ import (
 	"strings"
 )
 
-// Codec defines the interface Transport uses to encode and decode messages.  Note
+// Codec defines the interface Transport uses to encode and decode messages. Note
 // that implementations of this interface must be thread safe; a Codec's
 // methods can be called from concurrent goroutines.
 type Codec interface {
@@ -13,7 +13,7 @@ type Codec interface {
 	// Unmarshal parses the wire format into v.
 	Unmarshal(data []byte, v any) error
 	// Name returns the name of the Codec implementation. The returned string
-	// will be used as part of content type in transmission.  The result must be
+	// will be used as part of content type in transmission. The result must be
 	// static; the result cannot change between calls.
 	Name() string
 }
diff --git a/go.mod b/go.mod
index cfa4c661..094a59f3 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/v2
 
-go 1.21
+go 1.22
 
 require (
 	dario.cat/mergo v1.0.0
diff --git a/internal/httputil/http.go b/internal/httputil/http.go
index a2bdce26..b89b931f 100644
--- a/internal/httputil/http.go
+++ b/internal/httputil/http.go
@@ -13,7 +13,7 @@ func ContentType(subtype string) string {
 	return baseContentType + "/" + subtype
 }
 
-// ContentSubtype returns the content-subtype for the given content-type.  The
+// ContentSubtype returns the content-subtype for the given content-type. The
 // given content-type must be a valid content-type that starts with
 // but no content-subtype will be returned.
 // according rfc7231.
diff --git a/log/README.md b/log/README.md
index 126763ce..068410c6 100644
--- a/log/README.md
+++ b/log/README.md
@@ -42,6 +42,7 @@ log.Error("warn log")
 ```shell
 go get -u github.com/go-kratos/kratos/contrib/log/zap/v2
 ```
+
 ### logrus
 
 ```shell
@@ -58,4 +59,4 @@ go get -u github.com/go-kratos/kratos/contrib/log/fluent/v2
 
 ```shell
 go get -u github.com/go-kratos/kratos/contrib/log/aliyun/v2
-```
\ No newline at end of file
+```
diff --git a/log/filter.go b/log/filter.go
index d08421a6..ca4ec035 100644
--- a/log/filter.go
+++ b/log/filter.go
@@ -80,7 +80,7 @@ func (f *Filter) Log(level Level, keyvals ...any) error {
 		for i := 0; i < len(keyvals); i += 2 {
 			v := i + 1
 			if v >= len(keyvals) {
-				continue
+				break
 			}
 			if _, ok := f.key[keyvals[i]]; ok {
 				keyvals[v] = fuzzyStr
diff --git a/registry/README.md b/registry/README.md
index ebbc6a57..61274112 100644
--- a/registry/README.md
+++ b/registry/README.md
@@ -34,4 +34,4 @@ go get -u github.com/go-kratos/kratos/contrib/registry/kubernetes/v2
 
 ```shell
 go get -u github.com/go-kratos/kratos/contrib/registry/polaris/v2
-```
\ No newline at end of file
+```
diff --git a/selector/wrr/wrr.go b/selector/wrr/wrr.go
index 2ca2d520..fd59f821 100644
--- a/selector/wrr/wrr.go
+++ b/selector/wrr/wrr.go
@@ -35,7 +35,7 @@ func equalNodes(a, b []selector.WeightedNode) bool {
 	}
 
 	// Create a map of addresses from slice a
-	aMap := make(map[string]bool)
+	aMap := make(map[string]bool, len(a))
 	for _, node := range a {
 		aMap[node.Address()] = true
 	}
@@ -65,13 +65,13 @@ func (p *Balancer) Pick(_ context.Context, nodes []selector.WeightedNode) (selec
 	defer p.mu.Unlock()
 
 	// Check if the node list has changed
-	if len(p.lastNodes) != len(nodes) || !equalNodes(p.lastNodes, nodes) {
+	if !equalNodes(p.lastNodes, nodes) {
 		// Update lastNodes
 		p.lastNodes = make([]selector.WeightedNode, len(nodes))
 		copy(p.lastNodes, nodes)
 
 		// Create a set of current node addresses for cleanup
-		currentNodes := make(map[string]bool)
+		currentNodes := make(map[string]bool, len(nodes))
 		for _, node := range nodes {
 			currentNodes[node.Address()] = true
 		}
diff --git a/third_party/buf.yaml b/third_party/buf.yaml
index 0ac99f97..3af932d1 100644
--- a/third_party/buf.yaml
+++ b/third_party/buf.yaml
@@ -9,4 +9,4 @@ lint:
 build:
   excludes:
     - google
-    - validate
\ No newline at end of file
+    - validate
diff --git a/transport/grpc/client.go b/transport/grpc/client.go
index 8503ff6c..6a090d19 100644
--- a/transport/grpc/client.go
+++ b/transport/grpc/client.go
@@ -62,6 +62,13 @@ func WithMiddleware(m ...middleware.Middleware) ClientOption {
 	}
 }
 
+// WithStreamMiddleware with client stream middleware.
+func WithStreamMiddleware(m ...middleware.Middleware) ClientOption {
+	return func(o *clientOptions) {
+		o.streamMiddleware = m
+	}
+}
+
 // WithDiscovery with client discovery.
 func WithDiscovery(d registry.Discovery) ClientOption {
 	return func(o *clientOptions) {
diff --git a/transport/http/binding/encode.go b/transport/http/binding/encode.go
index 2ddce46a..605085b8 100644
--- a/transport/http/binding/encode.go
+++ b/transport/http/binding/encode.go
@@ -24,7 +24,7 @@ func EncodeURL(pathTemplate string, msg any, needQuery bool) string {
 	if strings.ContainsRune(pathTemplate, '{') {
 		path = reg.ReplaceAllStringFunc(pathTemplate, func(in string) string {
 			// it's unreachable because the reg means that must have more than one char in {}
-			// if len(in) < 4 { //nolint:mnd // **  explain the 4 number here :-) **
+			// if len(in) < 4 { //nolint:mnd // ** explain the 4 number here :-) **
 			//	return in
 			// }
 			key := in[1 : len(in)-1]
diff --git a/transport/http/calloption.go b/transport/http/calloption.go
index 921e18ac..cc3ffcf5 100644
--- a/transport/http/calloption.go
+++ b/transport/http/calloption.go
@@ -7,11 +7,11 @@ import (
 // CallOption configures a Call before it starts or extracts information from
 // a Call after it completes.
 type CallOption interface {
-	// before is called before the call is sent to any server.  If before
+	// before is called before the call is sent to any server. If before
 	// returns a non-nil error, the RPC fails with that error.
 	before(*callInfo) error
 
-	// after is called after the call has completed.  after cannot return an
+	// after is called after the call has completed. after cannot return an
 	// error, so any failures should be reported via output parameters.
 	after(*callInfo, *csAttempt)
 }
diff --git a/transport/http/codec_go1.20.go b/transport/http/codec_go1.20.go
index 2df5ec92..d5a73570 100644
--- a/transport/http/codec_go1.20.go
+++ b/transport/http/codec_go1.20.go
@@ -1,5 +1,4 @@
 //go:build go1.20
-// +build go1.20
 
 package http
 



Test patch:
diff --git a/cmd/kratos/internal/project/project_linux_test.go b/cmd/kratos/internal/project/project_linux_test.go
index 868cdf02..8e4ef237 100644
--- a/cmd/kratos/internal/project/project_linux_test.go
+++ b/cmd/kratos/internal/project/project_linux_test.go
@@ -1,5 +1,4 @@
 //go:build linux
-// +build linux
 
 package project
 
diff --git a/cmd/kratos/internal/project/project_windows_test.go b/cmd/kratos/internal/project/project_windows_test.go
index c86baf37..3ae1d230 100644
--- a/cmd/kratos/internal/project/project_windows_test.go
+++ b/cmd/kratos/internal/project/project_windows_test.go
@@ -1,5 +1,4 @@
 //go:build windows
-// +build windows
 
 package project
 
diff --git a/config/env/env_test.go b/config/env/env_test.go
index ecb736bc..7bc5b14e 100644
--- a/config/env/env_test.go
+++ b/config/env/env_test.go
@@ -14,7 +14,7 @@ const _testJSON = `
 {
     "test":{
         "server":{
-			"name":"${SERVICE_NAME}",
+            "name":"${SERVICE_NAME}",
             "addr":"${ADDR:127.0.0.1}",
             "port":"${PORT:8080}"
         }
diff --git a/config/file/file_test.go b/config/file/file_test.go
index 7354c018..fad425c1 100644
--- a/config/file/file_test.go
+++ b/config/file/file_test.go
@@ -63,9 +63,9 @@ const (
             "age":18
         }
     ],
-	"bar":{
-		"event":"update"
-	}
+    "bar":{
+        "event":"update"
+    }
 }`
 
 	//	_testYaml = `
diff --git a/config/reader_test.go b/config/reader_test.go
index af760784..df7e6bf5 100644
--- a/config/reader_test.go
+++ b/config/reader_test.go
@@ -93,8 +93,8 @@ func TestReader_Value(t *testing.T) {
 	}
 
 	ymlval := `
-a: 
-  b: 
+a:
+  b:
     X: 1
     Y: "lol"
     z: true
diff --git a/contrib/polaris/router_test.go b/contrib/polaris/router_test.go
index 53552145..c5e11d2a 100644
--- a/contrib/polaris/router_test.go
+++ b/contrib/polaris/router_test.go
@@ -22,41 +22,40 @@ func TestRouter(t *testing.T) {
 	}
 	data := `
 [
-   {
-       "name":"kratos",
-       "enable":false,
-       "description":"123",
-       "priority":2,
-       "routing_config":{
-           "@type":"type.googleapis.com/v2.RuleRoutingConfig",
-           "sources":[
-               {
-                   "service":"*",
-                   "namespace":"*",
-                   "arguments":[
-
-                   ]
-               }
-           ],
-           "destinations":[
-               {
-                   "labels":{
-                       "az":{
-                           "value":"1",
-                           "value_type":"TEXT",
-                           "type":"EXACT"
-                       }
-                   },
-                   "weight":100,
-                   "priority":1,
-                   "isolate":false,
-                   "name":"实例分组1",
-                   "namespace":"default",
-                   "service":"test-ut"
-               }
-           ]
-       }
-   }
+    {
+        "name":"kratos",
+        "enable":false,
+        "description":"123",
+        "priority":2,
+        "routing_config":{
+            "@type":"type.googleapis.com/v2.RuleRoutingConfig",
+            "sources":[
+                {
+                    "service":"*",
+                    "namespace":"*",
+                    "arguments":[
+                    ]
+                }
+            ],
+            "destinations":[
+                {
+                    "labels":{
+                        "az":{
+                            "value":"1",
+                            "value_type":"TEXT",
+                            "type":"EXACT"
+                        }
+                    },
+                    "weight":100,
+                    "priority":1,
+                    "isolate":false,
+                    "name":"实例分组1",
+                    "namespace":"default",
+                    "service":"test-ut"
+                }
+            ]
+        }
+    }
 ]
 `
 	res, err := makeJSONRequest("http://127.0.0.1:8090/naming/v2/routings", data, http.MethodPost, map[string]string{
diff --git a/internal/testdata/binding/test.proto b/internal/testdata/binding/test.proto
index f6df42fc..c55fc4d9 100644
--- a/internal/testdata/binding/test.proto
+++ b/internal/testdata/binding/test.proto
@@ -19,5 +19,5 @@ message HelloRequest {
 }
 
 message Sub{
-  string name = 1 [json_name="naming"];
+  string name = 1 [json_name = "naming"];
 }
diff --git a/internal/testdata/complex/complex.proto b/internal/testdata/complex/complex.proto
index f2a13235..caa48764 100644
--- a/internal/testdata/complex/complex.proto
+++ b/internal/testdata/complex/complex.proto
@@ -40,8 +40,8 @@ message Complex {
   google.protobuf.StringValue string = 23;
   google.protobuf.BytesValue bytes = 24;
 
-  map<string,string> map = 25;
-  map<int64,string> map_int64_key = 26 [json_name = "map_int64_key"];
+  map<string, string> map = 25;
+  map<int64, string> map_int64_key = 26 [json_name = "map_int64_key"];
 }
 
 message Simple {
@@ -51,4 +51,4 @@ message Simple {
 enum sex {
   man = 0;
   woman = 1;
-}
\ No newline at end of file
+}
diff --git a/internal/testdata/helloworld/helloworld.proto b/internal/testdata/helloworld/helloworld.proto
index ed068a38..24809eaf 100644
--- a/internal/testdata/helloworld/helloworld.proto
+++ b/internal/testdata/helloworld/helloworld.proto
@@ -9,10 +9,10 @@ option go_package = "github.com/go-kratos/kratos/v2/internal/testdata/helloworld
 // The greeting service definition.
 service Greeter {
   // Sends a greeting
-  rpc SayHello (HelloRequest) returns (HelloReply)  {
-        option (google.api.http) = {
-            get: "/helloworld/{name}",
-        };
+  rpc SayHello (HelloRequest) returns (HelloReply) {
+    option (google.api.http) = {
+      get: "/helloworld/{name}",
+    };
   }
   // Sends a greeting
   rpc SayHelloStream (stream HelloRequest) returns (stream HelloReply);
diff --git a/middleware/tracing/tracing_test.go b/middleware/tracing/tracing_test.go
index e57b1f12..420fe1c8 100644
--- a/middleware/tracing/tracing_test.go
+++ b/middleware/tracing/tracing_test.go
@@ -160,7 +160,7 @@ func TestServer(t *testing.T) {
 		t.Errorf("expected empty, got %v", childSpanID)
 	}
 	if reflect.DeepEqual(span.SpanContext().SpanID().String(), childSpanID) {
-		t.Errorf("span.SpanContext().SpanID().String()(%v)  is not equal to childSpanID(%v)", span.SpanContext().SpanID().String(), childSpanID)
+		t.Errorf("span.SpanContext().SpanID().String()(%v) is not equal to childSpanID(%v)", span.SpanContext().SpanID().String(), childSpanID)
 	}
 	if !reflect.DeepEqual(span.SpanContext().TraceID().String(), childTraceID) {
 		t.Errorf("expected %v, got %v", childTraceID, span.SpanContext().TraceID().String())
@@ -231,7 +231,7 @@ func TestClient(t *testing.T) {
 		t.Errorf("expected empty, got %v", childSpanID)
 	}
 	if reflect.DeepEqual(span.SpanContext().SpanID().String(), childSpanID) {
-		t.Errorf("span.SpanContext().SpanID().String()(%v)  is not equal to childSpanID(%v)", span.SpanContext().SpanID().String(), childSpanID)
+		t.Errorf("span.SpanContext().SpanID().String()(%v) is not equal to childSpanID(%v)", span.SpanContext().SpanID().String(), childSpanID)
 	}
 	if !reflect.DeepEqual(span.SpanContext().TraceID().String(), childTraceID) {
 		t.Errorf("expected %v, got %v", childTraceID, span.SpanContext().TraceID().String())
diff --git a/selector/random/random_test.go b/selector/random/random_test.go
index 33e68994..f90b2fe3 100644
--- a/selector/random/random_test.go
+++ b/selector/random/random_test.go
@@ -30,7 +30,7 @@ func TestWrr(t *testing.T) {
 		}))
 	random.Apply(nodes)
 	var count1, count2 int
-	for i := 0; i < 200; i++ {
+	for i := 0; i < 1000; i++ {
 		n, done, err := random.Select(context.Background(), selector.WithNodeFilter(filter.Version("v2.0.0")))
 		if err != nil {
 			t.Errorf("expect no error, got %v", err)
@@ -48,17 +48,17 @@ func TestWrr(t *testing.T) {
 			count2++
 		}
 	}
-	if count1 <= 80 {
-		t.Errorf("count1(%v) <= 80", count1)
+	if count1 <= 400 {
+		t.Errorf("count1(%v) <= 400", count1)
 	}
-	if count1 >= 120 {
-		t.Errorf("count1(%v) >= 120", count1)
+	if count1 >= 600 {
+		t.Errorf("count1(%v) >= 600", count1)
 	}
-	if count2 <= 80 {
-		t.Errorf("count2(%v) <= 80", count2)
+	if count2 <= 400 {
+		t.Errorf("count2(%v) <= 400", count2)
 	}
-	if count2 >= 120 {
-		t.Errorf("count2(%v) >= 120", count2)
+	if count2 >= 600 {
+		t.Errorf("count2(%v) >= 600", count2)
 	}
 }
 
diff --git a/transport/grpc/client_test.go b/transport/grpc/client_test.go
index b49794a1..1573c875 100644
--- a/transport/grpc/client_test.go
+++ b/transport/grpc/client_test.go
@@ -42,6 +42,17 @@ func TestWithMiddleware(t *testing.T) {
 	}
 }
 
+func TestWithStreamMiddleware(t *testing.T) {
+	o := &clientOptions{}
+	v := []middleware.Middleware{
+		func(middleware.Handler) middleware.Handler { return nil },
+	}
+	WithStreamMiddleware(v...)(o)
+	if !reflect.DeepEqual(v, o.streamMiddleware) {
+		t.Errorf("expect %v but got %v", v, o.streamInts)
+	}
+}
+
 type mockRegistry struct{}
 
 func (m *mockRegistry) GetService(_ context.Context, _ string) ([]*registry.ServiceInstance, error) {
@@ -148,6 +159,7 @@ func TestDialConn(t *testing.T) {
 		WithTimeout(10*time.Second),
 		WithEndpoint("abc"),
 		WithMiddleware(EmptyMiddleware()),
+		WithStreamMiddleware(EmptyMiddleware()),
 	)
 	if err != nil {
 		t.Error(err)