feat(goctl/rpc): support external proto imports with cross-package ty… (#5472)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
kesonan
2026-03-22 12:01:20 +08:00
committed by GitHub
parent c12c82b2f6
commit 004995f06a
93 changed files with 4871 additions and 270 deletions

View File

@@ -0,0 +1,78 @@
#!/usr/bin/env bash
# Scenario 08: compare old vs new goctl output — external proto, different Go package
# Usage: bash compare.sh
# Requires: go install github.com/zeromicro/go-zero/tools/goctl@latest (auto-installed)
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GOCTL_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
NEW_GOCTL="$GOCTL_ROOT/bin/goctl"
OLD_GOCTL="$(go env GOPATH)/bin/goctl"
OUT_OLD="$SCRIPT_DIR/output_old"
OUT_NEW="$SCRIPT_DIR/output_new"
verify_build() {
local dir="$1" label="$2"
echo "Verifying $label ..."
cd "$dir"
go mod tidy
if go build ./...; then
echo "$label: build passed"
else
echo "$label: build failed"
exit 1
fi
cd "$SCRIPT_DIR"
}
# Install released goctl and build local goctl
echo ">>> Installing goctl@latest ..."
go install github.com/zeromicro/go-zero/tools/goctl@latest
echo ">>> Building local goctl ..."
go build -o "$NEW_GOCTL" "$GOCTL_ROOT"
# Generate with old goctl
echo ">>> Generating with old goctl ..."
rm -rf "$OUT_OLD" && mkdir -p "$OUT_OLD/pb"
(cd "$OUT_OLD" && go mod init example.com/demo/s08_ext_diff_pkg > /dev/null 2>&1)
cd "$SCRIPT_DIR"
set +e
"$OLD_GOCTL" rpc protoc service.proto \
--go_out="$OUT_OLD/pb" \
--go-grpc_out="$OUT_OLD/pb" \
--zrpc_out="$OUT_OLD/rpc" \
--go_opt=paths=source_relative \
--go-grpc_opt=paths=source_relative \
--proto_path=. \
--proto_path=./ext_protos
GEN_STATUS=$?
set -e
if [ "$GEN_STATUS" -ne 0 ]; then
echo " ⚠️ old goctl does not support this feature (expected)"
else
verify_build "$OUT_OLD" "old"
fi
# Generate with new goctl
echo ">>> Generating with new goctl ..."
rm -rf "$OUT_NEW" && mkdir -p "$OUT_NEW/pb"
(cd "$OUT_NEW" && go mod init example.com/demo/s08_ext_diff_pkg > /dev/null 2>&1)
cd "$SCRIPT_DIR"
"$NEW_GOCTL" rpc protoc service.proto \
--go_out="$OUT_NEW/pb" \
--go-grpc_out="$OUT_NEW/pb" \
--zrpc_out="$OUT_NEW/rpc" \
--go_opt=paths=source_relative \
--go-grpc_opt=paths=source_relative \
--proto_path=. \
--proto_path=./ext_protos
verify_build "$OUT_NEW" "new"
# Diff old vs new (exclude go.mod / go.sum)
echo ""
echo ">>> Diff (old vs new):"
if diff -rq --exclude="go.mod" --exclude="go.sum" "$OUT_OLD" "$OUT_NEW" > /dev/null 2>&1; then
echo " [identical] no differences between old and new output"
else
diff -r --exclude="go.mod" --exclude="go.sum" "$OUT_OLD" "$OUT_NEW" || true
fi

View File

@@ -0,0 +1,18 @@
syntax = "proto3";
// 场景08外部目录的 proto不同 pkg
// 位于 ext_protos/common/ 子目录,通过 --proto_path=./ext_protos 引入
// go_package 与主 proto 不同,生成跨包 import
package common;
option go_package = "example.com/demo/s08_ext_diff_pkg/pb/common";
message ExtReq {
string key = 1;
string source = 2;
}
message ExtReply {
string value = 1;
int32 code = 2;
}

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env bash
# Scenario 08: external proto, different Go package
# Usage: bash gen.sh
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GOCTL_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
GOCTL="$GOCTL_ROOT/bin/goctl"
OUT="$SCRIPT_DIR/output"
# Build goctl from source
go build -o "$GOCTL" "$GOCTL_ROOT"
# Clean and initialize output directory
rm -rf "$OUT" && mkdir -p "$OUT/pb"
(cd "$OUT" && go mod init example.com/demo/s08_ext_diff_pkg > /dev/null 2>&1)
# Generate code
cd "$SCRIPT_DIR"
"$GOCTL" rpc protoc service.proto \
--go_out="$OUT/pb" \
--go-grpc_out="$OUT/pb" \
--zrpc_out="$OUT/rpc" \
--go_opt=paths=source_relative \
--go-grpc_opt=paths=source_relative \
--proto_path=. \
--proto_path=./ext_protos
# Verify build
echo "Running go mod tidy..."
cd "$OUT" && go mod tidy
echo "Checking build..."
if go build ./...; then
echo "✅ Build passed"
else
echo "❌ Build failed"
exit 1
fi
echo "Done. Output: $OUT"

View File

@@ -0,0 +1,14 @@
syntax = "proto3";
// 场景08外部 proto不同 Go pkg—— 请求/响应直接使用 common.ExtReq / common.ExtReply
// types.proto go_package 与 service.proto 不同,生成的 Go 代码需要跨包 import。
package svc;
option go_package = "example.com/demo/s08_ext_diff_pkg/pb";
import "common/types.proto";
service DataService {
rpc Fetch(common.ExtReq) returns (common.ExtReply);
}