Compare commits

...

1115 Commits
v1.0.x ... main

Author SHA1 Message Date
LinXiaoWei bffc1a0989
feat(transport): add endpoint option for server (#2904) 1 year ago
包子 32b1d13f90
deps: upgrade kratos version to v2.6.3 (#2903) 1 year ago
dependabot[bot] db2a565d1c
build(deps): bump github.com/prometheus/common (#2840) 1 year ago
jessetang fcd3b18e83
fix(encoding/form): failed to decode the map type (#2468) 1 year ago
freezeChen 3445f3ea8e
fix: logging middle don't get trace_id value when logger is filterLogger (#2869) 1 year ago
Tony Chen 32c0d2dd97
feat: add omitempty prefix to rule path (#2870) 1 year ago
xu0o0 e86ad248c3
fix(cli): fix import path with `--nomod` (#2775) 1 year ago
liaochuntao 69d73225a9
update polaris-standalone docker image (#2854) 1 year ago
Fengbin Shi 49ffd95a0c
fix: http parse pb message body panic (#2847) 1 year ago
haiyux 96480c11ee
fix: fix go import path when add project --nomod (#2837) 2 years ago
dependabot[bot] 1d50f50262
build(deps): bump actions/setup-go from 4.0.0 to 4.0.1 (#2829) 2 years ago
dependabot[bot] 6d741828c2
build(deps): bump google.golang.org/grpc in /contrib/opensergo (#2823) 2 years ago
Xudong Cai 4a56b5669d
chore: remove the dependency of grpc_testing module (#2824) 2 years ago
包子 56777ee655
deps: upgrade kratos version to v2.6.2 (#2817) 2 years ago
dependabot[bot] b1cd1d3cf8
build(deps): bump google.golang.org/grpc in /contrib/config/etcd (#2767) 2 years ago
dependabot[bot] 37a521d59f
build(deps): bump google.golang.org/grpc in /contrib/opensergo (#2768) 2 years ago
dependabot[bot] 6cf407b9bd
build(deps): bump github.com/prometheus/client_golang (#2787) 2 years ago
dependabot[bot] a904794546
build(deps): bump github.com/aliyun/aliyun-log-go-sdk (#2807) 2 years ago
chen quan a837603c6d
chore: embedding template (#2810) 2 years ago
dependabot[bot] 0b1fdbe51c
build(deps): bump go.etcd.io/etcd/client/v3 in /contrib/config/etcd (#2788) 2 years ago
dependabot[bot] 81988e6a85
build(deps): bump go.etcd.io/etcd/client/v3 in /contrib/registry/etcd (#2789) 2 years ago
Haibo 1f10166028
fix(tracing): use global provider by default, but allow custom providers (#2803) 2 years ago
dependabot[bot] c6a4604839
build(deps): bump github.com/hashicorp/consul/api (#2731) 2 years ago
Bin aed172b8dd
feat: jwt KeyFunc external return (#2809) 2 years ago
dependabot[bot] 520b321fe9
build(deps): bump golang.org/x/net in /contrib/opensergo (#2779) 2 years ago
ibrahim albarghouthi 3958f9d5c0
refactor: metadata supports key corresponding to multiple values (#2772) 2 years ago
dependabot[bot] e9870cb48f
build(deps): bump github.com/hashicorp/consul/api (#2733) 2 years ago
dependabot[bot] f8c19c37af
build(deps): bump google.golang.org/protobuf in /contrib/log/aliyun (#2751) 2 years ago
woniu317 d0847cd462
feat: log helper support sprint option (#2616) 2 years ago
jessetang f03f5f8988
fix(middleware/tracing): golang filename modify (#2727) 2 years ago
jessetang d470886977
refactor(transport): format import and init slice cap (#2741) 2 years ago
Bin 446774f9e5
fix:proto nesting causes template generation problems (#2718) 2 years ago
yonwoo9 e273c5188a
chore: update comment (#2747) 2 years ago
jessetang 393bf4dbcb
fix(contrib/registry/servicecomb): wrong stop ticker (#2749) 2 years ago
虫子樱桃 6a4d17d79a
add http.ResponseController type alias (#2713) 2 years ago
Bin 99ccd00434
fix: package path to filepath (#2672) 2 years ago
dependabot[bot] f47a238478
build(deps): bump k8s.io/client-go in /contrib/config/kubernetes (#2756) 2 years ago
dependabot[bot] 3d1af9af38
build(deps): bump k8s.io/apimachinery in /contrib/config/kubernetes (#2757) 2 years ago
jessetang 9a973d29c2
fix: rectification of non-standard lint codes (#2746) 2 years ago
jessetang 0c2d2632ac
fix(transport/grpc/resolver/discovery/resolver.go): remove attributes.Attributes.New() (#2742) 2 years ago
包子 78a2089f2b
feat: issue translate (#2744) 2 years ago
Xin d05729399e
fix: change the working directory of the command (#2560) 2 years ago
包子 8af9ca33bd
feat: support grpc balancer health check (#2736) 2 years ago
dependabot[bot] bd26120ec6
build(deps): bump actions/setup-go from 3.5.0 to 4.0.0 (#2737) 2 years ago
jessetang 6369db2e8e
fix(cmd/kratos/internal/base/repo.go): missing error (#2734) 2 years ago
jessetang 492248d032
fix(cmd): import format (#2735) 2 years ago
虫子樱桃 ae4dd7f4a8
fix: refactor project creation params process (#2714) 2 years ago
包子 33cb4576e9
Update Makefile (#2725) 2 years ago
包子 768ffd71d4
fix(grpc/balancer): fix the problem that the watch log cannot be closed (#2726) 2 years ago
jessetang 9ee4fcb48a
fix: remove repeat `net/http` package (#2708) 2 years ago
jessetang ae2dcb04c0
fix: markdown form format (#2721) 2 years ago
Xin 6602dc325e
fix: correct message of CmdServer (#2724) 2 years ago
包子 7eca8f8034
deps: upgrade kratos version to v2.6.1 (#2716) 2 years ago
yonwoo9 665a72e67f
fix: fix contrib registry eureka watcher as *watcher (#2693) 2 years ago
包子 a672980a15
fix: upgrade go.sum (#2715) 2 years ago
dependabot[bot] 51fac4ff90
build(deps): bump k8s.io/client-go in /contrib/config/kubernetes (#2695) 2 years ago
dependabot[bot] 9c7182058e
build(deps): bump github.com/hashicorp/consul/api (#2688) 2 years ago
dependabot[bot] 91be9c1071
build(deps): bump k8s.io/apimachinery in /contrib/config/kubernetes (#2694) 2 years ago
dependabot[bot] a11002d7ee
build(deps): bump github.com/hashicorp/consul/api (#2685) 2 years ago
dependabot[bot] 15de2007c7
build(deps): bump golang.org/x/sync in /contrib/registry/zookeeper (#2687) 2 years ago
dependabot[bot] 1579155a2c
build(deps): bump golang.org/x/net in /contrib/opensergo (#2699) 2 years ago
dependabot[bot] 51a34df0a6
build(deps): bump golang.org/x/net in /contrib/config/polaris (#2706) 2 years ago
dependabot[bot] 61176708e6
build(deps): bump golang.org/x/net (#2703) 2 years ago
dependabot[bot] b79c142580
build(deps): bump golang.org/x/net in /contrib/polaris (#2705) 2 years ago
dependabot[bot] f458e2535f
build(deps): bump github.com/prometheus/common (#2698) 2 years ago
dependabot[bot] 8203a90047
build(deps): bump golang.org/x/net in /contrib/registry/servicecomb (#2704) 2 years ago
dependabot[bot] c65f823c38
build(deps): bump golang.org/x/text in /cmd/protoc-gen-go-errors (#2675) 2 years ago
dependabot[bot] a6c9fdd9d3
build(deps): bump golang.org/x/text in /contrib/opensergo (#2678) 2 years ago
dependabot[bot] 7e89bbd799
build(deps): bump golang.org/x/text in /contrib/polaris (#2679) 2 years ago
包子 834b781ee2
feat: support load balance for streaming connection creation (#2669) 2 years ago
hoslo 19f008b483
feat: Add latency to the recover handler context (#2653) 2 years ago
180909 e4595db3d8
fix: cmd `proto add` nil pointer (#2670) 2 years ago
dependabot[bot] e33d644a78
build(deps): bump golang.org/x/text from 0.3.7 to 0.3.8 in /cmd/kratos (#2676) 2 years ago
180909 d8d231e725
fix(selector): version NodeFilter append func (#2671) 2 years ago
weetime bab67facad
fix(contrib): fix eureka server load too high (#2546) 2 years ago
thinkgo d0b1d84850
feat: add comment to http server interface method (#2657) 2 years ago
dependabot[bot] 54f19c1dcb
build(deps): bump github.com/prometheus/common (#2668) 2 years ago
dependabot[bot] 8d5010495a
build(deps): bump google.golang.org/grpc in /contrib/config/etcd (#2662) 2 years ago
jessetang 6330a5688e
chore: replace deprecated method (#2667) 2 years ago
包子 27eadd83b4
fix: polaris get service name (#2615) 2 years ago
YuanXin Hu 0a076443cb
feat: support polaris ratelimit ability (#2586) 2 years ago
aveyuan 7def38acde
feat(log): update zap interface (#2620) 2 years ago
LiuDui 77abb6356f
chore: update pull request template (#2649) 2 years ago
包子 50da181d69
fix: do not re register after service logout (#2647) 2 years ago
包子 a006328db6
fix: polaris temporarily delete the watch test (#2652) 2 years ago
leyou240 613282b096
chore(ci): update go.yaml support golang 1.20 (#2651) 2 years ago
LiuDui 08f37391e1
chore: clean up deprecated code (#2648) 2 years ago
cui fliter 239121155d
chore: fix comment (#2645) 2 years ago
jerjjj b242403bc1
update gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b to 3.0.0 (#2630) 2 years ago
Kevin Wan 63b23af418
chore: update go-zero link in readme (#2628) 2 years ago
liyaopinner 35800916dc
feat: add grpc client stream interceptor opts (#2610) 2 years ago
longxboy bebea0c103
feat: add subset alg for instances (#2613) 2 years ago
虫子樱桃 61744753eb
fix: project creation `--nomod` (#2611) 2 years ago
桂后昌 b2689af39c
feat(transport/http): request body read multiple times (#2542) 2 years ago
180909 e22775cfcc
chore(transport): fix the test name (#2543) 2 years ago
cui fliter 9cc1047c75
chore: fix a few function names on comments (#2430) 2 years ago
包子 7e896ae4c0
feat: support polaris service governance (#2605) 2 years ago
包子 33d51a84c3
feat(registry): consul support re-registry when service does not exist (#2606) 2 years ago
longxboy eafbe908a8
feat:add buf apis (#2604) 2 years ago
dependabot[bot] f49ac647e8
build(deps): bump github.com/aliyun/aliyun-log-go-sdk (#2598) 2 years ago
baeNewJeans 65c51594f9
fix(contrib/registry/etcd): rewatch when error occur (#2603) 2 years ago
包子 480b16b817
feat: grpc use the admin api (#2596) 2 years ago
dependabot[bot] b26023888d
build(deps): bump github.com/hashicorp/consul/api (#2561) 2 years ago
刘思圆 a3f24ee704
fix(contrib/log/tencent): tencentcloud-cls-sdk-go 为异步上传,需要显式调用"Start"方法开启才会生效 (#2514) 2 years ago
Remember 271b6c2924
fix(consul):return err if ctx is done (#2550) 2 years ago
Luckystar c442a320a0
feat: support for windows make install (#2554) 2 years ago
soukengo b0db594829
fix(registry): add zookeeper exists watcher when the node does not exist (#2555) 2 years ago
dependabot[bot] 33fff02a62
build(deps): bump github.com/aliyun/aliyun-log-go-sdk (#2577) 2 years ago
Juan C. Yamacho H d12498ed38
feat(middleware): redacter interface for logging (#2564) 2 years ago
虫子樱桃 852a77faa6
Feat project create with dir name add test (#2576) 2 years ago
dependabot[bot] 6f78ccacd9
build(deps): bump k8s.io/apimachinery in /contrib/config/kubernetes (#2581) 2 years ago
dependabot[bot] 2c3fab50a3
build(deps): bump actions/setup-go from 3.3.1 to 3.5.0 (#2585) 2 years ago
dependabot[bot] 2a9808df14
build(deps): bump github.com/polarismesh/polaris-go (#2589) 2 years ago
dependabot[bot] 89d8eeba62
build(deps): bump github.com/apolloconfig/agollo/v4 (#2591) 2 years ago
dependabot[bot] a017ab0957
build(deps): bump github.com/hashicorp/consul/api (#2563) 2 years ago
baozhecheng a45f3afdff Revert "feat: support polaris service governance" 2 years ago
baozhecheng b67d514bfa feat: support polaris service governance 2 years ago
Xingwang Liu facafba64a
fix(registry): ServiceInstance does not implement an Equal method for grpc Attributes. (#2575) 2 years ago
baozhecheng e36612e9ca Revert "fix issue:#2358 Support for creating a project with specifying the name for its place dir (#2573)" 2 years ago
虫子樱桃 3d322fe6c1
fix issue:#2358 Support for creating a project with specifying the name for its place dir (#2573) 2 years ago
woniu317 2cf82fa4a7
feat: consul registry support get services from multiple datacenters (#2536) 2 years ago
jessetang 3393990cd8
test(encoding/form/encode): add test and fix code style (#2539) 2 years ago
dependabot[bot] 3c3829795c
build(deps): bump github.com/aliyun/aliyun-log-go-sdk (#2548) 2 years ago
Ccheers 8732b76386
fix(circuitbreaker): add WithCircuitBreaker to fix WithGroup is useless (#2535) 2 years ago
Aurélien Perrier d779faf091
feat(transport/grpc): support custom healthcheck (#2541) 2 years ago
qshuai a82c82d49f
fix(config): fix codec NPE as parsing format wrongly, fix #2517 (#2518) 2 years ago
180909 c530d63e75
chore(cmd): use t.Cleanup (#2537) 2 years ago
包子 a7bae93ee0
deps: upgrade kratos version to v2.5.3 (#2500) 2 years ago
dependabot[bot] b339ae8956
build(deps): bump github.com/apolloconfig/agollo/v4 (#2421) 2 years ago
dependabot[bot] 3f698aa2c0
build(deps): bump go.etcd.io/etcd/client/v3 in /contrib/registry/etcd (#2384) 2 years ago
dependabot[bot] c5888ff464
build(deps): bump google.golang.org/grpc in /contrib/opensergo (#2452) 2 years ago
dependabot[bot] 878eca54ab
build(deps): bump google.golang.org/grpc in /contrib/config/etcd (#2453) 2 years ago
yeqown 275f815e40
typo: correct var name (#2496) 2 years ago
Cluas 383f28faeb
fix(selector): set global do not work (#2489) 2 years ago
dependabot[bot] e9ef3eea2d
build(deps): bump github.com/hashicorp/consul/api (#2472) 2 years ago
dependabot[bot] 58d9e3be56
build(deps): bump github.com/prometheus/client_golang (#2494) 2 years ago
dependabot[bot] 818452dd53
build(deps): bump github.com/polarismesh/polaris-go (#2493) 2 years ago
dependabot[bot] 699f0304ed
build(deps): bump github.com/aliyun/aliyun-log-go-sdk (#2492) 2 years ago
dependabot[bot] c888d50cc5
build(deps): bump google.golang.org/grpc in /contrib/registry/etcd (#2454) 2 years ago
jessetang a1a2b9dbd9
test(encoding/form): add unit test and code style modift (#2467) 2 years ago
JellyTony 590c469081
feat: add app Before and Afters option (#2403) 2 years ago
Miguel Martínez Triviño 0f38511ea8
fix(filter): filter out keyvals if keyFunc is provided (#2484) 2 years ago
jessetang 511f1917ce
fix(contrib/log): test case error (#2487) 2 years ago
jessetang 2a65502be2
style(config): code style tweaks and abstracts some methods (#2465) 2 years ago
dependabot[bot] 03d9494b19
build(deps): bump github.com/hashicorp/consul/api (#2473) 2 years ago
dependabot[bot] c4c1ebab47
build(deps): bump github.com/aliyun/aliyun-log-go-sdk (#2483) 2 years ago
Tony Chen f0878b0a78
fix ewma panic (#2480) 2 years ago
jessetang 3c65f16737
style(contrib/config): code style modify (#2475) 2 years ago
包子 dcae38d656
deps: upgrade kratos version to v2.5.2 (#2464) 2 years ago
Jesse a911f8f9ee
fix(log): toString float32 precision loss and convert uint use `FormatUint` (#2461) 2 years ago
dependabot[bot] 4bd1fde7ef
build(deps): bump actions/setup-go from 3.3.0 to 3.3.1 (#2462) 2 years ago
Jesse 54655e4b24
cleanup: use HTTP package methods replace GET POST DELETE... (#2412) 2 years ago
Tony Chen 185aaa7184
fix net error (#2460) 2 years ago
Guoqiang Ding 40300677ee
fix(metadata): sort services by lexicographical order on ListServices (#2397) 2 years ago
Jesse 6bb3ad6f27
fix: in for defer close (#2411) 2 years ago
Jesse 54c6fb3631
test(middleware/auth/jwt): add test TestNewContextAndFromContext (#2447) 2 years ago
Jesse b5482d1794
test(middleware/metadata): supplement test and modify code style (#2448) 2 years ago
Guoqiang Ding e3feea6eeb
docs(config/etcd): fix the missing step of Load (#2450) 2 years ago
ruohone d82d607c21
[Feature] add path prefix for http server (#2439) 2 years ago
jesse.tang 7a99e8bbdc
cleanup: regex replcae \. => . (#2435) 2 years ago
jesse.tang 77d260241c
test(middleware/logging): TestExtractError (#2443) 2 years ago
jesse.tang 2de6ba028c
cleanup: update scpSyntaxRe regexp (#2444) 2 years ago
jesse.tang b5cd1c693d
fix: contrib/registry/eureka/client.go serveice -> serivce (#2440) 2 years ago
jesse.tang c5e86ca36d
style: kratos interface check (#2441) 2 years ago
包子 8743f3e50c
deps: upgrade kratos version v2.5.1 (#2431) 2 years ago
jesse.tang 69fcd50c0a
feat: golangci add goimports local-prefixes (#2413) 2 years ago
jesse.tang 9f65c1a03d
cleanup: remove redundancy type conversion and golangci add unconvert (#2409) 2 years ago
Tony Chen a680321309
add custom binding (#2428) 2 years ago
Tony Chen 468630cc4b
expose request from transport (#2427) 2 years ago
180909 9301bfa407
chore(log): let log toString same (#2414) 2 years ago
leyou240 ff59a89b06
chore: Update go.yml (#2426) 2 years ago
jesse.tang 0ecc2b422f
style: modify declaring empty slices (#2378) 2 years ago
Gaffey faa3adc300
style(config/value): optimize atomicValue format string (#2401) 2 years ago
180909 b10e067fe9
test(log): add toString unit test (#2373) 2 years ago
jesse.tang 0e698b248a
cleanup: remove fmt and errors new err (#2377) 2 years ago
180909 2936b5ba80
cleanup: remove the repeated import (#2393) 2 years ago
jesse.tang 4d95050747
fix: fmt import (#2379) 2 years ago
swliao425 8d067a32db
fix(aliyun log): 'format bool' is missing in 'toString' function (#2406) 2 years ago
180909 2170a12aa4
fix: modify interface check way on selector (#2399) 2 years ago
180909 add67beeb3
fix(http/binding): fix http encode url (#2400) 2 years ago
包子 7866ff75fd
fix(registry/consul): use health check option to control custom checks (#2391) 2 years ago
Tony Chen 2d325fd386
fix(http/binding): fix http encode url (#2392) 2 years ago
jesse.tang 080165f2ee
cleanup: modify deprecated field (#2380) 2 years ago
jesse.tang 9737a3c5e4
fix: typo and grammatical errors (#2368) 2 years ago
Jiepeng Cao 7f2666be9f
typo for log (#2374) 2 years ago
jesse.tang 7a320233cd
fix: .gitignore del Repeated .*so (#2367) 2 years ago
Loner1024 d3f80c1061
test: supplement the unit testing of transport/grpc (#2371) 2 years ago
jesse.tang b0b49be383
feat: remote assert libraries (#2372) 2 years ago
jesse.tang 0ed01efdfd
revise err logic or null pointer exception (#2376) 2 years ago
jesse.tang f2a33929d0
fix: modify interface check way (#2375) 2 years ago
包子 ae505063fe
fix(apollo): config return nil when watch err 2 years ago
Guoqiang Ding 667d63839c
fix(makefile): add "make proto" for proto generating (#2130) 2 years ago
hshe e176ddfcdd
feat(internal/host): prefer ipv4 than ipv6 (#2342) 2 years ago
180909 0f0c75e20b
feat(cmd): user prePage to check changelog dev (#2340) 2 years ago
180909 18c5734930
test(cmd): add ModulePath test (#2337) 2 years ago
180909 8d76eebf8b
test(cmd/change): add ParseGithubURL test (#2339) 2 years ago
GongGuoWei cb69bf3714
test(config): add etcd config method test (#2349) 2 years ago
黄仲辉 617ee1aa39
fix(lint): Using deprecated package `io/ioutil` cause lint interrupted, change to `os` or `io` package. (#2353) 2 years ago
180909 39536d3279
fix(cmd): fix CmdAdd long message example (#2343) 2 years ago
dependabot[bot] e820b392e9
build(deps): bump github.com/hashicorp/consul/api (#2279) 2 years ago
dependabot[bot] aaabd07474
build(deps): bump actions/setup-go from 3.2.1 to 3.3.0 (#2313) 2 years ago
dependabot[bot] 7a336ca353
build(deps): bump google.golang.org/protobuf in /contrib/opensergo (#2248) 2 years ago
dependabot[bot] 503efd3825
build(deps): bump go.uber.org/zap in /contrib/log/zap (#2326) 2 years ago
icylight 60b00c8ade
fix(config/env): prefixs typo (#2321) 2 years ago
Wang-TaoTao ad7597c0b1
fix: init global selector to wrr (#2323) 2 years ago
icylight cbfb6db9cf
fix(internal/host): Extract can't return the minium index ip (#2298) 2 years ago
虫子樱桃 20c2425c18
fix `kratos new -r` not support scp styled git url.issue https://gith… (#2295) 2 years ago
包子 890bc21ac1
docs: update readme.md, remove qq group (#2341) 2 years ago
川桑 361391732b
test(selector): improve coverage (#2320) 2 years ago
包子 b354f185c0
feat(registry): consul support user custom checks (#2317) 2 years ago
jesse.tang 73a8323ee7
fix: slice/map make init cap (#2300) 2 years ago
Germiniku cb6176dbbb
feat(tracing) custom tracer name (#2310) 2 years ago
过客龙门 0ce9e8d069
specify array capacity hints (#2299) 2 years ago
dependabot[bot] b1bb0bd18f
build(deps): bump github.com/hashicorp/consul/api (#2278) 2 years ago
dependabot[bot] 869fcd57c8
build(deps): bump go.uber.org/zap in /contrib/log/zap (#2280) 2 years ago
icylight 5c3f0aa73e
style(metadata): specify map capacity hints (#2296) 2 years ago
jesse.tang 6ca225b078
add notes by not used defer (#2291) 2 years ago
YidaZhou ba72230477
doc: grammar problems in the Readme file (#2281) 2 years ago
Astone 205aa88d86
fix: encoding form decode field mask from well-know (#2285) 2 years ago
pwli bdfeb4bf78
fix typo (#2284) 2 years ago
haiyux 39796ea0dc
fix: delete endpoint service discovery compatibility (#2289) 2 years ago
包子 563ad0d34a
deps: upgreade kratos version to v2.5.0 (#2286) 2 years ago
包子 3f31b4d734
bc: apollo unable to get and watch to the properties file (#2269) 2 years ago
Tony Chen 2d206076f8
fix logger caller depth (#2283) 2 years ago
Germiniku de2f93fbec
refactor(log) aliyun use the same interface name (#2251) 2 years ago
longxboy 11cd43e3c3
refactor: unify selector filter (#2277) 2 years ago
kkf1 d11c6892b4
feat: add servicecomb registry (#2114) 2 years ago
Haibo 6d665c0ce6
fix: wrong order of Logger prefix kvs (#2273) 2 years ago
包子 84235462b7
feat(registry): consul get service support remote (#2275) 2 years ago
SeniorPlayer b9b7888d51
fix(log): DefaultCaller doesn't returns "pkg/file:line", it returns "file:line" now. For example, both biz/user.go and data/user.go are printed as user.go in logger. It's not clear. (#2274) 2 years ago
realityone f0c2a6ed90
Global logger (#2265) 2 years ago
Weizhen Wang 57dee517e5
fix(chore): set nacos-server v2.1.0 and consul v1.12.3 (#2268) 2 years ago
Kagaya e4d73db523
fix lint error (#2266) 2 years ago
dependabot[bot] 0aa9719e3a
build(deps): bump google.golang.org/protobuf in /contrib/log/aliyun (#2249) 2 years ago
shifengbin c407afc81d
fix: in case url or form bind param error should return BadRequest (#2256) 2 years ago
Germiniku fea863e783
feat(log): add tencent cls (#2244) 2 years ago
林晓炜 1f3ac4ea22
fix(registry): contrib/registry/zookeeper ephemeral nodes handling after restart (#2245) 2 years ago
dependabot[bot] aae0339692
build(deps): bump github.com/prometheus/common (#2210) 2 years ago
包子 eff368621f
deps: upgrade kratos version to v2.4.1 (#2242) 2 years ago
kiripeng a5eb913aa0
chore: go workspace contain go.work and go.work.sum (#2241) 2 years ago
180909 ffa1c2696c
update ignore for go workspace (#2240) 2 years ago
dependabot[bot] 86eba94646
build(deps): bump k8s.io/client-go in /contrib/config/kubernetes (#2217) 2 years ago
dependabot[bot] 2951b420f1
build(deps): bump k8s.io/client-go in /contrib/registry/kubernetes (#2218) 2 years ago
Tony Chen f3b0da3f04
feat(middleware): add selector matcher (#2239) 2 years ago
dependabot[bot] 377356d04d
build(deps): bump github.com/hashicorp/consul/api (#2211) 2 years ago
dependabot[bot] 247a74e631
build(deps): bump github.com/hashicorp/consul/api (#2209) 2 years ago
Tony Chen 3c54997dd8
fix default behavior for gRPC encoding (#2187) 2 years ago
dependabot[bot] e6767bc612
build(deps): bump k8s.io/api in /contrib/config/kubernetes (#2219) 2 years ago
dependabot[bot] 9d24dac487
build(deps): bump k8s.io/api in /contrib/registry/kubernetes (#2220) 2 years ago
dependabot[bot] e2c1fd7489
build(deps): bump github.com/go-zookeeper/zk (#2236) 2 years ago
hshe b7422717cf
proto build client structName not match to server's structName (#2200) 2 years ago
Haibo 59b758ceda
feat: support passing program args with run cmd (#2207) 2 years ago
林晓炜 246d8d9c28
fix: zookeeper add auto re-register (#2235) 2 years ago
Paul 92b3c8f94a
fix(contrib/config/polaris): Use injected client properly (#2238) 2 years ago
haiyux 14cfd65b62
fix: remove unuseful file when use nomod (#2234) 2 years ago
wangcong 82dfb955f5
fix(contrib): add logrus fatal level (#2222) 2 years ago
风雨雾凇 de0e4e2228
docs: update README_zh.md (#2208) 2 years ago
dependabot[bot] 1ab3d8f028
build(deps): bump github.com/prometheus/common (#2188) 2 years ago
dependabot[bot] 0ff80e42e7
build(deps): bump actions/setup-go from 3.2.0 to 3.2.1 (#2189) 2 years ago
Walrus Yu d1da8aa1ae
Feature/improve app test (#2190) 2 years ago
shengzhou ede5f889d4
test: increase endpoint,env, options and reader tests coverage. (#2192) 2 years ago
rogerogers bcef2b8e3f
test(contrib): update unit test for contrib/registry/polaris (#2196) 2 years ago
jakezhu9 85af73a84b
test(log): increase tests coverage (#2197) 2 years ago
包子 1451b9e0c0
deps: upgrade kratos version to v2.4.0 (#2186) 2 years ago
潘雄 96c8de9bc4
style(contrib/registry/*) annotation perfect (#2185) 2 years ago
Tony Chen d0a0edf67b
feat(http): add http router walk (#2181) 2 years ago
jakezhu9 afd108cdc7
test(options): increase tests coverage (#2183) 2 years ago
Ccheers b3eff576ce
test(transport): add unit test for transport coverage: 91.7% of state… (#2172) 2 years ago
rogerogers 63827466a3
test(contrib): add unit test for contrib/metrics/prometheus (#2182) 2 years ago
freezeChen 187c65bf8c
test(contrib/config/consul): add unit test for contrib/config/consul (#2179) 2 years ago
Tony Chen 6ac63e6439
fix(transport): http endpoint listening (#2180) 2 years ago
Tony Chen c90eab4577
fix transport early listening (#2177) 2 years ago
川桑 102391165e
test(errors): improve coverage (#2178) 2 years ago
Giovanny Gutiérrez 2209da5e24
feat(metadata): Ignore service if the dependencies are not found (#2171) 2 years ago
dependabot[bot] 1ea4ef7412
build(deps): bump k8s.io/client-go in /contrib/registry/kubernetes (#2120) 2 years ago
川桑 d88052b7dd
fix(errors): panic when err of Clone is nil (#2176) 2 years ago
darkweak c9fbb27b5b
tests(coverage): Increase middleware tests coverage (#2165) 2 years ago
shengzhou dec323113f
test(config/file): add format test (#2147) (#2168) 2 years ago
dependabot[bot] 8d0d7838ca
build(deps): bump github.com/hashicorp/consul/api (#2082) 2 years ago
rogerogers 2525e81e55
test(contrib): add unit test for contrib/registry/k8s (#2166) 2 years ago
dependabot[bot] 08fccfcb66
build(deps): bump github.com/hashicorp/consul/api (#2081) 2 years ago
dependabot[bot] 8e9e15e04b
build(deps): bump k8s.io/client-go in /contrib/config/kubernetes (#2122) 2 years ago
Betula-L e09d294388
feat: add logrus to contrib log (#2077) 2 years ago
dependabot[bot] 39bfeeb2f7
build(deps): bump k8s.io/api in /contrib/registry/kubernetes (#2124) 2 years ago
Y.Horie 106bc07def
test(contrib): add unit test for aliyun.go (#2164) 2 years ago
Tony Chen 0bcdb8d59c
fix(encoding/form): encode optional value (#2155) 2 years ago
shengzhou 5df19c47d8
test(encoding/form): well konw types test (#2147) (#2160) 2 years ago
Loner1024 62b58848d6
test: supplement the unit testing of metadata (#2161) 2 years ago
dependabot[bot] b6954d1aeb
build(deps): bump github.com/aliyun/aliyun-log-go-sdk (#2152) 2 years ago
rogerogers 6c36cc9544
feat: add contrib/config/polaris polaris as configcenter (#2158) 2 years ago
wangcong 20b7c9f4d7
test(nacos): add nacos unit test and remove unused function (#2145) 2 years ago
haiyux addcbba66e
feat: add protoc-gen-go-http annotations synchronization with protoc-gen-go-grpc (#2151) 2 years ago
Guoqiang Ding 035c2f5387
fix: typo on emptypb.Empty (#2150) 2 years ago
rogerogers 8c0a354797
test(contrib): add unit test for contrib/config/k8s (#2140) 2 years ago
freezeChen ed8b2352b7
test(contrib): add unit test for contrib/registry/consul (#2148) 2 years ago
liuyi0618 52031f1381
feat(contrib):add etcd watcher withKeysOnly option (#2146) 2 years ago
Y.Horie 9015ffb920
test(contrib): add unit test for fluent.go (#2141) 2 years ago
ThereWeGo 4ca25e4679
fix: show git output (#2143) 2 years ago
shifengbin 2ad7ffdd7e
fix: remove the output of the proto command 2 years ago
zoujiejun 3905182e98
test(contrib): add unit test for opensergo.go (#2137) 2 years ago
Ccheers 13c33fc4d3
feat(contrib): add unit test for zap_test.go & register_test.go (#2136) 2 years ago
haiyux 25c5996360
fix:fix url ptr not encode (#2117) 2 years ago
Guoqiang Ding 2f8703bff2
fix: allow the case of proto not found, such like gogo.proto (#2132) 2 years ago
charviki a3439c9713
fix: catch server stop error (#2125) 2 years ago
Tony Chen a0e624c0b8
fix(binding): fix bind field mask (#2112) 2 years ago
Cluas 6fa5700c3c
chore(contrib/config): uniformly canceled by CancelFunc (#2111) 2 years ago
包子 3aaac45e3d
fix: regenerate the proto file (#2108) 2 years ago
longxboy 2a989ea0fe
fix dup gen const for http (#2102) 2 years ago
YuanXin Hu e3c37b936f
use offical image (#2105) 2 years ago
Cluas 4f8d8ef8da
feat(config): add ErrorWatcherStopped and return on watcher.Next() after Watcher.Stop() (#2092) 2 years ago
haiyux 752f011ba1
fix:fix proto add underscore problem (#2101) 2 years ago
raw34 228ceaae9d
fix: kratos proto server cmd method name bugfix (#2089) (#2094) 2 years ago
包子 4b7afe52af
fix(config): apollo get the original configuration file directly (#2100) 2 years ago
longxboy 123fc1e6c8
feat: add peer for selector (#2088) 2 years ago
longxboy eb280903f0
fix: operation http constant name conflict (#2087) 2 years ago
longxboy 93adaba60a
add http operation const (#2086) 2 years ago
包子 874d4c3edc
doc: update pull request template (#2080) 2 years ago
workman-Lu d1550b366b
The clear interaction for user (#1916) 2 years ago
虫子樱桃 c6f6caa887
Add Flusher type alias . (#2078) 2 years ago
包子 95dce00852
deps: upgrade kratos version to v.2.3.1 (#2075) 2 years ago
haiyux ad5e9032a3
feat: make secure url to grpcs://127.0.0.1/ (#2072) 2 years ago
Tony Chen 1b3529fd0b
transport/http(feat): add redirector to forward request (#2074) 2 years ago
dependabot[bot] 5de1f081f6
build(deps): bump gopkg.in/yaml.v3 in /contrib/config/nacos (#2067) 2 years ago
dependabot[bot] b5e7b8d61b
build(deps): bump gopkg.in/yaml.v3 in /contrib/config/apollo (#2068) 2 years ago
Tony Chen 97c103a395
fix with logger (#2062) 3 years ago
dependabot[bot] b74e330289
build(deps): bump k8s.io/client-go in /contrib/config/kubernetes (#2056) 3 years ago
dependabot[bot] 7d425b898e
build(deps): bump k8s.io/client-go in /contrib/registry/kubernetes (#2057) 3 years ago
dependabot[bot] 8ad8578c40
build(deps): bump github.com/aliyun/aliyun-log-go-sdk (#2053) 3 years ago
dependabot[bot] a926195f66
build(deps): bump k8s.io/api in /contrib/config/kubernetes (#2052) 3 years ago
Tony Chen dccee86141
log: remove component logger to use global logger (#2061) 3 years ago
dependabot[bot] 925a0b725e
build(deps): bump k8s.io/api in /contrib/registry/kubernetes (#2058) 3 years ago
包子 6e685a474b
fix: config log 3 years ago
包子 c01fd054ec
feat: add config log (#2060) 3 years ago
Tony Chen 503ec03f37
app: fix instance nil when not registered (#2059) 3 years ago
dependabot[bot] 84b23fd301
build(deps): bump actions/setup-go from 2 to 3.2.0 (#2048) 3 years ago
dependabot[bot] 8fd0dc7680
build(deps): bump golangci/golangci-lint-action from 2 to 3 (#2047) 3 years ago
dependabot[bot] 6be806e7c0
build(deps): bump actions/checkout from 2 to 3 (#2046) 3 years ago
dependabot[bot] d1c6b732b4
build(deps): bump github/codeql-action from 1 to 2 (#2045) 3 years ago
包子 65d0ddbaae
Update dependabot.yml 3 years ago
包子 c304680444
Create dependabot.yml 3 years ago
longxboy 944d480f78
feat:add context for log (#2041) 3 years ago
包子 70317d05a0
deps: upgrade kratos version to v2.3.0 (#2036) 3 years ago
Tony Chen 97fd33ece7
opensergo: fix http path & method (#2035) 3 years ago
Kagaya 643caa6df9
feat(contrib/opensergo): add opensergo reportMetadata fields (#1996) 3 years ago
Tony Chen 79497dd3a5
log: fix global logger (#2034) 3 years ago
Tony Chen 6eae1745bd
http: handle default mux (#2033) 3 years ago
longxboy 655fe37188
fix:fix error camel case (#2032) 3 years ago
haiyux 71ea97fd93
deps: upgrade go mod version (#2028) 3 years ago
songzhibin97 398012aed4
Update project.go (#2024) 3 years ago
songzhibin97 0bbd008397
Update server.go (#2021) 3 years ago
songzhibin97 aa6529fb2d
style:change (#2022) 3 years ago
songzhibin97 ec2e3ab24e
Update path.go (#2023) 3 years ago
songzhibin97 bbb96f1e1f
Update run.go (#2025) 3 years ago
songzhibin97 c1dbc2dbd3
stype:gen_go_errors (#2026) 3 years ago
songzhibin97 b49b7c6ca8
Update server.go (#2027) 3 years ago
songzhibin97 0c511808ce
style:ewma (#2018) 3 years ago
songzhibin97 92ba6a3209
Style:trace (#2017) 3 years ago
songzhibin97 9e66ac2f5b
Update jwt.go (#2016) 3 years ago
songzhibin97 1dfac59204
Update metadata.go (#2015) 3 years ago
songzhibin97 2eb615b38a
style:log (#2014) 3 years ago
songzhibin97 5e0744a47b
Update encode.go (#2019) 3 years ago
Ccheers 8dec7cf5e8
feat(registry): zookeeper watch node changed (#1986) 3 years ago
songzhibin97 c412d65f57
Update endpoint.go (#2012) 3 years ago
songzhibin97 2ee49311c1
Update host.go (#2013) 3 years ago
songzhibin97 1dfb77bfe1
Update errors.go (#2009) 3 years ago
songzhibin97 ef6fb480c6
fix:#2006 config.atomicValue Other basic types are supported (#2007) 3 years ago
songzhibin97 8a8626331d
Update file.go (#2005) 3 years ago
qi 53c8877ce4
fix(protoc-gen-go-errors): fix generated function comments have extra blank lines. (#2008) 3 years ago
songzhibin97 5c66fcdc5a
fix:#2002 definition service lowercase generation cannot be exported (#2003) 3 years ago
JinChang 912abb4848
Added ability to configure protojson (#1993) 3 years ago
包子 c9f95dc2e8
fix: update ci gocyclo min-complexity 50 (#2000) 3 years ago
pwli f0a058713f
fix:(transport/http): fix unexpected overriding behavior when return an error (#1984) 3 years ago
houseme 0d9319b1ee
fix: Replace the docker image of Polaris (#1999) 3 years ago
songzhibin97 8ff5f2fe88
fix:#1987 Http and grpc generate route alignment (#1988) 3 years ago
Comolli ec78198050
feat: decode google.protobuf.BytesValue compatible base64.URLEncoding. (#1991) 3 years ago
Kagaya ab04490d49
docs: remove redundant info & fix typo in pr template (#1997) 3 years ago
Kagaya bf9f4886e9
ignore polaris test & add eureka consul test (#1998) 3 years ago
qi c8c870b77f
fix: query params: parse list failed, unsupported message type: "google.protobuf.Struct" #1967 (#1989) 3 years ago
Nikita Krasnikov ed144f6813
Fix buildMethodDesc for two and more message field (#1979) 3 years ago
witt ddc82ce45e
fix: delete redundant type conversion (#1977) 3 years ago
Jinming Guo bc9d2074af
fix: add 'go mod tidy' cmd to make quick-start available (#1973) 3 years ago
Underworld511 36dfcdb0a6
Update README_zh.md (#1975) 3 years ago
包子 091ba2dae7
deps: upgrade kratos version to v2.2.2 (#1944) 3 years ago
Elric Li eb2dcae83d
feat(log): Helper implemented io.Writer (#1927) 3 years ago
JeffreyBool 245f55d3ba
feat: protoc-gen-go-errors add comment (#1961) 3 years ago
林晓炜 9098e9dd39
feat(registry): contrib/registry/zookeeper add digest acl support (#1964) 3 years ago
张东龙 60465ccca2
fix(transport/http): responseEncoder should not write any data when it need to write nil (#1945) 3 years ago
haiyux 4e73384a9e
feat:new and add karge warehouse (#1953) 3 years ago
haiyux 73545347e8
fix: fix kratos run when cmd number is one (#1956) 3 years ago
haiyux d4c4908ef6
fix: fix choose failed when paths cmd/server (#1954) 3 years ago
Casper-Mars d4e1942480
fix(contrib/opensergo): fix index error (#1951) 3 years ago
张东龙 259cd84653
fix bind test errors (#1950) 3 years ago
李洛克 4472cdbf49
fix client do method done not use when err not nil (#1948) 3 years ago
Tony Chen ae230eb550
feat: add opensergo metadata (#1947) 3 years ago
yeqown fbf7855cf2
feat(discovery): provide an option to disable discovery debug log (#1942) 3 years ago
Tony Chen d0b704b8f3
feat(selector): add node scheme (#1932) 3 years ago
Windfarer 3990d91b9b
correct the func name in meatadata log (#1915) 3 years ago
Xudong Cai 9ca08888df
fix: error case2Camel (#1923) 3 years ago
Tony Chen a72fc68ffd
feat: add error cause for statck trace (#1910) 3 years ago
Casper-Mars 96cfbe6c22
feat: change description of Kratos (#1920) 3 years ago
Casper-Mars 19637d9b87
feat(registry): consul client add DeregisterCriticalServiceAfter option (#1917) 3 years ago
Casper-Mars 4f21094a56
fix(cmd/protoc-gen-go-errors):fix lint problem (#1919) 3 years ago
yoogo d5a2fb59ad
fix(cmd): protoc-gen-go-http use self release (#1909) 3 years ago
Tony Chen fd2335ba38
add json codec for grpc (#1908) 3 years ago
包子 558ef4ebae
fix(transport): fix the problem that the context is not delivered correctly (#1906) 3 years ago
包子 99a0646acb
fix(log/aliyun): Improper Input Validation in GoGo Protobuf CVE-2021-3121 (#1902) 3 years ago
Cluas 13208d7908
fix(log): FilterFunc keyvals lost logger prefix (#1901) 3 years ago
Cluas d4c0c57681
feat(log): log load config only when Debug level (#1899) 3 years ago
weetime 69df1ab9a6
feat(contrib): add eureka registry (#1792) (#1793) 3 years ago
Tony Chen 7a5c2207a1
fix: starter parent ctx (#1895) 3 years ago
longxboy e66a2905ab
feat: supprt non-kratos instance in consul registry (#1892) 3 years ago
包子 e98c0078cb
deps: upgrade kratos version to 2.2.1 (#1890) 3 years ago
包子 93b56d364d
fix: update semantic (#1891) 3 years ago
包子 de2d4eacda
fix(cmd): proto-gen-go-http warn only when ending with a slash (#1887) 3 years ago
Tony Chen 51fb0e0440
fix(log): call depth (#1885) 3 years ago
letian d373c51acf
fix: kratos command error on windows (#1884) 3 years ago
Tony Chen c550a886e9
fix: decode empty body (#1882) 3 years ago
Sasha Melentyev 096e2b0d79
ci: Add 1.18 (#1880) 3 years ago
hoslo f68702a8c2
fix: graceful shutdown (#1873) 3 years ago
包子 64bd619967
chore: remove examples (#1871) 3 years ago
包子 1c37eff18a
feat: add semantic.yml (#1876) 3 years ago
kwanhur ac99a5c877
style(cmd/errors/examples/middleware/transport): fix common words' spelling mistakes (#1872) 3 years ago
Chen Xinyuan 4387085047
fix: fix some typos (#1869) 3 years ago
kwanhur 79057d4326
chore(examples): optimize typos of swagger/server (#1862) 3 years ago
cui fliter ed6ab7caf9
docs: fix some typos (#1852) 3 years ago
YuanXin Hu e739f1d282
Example for Polaris (#1850) 3 years ago
Tony Chen 03ad2b6636
fix: error code judgment (#1849) 3 years ago
Sasha Melentyev 48d407cc9b
perf: add prealloc (#1846) 3 years ago
Sasha Melentyev da147b5763
feat: add zero prealloc (#1847) 3 years ago
Sasha Melentyev 997b6a9f79
build: add matrix strategy with go version (#1845) 3 years ago
Sasha Melentyev d679466a7b
perf(app): add prealloc (#1843) 3 years ago
Sasha Melentyev f56b325a3d
feat(example/transaction/ent): add ent install in Makefile (#1844) 3 years ago
YuanXin Hu f3313476ac
Discovery For Tencent Polaris (#1839) 3 years ago
高永立 2ee4e5f37a
feat(examples/transaction): feature transaction gorm (#1838) 3 years ago
Casper-Mars 5e18a15109
fix(config/config):fix type not match bug (#1837) 3 years ago
包子 d6896127b1
deps: upgrade kratos version to 2.2.0 (#1834) 3 years ago
包子 c9f1d7db6d
feat(examples/transaction): add transaction examples (#1836) 3 years ago
haiyux 24393ee655
fix lint (#1833) 3 years ago
youn a52b17c268
fix: add yaml / yml parser (#1808) 3 years ago
Zhen Wang 4dadafff90
fix(jwt): parse server custom claims (#1817) 3 years ago
Jin Peng 85800cedb9
fix(contrib): get nacos service of customize group name (#1798) 3 years ago
haiyux 9dec67bddd
update contrib readme (#1831) 3 years ago
YuanXin Hu 6446212258
feat(registry/polaris): add registry for Tencent Polaris (#1816) 3 years ago
Casper-Mars c1e98e41de
fix(config/consul):Config from consul skip empty key (#1830) 3 years ago
Tony Chen 6ec695064b
move container group to internal (#1827) 3 years ago
包子 991bb932f0
deps(thirdparty): clean oepnapi2 proto (#1826) 3 years ago
haiyux 370a1585a5
fix: fix the latest version of lint problem (#1825) 3 years ago
包子 cde962a6c1
fix(cmd/http): warn only when a get or delete request declares a body (#1789) 3 years ago
Jason C.H 471a2aab79
fix: k8s discovery interface (#1820) 3 years ago
haiyux 9662ef3c21
feat:add examples redirect url (#1807) 3 years ago
haiyux 86b8b6c366
fix: fix ci tool (#1803) 3 years ago
Tony Chen 34d0cccefd
fix: allocates new objects each time (#1802) 3 years ago
haiyux 18315303f0
deps:upgrade go mod version (#1800) 3 years ago
zjx-ERROR 0f23c1c516
解决consul client以IPv6地址格式register consul server health check时报错:[Check socket connection failed ... too many colons in address] (#1790) 3 years ago
包子 9ea78f302d
deps: upgrade kratos version to v2.1.5 (#1785) 3 years ago
guihouchang 1c18228d61
feat: add logger sdk for aliyun (#1748) 3 years ago
gopower ef99b7d1ef
deps[cmd]: Upgrade Cobra 1.2.1 -> v1.3.0 (#1783) 3 years ago
ArthurQ 92e4a83dbf
fix: change consul config docs (#1784) 3 years ago
longxboy a87abe223c
fix: consul heartbeat ttl not registered (#1781) 3 years ago
shengwudiyi c250958af6
fix: perhaps MISSING (#1779) 3 years ago
yangjianfeng9527 f050b07432
fixed the problem that grpc stop could not close properly 3 years ago
haiyux 9bf178b1d1
fix:fix log caller error (#1773) 3 years ago
haiyux 89583885e4
feat:add stream interceptor use ctx encapsulation (#1770) 3 years ago
Tony Chen 0965bf8e22
fix(cmd/kratos): specified version for upgrade (#1772) 3 years ago
realityone 83fad75c0f
make logger appliance as logger proxy (#1765) 3 years ago
haiyux 00c05e82a3
test:remove testify go mod (#1766) 3 years ago
MARATRIX Li c6c5e4595c
optimization: optimize global logger (#1763) 3 years ago
包子 a0006677e9
fix(cmd/kratos): filepath walk nil pointer reference problem (#1762) 3 years ago
realityone 0ed2e0f379
feat(log): add global logger appliance, as process level default logger (#1761) 3 years ago
Heelie d082075676
fix: change installation package path for protoc-gen-openapi (#1759) 3 years ago
kwame 8bb55663d9
zk 作为注册服务,异常端开,zk节点信息没有清理 (#1758) 3 years ago
haiyux cd4aa7f412
feat:sync to gitee where release a version (#1755) 3 years ago
Casper-Mars 76ab0baa56
feat(middleware/auth/jwt): add customer header (#1752) 3 years ago
haiyux 1c3185f9e5
readme:add log third party log library readme (#1753) 3 years ago
haiyux da70e22201
upgrade:upgrade grpc and opentelemetry version (#1751) 3 years ago
包子 7fe194ead4
deps: uprade kratos version to v2.1.4 (#1749) 3 years ago
Windfarer 0bbda71794
sync to gitee (#1746) 3 years ago
haiyux 25774fd3cf
upgrade(examples):upgrade go mod version (#1745) 3 years ago
wangcong 8172f9fff3
fix: k8s client logr incompatible update (#1744) 3 years ago
haiyux 4d3092b7aa
test(errors): add errors test (#1739) 3 years ago
haiyux f38cd9875f
optimization: optimize error (#1740) 3 years ago
letian d2f8b45603
feat(registry/consul): add WithHeartbeat option (#1738) 3 years ago
letian 1e749de5db
fix(registry/consul):fix can't get service instance in async mode (#1731) 3 years ago
letian 17201cd284
fix(registry/consul): fix can not find service in 20s (#1728) 3 years ago
haiyux ed86f36476
feat(examples/):add etcd registry cmux example (#1734) 3 years ago
haiyux 7f003a8742
test(transport): add transport Listener test (#1735) 3 years ago
haiyux 3625634d3c
feat(transport):add grpc and http with listen (#1729) 3 years ago
Jason Song b421389227
fix: remove the use of client timeout as discovery time (#1715) 3 years ago
haiyux d9530ed54b
fix(cmd/kratos): add look protoc-gen-openapi when use kratos proto client (#1726) 3 years ago
Tony Chen 11a6120a2e
fix FieldMask are converted to/from lower-camel naming conventions. (#1724) 3 years ago
Giovanny Gutiérrez b6b95089c4
fix(cmd/protoc-gen-go-http): Fix when replacement rule is not ending (#1721) 3 years ago
aldslvda c1ab0cce3c
fix: fix typo in cmd/protoc-gen-go-http/http.go(is does not -> does not) (#1718) 3 years ago
包子 3642f5d0ba
feat(cmd/kratos): generating API documentation using Gnostic (#1716) 3 years ago
Giovanny Gutiérrez ccb649a201
fix(protoc-gen-go-http): Update http rule when path mappings (#1704) 3 years ago
Xudong Cai e95452276f
fix(cmd): fixed a camel word enum error 3 years ago
包子 0e72cc2dcb
fix(cmd/proto-gen-http-go): remove go.mod replace (#1707) 3 years ago
包子 1117350b9c
deps: update kratos version to 2.1.3 (#1706) 3 years ago
包子 5aeb14d381
feat(transport/grpc): gRPC client discovery supports incoming logger and timeout (#1702) 3 years ago
白玉堂 72f9cc3518
docs: some wrong err msg description 3 years ago
JerryZhou 94d674fd4c
fix(cmd/proto-gen-errors): non nil assertion for error (#1700) 3 years ago
包子 32158bcef2
fix(nacos): call unsubscribe when watching is stopped (#1697) 3 years ago
hshe 7aa9f352f8
fix:internal/host:选择ip未判断ip是否可用&&返回序号最小的ip(#1686) (#1687) 3 years ago
Cluas 03f5ee015c
consul: support WithServiceResolver option (#1693) 3 years ago
haiyux 2e045c3e42
feat: middleware seletor add ctx match (#1652) 3 years ago
Cluas e1e8184768
transport/http: delay pass context.Context (#1684) 3 years ago
Cluas 5df28f4fdc
registry/nacos: reduce twice string copies (#1681) 3 years ago
kiripeng 041ffffb15
fix: map 其桶中只能存储 8 个键值对元素,超过后会储存到溢出桶或者扩容,影响性能,预先声明容量以免影响性能 (#1671) 3 years ago
xiaoxiaodek 413cc77f7d
fix(config): apollo close function: useless infinite loop causes high cpu usage (#1674) 3 years ago
Richard c9e19f1d98
chore: completion command in the comment (#1680) 3 years ago
china小宇 83ebf53b93
fix: circuitbreaker use client context (#1679) 3 years ago
songzhibin97 8c9e70b47b
style: format (#1667) 3 years ago
sxpsxp12 63a7ffae04
fix: fix nacos.Register many endpoint metadata kind error (#1664) 3 years ago
Giovanny Gutiérrez 2471f1d955
fix(grpc): Block the RCP unil a new picker is available (#1660) 3 years ago
leyou240 67161b62eb
feat(registry/nacos): add default kind option (#1650) 3 years ago
longxboy 98fd40bcb4
revert to select filters (#1656) 3 years ago
Wimi Yuan 2acede53f3
feat(app): app info delivery to stop context (#1649) 3 years ago
haiyux 27cfec93d6
optimize:chan bool to chan struct{} (#1648) 3 years ago
haiyux ef3322ec07
fix: remove cmd replace (#1640) 3 years ago
包子 7e0045cd0f
fix: nacos a vulnerable dependency was referenced (#1639) 3 years ago
包子 6b53d7d229
deps: upgrade 2.1.2 (#1638) 3 years ago
wuxingzhong 7d821541b3
fix doc (#1636) 3 years ago
lcsin 3231b35420
Update main.go (#1627) 3 years ago
haiyux 3607ce1b92
feat: upgrade grpc version to 1.42.0 (#1626) 3 years ago
haiyux 05ecd2ce2c
fix:add consul all health check (#1620) 3 years ago
Eng Zer Jun 77b16286f8
refactor: move from io/ioutil to io and os packages (#1633) 3 years ago
Giovanny Gutiérrez 7a52468ea8
fix(cmd/protoc-gen-go-http): follow the http rule to use query strings (#1629) 3 years ago
包子 268243d8a3
fix(cmd/new): print the correct error message (#1630) 3 years ago
李鑫 780a6c0527
docs of etcd config (#1622) 3 years ago
yeqown c392528e11
docs: replenish config/apollo and registry/discovery readme (#1625) 3 years ago
spume 0f423be434
fix(middleware/tracing): modify kartos to kratos (#1628) 3 years ago
Soul 0fad751032
feat(form/form): add support google.protobuf.Struct; (#1617) 3 years ago
thinkgo c70cdc9a11
fix[cmd]: if enum is a word in proto file, it should be camel too. (#1618) 3 years ago
Windfarer a8692e7dde
feat(contrib/config): use key file extension as format & config load log (#1619) 3 years ago
zhaohaiyux fcd9351717
fix:modify annotation and wrong words (#1615) 3 years ago
longxboy 988c2312b4
feat: add base fitler to improve performace (#1612) 3 years ago
wangcong c3d0bb66bb
fix: nacos registry test data race (#1613) 3 years ago
letian 32272fe441
feat(http): http client support service discovery in Do (#1563) 3 years ago
Windfarer 4f013de2ec
test: add nacos test (#1603) 3 years ago
包子 5aac2ef5a7
fix(cmd/http): fixed cannot declare a route with a regular expression (#1608) 3 years ago
longxboy cd79c2a458
feat: add raw node (#1611) 3 years ago
hoolio 9d2719f9f4
make the output of gin example right (#1598) 3 years ago
wangcong cf385f6285
fix: k8s nacos and zookeeper registry lint (#1599) 3 years ago
longxboy f42b1c4dd2
fix: fix p2c test (#1607) 3 years ago
longxboy 037296cdbf
export selector node (#1606) 3 years ago
Evan f9a132c9dd
feat: recovery logger with ctx (#1601) 3 years ago
包子 ce8ed35c1d
fix(cmd/kratos): use context timeout control, add timeout param (#1592) 3 years ago
包子 143dc584cb
feat: add descriptor.proto (#1590) 3 years ago
包子 70f58b264a
fix(app): use new context when app stop (#1589) 3 years ago
Tony Chen b353ab91f1
add pprof handler (#1587) 3 years ago
Xiong Liu ef686a1cc7
feat: Add consul kv config provider (#1499) 3 years ago
包子 806a6b3e13
doc: create CODE_OF_CONDUCT.md (#1585) 3 years ago
包子 5097c3d743
Create CONTRIBUTING.md 3 years ago
Windfarer ea1a0c30ed
chore: update badge (#1582) 3 years ago
海雨 3da927759a
test: add transport http test (#1579) 3 years ago
longxboy 91714bcd34
test: add transport grpc test (#1580) 3 years ago
longxboy ae57ae9bde
test : add selector & balancer test (#1577) 3 years ago
海雨 7cd9503b95
test: add log test (#1576) 3 years ago
Yeqllo eec45a3d0a
fix(config/apollo): apollo namespace (#1516) 3 years ago
海雨 eb0730a1b0
feat: add encodeing test (#1573) 3 years ago
longxboy 52876d3e20
test: add app and transport test (#1572) 3 years ago
海雨 fecfb7dc86
test: arrangement test proto and add test (#1567) 3 years ago
sxpsxp12 63b1764a04
fix: fix log.Helper.WithContext msg key missing (#1571) 3 years ago
海雨 ad7df8d4bc
fix: fix encode form well known message bug (#1568) 3 years ago
leyou240 318cacd04d
feat: add msgpack Codec (#1555) 3 years ago
longXboy 1b7a40c28b change version to v2.1.1 3 years ago
longxboy 86dec76aa3
fix global selector bug (#1564) 3 years ago
longxboy 2d026f1f95
fix: cmd http embed message path generate (#1561) 3 years ago
longxboy 210e414e6f
fix: fix encode proto well known types in form and url query (#1559) 3 years ago
包子 014778b72a
fix(cmd/proto-gen-http): fix the problem that the field declaration does not exist causing panic (#1553) 3 years ago
包子 979ec39c53
deps: update kratos version (#1554) 3 years ago
包子 872d31343a
revert: revert #1544 (#1548) 3 years ago
letian 3d23d295c4
feat(log): default message key (#1545) 3 years ago
storyicon 1e86faea1b
fix(protoc-gen-go-errors): fix the camel case bug of name (#1544) 3 years ago
包子 250bb5c8e7
feat(log/helper): log helper add WithMessageKey option (#1541) 3 years ago
aiscrm 9743ad8d32
fix registry TTL. (#1537) 3 years ago
longxboy 69fc5cca87
feat: add config slice map support (#1538) 3 years ago
Windfarer f3e75bffca
feat: update go version to 1.16 (#1536) 3 years ago
longxboy d0c65fbd75
feat: change to v2.1.0 (#1535) 3 years ago
longxboy 056812e4b2
feat: add http transport interface (#1533) 3 years ago
ONG-YA a99659052a
feat: add backupConfigPath method (#1511) 3 years ago
Tt yo 3b477e7e52
fix: consul lint error (#1530) 3 years ago
Bear 5e88a20cd4
fix: 'tokenInfo' might have 'nil' or bad value (#1534) 3 years ago
倒霉狐狸 0597883e70
fix: contrib config kubernetes lint err (#1523) 3 years ago
海雨 23a96a3d63
feat:add warning when http path filed use map or list (#1526) 3 years ago
Yeqllo a2f53128cf
fix(registry/discovery): watch quit while context cancel; supplement metadata (#1524) 3 years ago
倒霉狐狸 74e630c21a
fix: contrib config nacos lint err (#1522) 3 years ago
longxboy 0aace47d08
fix: fix registry go mod(#1521) 3 years ago
Yeqllo 5786f61e13
feat(registry): support discovery registry center (#1480) 3 years ago
倒霉狐狸 bae20ba735
fix: contrib metrics datadog lint err (#1517) 3 years ago
hotcha 7cc6565d01
fix typo (#1509) 3 years ago
海雨 953deaa363
fix:etcd prifex find error (#1507) 3 years ago
包子 c180cd4ab0
chore: fix readme typo (#1505) 3 years ago
海雨 6f45cb0dfb
feat:edit readme and roadmap (#1504) 3 years ago
longxboy feeec630d7
feat: add selector and filters examples (#1485) 3 years ago
包子 25f448794d
deps: otel upgrade to v1.0.0 (#1500) 3 years ago
404_K aba30889c9
chrone: fix doc error (#1498) 3 years ago
longxboy 3cbe4755ed
fix http resvoler test case (#1496) 3 years ago
seasrain 423b60b330
fix:http server start panic when use Endpoint (#1492) 3 years ago
seasrain 55e00ce9f3
fix:server start panic when use Endpoint (#1491) 3 years ago
SparkLee 09969457e2
fix typo (#1490) 3 years ago
Kagaya 04bc0e63ba
test(middleware/tracing): tracing unit test enhancement (#1484) 3 years ago
letian db2122860d
add endpoint option in grpc server (#1488) 3 years ago
longXboy 039ce62778 remove http client call option:selectFilter 3 years ago
letian 53563ab498
fix error in file test (#1483) 3 years ago
letian 894fc1a058
fix defer leak (#1477) 3 years ago
letian 2ce8f22fac
fix bug of host.Extract (#1481) 3 years ago
seasrain 24ec23f0e4
deps: remove x/net package (#1476) 3 years ago
包子 73bba905b4
typo(examples/blog): change ”make run“ to ”kratos run“ (#1474) 3 years ago
祈緒ちゃん - Kiochan 32c41f47d5
docs: fix typo (#1473) 3 years ago
seasrain 1dd8786ed9
fix:move test proto file to internal (#1471) 3 years ago
letian 754d83ea9d
add test for HandleHeader (#1467) 3 years ago
Tony Chen b92e8a9da8
deps: update otel to v1.0.0-rc3 (#1466) 3 years ago
longxboy 20f0a07d36
Feat: add load balancer (#1437) 3 years ago
Tony Chen 0184d217cf
fix(transport/grpc): default base ctx (#1465) 3 years ago
seasrain 798adbff5e
fix:http rehister url lack / (#1464) 3 years ago
Tony Chen 6e6526efd9
fix: middleware uses sentinel error (#1463) 3 years ago
seasrain 558070f4d9
fix:edit the config's readmes (#1462) 3 years ago
Windfarer 1148bbd968
refactor(contrib/config): move etcd config (#1457) 3 years ago
seasrain 8b1086ad56
fix: optimizate with context (#1460) 3 years ago
letian 4bdafa6393
feat: add http header handler (#1461) 3 years ago
Casper-Mars ab5152dbe1
feat(middleware/auth): add auth middleware (#1274) 3 years ago
Tony Chen aed6af7acc
fix http server handler (#1456) 3 years ago
Kagaya 736fb38e79
fix: examples lint error (#1454) 3 years ago
Tony Chen b38c1145cf
fix(middleware/circuitbreaker): add breaker group (#1453) 3 years ago
Tony Chen 009cf68312
feat: add container group (#1452) 3 years ago
pwli 378d1ee3c7
fix: enhance error.FromError (#1451) 3 years ago
杜晨昊 2024fa7cdb
feat: zap log (#1424) 3 years ago
yuemoxi 6ca81236b6
fix: Fix lint of files in cmd/kratos (#1442) 3 years ago
Casper-Mars f5339e3ea3
fix(cmd/protoc-gen-go-http):part of #1430,fix cmd/protoc-gen-go-http (#1440) 3 years ago
Casper-Mars 73ce2941bd
fix(contrib/registry/etcd):part of #1430,fix contrib/registry/etcd (#1441) 3 years ago
Jack Lee aa5743147c
docs: Use go install when install kratos instead of go get (#1438) 3 years ago
Casper-Mars 2a4d440680
fix(cmd/protoc-gen-go-errors):part of #1430,fix cmd/protoc-gen-go-errors (#1435) 3 years ago
cachalots cd35233d1d
fix: add context for kubernetes registry, implement the registrar interface (#1436) 3 years ago
Kagaya 842be155a3
docs: update pull request template (#1434) 3 years ago
Casper-Mars 3f51a15949
Fix lint of files in ./contrib/log/fluent (#1432) 3 years ago
yuemoxi 8823a1c618
feat:middleware selector add func match (#1329) 3 years ago
Kagaya 29a5327291
ci: submodule ci check (#1401) 3 years ago
包子 fd9d324906
fix(config/apollo): rename func NewSouceWithConfig (#1425) 3 years ago
longxboy 906a9ead4f
fix:reuse parent ctx cause unexpected stop of App (#1429) 3 years ago
letian fa54a1dd3a
feat: Support custom status code conversion from HTTP and gRPC. (#1410) 3 years ago
Tony Chen 1ac50be94c
fix: sra to aegis (#1420) 3 years ago
包子 1517321dd8
chore(examples/event): add memory and rename Message to Event (#1282) 3 years ago
Kagaya de55281108
feat(middleware/ratelimit): add rate limiter middleware (#1271) 3 years ago
Kagaya 47f039792b
feat(middleware/breaker): add circuit breaker middleware (#1299) 3 years ago
杜晨昊 221fa98319
chore: fix metrics readme (#1415) 3 years ago
包子 7b3b1cf862
feat: move nacos config、datadog、 fluent to contrib and modify prom path (#1405) 3 years ago
塔塔开 a78f740bd5
fix change unit to seconds (#1408) 3 years ago
包子 8468cfdd45
feat: add apollo example and some problems of fix apollo config (#1411) 3 years ago
Casper-Mars 515b71ec90
test(transport/http):fix nil problem (#1406) 3 years ago
Windfarer 0ec3ff0b46
refactor: move plugins to contrib dir (#1399) 3 years ago
Kagaya f89e33d719
ci: adjust magic number check (#1402) 3 years ago
yuemoxi a180043076
fix: update config readme (#1396) 3 years ago
Kagaya f7588a47de
fix: ci lint error (#1391) 3 years ago
yuemoxi a1f35ecc05
fix:rename kube to kubernetes (#1393) 3 years ago
包子 112ca9c78a
fix(config/apollo): code style (#1395) 3 years ago
wwwhaoxu df6bbaa091
fix(errors): code error (#1394) 3 years ago
yuemoxi 4536b460f1
feat: move kute to kratos (#1383) 3 years ago
包子 7b6332ee75
deps: middleware add separate go.mod and removes framework deps (#1385) 3 years ago
Kagaya c55528f321
ci: improve golangci static check (#1387) 3 years ago
yuemoxi e3d55b74bd
fix:update registry's readme (#1389) 3 years ago
Joe Zou ee3da3a189
feat: add apollo module for kratos (#1370) 3 years ago
yuemoxi 8a934715c9
fix: edit registry and metrics readme (#1384) 3 years ago
yuemoxi 0dfab173f9
fix:modify encoding test proto path (#1388) 3 years ago
yuemoxi 12f17a3e2e
test(middleware/) add test (#1379) 3 years ago
yuemoxi 10ecd91fe9
feat: move promethues to kratos (#1380) 3 years ago
Kagaya fee1b34973
test(config): add test case for resolver (#1377) 3 years ago
yuemoxi a67ec16bf0
test(internal/context,internal/host) add test (#1334) 3 years ago
包子 925e55a04d
fix(config): replace text with "${}" only (#1375) 3 years ago
包子 eaf0ceab0c
chore(registry): unified management of decentralized warehouses (#1368) 3 years ago
包子 f3b68b0147
chore(issue/template): modify feature template and add proposal template (#1362) 3 years ago
yuemoxi 9b32ad7926
fix: edit kratos version (#1367) 3 years ago
喵喵大人 aa75ac5467
chore: add icon in issues template (#1364) 3 years ago
Harvey Li 050b14c1e0
fix: correct client code in the example of TLS connection (#1355) 3 years ago
aiscrm 0b09fcd76d
refactor(encoding): optimize json encoding (#1339) 3 years ago
longXboy dee204efc2 add version v2.0.5 3 years ago
yuemoxi 9c6f2713e7
optimize: template spaces to tabs (#1352) 3 years ago
Ccheers 807edfce82
fix: 修复swagger 引用errors时找不到proto的错误 (#1348) 3 years ago
包子 817c13a80c
fix: code style (#1342) 3 years ago
Xudong Cai b44e47b087
refactor: optimize the code and use golangci-lint to check for any errors (#1298) 3 years ago
徐胖 3026f9490e
chore(config/env): polish watcher (#1341) 3 years ago
Xudong Cai 80378ca10d
fix: if not kratos context then panic will result (#1338) 3 years ago
包子 3f68c9a9e0
fix(cmd/run): command execution directory error (#1336) 3 years ago
yuemoxi c2b4d45cdf
test(internal/) add test (#1333) 3 years ago
Giovanny Gutiérrez 9a6c03a9e5
fix(config): Support colon as default value in config.yaml (#1332) 3 years ago
yuemoxi 4b6ab21ae5
test(internal/) add test (#1331) 3 years ago
月墨夕 86621a9573
test(internal/context,middleware) add test (#1326) 3 years ago
月墨夕 fdce5f0746
fix:config groutine(watch) leak (#1327) 3 years ago
月墨夕 55cf83062f
add: metadata test (#1324) 3 years ago
Windfarer a128566cef
test(transport) add test (#1325) 3 years ago
longXboy ef6b347d6b change to v2.0.4 3 years ago
haozibi 4e26fada3e
chore: just fix readme_zh.md (#1323) 3 years ago
byteneco 39a36b49e1
append config watchers when watch source (#1320) 3 years ago
月墨夕 6ae2e8712d
fix:etcd<3.13 block question (#1317) 3 years ago
Windfarer 6d06721fc8
fix(config): fix data race (#1316) 3 years ago
月墨夕 9bbf4696d4
upgrade examples mod dependent version (#1314) 3 years ago
longxboy a17eaeeff4
upgrade: grpc to 1.39 (#1312) 3 years ago
寻寻觅觅的Gopher 6e65616e31
fix(config): clean code (#1311) 3 years ago
包子 ff78611766
feat(cmd/pgh): add processing when generating HTTP code (#1306) 3 years ago
月墨夕 e5ae8dc3f1
fix: upgrade etcd version (#1302) 3 years ago
月墨夕 c1b9ace84e
feat: kratos tool support generate stream service code (#1284) 3 years ago
longxboy f65a0a9134
feat: enhance tracing (#1300) 3 years ago
杜晨昊 2fa9168bde
fix example blog makefile (#1296) 3 years ago
longxboy 2e17f18d66
feat: change grpc gateway import path (#1295) 3 years ago
zwhyb 9c470b217a
add appinfo test (#1293) 3 years ago
Windfarer f93084ba9f
test: option tests (#1292) 3 years ago
Yongzheng Lai b68265c365
fix: using t.TempDir (#1289) 3 years ago
zwhyb 5710bf0e30
fix endpoint panic (#1291) 3 years ago
Kagaya 05e14e2a18
ci: add pull request template (#1280) 3 years ago
zwhyb 6aba247990
add selector code annotation (#1275) 3 years ago
Tony Chen bc35f20228
feat(endpoint): add endpoint parser (#1273) 3 years ago
zwhyb 8f4e78b47d
grpc‘s secure discovery (#1270) 3 years ago
opensite a636fd52a4
feat(cmd): support the third party specify by self and fix the warning when third party is not in current directory (#1266) 3 years ago
zwhyb 352d6c8d66
Merge pull request #1269 from CryBecase/main 3 years ago
wz 3279839221
Merge branch 'go-kratos:main' into main 3 years ago
王真 8f55924c47 optimize 3 years ago
王真 4f15df4caf remove useless judgment 3 years ago
Tony Chen 5ca42fe921
feat(transport): add transport tls config (#1267) 3 years ago
wz ce0cba4f41
fix(transport/http): typo (#1268) 3 years ago
王真 b04e214ec8 fix annotation 3 years ago
Tony Chen e7d2f4966a
upgrade kratos to v2.0.3 (#1264) 3 years ago
zwhyb 407250bf6c
create watcher overtime (#1263) 3 years ago
Tony Chen b3594c25d3
update release version (#1262) 3 years ago
Tony Chen 97694b19ad
test: add registry tests (#1260) 3 years ago
longXboy f5e90c90db fix go mod 3 years ago
longxboy cdf95046fd
upgrade consul version (#1261) 3 years ago
Tony Chen 7773d15256
fix(grpc/resolver): fix builder context (#1258) 3 years ago
徐胖 025ae38acc
fix(config/env): fix env.load() index out of range (#1252) 3 years ago
包子 9808ceb7a8
feat(cmd/upgrade): compatible with go get and go install (#1255) 3 years ago
Julian-Chu c7fcd388b5
chore(examples/i18n): typo (#1250) 3 years ago
Tony Chen 623fc5cb3f
update version to v2.1.0-dev (#1249) 3 years ago
Windfarer b6f92ed3d3
add codecov (#1195) 3 years ago
xianmian168 05c44d9033
repair some misspelling (#1248) 3 years ago
zwhyb 7977deac65
middleware/selector (#1244) 3 years ago
Kagaya 3660a8d65d
fix(env): index out panic when env key is preifix (#1247) 3 years ago
喵喵大人 d09ba5e3ee
style: add gosimple linter and gofmt linter (#1242) 3 years ago
Tony Chen f872ec4685
mod: clean cmd mod (#1240) 3 years ago
Tony Chen 77a39d3bb6
mod: upgrade uuid & form (#1239) 3 years ago
Tony Chen cb7fc2d72a
Revert "replace env underscore to dot (#1229)" (#1235) 3 years ago
longxboy dca963a236
fix http resovler bug (#1231) 3 years ago
longxboy 38c9def445
replace env underscore to dot (#1229) 3 years ago
zwhyb d4ac341bc8
http get方法 url 参数带中括号 (#1226) 3 years ago
徐胖 77d2cfb653
chore(config/env): minor refactor (#1232) 3 years ago
Yongzheng Lai 97222012e4
fix: using rv directly (#1213) 3 years ago
包子 b6d005b21e
chore(examples/event): examples of increasing use of event (#1228) 3 years ago
longxboy e1228d454a
support expand config keys (#1224) 3 years ago
包子 1a0a1b8a89
fix(cmd/new): print exception to console (#1227) 3 years ago
Kuiba 0e70bddaa9
fix(config): load env and file source order bug (#1220) 3 years ago
pokitpeng ab45baf5ec
chore: add zookeeper registry example (#1223) 3 years ago
包子 41ad9061db
fix: fixed kratos "new" command #1218 (#1221) 3 years ago
包子 5559923193
feat(cmd/changelog): add chore group (#1217) 3 years ago
longxboy dba4b4007d
update WithDecoder comment 3 years ago
longxboy a02d9b4192
add zero endpoint protection (#1215) 3 years ago
Kuiba 44dd641f28
test config struct (#1212) 3 years ago
Richard ff24e18a94
chore: optimize import sort and the short description of run cmd (#1211) 3 years ago
包子 c2e25ffd11
chore(typo): fixed document errors in README_ZH (#1209) 3 years ago
longXboy f0d077a328 change version to 2.0.1 3 years ago
longxboy 4e529d1e30
add router group for http server (#1208) 3 years ago
longXboy 078ca6bc9b add sub router for http 3 years ago
拉小轰 5d07a94b16
use "and" replace "sub" (#1207) 3 years ago
longXboy 2920c12ead add gin examples 3 years ago
包子 5f678de2cc
fix(transport/http): fixed the problem of getting empty node list (#1206) 3 years ago
longxboy b2ba585b2e
upgrade consul (#1205) 3 years ago
Casper-Mars e8e0f6734a
typo: modify the comments of the proto-gen-go-errors (#1204) 3 years ago
Kuiba 060cb24535
<test> config/file: add tests for file watcher (#1199) 3 years ago
包子 dc0ed5bc42
docs: add wechat official account image to the Chinese document (#1190) 3 years ago
opensite f27047c05b
style(transport): remove duplicate get path code (#1188) 3 years ago
pokitpeng e8c9a361d3
fix(examples/config): fixed spelling mistake (#1186) 3 years ago
Kagaya 7f394d0d0a
feat(env): add config env source (#1181) 3 years ago
miya 21a729bc3a
fix(examples/cors): method misuse (#1184) 3 years ago
喵喵大人 43b3ebb89d
docs: default documents points to the english document (#1180) 3 years ago
喵喵大人 aaecd4a642
Merge pull request #1179 from ymh199478/fixed/parse-float 3 years ago
ymh199478 c2e3a59ebc fix(config): strconv.ParseFloat use correct bitSize 3 years ago
喵喵大人 4780b6e1fd
ci(github action): use golangci-lint to replace the deprecated golint (#1175) 3 years ago
Windfarer a7b1af764f
feat(examples/i18n) add i18n example (#1157) 3 years ago
Kagaya e19730e4b6
feat(config): support Resolver for config variable placeholders (#1135) 3 years ago
喵喵大人 3089419e14
docs: Added a list of acknowledgments that influence on kratos's design. (#1171) 3 years ago
Tt yo 567ff27eff
examples: add echo example (#1162) 3 years ago
包子 ac8c27ff9f
fix(cmd/run): fix the problem of looking for the cmd directory outside the project (#1166) 3 years ago
包子 6e9ce7af22
chore(example/blog): add ent tracing, and print the original SQL (#1163) 3 years ago
longXboy 14d383bc6f add v2.0.0 3 years ago
longxboy 23a7f15541
add form for codec (#1158) 3 years ago
Kagaya 9280af7165
add readValue (#1161) 3 years ago
longXboy 26e94aa2ad add swagger api examples 3 years ago
喵喵大人 02e8bf6bde
docs: optimization the README.md (#1149) 3 years ago
包子 e9969bc655
fix(cmd/run): fixed a problem that did not run correctly on windows (#1153) 3 years ago
包子 1ef817507a
fix(cmd): modify the problem of getting length error of kratos run command array (#1150) 3 years ago
包子 a7a8d5d91a
fix(cmd): fixed a problem where prefix could not be matched in some cases (#1151) 3 years ago
longxboy 6f1640b81d
add url for docs (#1147) 3 years ago
包子 a2bb5de1bc
kratos run command support to find the cmd directory from the parent directory (#1146) 3 years ago
包子 70e3692698
feat(cmd): add kratos run command and clean code (#1145) 3 years ago
包子 f10605fd51
docs: update readme, add conventional commits #1096 (#1143) 3 years ago
Tony Chen 3795eddcf5
fix config decoder (#1142) 3 years ago
Tony Chen 81f96ee74d
fix(http): fix error encoder (#1141) 3 years ago
包子 7755bd36dc
feat(cmd): add kratos changelog command (#1140) 3 years ago
youn c268f98404
add form encoding (#1138) 3 years ago
包子 bdb51d2696
feat(examples): add benchmark example (#1134) 3 years ago
longxboy 798b0e6e7d
upgrade otel to v1 rc1 (#1132) 3 years ago
Kagaya bba6f16017
feat: add int/int32/Stringer support when get atomicValue (#1130) 3 years ago
dachang e45caab322
http stop should use ctx (#1131) 3 years ago
longxboy 7530fadde0
Feat/fix examples (#1129) 3 years ago
包子 6dd3f7f301
fix(cmd): fix kratos proto client, add parameter ./third_party (#1127) 3 years ago
Tony Chen d4d6925cd0
cmd/protoc-gen-go-http: fix http protoc to bind query_string (#1126) 3 years ago
IMTTX 0cdeb6c16b
fix typos (#1128) 3 years ago
longxboy a639340274
add rc7 (#1125) 3 years ago
Kuiba 09be032575
Add logrus example (#1124) 3 years ago
longxboy 545ffd1084
add response header (#1119) 3 years ago
包子 493c11929f
fix(examples): rename config to cfg in blog (#1122) 3 years ago
包子 725d60134c
examples: add examples/middleware (#1121) 3 years ago
Scaat Feng c7c91edeb6
[FIX]the flag name, remove redundant hyphen (#1118) 3 years ago
opensite 01409cfb78
kratos/typs(trace): the world spelling corrects (#1116) 3 years ago
longxboy 87eb5ed5c0
add http ip port support (#1115) 3 years ago
longxboy c8b477d167
add error third party (#1114) 3 years ago
longxboy ec7c2181e2
add source code installing (#1113) 3 years ago
包子 db086d0d0e
fix cmd proto server (#1112) 3 years ago
longxboy 953c91d354
keep balancer nodes (#1110) 3 years ago
包子 8d30b6d489
update examples (#1108) 3 years ago
longxboy 07f9fa3e91
change debug level to -1 (#1105) 3 years ago
Ccheers 95fc17a743
fix kratos cmd proto generate path 3 years ago
包子 9f4c4d9877
Update cmd/upgrade (#1101) 3 years ago
包子 8cf377cf9c
fix cmd proto server (#1098) 3 years ago
opensite 5f41ea0f04
fix(cmd): fix kratos cmd (#1102) 3 years ago
包子 4a6eb3e47f
Fix rename tracing.WithPropagators to tracing.WithPropagator (#1095) 3 years ago
opensite 4236b40c94
feat(cmd): support the validate pb file generate for kratos proto client command (#1094) 3 years ago
包子 6dc8300ee8
add examples/validate (#1093) 3 years ago
longxboy b6fc811744
fix version (#1090) 3 years ago
Tony Chen 59f54b2661
Revert/root ctx v2 (#1088) 3 years ago
包子 b4dd478bc9
update log/readme.md (#1085) 3 years ago
拉小轰 a928622f27
golang syntax log README.md (#1084) 3 years ago
miya b22bc26a02
middleware/tracing: add test (#1083) 3 years ago
Tony Chen 30334dc47c
transport/http: rename route to router (#1082) 3 years ago
Tony Chen 1dab58616b
remove app info (#1081) 3 years ago
Tony Chen e5e7832306
fix cors filter (#1080) 3 years ago
longxboy e278a4cf36
fix protoc http cmd (#1079) 3 years ago
longxboy 4241dc8106
add rc5 (#1078) 3 years ago
包子 7b41acf241
add examples/errors (#1077) 3 years ago
longxboy 8baa2ede4b
add path pattern for http (#1076) 3 years ago
isfk a50bbbd0d5
update kratos version (#1074) 3 years ago
longxboy 25c8e2bd3b
fix wrapper seq (#1073) 3 years ago
longxboy 1e543c2a9e
add website (#1072) 3 years ago
longxboy 3af16d771d
add comment (#1071) 3 years ago
Tony Chen 16b1da04e0
transport/http: fix content type (#1070) 3 years ago
longxboy db02034dd1
fix error decode (#1068) 3 years ago
Windfarer 4e96e08471
config test (#1063) 3 years ago
包子 53522c4098
add log fatal level (#1067) 3 years ago
Tony Chen 51a3a32502
middleware/metadata: add md test (#1064) 3 years ago
longxboy 60b1e593f1
add http transport (#1060) 3 years ago
Tony Chen 7f72b72ddb
fix endpoint extract (#1061) 3 years ago
Tony Chen 6ee0607f03
transport: add transport kind (#1059) 3 years ago
包子 258e911f4f
fix log filter (#1056) 3 years ago
Windfarer 0ff1c6f89a
test http (#1045) 3 years ago
longxboy dc80d0865f
add omitempty (#1054) 3 years ago
包子 864a791e04
Merge pull request #1053 from go-kratos/log-filter 3 years ago
chenzhihui dc476c3b57 fix 3 years ago
chenzhihui b378f993c4 fix 3 years ago
chenzhihui 91a01798f4 fix 3 years ago
chenzhihui f92d4742bb fix 3 years ago
longxboy 68e7f4854c
add range (#1052) 3 years ago
包子 ba2607530d fix log filter 3 years ago
chenzhihui 51725f1912 fix 3 years ago
chenzhihui 0e6c53fda9 fix 3 years ago
chenzhihui 7340fecf27 fix 3 years ago
包子 34d6d7b90e add log filter benchmark 3 years ago
包子 7bebc58381 modify log caller 3 years ago
包子 38673521e4 clean log filter 3 years ago
Tony Chen 8d8cd8c8a8
Middleware/metadata v2 (#1050) 3 years ago
包子 ecb0030d48 update log filter 3 years ago
包子 58c99b2768 clean log filter and update value caller 3 years ago
包子 582a24c0a6 add log filter 3 years ago
Tony Chen 7f2e3becbe
clean metrics (#1049) 3 years ago
Tony Chen 8c26c8c328
examples: add cors example (#1048) 3 years ago
包子 c114f5c96b
fix proto-gen-go-errors bug (#1047) 3 years ago
包子 1d0c958a04
add examples/metrics (#1046) 3 years ago
Tony Chen 40e34b32f1
clean examples (#1041) 3 years ago
Tony Chen 99719dd667
cmd: update cmd version (#1040) 3 years ago
Tony Chen 2729caeecf
http/binding: rename encode url (#1039) 3 years ago
Tony Chen eca0f35cb5
transport/http: add vars to http context (#1037) 3 years ago
Tony Chen 00088f644a
examples: clean examples (#1036) 3 years ago
包子 67c1e4584b
modify cmd/proto-gen-go-errors (#1035) 3 years ago
Tony Chen 1b13abd136
transport/http: add http route (#1029) 3 years ago
Tony Chen 4a257c1a34
Revert "add json test (#1031)" (#1033) 3 years ago
Tony Chen 6ca3c788dd
add json test (#1031) 3 years ago
Tony Chen 828a7c5219
copy errors proto (#1030) 3 years ago
longxboy 736385c8e6
Feat/uni transport (#1028) 3 years ago
包子 5d1228a5d7
fix log caller (#1025) 3 years ago
Tony Chen 05c2e16b9e
fix http rules empty (#1023) 3 years ago
Tony Chen d23a91650a
fix log print (#1021) 3 years ago
Tony Chen 50e3dea2ee
fix errors proto (#1020) 3 years ago
包子 996922fa87
Clean errors (#1019) 3 years ago
包子 7585257f9e
modify proto-gen-go-errors version and func name (#1018) 3 years ago
包子 0834128e57
add protoc-gen-errors (#1017) 3 years ago
miya c551448bbd
error.Code def support http , mw/log&metrics update (#1015) 3 years ago
miya 544e08f729
mw/log: http code 0 (#1010) 3 years ago
Tony Chen 5cbda8ebd7
remove proto names (#1006) 4 years ago
Cluas 49064e7232
encoding: remove reflect on yaml and xml (#1005) 4 years ago
miya 0f011ad688
add test recovery (#1004) 4 years ago
miya 97946ddcbd
add middle/validate test (#1002) 4 years ago
包子 48851a1ffd
add examples/log/zap (#1001) 4 years ago
longXboy 6c70049d2f delete trace 4 years ago
longXboy bf00542cb0 fix loggin middleware 4 years ago
longXboy fd84ed4b52 fix spanid 4 years ago
longXboy c2f077e7f1 add spanid valuer 4 years ago
longXboy 08d4db2c0c add default tracer valuer 4 years ago
longxboy 4860f42637
add ctx for logger (#998) 4 years ago
Tony Chen 5ed0c006a0
clean access logging (#996) 4 years ago
longxboy af14c07762
fix http util (#995) 4 years ago
longxboy 5051609aef
add client closed (#993) 4 years ago
longxboy 7bef6cc7d4
add err gateway timeout (#992) 4 years ago
longxboy bfc79d5ef0
Merge pull request #991 from go-kratos/feat/delete_grpc_recovery 4 years ago
longXboy f90e5874ef delete http recovery 4 years ago
longXboy 864008ea6b delete grpc recovery 4 years ago
Tony Chen 92b6bf54eb
add grpc interceptor option (#990) 4 years ago
Tony Chen 29e387a39c
add grpc interceptor option (#987) 4 years ago
Tony Chen 42b60381c9
transport: clean endpoint listen (#989) 4 years ago
包子 02f9ea49c7
add cmd specify the version or branch #977 (#986) 4 years ago
Cluas c547c61f89
json: uses proto field name instead of lowerCamelCase name (#985) 4 years ago
Tony Chen bef6d8d818
transport/http: clean http client (#981) 4 years ago
Tony Chen 079f11fb50
add endpoint context (#979) 4 years ago
Tony Chen f83438b693
http/health: remove health handler (#978) 4 years ago
Michael Li ad8f12c9fd
remove redundant statements in generated code template for protoc-gen-go-http (#976) 4 years ago
longxboy 930d1f6cf7
get req from ctx (#975) 4 years ago
Richard f51bd97324
chore: format import sort (#973) 4 years ago
longXboy 156146036b fix test 4 years ago
longXboy f69cf59537 fix loopback addr 4 years ago
longxboy e1d6377542
add feat endpoint (#972) 4 years ago
longXboy 493373dc13 fix addr listen bug 4 years ago
longXboy 63191930ed fix server info bug 4 years ago
Tony Chen 149fc0195e
kratos: add application info (#968) 4 years ago
Sycamor 7f835db398
chore: change nil slice to maked slice (#967) 4 years ago
Tony Chen e7ddc1ba1e
Change the default func to public (#966) 4 years ago
Tony Chen 4cb3fd62e3
rename Registry to Endpointer (#964) 4 years ago
Tony Chen 41ea1fbc76
fix data race (#963) 4 years ago
Tony Chen 9b31e6293b
app: fix app ready (#961) 4 years ago
longXboy b32e7d6e70 fix swagger api 4 years ago
Windfarer 839aef1ae2
trace config (#956) 4 years ago
Shuhui Xu ce04916181
transport/http: rename CodecForRequest func (#960) 4 years ago
longXboy cc0214d78b mv balancer 4 years ago
longXboy a24bcdff45 fix nacos 4 years ago
longXboy c61cd27a5f fix go mod 4 years ago
Tony Chen 7dec80ccfd
fix error code and regenerate proto (#954) 4 years ago
longXboy 637af7f4b0 change filename 4 years ago
longxboy 28abad2268
Feat/http resovler (#953) 4 years ago
longxboy c1e5b1c17b
add protojson (#952) 4 years ago
longxboy eb958b2093
add path for rpc stub (#947) 4 years ago
Tony Chen 66412031fd
errors: refactor status code (#948) 4 years ago
Tony Chen cc0221b5ce
errors: add errors coder (#946) 4 years ago
longxboy 9a3a02fc68
add http client rpc stub (#943) 4 years ago
opensite 44c2641da2
example/blog: add the usage example of validate in proto file for blog (#942) 4 years ago
Tony Chen 15d0f22fb7
fix handler options (#941) 4 years ago
包子 e2031dcfe6
remove example/traces/go.mod (#940) 4 years ago
Tony Chen 4d0770a6a2
fix http handler (#939) 4 years ago
Tony Chen b9f821c29f
transport/http: add http handler (#937) 4 years ago
Tony Chen ef6e52d1ba
add multiple middlewares (#936) 4 years ago
webliupeng 248d30f068
fix incorrect return type in service template (#935) 4 years ago
包子 65d8b48f9a
add examples/traces (#932) 4 years ago
dowenliu-xyz aab0d5aa43
fix tracing: call tracer.End() in closure. (#928) 4 years ago
Tony Chen ba5b8d1ee3
api/metadata: clean package (#926) 4 years ago
Tony Chen 5d36b6e67c
kratos: fix: unable to get the correct port when registering the service (#925) 4 years ago
Tony Chen e989bb04e3
add yaml encoder (#924) 4 years ago
Tony Chen 2de0fa330c
remove event interface (#923) 4 years ago
Tony Chen 0dbcaa2443
clean transport (#920) 4 years ago
longxboy 8f8b861f7d
add default propagation for trace (#919) 4 years ago
Tony Chen d78eb3ee4b
log: add level printer (#918) 4 years ago
dowenliu-xyz 24b1ca6bc3
tracing: set tracing status after request. (#911) 4 years ago
Jason C.H e7926b989d
Import direct resovler for grpc client (#913) 4 years ago
包子 6791cd665b
Modify cmd new project terminal output style (#908) 4 years ago
包子 0e4a057027
modify kratos cmd new project (#907) 4 years ago
longXboy 42313e9368 fix api proto import path 4 years ago
longXboy d8edff0b84 fix api metadata 4 years ago
Cluas 7e7bbdbed6
encoding/xml: add xml encode support (#905) 4 years ago
Cluas eb732c4de0
internal/http: optimize support more content_type (#904) 4 years ago
longXboy a83d396b74 fix example build 4 years ago
longXboy 86193a2a5f fix api meta proto path 4 years ago
longxboy 0e0be64cba
add api metadata (#901) 4 years ago
miya dc0f4ed9b8
mw/logging:enhance req.(fmt.Stringer) (#898) 4 years ago
Tony Chen eed0ac7d4a
add layout env (#897) 4 years ago
Tony Chen 2e4bb11f00
remove proto gopath (#896) 4 years ago
Tony Chen eeab979d5f
remove errors generator (#892) 4 years ago
Tony Chen 801f89b6db
log: rename Print to Log (#886) 4 years ago
miya f81f95cbbc
example/blog: enhance ctx (#887) 4 years ago
opensite 83eba7083a
examples/blog:update the trace to be consistent with the official (#888) 4 years ago
Joe 21d9ff2c39
refactor: format new.go (#885) 4 years ago
Tony Chen d85f5e9ae1
encoding/json: fix nil value (#884) 4 years ago
Tzz 18ea3a6a47
Fix: marshalJson error, when values contains map[interface{}]interface{} (#883) 4 years ago
Tony Chen 6919f158cd
api/errors: fix parse error (#881) 4 years ago
Tony Chen 7c6f53132f
api/errors: refactor to grpc statas (#880) 4 years ago
Cluas 8b875e43a5
binding: ignore unexpected field (#879) 4 years ago
包子 f33bd70d75
middleware/logging client add traceid (#878) 4 years ago
opensite 8dc92ef8b4
examples/blog:keep the grpc and http error consistent (#873) 4 years ago
包子 b8d5d709e9
middleware/logging add traceid to the printed log,modify the example code and update the dependent version (#877) 4 years ago
Tony Chen 7c3212c306
transport/http: uses gRPC status to the HTTP error. (#870) 4 years ago
包子 b03c810dce
fix middleware/logging unable to print params (#868) 4 years ago
opensite 4f1d2f056f
feat:add grpc reflection register (#865) 4 years ago
Tony Chen e1c84ece84
refactor errors (#863) 4 years ago
opensite b9e905c1af
transport/grpc: add health check (#861) 4 years ago
Tony Chen 3780f70c91
examples: update mod (#862) 4 years ago
Tony Chen 9806191b7f
errors: Error v2 (#860) 4 years ago
Serhat Şevki Dinçer 5d9b5818f2
simplify codeql configuration (#846) 4 years ago
miya cb68659cff
ws demo (#853) 4 years ago
Windfarer fc539738f1
examples/blog: add cleanup (#845) 4 years ago
伊文龙 46acad3400
Fix README file of the blog example. (#842) 4 years ago
伊文龙 2a47af33c0
Add README file for http & helloworld examples (#839) 4 years ago
Tony Chen e35fd9af6f
http/health: add health checker (#830) 4 years ago
Cluas e93da2468c
cmd: use structured path (#838) 4 years ago
另维64 089cf9d0cb
doc: update readme (#837) 4 years ago
miya e1fe688e0c
examples/registry: nacos (#836) 4 years ago
Cluas b88db2a533
registry: fix typo (#835) 4 years ago
miya c673439d96
resolver/discovery: fix endpoint, scheme don't match grpc (#831) 4 years ago
Tony Chen 0921f0156e Update issue templates 4 years ago
Cluas 2ccf15a048
proto/add: avoid panic when using non-hierarchical path (#829) 4 years ago
Tony Chen 8349b6c69f Update issue templates 4 years ago
Cluas e90e72ebeb
roadmap: update roadmap progress (#828) 4 years ago
Cluas c086eb1147
proto/add: rename to export && remove unnecessary type conversion (#825) 4 years ago
Cluas 35d7b4113f
proto/client: print correct err (#826) 4 years ago
Tony Chen d92c1edc26
fix incorrect conversion between integer types (#824) 4 years ago
Tony Chen a6c985e9c9
Create SECURITY.md 4 years ago
Serhat Şevki Dinçer ac13c0c1f6
Create codeql-analysis.yml (#823) 4 years ago
Tony Chen 1afbf70184
examples: add http examples (#822) 4 years ago
Tony Chen af11512ee3
add protoc args (#821) 4 years ago
Cluas 3636179347
fix: typo and avoid collides with log package name (#819) 4 years ago
Cluas e1b9dd5244
host: optimize isPrivateIP (#817) 4 years ago
包子 afd2a6b19a
Modify the tool version number as beta3 (#813) 4 years ago
包子 35d52295db
Modify the command line tool to specify a custom layout repo when creating a new project (#814) 4 years ago
Tony Chen ae73827c93
Update README_zh.md 4 years ago
Tony Chen 4f502ee285
remove publish async (#811) 4 years ago
Tony Chen a0fe496a91
fix proto options (#804) 4 years ago
Tony Chen 1ee3225155 rename event 4 years ago
Tony Chen 4f9319d1a6
Update README.md 4 years ago
Tony Chen cc4814643c
update roadmap (#794) 4 years ago
Tony Chen dba77a3049
Update FUNDING.yml 4 years ago
Tony Chen 6f2f48eae1
rename pubsub to event (#795) 4 years ago
Tony Chen dc9c808e02
queue: add pubsub abstraction (#792) 4 years ago
Mikado 1b16831cf6
adjust trace middleware and fix blog's trace middleware use case (#791) 4 years ago
Tony Chen db98d59b11
add default round_robin to grpc balancer (#790) 4 years ago
Windfarer 3054c4ba7b
Update README.md 4 years ago
Tony Chen 2eaeda0b17
remove unused (#786) 4 years ago
Tony Chen 311a65367e
update kratos (#785) 4 years ago
Mikado 4e2ae2077d
http: fix encodeError can't write response header (#782) 4 years ago
Tony Chen 8e21de5ea8
update quick start (#784) 4 years ago
Mikado dcd4131d10
middleware: trace middleware change to using OpenTelemetry (#781) 4 years ago
Tony Chen 2b47dc4dfb
fix http templates (#783) 4 years ago
Tony Chen f9522036da
api: update extension index (#775) 4 years ago
Tony Chen a185916df6
cmd: update kratos version (#773) 4 years ago
Tony Chen 32f7322b82
fix nil target (#774) 4 years ago
Tony Chen 0b93bef031
add log verbose (#772) 4 years ago
Tony Chen 5a8acec808
examples: fix dir structure (#768) 4 years ago
Tony Chen 74272546ca
fix json tag (#769) 4 years ago
Tony Chen ee211bfe1b
remove unused options (#767) 4 years ago
Tony Chen 21557b38f6
log: add log context (#766) 4 years ago
Tony Chen e335c1304a
examples: add etcd registry (#762) 4 years ago
Windfarer 5546be9188
fix example (#755) 4 years ago
Tony Chen a4409adf16
fix interface defines (#760) 4 years ago
宗川凉介 b80fdb878e
kratos工具版本号修改 (#759) 4 years ago
Tony Chen 28009889bb
encoding/json: remove proto json (#753) 4 years ago
longxboy f526d6b975
add exmaple consul registry (#754) 4 years ago
Tony Chen 11737f67b2
add pgv proto (#752) 4 years ago
Tony Chen 50af5b2588
add before&after hooks (#751) 4 years ago
libi 26cf7c80ad
fix discovery resolver watch goroutine leak (#750) 4 years ago
Tony Chen 39886e0a0c
docs: README.md (#749) 4 years ago
Tony Chen 98b5903113
examples (#748) 4 years ago
Tony Chen 8722894939
fix registry interface (#747) 4 years ago
Tony Chen f86c91849b
fix lint check (#746) 4 years ago
storyicon 18752bf0ec
set transport.kind to be strongly typed (#728) 4 years ago
邓小川 27dc0d45df
fix resolver (#740) 4 years ago
Tony Chen 330d878aa3
http: fix request context (#745) 4 years ago
Tony Chen 946e9ca814
fix http decode (#742) 4 years ago
LI Tongyu f8eeb9f388
fix(http): fix typo in transport/http (#741) 4 years ago
cacosub7 1f265a1590 more accurate correction on README 4 years ago
chenzhihui b97c3c4160 fix registry option 4 years ago
chenzhihui b103c72192 update kratos 4 years ago
Tony Chen d964ba82bf
init roadmap (#724) 4 years ago
Tony Chen 496edc6fb1
Http/refactor register service (#734) 4 years ago
Windfarer a500fe2f0d
Cmd use GOMODCACHE env (#733) 4 years ago
Tony Chen 204bf7be87
fix protoc check (#732) 4 years ago
longXboy f984dc5c6d rename naming 4 years ago
longxboy 68e857746d
Merge pull request #730 from go-kratos/refactor/naming 4 years ago
longXboy 4444e7a638 fix to discoverer 4 years ago
longXboy 8f064855d9 split naming registry 4 years ago
chenzhihui e10aa8ae75 fix unknown revision 4 years ago
storyicon 0008794b80
display error messages (#727) 4 years ago
Tony Chen 4f778e5fdf
Update README.md 4 years ago
Tony Chen ad5198999b add ENG readme (#725) 4 years ago
Tony Chen 1aa4dee6d8
Update README.md 4 years ago
Tony Chen 7cbb0574b9
add proto client/server (#719) 4 years ago
Windfarer 5b0b39e3df Revert "update workflow" (#723) 4 years ago
Windfarer 38e95d5a50 update workflow 4 years ago
Tony Chen 1fd1332c92
fix middleware errors (#717) 4 years ago
Tanghui Lin ef996c826a
add context for registry (#716) 4 years ago
Tony Chen 18d43d6006
add logger wrapper (#715) 4 years ago
chenzhihui 283313c2a1 Merge branch 'main' of github.com:go-kratos/kratos into main 4 years ago
chenzhihui 1ee7e70939 add request params 4 years ago
realotz db2b8bcba0
repair tracing opentracing.HTTPHeadersCarrier panic (#714) 4 years ago
chenzhihui e25ebc73bc fix client context 4 years ago
Tony Chen 7fb7347671
Update README.md 4 years ago
chenzhihui 2a011cd288 add prefix handle to register other router 4 years ago
chenzhihui c97bfa41d8 Merge branch 'main' of github.com:go-kratos/kratos into main 4 years ago
chenzhihui 01d93ec61a fix bind vars 4 years ago
Tony Chen c75b104b52
Update README.md 4 years ago
Tony Chen 7d56eaa57d
Update README.md 4 years ago
Tony Chen f83c9ad053 Update README.md 4 years ago
chenzhihui 0b8e30313d fix 4 years ago
chenzhihui 9353d98572 Merge branch 'main' of github.com:go-kratos/kratos into main 4 years ago
Windfarer 2a3c35dfca
Update FUNDING.yml 4 years ago
chenzhihui 141db56a54 add opencollective group 4 years ago
chenzhihui 1de3a6607f add metrics options 4 years ago
Tony Chen 6907a9ee61
add metrics middleware (#711) 4 years ago
chenzhihui ad97e72c15 add validator middleware 4 years ago
Tony Chen c7827ff701
fix http middleware (#710) 4 years ago
chenzhihui 4c67fa1235 fix http.Server closed 4 years ago
chenzhihui c089611e5d fix codec nil 4 years ago
Tony Chen f50b731aa3
Develop (#708) 4 years ago
chenzhihui cdcc6e40a5 Merge branch 'main' of github.com:go-kratos/kratos into main 4 years ago
chenzhihui d161702ae6 fix cmd version to v2 4 years ago
Tony Chen c4e4aa5638
Create go.yml 4 years ago
chenzhihui 5928009fa0 add docs related 4 years ago
chenzhihui 3566386a89 init v2 4 years ago
  1. 2
      .github/FUNDING.yml
  2. 26
      .github/ISSUE_TEMPLATE/bug-report.md
  3. 5
      .github/ISSUE_TEMPLATE/config.yml
  4. 54
      .github/ISSUE_TEMPLATE/feature-request.md
  5. 73
      .github/ISSUE_TEMPLATE/proposal.md
  6. 10
      .github/ISSUE_TEMPLATE/question.md
  7. 87
      .github/dependabot.yml
  8. 40
      .github/pull_request_template.md
  9. 33
      .github/semantic.yml
  10. 12
      .github/stable.yml
  11. 22
      .github/workflows/codeql-analysis.yml
  12. 27
      .github/workflows/gitee-sync.yml
  13. 194
      .github/workflows/go.yml
  14. 16
      .github/workflows/issue-translator.yml
  15. 36
      .github/workflows/lint.yml
  16. 55
      .gitignore
  17. 195
      .golangci.yml
  18. 59
      .travis.yml
  19. 128
      CODE_OF_CONDUCT.md
  20. 122
      CONTRIBUTING.md
  21. 2
      LICENSE
  22. 102
      Makefile
  23. 164
      README.md
  24. 149
      README_zh.md
  25. 82
      ROADMAP.md
  26. 19
      SECURITY.md
  27. 1
      api/README.md
  28. 365
      api/metadata/metadata.pb.go
  29. 43
      api/metadata/metadata.proto
  30. 145
      api/metadata/metadata_grpc.pb.go
  31. 109
      api/metadata/metadata_http.pb.go
  32. 206
      api/metadata/server.go
  33. 207
      app.go
  34. 285
      app_test.go
  35. 15
      cmd/kratos/go.mod
  36. 79
      cmd/kratos/go.sum
  37. 28
      cmd/kratos/internal/base/install.go
  38. 24
      cmd/kratos/internal/base/install_compatible.go
  39. 62
      cmd/kratos/internal/base/mod.go
  40. 43
      cmd/kratos/internal/base/mod_test.go
  41. 108
      cmd/kratos/internal/base/path.go
  42. 126
      cmd/kratos/internal/base/repo.go
  43. 51
      cmd/kratos/internal/base/repo_test.go
  44. 58
      cmd/kratos/internal/base/vcs_url.go
  45. 55
      cmd/kratos/internal/base/vcs_url_test.go
  46. 45
      cmd/kratos/internal/change/change.go
  47. 213
      cmd/kratos/internal/change/get.go
  48. 25
      cmd/kratos/internal/change/get_test.go
  49. 67
      cmd/kratos/internal/project/add.go
  50. 64
      cmd/kratos/internal/project/new.go
  51. 149
      cmd/kratos/internal/project/project.go
  52. 29
      cmd/kratos/internal/project/project_linux_test.go
  53. 144
      cmd/kratos/internal/project/project_test.go
  54. 30
      cmd/kratos/internal/project/project_windows_test.go
  55. 78
      cmd/kratos/internal/proto/add/add.go
  56. 38
      cmd/kratos/internal/proto/add/add_test.go
  57. 40
      cmd/kratos/internal/proto/add/proto.go
  58. 52
      cmd/kratos/internal/proto/add/template.go
  59. 130
      cmd/kratos/internal/proto/client/client.go
  60. 22
      cmd/kratos/internal/proto/proto.go
  61. 120
      cmd/kratos/internal/proto/server/server.go
  62. 102
      cmd/kratos/internal/proto/server/server_test.go
  63. 142
      cmd/kratos/internal/proto/server/template.go
  64. 145
      cmd/kratos/internal/run/run.go
  65. 32
      cmd/kratos/internal/upgrade/upgrade.go
  66. 34
      cmd/kratos/main.go
  67. 4
      cmd/kratos/version.go
  68. 135
      cmd/protoc-gen-go-errors/errors.go
  69. 229
      cmd/protoc-gen-go-errors/errors/errors.pb.go
  70. 25
      cmd/protoc-gen-go-errors/errors/errors.proto
  71. 17
      cmd/protoc-gen-go-errors/errorsTemplate.tpl
  72. 62
      cmd/protoc-gen-go-errors/errors_test.go
  73. 8
      cmd/protoc-gen-go-errors/go.mod
  74. 33
      cmd/protoc-gen-go-errors/go.sum
  75. 32
      cmd/protoc-gen-go-errors/main.go
  76. 35
      cmd/protoc-gen-go-errors/template.go
  77. 4
      cmd/protoc-gen-go-errors/version.go
  78. 8
      cmd/protoc-gen-go-http/go.mod
  79. 130
      cmd/protoc-gen-go-http/go.sum
  80. 334
      cmd/protoc-gen-go-http/http.go
  81. 93
      cmd/protoc-gen-go-http/httpTemplate.tpl
  82. 87
      cmd/protoc-gen-go-http/http_test.go
  83. 35
      cmd/protoc-gen-go-http/main.go
  84. 52
      cmd/protoc-gen-go-http/template.go
  85. 4
      cmd/protoc-gen-go-http/version.go
  86. 3
      codecov.yml
  87. 25
      config/README.md
  88. 158
      config/config.go
  89. 184
      config/config_test.go
  90. 67
      config/env/env.go
  91. 429
      config/env/env_test.go
  92. 30
      config/env/watcher.go
  93. 32
      config/env/watcher_test.go
  94. 80
      config/file/file.go
  95. 341
      config/file/file_test.go
  96. 10
      config/file/format.go
  97. 43
      config/file/format_test.go
  98. 68
      config/file/watcher.go
  99. 133
      config/options.go
  100. 228
      config/options_test.go
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,2 @@
open_collective: go-kratos
github: [go-kratos]

@ -0,0 +1,26 @@
---
name: "\U0001F41B Bug Report"
about: Report something that's broken. Please ensure your kratos version is still supported.
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:
#### How to reproduce it (as minimally and precisely as possible):
#### Anything else we need to know?:
#### Environment:
- Kratos version (use `kratos -v`):
- Go version (use `go version`):
- OS (e.g: `cat /etc/os-release`):
- Others:

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Documentation issue
url: https://go-kratos.dev/en/docs/
about: For documentation issues, open a pull request at the go-kratos/go-kratos.dev repository

@ -0,0 +1,54 @@
---
name: "\U0001F4A1 Feature Request"
about: For ideas or feature requests, start a new discussion.
title: "[Feature]"
labels: feature
assignees: ''
---
Please see the FAQ in our main README.md before submitting your issue.
<!--
In order to accurately distinguish that the needs put forward by users are the needs of most users and reasonable needs, solicit community opinions through the process, and the features adopted by the community will be realized as new functions.
In order to make the proposal process as simple as possible, the process includes three stages: feature request - > proposal - > pull-request, where feature, proposal is issue and pull-request is the specific function implementation.
### Feature-request
In order to help the community correctly understand the requirements of the feature, the feature request issue needs to describe the functional requirements and relevant references or documents in detail. And the feature request issue can contain the basic description of the function, which can be used as a reference for the function implementation in the proposal.
### Proposal
Proposal contains the basic implementation methods of functions, such as interface definition, general usage of functions, etc.
### Pull-request
After the function is realized, a merge request will be initiated to associate the proposal issue with the function issue. After the merger is completed, all questions will be closed and the process will end.
### Decision process
When more than five maintainer members agree to implement the feature, a proposal issue will be created for detailed design. The status of the proposal is divided into: under discussion, finalized and abandoned. After reaching the final status, start specific implementation (PR can also be implemented synchronously during the discussion)
### Final decision maker mechanism
If the maintainer team members have major differences on a requirement, the final decision is made by @Terry Mao.
-->
### What problem is the feature used to solve?
<!--
example:
We hope to add event interface to Kratos framework to access middleware such as Kafka and rabbitmq
-->
### Requirements description of the feature
<!--
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:
- [nats](http://xxxxx)
- [kafka](http://xxxxx)
- [rabbitmq](http://xxxxx)
-->

@ -0,0 +1,73 @@
---
name: "\U0001F9F1 Proposal Request"
about: Implementation draft of feature.
title: "[Proposal]"
labels: proposal
assignees: ''
---
Please see the FAQ in our main README.md before submitting your issue.
<!--
In order to accurately distinguish that the needs put forward by users are the needs of most users and reasonable needs, solicit community opinions through the process, and the features adopted by the community will be realized as new functions.
In order to make the proposal process as simple as possible, the process includes three stages: feature request - > proposal - > pull-request, where feature, proposal is issue and pull-request is the specific function implementation.
### Feature-request
In order to help the community correctly understand the requirements of the feature, the feature request issue needs to describe the functional requirements and relevant references or documents in detail. And the feature request issue can contain the basic description of the function, which can be used as a reference for the function implementation in the proposal.
### Proposal
Proposal contains the basic implementation methods of functions, such as interface definition, general usage of functions, etc.
### Pull-request
After the function is realized, a merge request will be initiated to associate the proposal issue with the function issue. After the merger is completed, all questions will be closed and the process will end.
### Decision process
When more than five maintainer members agree to implement the feature, a proposal issue will be created for detailed design. The status of the proposal is divided into: under discussion, finalized and abandoned. After reaching the final status, start specific implementation (PR can also be implemented synchronously during the discussion)
### Final decision maker mechanism
If the maintainer team members have major differences on a requirement, the final decision is made by @Terry Mao.
-->
### Proposal description
<!--
example:
Add event interface for accessing message oriented middleware
-->
### Implementation mode
<!--
```go
example:
type Message interface {
Key() string
Value() []byte
Header() map[string]string
Ack() error
Nack() error
}
type Handler func(context.Context, Message) error
type Event interface {
Send(ctx context.Context, key string, value []byte]) error
Receive(ctx context.Context, handler Handler) error
Close() error
}
````
-->
### Usage demonstration
<!--
example:
```go
msg := kafka.NewMessage("kratos", []byte("hello world"), map[string]string{
"user": "kratos",
"phone": "123456",
})
err := sender.Send(context.Background(), msg)
```
-->

@ -0,0 +1,10 @@
---
name: "\U0001F680 Question"
about: Ask a question about Kratos.
title: "[Question]"
labels: question
assignees: ''
---
Please see the FAQ in our main README.md before submitting your issue.

@ -0,0 +1,87 @@
---
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
directory: "/contrib/config/apollo"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/config/consul"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/config/etcd"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/config/kubernetes"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/config/nacos"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/encoding/msgpack"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/log/aliyun"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/log/zap"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/log/fluent"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/metrics/datadog"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/metrics/prometheus"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/opensergo"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/registry/apollo"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/registry/consul"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/registry/etcd"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/registry/kubernetes"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/registry/nacos"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/registry/zookeeper"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/registry/eureka"
schedule:
interval: "weekly"
- package-ecosystem: "gomod"
directory: "/contrib/registry/polaris"
schedule:
interval: "weekly"

@ -0,0 +1,40 @@
<!--
🎉 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、如果 PR 未完成,您可能需要将其标记为 WIP(Work In Progress)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
-->
#### 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)`.
-->
#### Other special notes for the reviewers:
<!--
* Somethings that need extra attention for the reviewers
* Some additional notes, TODO list, etc.
-->

@ -0,0 +1,33 @@
titleOnly: true
commitOnly: false
titleAndCommits: false
scopes:
- api
- cmd
- config
- contrib
- docs
- encoding
- hack
- internal
- log
- metadata
- metrics
- middleware
- registry
- selector
- third_party
- transport
types:
- deps
- feat
- fix
- docs
- style
- refactor
- perf
- test
- build
- ci
- chore
- revert

@ -0,0 +1,12 @@
daysUntilStale: 30
daysUntilClose: 3
exemptLabels:
- pinned
- security
- bug
staleLabel: wontfix
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

@ -0,0 +1,22 @@
name: "CodeQL"
on:
push:
branches: [ main, v1.0.x ]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: go
- name: CodeQL Analysis
uses: github/codeql-action/analyze@v2

@ -0,0 +1,27 @@
on:
push:
branches:
- main
tags:
- "*"
name: Sync to Gitee
jobs:
run:
name: Run
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: Mirror Github to Gitee
uses: Yikun/hub-mirror-action@v1.2
with:
src: github/go-kratos
dst: gitee/go-kratos
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
dst_token: ${{ secrets.GITEE_TOKEN }}
account_type: org
timeout: 600
debug: true
force_update: true
static_list: "kratos"

@ -2,130 +2,84 @@ name: Go
on: on:
push: push:
branches: [ master ] branches:
- main
pull_request: pull_request:
branches: [ master ] branches:
- main
workflow_dispatch:
jobs: jobs:
build: build:
name: Build on ${{ matrix.os }} - Go${{ matrix.go_version }}
runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
go_version: go: [1.19,1.20.x]
- 1.13 name: build & test
os: runs-on: ubuntu-latest
- ubuntu-latest services:
etcd:
image: gcr.io/etcd-development/etcd:v3.5.0
ports:
- 2379:2379
env:
ETCD_LISTEN_CLIENT_URLS: http://0.0.0.0:2379
ETCD_ADVERTISE_CLIENT_URLS: http://0.0.0.0:2379
consul:
image: consul:1.12.3
ports:
- 8500:8500
nacos:
image: nacos/nacos-server:v2.1.0
env:
MODE: standalone
ports:
- "8848:8848"
- "9848:9848"
polaris:
image: polarismesh/polaris-standalone:latest
ports:
- 8090:8090
- 8091:8091
- 8093:8093
steps: steps:
- uses: actions/checkout@v3
- name: Set up Go ${{ matrix.go_version }} - name: Set up Go
uses: actions/setup-go@v1 uses: actions/setup-go@v4.0.1
with: with:
go-version: ${{ matrix.go_version }} go-version: ${{ matrix.go }}
id: go
- name: Setup Environment
- name: Set up Env run: |
run: | echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Module cache
- name: Check out code into the Go module directory uses: actions/cache@v3
uses: actions/checkout@v2 with:
path: |
- name: Cache dependencies ~/.cache/go-build
uses: actions/cache@v2 ~/go/pkg/mod
with: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
# Cache restore-keys: |
path: ~/go/pkg/mod ${{ runner.os }}-go
# Cache key
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - name: Build
# An ordered list of keys to use for restoring the cache if no cache hit occurred for key run: go build ./...
restore-keys: |
${{ runner.os }}-go- - name: Test
run: make test-coverage
- name: Get dependencies
run: | - name: Upload coverage to Codecov
go get -v -t -d ./... run: bash <(curl -s https://codecov.io/bash)
if [ -f Gopkg.toml ]; then
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh - name: Kratos
dep ensure run: |
fi cd cmd/kratos
go build ./...
- name: Build go test ./...
run: go build ./...
- name: HTTP
- name: Golangci run: |
run: | cd cmd/protoc-gen-go-http
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.33.0 go build ./...
golangci-lint run --out-format=github-actions go test ./...
- name: Test
run: go test ./... -coverprofile=coverage.txt -covermode=atomic
- name: Coverage
run: bash <(curl -s https://codecov.io/bash)
scaffold:
name: Scaffold Test on ${{ matrix.os }} - Go${{ matrix.go_version }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
go_version:
- 1.13
os:
- ubuntu-latest
steps:
- name: Set up Go ${{ matrix.go_version }}
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go_version }}
id: go
- name: Set up Env
run: |
echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Cache dependencies
uses: actions/cache@v2
with:
# Cache
path: ~/go/pkg/mod
# Cache key
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
# An ordered list of keys to use for restoring the cache if no cache hit occurred for key
restore-keys: |
${{ runner.os }}-go-
- name: Get dependencies
run: |
go get -v -t -d ./...
if [ -f Gopkg.toml ]; then
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure
fi
wget https://github.com/google/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_64.zip
unzip protoc-3.11.4-linux-x86_64.zip
chmod +x bin/protoc
sudo mv bin/protoc /usr/local/bin
sudo mv include /usr/local/bin
go get -u github.com/golang/protobuf/protoc-gen-go
go get -u github.com/gogo/protobuf/protoc-gen-gofast
- name: Tool
run: |
go install ./...
mkdir -p $GOPATH/src
cp -R ../kratos $GOPATH/src
cd $GOPATH/src
kratos new kratos-demo
cd kratos-demo
go build ./...

@ -0,0 +1,16 @@
name: 'issue-translator'
on:
issue_comment:
types: [created]
issues:
types: [opened]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: usthe/issues-translate-action@v2.7
with:
IS_MODIFY_TITLE: true
CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
BOT_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}

@ -0,0 +1,36 @@
name: Lint
on:
push:
pull_request:
branches:
- main
workflow_dispatch:
jobs:
resolve-modules:
name: resolve module
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout Repo
uses: actions/checkout@v3
- id: set-matrix
run: ./hack/resolve-modules.sh
lint:
name: lint module
runs-on: ubuntu-latest
needs: resolve-modules
strategy:
matrix: ${{ fromJson(needs.resolve-modules.outputs.matrix) }}
steps:
- uses: actions/checkout@v3
- name: Lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
working-directory: ${{ matrix.workdir }}
skip-pkg-cache: true

55
.gitignore vendored

@ -1,32 +1,39 @@
# idea ignore # Reference https://github.com/github/gitignore/blob/master/Go.gitignore
.idea/ # Binaries for programs and plugins
*.ipr
*.iml
*.iws
.vscode/
# temp ignore
*.log
*.cache
*.diff
*.exe *.exe
*.exe~ *.exe~
*.patch *.dll
*.swp *.dylib
*.tmp
# system ignore # Test binary, built with `go test -c`
.DS_Store *.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
vendor/
# Go workspace file
go.work
go.work.sum
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# OS General
Thumbs.db Thumbs.db
.DS_Store
# project # project
*.cert *.cert
*.key *.key
tool/kratos/kratos *.log
tool/kratos-protoc/kratos-protoc bin/
tool/kratos-gen-bts/kratos-gen-bts
tool/kratos-gen-mc/kratos-gen-mc # Develop tools
tool/kratos/kratos-protoc/kratos-protoc .vscode/
tool/kratos/protobuf/protoc-gen-bm/protoc-gen-bm .idea/
tool/kratos/protobuf/protoc-gen-ecode/protoc-gen-ecode *.swp
tool/kratos/protobuf/protoc-gen-bswagger/protoc-gen-bswagger

@ -1,138 +1,71 @@
# [index] https://github.com/golangci/golangci-lint
# [example] https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml
run: run:
tests: true #是否包含测试文件 timeout: 5m
issues-exit-code: 0 modules-download-mode: readonly
linters-settings:
# govet:
# check-shadowing: true #启用了对同名变量名在函数中被隐藏的警告
gofmt:
simplify: true
goimports:
local-prefixes: "github.com/go-kratos/kratos" # 格式化代码时,本地代码单独块
gocritic:
enabled-tags:
- diagnostic
# - style
# - performance
disabled-checks:
#- wrapperFunc
#- dupImport # https://github.com/go-critic/go-critic/issues/845
- commentedOutCode
- ifElseChain
- elseif
settings: # settings passed to gocritic
captLocal: # must be valid enabled check name
paramsOnly: true
# rangeValCopy:
# sizeThreshold: 32
lll:
line-length: 500
funlen:
lines: 500
statements: 500
gocyclo:
min-complexity: 100
linters: linters:
disable-all: true disable-all: true
fast: false
enable: enable:
# https://golangci-lint.run/usage/configuration/ - bodyclose
- bodyclose # http.resp.body 内存泄露检查 - deadcode
- deadcode # 无用的变量声明检查 - dogsled
- depguard # 自定义依赖包白、黑名单 控制导包 - durationcheck
- dogsled # 空白标识符的赋值检查 默认为2 - errcheck
#- dupl # 重复代码检查 - exportloopref
- errcheck # 未判断的error返回值检查 - govet
- funlen # 接口最大行数检查 - gosimple
#- gochecknoinits # 包中定义init()函数检查 - gofmt
#- goconst # 常量字符串检查 - gofumpt
- gocritic # - goconst
- gocyclo # 代码复杂度检查 - goimports
- gofmt # 优化代码 - gomnd
- goimports # 自动增加和删除包 - gocyclo
- golint # 代码风格检查 - ineffassign
#- gomnd # 参数、赋值、用例、条件、操作和返回语句检查 - lll
- goprintffuncname # - prealloc
- gosec # 源代码安全检查 - revive
- gosimple # 可以优化的代码检查 注:该工具已整合到staticcheck中 - staticcheck
- govet # 代码正确性检查 - structcheck
- ineffassign # 无效赋值检查 - typecheck
- interfacer # 建议接口的使用方式 - unused
- lll # 行最大字符 - varcheck
- misspell # 拼写错误检查 - whitespace
- nakedret # 大于指定函数长度的函数的无约束返回值检查 - wastedassign
- nolintlint # - unconvert
- rowserrcheck # sql.Rows.Err检查
- scopelint # 循环变量引用检查,排除test文件
- staticcheck # 静态检查
- structcheck # 结构体字段的约束条件检查
- stylecheck # 代码风格检查
- typecheck # 类型检查
- unconvert # 类型转换检查
- unparam # 未使用参数检查
#- unused # 未使用变量、函数检查
- varcheck # 报告exported变量和常量
- whitespace # 空行检查
severity: # don't enable:
# Default value is empty string. # - asciicheck
# Set the default severity for issues. If severity rules are defined and the issues # - scopelint
# do not match or no severity is provided to the rule this will be the default # - gochecknoglobals
# severity applied. Severities should match the supported severity names of the # - gocognit
# selected out format. # - godot
# - Code climate: https://docs.codeclimate.com/docs/issues#issue-severity # - godox
# - Checkstyle: https://checkstyle.sourceforge.io/property_types.html#severity # - goerr113
# - Github: https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-error-message # - interfacer
default-severity: error # - maligned
# The default value is false. # - nestif
# If set to true severity-rules regular expressions become case sensitive. # - prealloc
case-sensitive: false # - testpackage
# Default value is empty list. # - stylrcheck
# When a list of severity rules are provided, severity information will be added to lint # - wsl
# issues. Severity rules have the same filtering capability as exclude rules except you
# are allowed to specify one matcher per severity rule.
# Only affects out formats that support setting severity information.
rules:
- linters:
- dupl
- nakedret
- lll
- misspell
- goprintffuncname
- stylecheck
- deadcode
- whitespace
- unparam
- golint
- gosec
- staticcheck
- structcheck
- gocritic
- errcheck
- rowserrcheck
- unconvert
- gosimple
- rowserrcheck
- ineffassign
severity: warning
issues: linters-settings:
# Excluding configuration per-path, per-linter, per-text and per-source govet:
exclude-rules: check-shadowing: true
- path: _test\.go whitespace:
linters: multi-func: true
- gomnd lll:
- gocyclo line-length: 160
- errcheck gomnd:
- dupl # don't include the "operation", "argument" and "assign"
- gosec checks:
- scopelint - case
- interfacer - condition
- govet - return
# https://github.com/go-critic/go-critic/issues/926 goconst:
- linters: ignore-tests: true
- gocritic gocyclo:
text: "unnecessaryDefer:" # recommend 10-20
min-complexity: 50
goimports:
local-prefixes: github.com/go-kratos # Put imports beginning with prefix after 3rd-party packages

@ -1,59 +0,0 @@
language: go
go:
- 1.12.x
- 1.13.x
services:
- docker
# Only clone the most recent commit.
git:
depth: 1
# Force-enable Go modules. This will be unnecessary when Go 1.12 lands.
env:
global:
- GO111MODULE=on
- REGION=sh
- ZONE=sh001
- DEPLOY_ENV=dev
- DISCOVERY_NODES=127.0.0.1:7171
- HTTP_PERF=tcp://0.0.0.0:0
- DOCKER_COMPOSE_VERSION=1.24.1
- ZK_VERSION=3.5.6
before_install:
# docker-compose
- sudo rm /usr/local/bin/docker-compose
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
- chmod +x docker-compose
- sudo mv docker-compose /usr/local/bin
# zookeeper
- wget "http://apache.cs.utah.edu/zookeeper/zookeeper-${ZK_VERSION}/apache-zookeeper-${ZK_VERSION}-bin.tar.gz"
- tar -xvf "apache-zookeeper-${ZK_VERSION}-bin.tar.gz"
- mv apache-zookeeper-${ZK_VERSION}-bin zk
- chmod +x ./zk/bin/zkServer.sh
# Skip the install step. Don't `go get` dependencies. Only build with the code
# in vendor/
install: true
# Anything in before_script that returns a nonzero exit code will flunk the
# build and immediately stop. It's sorta like having set -e enabled in bash.
# Make sure golangci-lint is vendored.
before_script:
- curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $GOPATH/bin
# discovery
- curl -sfL https://raw.githubusercontent.com/bilibili/discovery/master/install.sh | sh -s -- -b $GOPATH/bin
- curl -sfL https://raw.githubusercontent.com/bilibili/discovery/master/cmd/discovery/discovery-example.toml -o $GOPATH/bin/discovery.toml
- nohup bash -c "$GOPATH/bin/discovery -conf $GOPATH/bin/discovery.toml &"
# zookeeper
- sudo ./zk/bin/zkServer.sh start ./zk/conf/zoo_sample.cfg 1> /dev/null
script:
- go build ./...
- go test ./...
after_success:
- golangci-lint run # run a bunch of code checkers/linters in parallel

@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
iammao@vip.qq.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
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
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

@ -0,0 +1,122 @@
The kratos community wants to be helped by a wide range of developers, so you'd like to take a few minutes to read this guide before you mention the problem or pull request.
## Reporting Bug or Fixing Bugs
We use GitHub issues to manage issues. If you want to submit , first make sure you've searched for existing issues, pull requests and read our [FAQ](https://go-kratos.dev/docs/intro/faq).
When submitting a bug report, use the issue template we provide to clearly describe the problems encountered and how to reproduce, and if convenient it is best to provide a minimal reproduce repository.
## 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.
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.
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.
## How to submit code
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
- Write code
- Submit code to the far end branch
- Submit a PR request in github
- Wait for review and merge to the main branch
**Note That when you submit a PR request, you first ensure that the code uses the correct coding specifications and that there are complete test cases, and that the information in the submission of the PR is best associated with the relevant issue to ease the workload of the auditor.**
## Conventional Commits
```
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
> More: [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary)
### type
There are the following types of commit:
#### Main
- **fix**: A bug fix
- **feat**: A new feature
- **deps**: Changes external dependencies
- **break**: Changes has break change
#### Other
- **docs**: Documentation only changes
- **refactor**: A code change that neither fixes a bug nor adds a feature
- **style**: Changes that do not affect the meaning of the code (white-space, formatting, etc)
- **test**: Adding missing tests or correcting existing tests
- **chore** Daily work, examples, etc.
- **ci**: Changes to our CI configuration files and scripts
### scope
The following is the list of supported scopes:
- transport
- examples
- middleware
- config
- cmd
- etc.
### description
The description contains a succinct description of the change
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
### body
The body should include the motivation for the change and contrast this with previous behavior.
### footer
The footer should contain any information about **Breaking Changes** and is also the place to reference GitHub issues that this commit Closes.
### examples
#### Only commit message
```
fix: The log debug level should be -1
```
#### Attention
```
refactor!(transport/http): replacement underlying implementation
```
#### Full commit message
```
fix(log): [BREAKING-CHANGE] unable to meet the requirement of log Library
Explain the reason, purpose, realization method, etc.
Close #777
Doc change on doc/#111
BREAKING CHANGE:
Breaks log.info api, log.log should be used instead
```
## Release
You can use `kratos changelog dev` to generate a change log during.
The following is the list of supported types:
- Breaking Change
- Dependencies
- Bug Fixes
- Others

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2018 bilibili Copyright (c) 2020 go-kratos
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

@ -0,0 +1,102 @@
user := $(shell whoami)
rev := $(shell git rev-parse --short HEAD)
os := $(shell expr substr $(shell uname -s) 1 5)
# GOBIN > GOPATH > INSTALLDIR
# Mac OS X
ifeq ($(shell uname),Darwin)
GOBIN := $(shell echo ${GOBIN} | cut -d':' -f1)
GOPATH := $(shell echo $(GOPATH) | cut -d':' -f1)
endif
# Linux
ifeq ($(os),Linux)
GOBIN := $(shell echo ${GOBIN} | cut -d':' -f1)
GOPATH := $(shell echo $(GOPATH) | cut -d':' -f1)
endif
# Windows
ifeq ($(os),MINGW)
GOBIN := $(subst \,/,$(GOBIN))
GOPATH := $(subst \,/,$(GOPATH))
GOBIN :=/$(shell echo "$(GOBIN)" | cut -d';' -f1 | sed 's/://g')
GOPATH :=/$(shell echo "$(GOPATH)" | cut -d';' -f1 | sed 's/://g')
endif
BIN := ""
TOOLS_SHELL="./hack/tools.sh"
# golangci-lint
LINTER := bin/golangci-lint
# check GOBIN
ifneq ($(GOBIN),)
BIN=$(GOBIN)
else
# check GOPATH
ifneq ($(GOPATH),)
BIN=$(GOPATH)/bin
endif
endif
$(LINTER):
curl -SL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s latest
all:
@cd cmd/kratos && go build && cd - &> /dev/null
@cd cmd/protoc-gen-go-errors && go build && cd - &> /dev/null
@cd cmd/protoc-gen-go-http && go build && cd - &> /dev/null
.PHONY: install
install: all
ifeq ($(user),root)
#root, install for all user
@cp ./cmd/kratos/kratos /usr/bin
@cp ./cmd/protoc-gen-go-errors/protoc-gen-go-errors /usr/bin
@cp ./cmd/protoc-gen-go-http/protoc-gen-go-http /usr/bin
else
#!root, install for current user
$(shell if [ -z '$(BIN)' ]; then read -p "Please select installdir: " REPLY; mkdir -p $${REPLY};\
cp ./cmd/kratos/kratos $${REPLY}/;cp ./cmd/protoc-gen-go-errors/protoc-gen-go-errors $${REPLY}/;cp ./cmd/protoc-gen-go-http/protoc-gen-go-http $${REPLY}/;else mkdir -p '$(BIN)';\
cp ./cmd/kratos/kratos '$(BIN)';cp ./cmd/protoc-gen-go-errors/protoc-gen-go-errors '$(BIN)';cp ./cmd/protoc-gen-go-http/protoc-gen-go-http '$(BIN)'; fi)
endif
@which protoc-gen-go &> /dev/null || go get google.golang.org/protobuf/cmd/protoc-gen-go
@which protoc-gen-go-grpc &> /dev/null || go get google.golang.org/grpc/cmd/protoc-gen-go-grpc
@which protoc-gen-validate &> /dev/null || go get github.com/envoyproxy/protoc-gen-validate
@echo "install finished"
.PHONY: uninstall
uninstall:
$(shell for i in `which -a kratos | grep -v '/usr/bin/kratos' 2>/dev/null | sort | uniq`; do read -p "Press to remove $${i} (y/n): " REPLY; if [ $${REPLY} = "y" ]; then rm -f $${i}; fi; done)
$(shell for i in `which -a protoc-gen-go-grpc | grep -v '/usr/bin/protoc-gen-go-errors' 2>/dev/null | sort | uniq`; do read -p "Press to remove $${i} (y/n): " REPLY; if [ $${REPLY} = "y" ]; then rm -f $${i}; fi; done)
$(shell for i in `which -a protoc-gen-validate | grep -v '/usr/bin/protoc-gen-go-errors' 2>/dev/null | sort | uniq`; do read -p "Press to remove $${i} (y/n): " REPLY; if [ $${REPLY} = "y" ]; then rm -f $${i}; fi; done)
@echo "uninstall finished"
.PHONY: clean
clean:
@${TOOLS_SHELL} tidy
@echo "clean finished"
.PHONY: fix
fix: $(LINTER)
@${TOOLS_SHELL} fix
@echo "lint fix finished"
.PHONY: test
test:
@${TOOLS_SHELL} test
@echo "go test finished"
.PHONY: test-coverage
test-coverage:
@${TOOLS_SHELL} test_coverage
@echo "go test with coverage finished"
.PHONY: lint
lint: $(LINTER)
@${TOOLS_SHELL} lint
@echo "lint check finished"
.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

@ -1,76 +1,114 @@
![kratos](docs/img/kratos3.png) <p align="center"><a href="https://go-kratos.dev/" target="_blank"><img src="https://github.com/go-kratos/kratos/blob/main/docs/images/kratos-large.png?raw=true"></a></p>
[![Language](https://img.shields.io/badge/Language-Go-blue.svg)](https://golang.org/) <p align="center">
[![Build Status](https://github.com/go-kratos/kratos/workflows/Go/badge.svg)](https://github.com/go-kratos/kratos/actions) <a href="https://github.com/go-kratos/kratos/actions"><img src="https://github.com/go-kratos/kratos/workflows/Go/badge.svg" alt="Build Status"></a>
[![GoDoc](https://godoc.org/github.com/go-kratos/kratos?status.svg)](https://godoc.org/github.com/go-kratos/kratos) <a href="https://pkg.go.dev/github.com/go-kratos/kratos/v2"><img src="https://pkg.go.dev/badge/github.com/go-kratos/kratos/v2" alt="GoDoc"></a>
[![Go Report Card](https://goreportcard.com/badge/github.com/go-kratos/kratos)](https://goreportcard.com/report/github.com/go-kratos/kratos) <a href="https://codecov.io/gh/go-kratos/kratos"><img src="https://codecov.io/gh/go-kratos/kratos/master/graph/badge.svg" alt="codeCov"></a>
[![Discord](https://img.shields.io/discord/766619759214854164?label=chat&logo=discord)](https://discord.gg/BWzJsUJ) <a href="https://goreportcard.com/report/github.com/go-kratos/kratos"><img src="https://goreportcard.com/badge/github.com/go-kratos/kratos" alt="Go Report Card"></a>
<a href="https://github.com/go-kratos/kratos/blob/main/LICENSE"><img src="https://img.shields.io/github/license/go-kratos/kratos" alt="License"></a>
# Kratos <a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg" alt="Awesome Go"></a>
<a href="https://discord.gg/BWzJsUJ"><img src="https://img.shields.io/discord/766619759214854164?label=chat&logo=discord" alt="Discord"></a>
Kratos是[bilibili](https://www.bilibili.com)开源的一套Go微服务框架,包含大量微服务相关框架及工具。 </p>
<p align="center">
> 名字来源于:《战神》游戏以希腊神话为背景,讲述由凡人成为战神的奎托斯(Kratos)成为战神并展开弑神屠杀的冒险历程。 <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>
## Goals
##### Translate to: [简体中文](README_zh.md)
我们致力于提供完整的微服务研发体验,整合相关框架及工具后,微服务治理相关部分可对整体业务开发周期无感,从而更加聚焦于业务交付。对每位开发者而言,整套Kratos框架也是不错的学习仓库,可以了解和参考到[bilibili](https://www.bilibili.com)在微服务方面的技术积累和经验。
## About Kratos
## Features
* HTTP Blademaster:核心基于[gin](https://github.com/gin-gonic/gin)进行模块化设计,简单易用、核心足够轻量; > 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.
* GRPC Warden:基于官方gRPC开发,集成[discovery](https://github.com/bilibili/discovery)服务发现,并融合P2C负载均衡;
* Cache:优雅的接口化设计,非常方便的缓存序列化,推荐结合代理模式[overlord](https://github.com/bilibili/overlord); 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:
* Database:集成MySQL/HBase/TiDB,添加熔断保护和统计支持,可快速发现数据层压力;
* Config:方便易用的[paladin sdk](https://go-kratos.github.io/kratos/#/config),可配合远程配置中心,实现配置版本管理和更新; - The [communication protocol](https://go-kratos.dev/en/docs/component/api) is based on the HTTP/gRPC through the definition of Protobuf.
* Log:类似[zap](https://github.com/uber-go/zap)的field实现高性能日志库,并结合log-agent实现远程日志管理; - Abstract [transport](https://go-kratos.dev/en/docs/component/transport/overview) layer support: [HTTP](https://go-kratos.dev/en/docs/component/transport/http) / [gRPC](https://go-kratos.dev/en/docs/component/transport/grpc).
* Trace:基于opentracing,集成了全链路trace支持(gRPC/HTTP/MySQL/Redis/Memcached); - Powerful [middleware](https://go-kratos.dev/en/docs/component/middleware/overview) design, support: [Tracing (OpenTelemetry)](https://go-kratos.dev/en/docs/component/middleware/tracing), [Metrics (Prometheus is default)](https://go-kratos.dev/en/docs/component/middleware/metrics), [Recovery](https://go-kratos.dev/en/docs/component/middleware/recovery) and more.
* Kratos Tool:工具链,可快速生成标准项目,或者通过Protobuf生成代码,非常便捷使用gRPC、HTTP、swagger文档; - [Registry](https://go-kratos.dev/en/docs/component/registry) interface able to be connected with various other centralized registries through plug-ins.
- The [standard log interfaces](https://go-kratos.dev/en/docs/component/log) ease the integration of the third-party log libs with logs collected through the *Fluentd*.
## Quick start - Automatically support the selection of the content [encoding](https://go-kratos.dev/en/docs/component/encoding) with Accept and Content-Type.
- Multiple data sources are supported for [configurations](https://go-kratos.dev/en/docs/component/config) and dynamic configurations (use atomic operations).
### Requirments - In the protocol of HTTP/gRPC, use the uniform [metadata](https://go-kratos.dev/en/docs/component/metadata) transfer method.
- You can define [errors](https://go-kratos.dev/en/docs/component/errors/) in protos and generate enums with protoc-gen-go.
Go version>=1.13 - You can define [verification rules](https://go-kratos.dev/en/docs/component/middleware/validate) in Protobuf supported by the HTTP/gRPC service.
- [Swagger API](https://go-kratos.dev/en/docs/guide/openapi) is generated Automatically and embed Swagger UI endpoint can be started by adding [Swagger plugin](https://github.com/go-kratos/swagger-api).
### Installation
Kratos is accessible, powerful, and provides tools required for large, robust applications.
## Learning Kratos
Kratos has the most extensive and thorough [documentation](https://go-kratos.dev/en/docs/getting-started/start) and [example](https://github.com/go-kratos/examples) library of all modern web application frameworks, making it a breeze to get started with the framework.
We also provide a [modern template](https://github.com/go-kratos/kratos-layout). This template should help reduce the work required to setup up modern projects.
### Goals
Kratos boosts your productivity. With the integration of excellent resources and further support, programmers can get rid of most issues might encounter in the field of distributed systems and software engineering such that they are allowed to focus on the release of businesses only. Additionally, for each programmer, Kratos is also an ideal one learning warehouse for many aspects of microservices to enrich their experiences and skills.
### Principles
* **Simple**: Appropriate design with plain and easy code.
* **General**: Cover the various utilities for business development.
* **Highly efficient**: Speeding up the efficiency of businesses upgrading.
* **Stable**: The base libs validated in the production environment have the characteristics of high testability, high coverage as well as high security and reliability.
* **Robust**: Eliminating misusing through high quality of the base libs.
* **High-performance**: Optimal performance excluding the optimization of hacking in case of *unsafe*. 
* **Expandability**: Properly designed interfaces where you can expand utilities such as base libs to meet your further requirements.
* **Fault-tolerance**: Designed against failure, enhance the understanding and exercising of SRE within Kratos to achieve more robustness.
* **Toolchain**: Includes an extensive toolchain, such as the code generation of cache, the lint tool, and so forth.
## Getting Started
Create a kratos playground through [docker](https://www.docker.com/products/docker-desktop):
```shell ```shell
# Linux/macOS docker run -it --rm -p 8000:8000 --workdir /workspace golang
GO111MODULE=on && go get -u github.com/go-kratos/kratos/tool/kratos ```
# Windows (Powershell) ```shell
go env -w GO111MODULE=on ; go get -u github.com/go-kratos/kratos/tool/kratos apt-get update && apt-get -y install protobuf-compiler
export GOPROXY=https://goproxy.io,direct
# Windows (CMD) go install github.com/go-kratos/kratos/cmd/kratos/v2@latest && kratos upgrade
go env -w GO111MODULE=on && go get -u github.com/go-kratos/kratos/tool/kratos ```
cd $GOPATH/src ```shell
kratos new kratos-demo 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!
通过 `kratos new` 会快速生成基于kratos库的脚手架代码,如生成 [kratos-demo](https://github.com/bilibili/kratos-demo) If you need more, please visit the kratos [documentation](https://go-kratos.dev/en/docs/getting-started/start).
### Build & Run ## Security Vulnerabilities
```shell If you discover a security vulnerability within Kratos, please send an e-mail to tonybase via go-kratos@googlegroups.com. All security vulnerabilities will be promptly addressed.
cd kratos-demo/cmd
go build
./cmd -conf ../configs
```
打开浏览器访问:[http://localhost:8000/kratos-demo/start](http://localhost:8000/kratos-demo/start),你会看到输出了`Golang 大法好 !!!` ## Community
[快速开始](https://go-kratos.github.io/kratos/#/quickstart) [kratos工具](https://go-kratos.github.io/kratos/#/kratos-tool) - [Wechat Group](https://github.com/go-kratos/kratos/issues/682)
- [Discord Group](https://discord.gg/BWzJsUJ)
- [go-kratos.dev](https://go-kratos.dev/en)
## Documentation ## Contributors
> [简体中文](https://go-kratos.github.io/kratos) Thank you for considering contributing to the Kratos framework! The contribution guide can be found in the [Kratos documentation](https://go-kratos.dev/en/docs/community/contribution).
> [简体中文(国内镜像)](https://go-kratos.gitee.io/kratos/)
> [FAQ](https://go-kratos.github.io/kratos/#/FAQ)
## 社区 <a href="https://github.com/go-kratos/kratos/graphs/contributors">
* [官方微信群](https://github.com/go-kratos/kratos/issues/682) (推荐) <img src="https://contrib.rocks/image?repo=go-kratos/kratos" />
* [Discord Group](https://discord.gg/BWzJsUJ) </a>
## License ## License
Kratos is under the MIT license. See the [LICENSE](./LICENSE) file for details.
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.
- [zeromicro/go-zero](https://github.com/zeromicro/go-zero) is a web and rpc framework with lots of builtin engineering practices.
- [beego/beego](https://github.com/beego/beego) is a web framework including RESTful APIs, web apps and backend services.

@ -0,0 +1,149 @@
<p align="center"><a href="https://go-kratos.dev/" target="_blank"><img src="https://github.com/go-kratos/kratos/blob/main/docs/images/kratos-large.png?raw=true"></a></p>
<p align="center">
<a href="https://github.com/go-kratos/kratos/actions"><img src="https://github.com/go-kratos/kratos/workflows/Go/badge.svg" alt="Build Status"></a>
<a href="https://pkg.go.dev/github.com/go-kratos/kratos/v2"><img src="https://pkg.go.dev/badge/github.com/go-kratos/kratos/v2" alt="GoDoc"></a>
<a href="https://codecov.io/gh/go-kratos/kratos"><img src="https://codecov.io/gh/go-kratos/kratos/master/graph/badge.svg" alt="codeCov"></a>
<a href="https://goreportcard.com/report/github.com/go-kratos/kratos"><img src="https://goreportcard.com/badge/github.com/go-kratos/kratos" alt="Go Report Card"></a>
<a href="https://github.com/go-kratos/kratos/blob/main/LICENSE"><img src="https://img.shields.io/github/license/go-kratos/kratos" alt="License"></a>
<a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg" alt="Awesome Go"></a>
<a href="https://discord.gg/BWzJsUJ"><img src="https://img.shields.io/discord/766619759214854164?label=chat&logo=discord" alt="Discord"></a>
</p>
<p align="center">
<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>
Translations: [English](README.md) | [简体中文](README_zh.md)
# Kratos
Kratos 一套轻量级 Go 微服务框架,包含大量微服务相关功能及工具。
> 名字来源于:《战神》游戏以希腊神话为背景,讲述奎托斯(Kratos)由凡人成为战神并展开弑神屠杀的冒险经历。
## Goals
我们致力于提供完整的微服务研发体验,整合相关框架及工具后,微服务治理相关部分可对整体业务开发周期无感,从而更加聚焦于业务交付。对每位开发者而言,整套 Kratos 框架也是不错的学习仓库,可以了解和参考到微服务方面的技术积累和经验。
### Principles
* 简单:不过度设计,代码平实简单;
* 通用:通用业务开发所需要的基础库的功能;
* 高效:提高业务迭代的效率;
* 稳定:基础库可测试性高,覆盖率高,有线上实践安全可靠;
* 健壮:通过良好的基础库设计,减少错用;
* 高性能:性能高,但不特定为了性能做 hack 优化,引入 unsafe ;
* 扩展性:良好的接口设计,来扩展实现,或者通过新增基础库目录来扩展功能;
* 容错性:为失败设计,大量引入对 SRE 的理解,鲁棒性高;
* 工具链:包含大量工具链,比如 cache 代码生成,lint 工具等等;
## Features
* [APIs](https://go-kratos.dev/docs/component/api) :协议通信以 HTTP/gRPC 为基础,通过 Protobuf 进行定义;
* [Errors](https://go-kratos.dev/docs/component/errors/) :通过 Protobuf 的 Enum 作为错误码定义,以及工具生成判定接口;
* [Metadata](https://go-kratos.dev/docs/component/metadata) :在协议通信 HTTP/gRPC 中,通过 Middleware 规范化服务元信息传递;
* [Config](https://go-kratos.dev/docs/component/config) :支持多数据源方式,进行配置合并铺平,通过 Atomic 方式支持动态配置;
* [Logger](https://go-kratos.dev/docs/component/log) :标准日志接口,可方便集成三方 log 库,并可通过 fluentd 收集日志;
* [Metrics](https://go-kratos.dev/docs/component/middleware/metrics) :统一指标接口,可以实现各种指标系统,默认集成 Prometheus;
* [Tracing](https://go-kratos.dev/docs/component/middleware/tracing) :遵循 OpenTelemetry 规范定义,以实现微服务链路追踪;
* [Encoding](https://go-kratos.dev/docs/component/encoding) :支持 Accept 和 Content-Type 进行自动选择内容编码;
* [Transport](https://go-kratos.dev/docs/component/transport/overview) :通用的 [HTTP](https://go-kratos.dev/docs/component/transport/http) /[gRPC](https://go-kratos.dev/docs/component/transport/grpc) 传输层,实现统一的 [Middleware](https://go-kratos.dev/docs/component/middleware/overview) 插件支持;
* [Registry](https://go-kratos.dev/docs/component/registry) :实现统一注册中心接口,可插件化对接各种注册中心;
* [Validation](https://go-kratos.dev/docs/component/middleware/validate): 通过Protobuf统一定义校验规则,并同时适用于HTTP/gRPC服务.
* [SwaggerAPI](https://go-kratos.dev/docs/guide/openapi): 通过集成第三方[Swagger插件](https://github.com/go-kratos/swagger-api) 能够自动生成Swagger API json并启动一个内置的Swagger UI服务.
## Getting Started
### Required
- [go](https://golang.org/dl/)
- [protoc](https://github.com/protocolbuffers/protobuf)
- [protoc-gen-go](https://github.com/protocolbuffers/protobuf-go)
### Installing
##### go install 安装:
```
go install github.com/go-kratos/kratos/cmd/kratos/v2@latest
kratos upgrade
```
##### 源码编译安装:
```
git clone https://github.com/go-kratos/kratos
cd kratos
make install
```
### Create a service
```
# 创建项目模板
kratos new helloworld
cd helloworld
# 拉取项目依赖
go mod download
# 生成proto模板
kratos proto add api/helloworld/helloworld.proto
# 生成proto源码
kratos proto client api/helloworld/helloworld.proto
# 生成server模板
kratos proto server api/helloworld/helloworld.proto -t internal/service
# 生成所有proto源码、wire等等
go generate ./...
# 运行程序
kratos run
```
### Kratos Boot
```
import "github.com/go-kratos/kratos/v2"
import "github.com/go-kratos/kratos/v2/transport/grpc"
import "github.com/go-kratos/kratos/v2/transport/http"
httpSrv := http.NewServer(http.Address(":8000"))
grpcSrv := grpc.NewServer(grpc.Address(":9000"))
app := kratos.New(
kratos.Name("kratos"),
kratos.Version("latest"),
kratos.Server(httpSrv, grpcSrv),
)
app.Run()
```
## Related
* [Docs](https://go-kratos.dev/)
* [Examples](https://github.com/go-kratos/examples)
* [Service Layout](https://github.com/go-kratos/kratos-layout)
## Community
* [Wechat Group](https://github.com/go-kratos/kratos/issues/682)
* [Discord Group](https://discord.gg/BWzJsUJ)
* Website: [go-kratos.dev](https://go-kratos.dev)
* QQ Group: 716486124
## WeChat Official Account
![kratos](docs/images/wechat.png)
## Conventional commits
提交信息的结构应该如下所示:
```text
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
提交信息应按照下面的格式:
- fix: simply describe the problem that has been fixed
- feat(log): simple describe of new features
- deps(examples): simple describe the change of the dependency
- break(http): simple describe the reasons for breaking change
## Sponsors and Backers
![kratos](docs/images/alipay.png)
## License
Kratos is MIT licensed. See the [LICENSE](./LICENSE) file for details.

@ -0,0 +1,82 @@
# Kratos
This document defines the roadmap for Kratos development.
## Features
- [x] Config
- [x] Local Files
- [x] K8s ConfigMap
- [x] Consul
- [x] Etcd
- [x] Nacos
- [x] Registry
- [x] Consul
- [x] Etcd
- [x] K8s
- [x] Nacos
- [x] Encoding
- [x] JSON
- [x] Protobuf
- [x] Transport
- [x] HTTP
- [x] gRPC
- [x] Middleware
- [x] Logging
- [x] metrics
- [x] recovery
- [x] gRPC status
- [x] transport tracing
- [x] Validator
- [x] Authentication
- [x] Ratelimit
- [x] CircuitBreaker
- [x] Metrics
- [x] Prometheus
- [x] DataDog
- [x] Tracing
- [x] HTTP
- [x] TLS
- [x] Client
- [x] Service Registrar
- [ ] javascript/typescript clients
- [x] gRPC
- [x] TLS
- [x] Uarry Handler
- [x] Streaming Handler
- [ ] Cache
- [ ] go-redis
- [x] Event
- [x] Pub/Sub
- [x] Kafka
- [ ] Nats
- [x] Database
- [x] Ent
- [ ] Gorm
## Platform
- [ ] Kratos API
- [ ] Auth
- [ ] Config
- [ ] Registry
- [ ] Events
- [ ] Kratos Runtime
- [ ] Secrets
- [ ] Service-to-Service
- [ ] Publish and Subscribe
- [ ] Observability
- [ ] Controllable
- [ ] Kratos UI
- [ ] Auth
- [ ] Config
- [ ] Services
- [ ] Endpoints
- [ ] Ratelimit
- [ ] CircuitBreaker
- [ ] FaultInjection
- [ ] TrafficPolicy
## Tools
- [x] Kratos
- [x] HTTP Generator
- [ ] API YAML
- [x] Errors Generator

@ -0,0 +1,19 @@
# Security Policy
## Supported Versions
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: |
## Reporting a Vulnerability
Use this section to tell people how to report a vulnerability.
Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.

@ -0,0 +1 @@
# API proto

@ -0,0 +1,365 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.0
// protoc v3.19.4
// source: metadata/metadata.proto
package metadata
import (
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
descriptorpb "google.golang.org/protobuf/types/descriptorpb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ListServicesRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *ListServicesRequest) Reset() {
*x = ListServicesRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_metadata_metadata_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ListServicesRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListServicesRequest) ProtoMessage() {}
func (x *ListServicesRequest) ProtoReflect() protoreflect.Message {
mi := &file_metadata_metadata_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListServicesRequest.ProtoReflect.Descriptor instead.
func (*ListServicesRequest) Descriptor() ([]byte, []int) {
return file_metadata_metadata_proto_rawDescGZIP(), []int{0}
}
type ListServicesReply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Services []string `protobuf:"bytes,1,rep,name=services,proto3" json:"services,omitempty"`
Methods []string `protobuf:"bytes,2,rep,name=methods,proto3" json:"methods,omitempty"`
}
func (x *ListServicesReply) Reset() {
*x = ListServicesReply{}
if protoimpl.UnsafeEnabled {
mi := &file_metadata_metadata_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ListServicesReply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListServicesReply) ProtoMessage() {}
func (x *ListServicesReply) ProtoReflect() protoreflect.Message {
mi := &file_metadata_metadata_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListServicesReply.ProtoReflect.Descriptor instead.
func (*ListServicesReply) Descriptor() ([]byte, []int) {
return file_metadata_metadata_proto_rawDescGZIP(), []int{1}
}
func (x *ListServicesReply) GetServices() []string {
if x != nil {
return x.Services
}
return nil
}
func (x *ListServicesReply) GetMethods() []string {
if x != nil {
return x.Methods
}
return nil
}
type GetServiceDescRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
}
func (x *GetServiceDescRequest) Reset() {
*x = GetServiceDescRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_metadata_metadata_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetServiceDescRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetServiceDescRequest) ProtoMessage() {}
func (x *GetServiceDescRequest) ProtoReflect() protoreflect.Message {
mi := &file_metadata_metadata_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetServiceDescRequest.ProtoReflect.Descriptor instead.
func (*GetServiceDescRequest) Descriptor() ([]byte, []int) {
return file_metadata_metadata_proto_rawDescGZIP(), []int{2}
}
func (x *GetServiceDescRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
type GetServiceDescReply struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
FileDescSet *descriptorpb.FileDescriptorSet `protobuf:"bytes,1,opt,name=file_desc_set,json=fileDescSet,proto3" json:"file_desc_set,omitempty"`
}
func (x *GetServiceDescReply) Reset() {
*x = GetServiceDescReply{}
if protoimpl.UnsafeEnabled {
mi := &file_metadata_metadata_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetServiceDescReply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetServiceDescReply) ProtoMessage() {}
func (x *GetServiceDescReply) ProtoReflect() protoreflect.Message {
mi := &file_metadata_metadata_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetServiceDescReply.ProtoReflect.Descriptor instead.
func (*GetServiceDescReply) Descriptor() ([]byte, []int) {
return file_metadata_metadata_proto_rawDescGZIP(), []int{3}
}
func (x *GetServiceDescReply) GetFileDescSet() *descriptorpb.FileDescriptorSet {
if x != nil {
return x.FileDescSet
}
return nil
}
var File_metadata_metadata_proto protoreflect.FileDescriptor
var file_metadata_metadata_proto_rawDesc = []byte{
0x0a, 0x17, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x6b, 0x72, 0x61, 0x74, 0x6f,
0x73, 0x2e, 0x61, 0x70, 0x69, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f,
0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x49, 0x0a, 0x11,
0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c,
0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20,
0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x18, 0x0a,
0x07, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07,
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x22, 0x2b, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5d, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x46, 0x0a, 0x0d, 0x66,
0x69, 0x6c, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x22, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x52, 0x0b, 0x66, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63,
0x53, 0x65, 0x74, 0x32, 0xdd, 0x01, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x12, 0x61, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x12, 0x1f, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x1d, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79,
0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x12, 0x6e, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x44, 0x65, 0x73, 0x63, 0x12, 0x21, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73,
0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f,
0x73, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x44, 0x65, 0x73, 0x63, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x12, 0x12, 0x10, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x7b, 0x6e, 0x61,
0x6d, 0x65, 0x7d, 0x42, 0x63, 0x0a, 0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x61, 0x70, 0x69, 0x50, 0x01, 0x5a, 0x3c,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72,
0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x61,
0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f,
0x61, 0x70, 0x69, 0x3b, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xa2, 0x02, 0x09, 0x4b,
0x72, 0x61, 0x74, 0x6f, 0x73, 0x41, 0x50, 0x49, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_metadata_metadata_proto_rawDescOnce sync.Once
file_metadata_metadata_proto_rawDescData = file_metadata_metadata_proto_rawDesc
)
func file_metadata_metadata_proto_rawDescGZIP() []byte {
file_metadata_metadata_proto_rawDescOnce.Do(func() {
file_metadata_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_metadata_metadata_proto_rawDescData)
})
return file_metadata_metadata_proto_rawDescData
}
var file_metadata_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_metadata_metadata_proto_goTypes = []interface{}{
(*ListServicesRequest)(nil), // 0: kratos.api.ListServicesRequest
(*ListServicesReply)(nil), // 1: kratos.api.ListServicesReply
(*GetServiceDescRequest)(nil), // 2: kratos.api.GetServiceDescRequest
(*GetServiceDescReply)(nil), // 3: kratos.api.GetServiceDescReply
(*descriptorpb.FileDescriptorSet)(nil), // 4: google.protobuf.FileDescriptorSet
}
var file_metadata_metadata_proto_depIdxs = []int32{
4, // 0: kratos.api.GetServiceDescReply.file_desc_set:type_name -> google.protobuf.FileDescriptorSet
0, // 1: kratos.api.Metadata.ListServices:input_type -> kratos.api.ListServicesRequest
2, // 2: kratos.api.Metadata.GetServiceDesc:input_type -> kratos.api.GetServiceDescRequest
1, // 3: kratos.api.Metadata.ListServices:output_type -> kratos.api.ListServicesReply
3, // 4: kratos.api.Metadata.GetServiceDesc:output_type -> kratos.api.GetServiceDescReply
3, // [3:5] is the sub-list for method output_type
1, // [1:3] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_metadata_metadata_proto_init() }
func file_metadata_metadata_proto_init() {
if File_metadata_metadata_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_metadata_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListServicesRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_metadata_metadata_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListServicesReply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_metadata_metadata_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetServiceDescRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_metadata_metadata_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetServiceDescReply); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_metadata_metadata_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_metadata_metadata_proto_goTypes,
DependencyIndexes: file_metadata_metadata_proto_depIdxs,
MessageInfos: file_metadata_metadata_proto_msgTypes,
}.Build()
File_metadata_metadata_proto = out.File
file_metadata_metadata_proto_rawDesc = nil
file_metadata_metadata_proto_goTypes = nil
file_metadata_metadata_proto_depIdxs = nil
}

@ -0,0 +1,43 @@
syntax = "proto3";
package kratos.api;
import "google/protobuf/descriptor.proto";
import "google/api/annotations.proto";
option go_package = "github.com/go-kratos/kratos/v2/api/proto/kratos/api;metadata";
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",
};
}
// GetServiceDesc get the full fileDescriptorSet of service.
rpc GetServiceDesc (GetServiceDescRequest) returns (GetServiceDescReply) {
option (google.api.http) = {
get: "/services/{name}",
};
}
}
message ListServicesRequest {}
message ListServicesReply {
repeated string services = 1;
repeated string methods = 2;
}
message GetServiceDescRequest {
string name = 1;
}
message GetServiceDescReply {
google.protobuf.FileDescriptorSet file_desc_set = 1;
}

@ -0,0 +1,145 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.19.4
// source: metadata/metadata.proto
package metadata
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// MetadataClient is the client API for Metadata service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type MetadataClient interface {
// ListServices list the full name of all services.
ListServices(ctx context.Context, in *ListServicesRequest, opts ...grpc.CallOption) (*ListServicesReply, error)
// GetServiceDesc get the full fileDescriptorSet of service.
GetServiceDesc(ctx context.Context, in *GetServiceDescRequest, opts ...grpc.CallOption) (*GetServiceDescReply, error)
}
type metadataClient struct {
cc grpc.ClientConnInterface
}
func NewMetadataClient(cc grpc.ClientConnInterface) MetadataClient {
return &metadataClient{cc}
}
func (c *metadataClient) ListServices(ctx context.Context, in *ListServicesRequest, opts ...grpc.CallOption) (*ListServicesReply, error) {
out := new(ListServicesReply)
err := c.cc.Invoke(ctx, "/kratos.api.Metadata/ListServices", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *metadataClient) GetServiceDesc(ctx context.Context, in *GetServiceDescRequest, opts ...grpc.CallOption) (*GetServiceDescReply, error) {
out := new(GetServiceDescReply)
err := c.cc.Invoke(ctx, "/kratos.api.Metadata/GetServiceDesc", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// MetadataServer is the server API for Metadata service.
// All implementations must embed UnimplementedMetadataServer
// for forward compatibility
type MetadataServer interface {
// ListServices list the full name of all services.
ListServices(context.Context, *ListServicesRequest) (*ListServicesReply, error)
// GetServiceDesc get the full fileDescriptorSet of service.
GetServiceDesc(context.Context, *GetServiceDescRequest) (*GetServiceDescReply, error)
mustEmbedUnimplementedMetadataServer()
}
// UnimplementedMetadataServer must be embedded to have forward compatible implementations.
type UnimplementedMetadataServer struct {
}
func (UnimplementedMetadataServer) ListServices(context.Context, *ListServicesRequest) (*ListServicesReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListServices not implemented")
}
func (UnimplementedMetadataServer) GetServiceDesc(context.Context, *GetServiceDescRequest) (*GetServiceDescReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetServiceDesc not implemented")
}
func (UnimplementedMetadataServer) mustEmbedUnimplementedMetadataServer() {}
// UnsafeMetadataServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MetadataServer will
// result in compilation errors.
type UnsafeMetadataServer interface {
mustEmbedUnimplementedMetadataServer()
}
func RegisterMetadataServer(s grpc.ServiceRegistrar, srv MetadataServer) {
s.RegisterService(&Metadata_ServiceDesc, srv)
}
func _Metadata_ListServices_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListServicesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MetadataServer).ListServices(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/kratos.api.Metadata/ListServices",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MetadataServer).ListServices(ctx, req.(*ListServicesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Metadata_GetServiceDesc_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetServiceDescRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MetadataServer).GetServiceDesc(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/kratos.api.Metadata/GetServiceDesc",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MetadataServer).GetServiceDesc(ctx, req.(*GetServiceDescRequest))
}
return interceptor(ctx, in, info, handler)
}
// Metadata_ServiceDesc is the grpc.ServiceDesc for Metadata service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Metadata_ServiceDesc = grpc.ServiceDesc{
ServiceName: "kratos.api.Metadata",
HandlerType: (*MetadataServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ListServices",
Handler: _Metadata_ListServices_Handler,
},
{
MethodName: "GetServiceDesc",
Handler: _Metadata_GetServiceDesc_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "metadata/metadata.proto",
}

@ -0,0 +1,109 @@
// Code generated by protoc-gen-go-http. DO NOT EDIT.
// versions:
// protoc-gen-go-http v2.3.0
package metadata
import (
context "context"
http "github.com/go-kratos/kratos/v2/transport/http"
binding "github.com/go-kratos/kratos/v2/transport/http/binding"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the kratos package it is being compiled against.
var _ = new(context.Context)
var _ = binding.EncodeURL
const _ = http.SupportPackageIsVersion1
type MetadataHTTPServer interface {
GetServiceDesc(context.Context, *GetServiceDescRequest) (*GetServiceDescReply, error)
ListServices(context.Context, *ListServicesRequest) (*ListServicesReply, error)
}
func RegisterMetadataHTTPServer(s *http.Server, srv MetadataHTTPServer) {
r := s.Route("/")
r.GET("/services", _Metadata_ListServices0_HTTP_Handler(srv))
r.GET("/services/{name}", _Metadata_GetServiceDesc0_HTTP_Handler(srv))
}
func _Metadata_ListServices0_HTTP_Handler(srv MetadataHTTPServer) func(ctx http.Context) error {
return func(ctx http.Context) error {
var in ListServicesRequest
if err := ctx.BindQuery(&in); err != nil {
return err
}
http.SetOperation(ctx, "/kratos.api.Metadata/ListServices")
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.ListServices(ctx, req.(*ListServicesRequest))
})
out, err := h(ctx, &in)
if err != nil {
return err
}
reply := out.(*ListServicesReply)
return ctx.Result(200, reply)
}
}
func _Metadata_GetServiceDesc0_HTTP_Handler(srv MetadataHTTPServer) func(ctx http.Context) error {
return func(ctx http.Context) error {
var in GetServiceDescRequest
if err := ctx.BindQuery(&in); err != nil {
return err
}
if err := ctx.BindVars(&in); err != nil {
return err
}
http.SetOperation(ctx, "/kratos.api.Metadata/GetServiceDesc")
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.GetServiceDesc(ctx, req.(*GetServiceDescRequest))
})
out, err := h(ctx, &in)
if err != nil {
return err
}
reply := out.(*GetServiceDescReply)
return ctx.Result(200, reply)
}
}
type MetadataHTTPClient interface {
GetServiceDesc(ctx context.Context, req *GetServiceDescRequest, opts ...http.CallOption) (rsp *GetServiceDescReply, err error)
ListServices(ctx context.Context, req *ListServicesRequest, opts ...http.CallOption) (rsp *ListServicesReply, err error)
}
type MetadataHTTPClientImpl struct {
cc *http.Client
}
func NewMetadataHTTPClient(client *http.Client) MetadataHTTPClient {
return &MetadataHTTPClientImpl{client}
}
func (c *MetadataHTTPClientImpl) GetServiceDesc(ctx context.Context, in *GetServiceDescRequest, opts ...http.CallOption) (*GetServiceDescReply, error) {
var out GetServiceDescReply
pattern := "/services/{name}"
path := binding.EncodeURL(pattern, in, true)
opts = append(opts, http.Operation("/kratos.api.Metadata/GetServiceDesc"))
opts = append(opts, http.PathTemplate(pattern))
err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...)
if err != nil {
return nil, err
}
return &out, err
}
func (c *MetadataHTTPClientImpl) ListServices(ctx context.Context, in *ListServicesRequest, opts ...http.CallOption) (*ListServicesReply, error) {
var out ListServicesReply
pattern := "/services"
path := binding.EncodeURL(pattern, in, true)
opts = append(opts, http.Operation("/kratos.api.Metadata/ListServices"))
opts = append(opts, http.PathTemplate(pattern))
err := c.cc.Invoke(ctx, "GET", path, nil, &out, opts...)
if err != nil {
return nil, err
}
return &out, err
}

@ -0,0 +1,206 @@
package metadata
import (
"bytes"
"compress/gzip"
"context"
"errors"
"fmt"
"io"
"sort"
"sync"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
dpb "google.golang.org/protobuf/types/descriptorpb"
"github.com/go-kratos/kratos/v2/log"
)
// Server is api meta server
type Server struct {
UnimplementedMetadataServer
srv *grpc.Server
lock sync.Mutex
services map[string]*dpb.FileDescriptorSet
methods map[string][]string
}
// NewServer create server instance
func NewServer(srv *grpc.Server) *Server {
return &Server{
srv: srv,
services: make(map[string]*dpb.FileDescriptorSet),
methods: make(map[string][]string),
}
}
func (s *Server) load() error {
if len(s.services) > 0 {
return nil
}
if s.srv != nil {
for name, info := range s.srv.GetServiceInfo() {
fd, err := parseMetadata(info.Metadata)
if err != nil {
return fmt.Errorf("invalid service %s metadata err:%v", name, err)
}
protoSet, err := allDependency(fd)
if err != nil {
return err
}
s.services[name] = &dpb.FileDescriptorSet{File: protoSet}
for _, method := range info.Methods {
s.methods[name] = append(s.methods[name], method.Name)
}
}
return nil
}
var err error
protoregistry.GlobalFiles.RangeFiles(func(fd protoreflect.FileDescriptor) bool {
if fd.Services() == nil {
return true
}
for i := 0; i < fd.Services().Len(); i++ {
svc := fd.Services().Get(i)
fdp, e := fileDescriptorProto(fd.Path())
if e != nil {
err = e
return false
}
fdps, e := allDependency(fdp)
if e != nil {
if errors.Is(e, protoregistry.NotFound) {
// Skip this service if one of its dependencies is not found.
continue
}
err = e
return false
}
s.services[string(svc.FullName())] = &dpb.FileDescriptorSet{File: fdps}
if svc.Methods() == nil {
continue
}
for j := 0; j < svc.Methods().Len(); j++ {
method := svc.Methods().Get(j)
s.methods[string(svc.FullName())] = append(s.methods[string(svc.FullName())], string(method.Name()))
}
}
return true
})
return err
}
// ListServices return all services
func (s *Server) ListServices(_ context.Context, _ *ListServicesRequest) (*ListServicesReply, error) {
s.lock.Lock()
defer s.lock.Unlock()
if err := s.load(); err != nil {
return nil, err
}
reply := &ListServicesReply{
Services: make([]string, 0, len(s.services)),
Methods: make([]string, 0, len(s.methods)),
}
for name := range s.services {
reply.Services = append(reply.Services, name)
}
for name, methods := range s.methods {
for _, method := range methods {
reply.Methods = append(reply.Methods, fmt.Sprintf("/%s/%s", name, method))
}
}
sort.Strings(reply.Services)
sort.Strings(reply.Methods)
return reply, nil
}
// GetServiceDesc return service meta by name
func (s *Server) GetServiceDesc(_ context.Context, in *GetServiceDescRequest) (*GetServiceDescReply, error) {
s.lock.Lock()
defer s.lock.Unlock()
if err := s.load(); err != nil {
return nil, err
}
fds, ok := s.services[in.Name]
if !ok {
return nil, status.Errorf(codes.NotFound, "service %s not found", in.Name)
}
return &GetServiceDescReply{FileDescSet: fds}, nil
}
// parseMetadata finds the file descriptor bytes specified meta.
// For SupportPackageIsVersion4, m is the name of the proto file, we
// call proto.FileDescriptor to get the byte slice.
// For SupportPackageIsVersion3, m is a byte slice itself.
func parseMetadata(meta interface{}) (*dpb.FileDescriptorProto, error) {
// Check if meta is the file name.
if fileNameForMeta, ok := meta.(string); ok {
return fileDescriptorProto(fileNameForMeta)
}
// Check if meta is the byte slice.
if enc, ok := meta.([]byte); ok {
return decodeFileDesc(enc)
}
return nil, fmt.Errorf("proto not sumpport metadata: %v", meta)
}
// decodeFileDesc does decompression and unmarshalling on the given
// file descriptor byte slice.
func decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) {
raw, err := decompress(enc)
if err != nil {
return nil, fmt.Errorf("failed to decompress enc: %v", err)
}
fd := new(dpb.FileDescriptorProto)
if err := proto.Unmarshal(raw, fd); err != nil {
return nil, fmt.Errorf("bad descriptor: %v", err)
}
return fd, nil
}
func allDependency(fd *dpb.FileDescriptorProto) ([]*dpb.FileDescriptorProto, error) {
var files []*dpb.FileDescriptorProto
for _, dep := range fd.Dependency {
fdDep, err := fileDescriptorProto(dep)
if err != nil {
log.Warnf("%s", err)
continue
}
temp, err := allDependency(fdDep)
if err != nil {
return nil, err
}
files = append(files, temp...)
}
files = append(files, fd)
return files, nil
}
// decompress does gzip decompression.
func decompress(b []byte) ([]byte, error) {
r, err := gzip.NewReader(bytes.NewReader(b))
if err != nil {
return nil, fmt.Errorf("bad gzipped descriptor: %v", err)
}
out, err := io.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("bad gzipped descriptor: %v", err)
}
return out, nil
}
func fileDescriptorProto(path string) (*dpb.FileDescriptorProto, error) {
fd, err := protoregistry.GlobalFiles.FindFileByPath(path)
if err != nil {
return nil, fmt.Errorf("find proto by path failed, path: %s, err: %s", path, err)
}
fdpb := protodesc.ToFileDescriptorProto(fd)
return fdpb, nil
}

207
app.go

@ -0,0 +1,207 @@
package kratos
import (
"context"
"errors"
"os"
"os/signal"
"sync"
"syscall"
"time"
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/registry"
"github.com/go-kratos/kratos/v2/transport"
"github.com/google/uuid"
"golang.org/x/sync/errgroup"
)
// AppInfo is application context value.
type AppInfo interface {
ID() string
Name() string
Version() string
Metadata() map[string]string
Endpoint() []string
}
// App is an application components lifecycle manager.
type App struct {
opts options
ctx context.Context
cancel func()
mu sync.Mutex
instance *registry.ServiceInstance
}
// New create an application lifecycle manager.
func New(opts ...Option) *App {
o := options{
ctx: context.Background(),
sigs: []os.Signal{syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT},
registrarTimeout: 10 * time.Second,
stopTimeout: 10 * time.Second,
}
if id, err := uuid.NewUUID(); err == nil {
o.id = id.String()
}
for _, opt := range opts {
opt(&o)
}
if o.logger != nil {
log.SetLogger(o.logger)
}
ctx, cancel := context.WithCancel(o.ctx)
return &App{
ctx: ctx,
cancel: cancel,
opts: o,
}
}
// ID returns app instance id.
func (a *App) ID() string { return a.opts.id }
// Name returns service name.
func (a *App) Name() string { return a.opts.name }
// Version returns app version.
func (a *App) Version() string { return a.opts.version }
// Metadata returns service metadata.
func (a *App) Metadata() map[string]string { return a.opts.metadata }
// Endpoint returns endpoints.
func (a *App) Endpoint() []string {
if a.instance != nil {
return a.instance.Endpoints
}
return nil
}
// Run executes all OnStart hooks registered with the application's Lifecycle.
func (a *App) Run() error {
instance, err := a.buildInstance()
if err != nil {
return err
}
a.mu.Lock()
a.instance = instance
a.mu.Unlock()
sctx := NewContext(a.ctx, a)
eg, ctx := errgroup.WithContext(sctx)
wg := sync.WaitGroup{}
for _, fn := range a.opts.beforeStart {
if err = fn(sctx); err != nil {
return err
}
}
for _, srv := range a.opts.servers {
srv := srv
eg.Go(func() error {
<-ctx.Done() // wait for stop signal
stopCtx, cancel := context.WithTimeout(NewContext(a.opts.ctx, a), a.opts.stopTimeout)
defer cancel()
return srv.Stop(stopCtx)
})
wg.Add(1)
eg.Go(func() error {
wg.Done() // here is to ensure server start has begun running before register, so defer is not needed
return srv.Start(sctx)
})
}
wg.Wait()
if a.opts.registrar != nil {
rctx, rcancel := context.WithTimeout(ctx, a.opts.registrarTimeout)
defer rcancel()
if err = a.opts.registrar.Register(rctx, instance); err != nil {
return err
}
}
for _, fn := range a.opts.afterStart {
if err = fn(sctx); err != nil {
return err
}
}
c := make(chan os.Signal, 1)
signal.Notify(c, a.opts.sigs...)
eg.Go(func() error {
select {
case <-ctx.Done():
return nil
case <-c:
return a.Stop()
}
})
if err = eg.Wait(); err != nil && !errors.Is(err, context.Canceled) {
return err
}
for _, fn := range a.opts.afterStop {
err = fn(sctx)
}
return err
}
// Stop gracefully stops the application.
func (a *App) Stop() (err error) {
sctx := NewContext(a.ctx, a)
for _, fn := range a.opts.beforeStop {
err = fn(sctx)
}
a.mu.Lock()
instance := a.instance
a.mu.Unlock()
if a.opts.registrar != nil && instance != nil {
ctx, cancel := context.WithTimeout(NewContext(a.ctx, a), a.opts.registrarTimeout)
defer cancel()
if err = a.opts.registrar.Deregister(ctx, instance); err != nil {
return err
}
}
if a.cancel != nil {
a.cancel()
}
return err
}
func (a *App) buildInstance() (*registry.ServiceInstance, error) {
endpoints := make([]string, 0, len(a.opts.endpoints))
for _, e := range a.opts.endpoints {
endpoints = append(endpoints, e.String())
}
if len(endpoints) == 0 {
for _, srv := range a.opts.servers {
if r, ok := srv.(transport.Endpointer); ok {
e, err := r.Endpoint()
if err != nil {
return nil, err
}
endpoints = append(endpoints, e.String())
}
}
}
return &registry.ServiceInstance{
ID: a.opts.id,
Name: a.opts.name,
Version: a.opts.version,
Metadata: a.opts.metadata,
Endpoints: endpoints,
}, nil
}
type appKey struct{}
// NewContext returns a new Context that carries value.
func NewContext(ctx context.Context, s AppInfo) context.Context {
return context.WithValue(ctx, appKey{}, s)
}
// FromContext returns the Transport value stored in ctx, if any.
func FromContext(ctx context.Context) (s AppInfo, ok bool) {
s, ok = ctx.Value(appKey{}).(AppInfo)
return
}

@ -0,0 +1,285 @@
package kratos
import (
"context"
"errors"
"net/url"
"reflect"
"sync"
"testing"
"time"
"github.com/go-kratos/kratos/v2/registry"
"github.com/go-kratos/kratos/v2/transport/grpc"
"github.com/go-kratos/kratos/v2/transport/http"
)
type mockRegistry struct {
lk sync.Mutex
service map[string]*registry.ServiceInstance
}
func (r *mockRegistry) Register(_ context.Context, service *registry.ServiceInstance) error {
if service == nil || service.ID == "" {
return errors.New("no service id")
}
r.lk.Lock()
defer r.lk.Unlock()
r.service[service.ID] = service
return nil
}
// Deregister the registration.
func (r *mockRegistry) Deregister(_ context.Context, service *registry.ServiceInstance) error {
r.lk.Lock()
defer r.lk.Unlock()
if r.service[service.ID] == nil {
return errors.New("deregister service not found")
}
delete(r.service, service.ID)
return nil
}
func TestApp(t *testing.T) {
hs := http.NewServer()
gs := grpc.NewServer()
app := New(
Name("kratos"),
Version("v1.0.0"),
Server(hs, gs),
BeforeStart(func(_ context.Context) error {
t.Log("BeforeStart...")
return nil
}),
BeforeStop(func(_ context.Context) error {
t.Log("BeforeStop...")
return nil
}),
AfterStart(func(_ context.Context) error {
t.Log("AfterStart...")
return nil
}),
AfterStop(func(_ context.Context) error {
t.Log("AfterStop...")
return nil
}),
Registrar(&mockRegistry{service: make(map[string]*registry.ServiceInstance)}),
)
time.AfterFunc(time.Second, func() {
_ = app.Stop()
})
if err := app.Run(); err != nil {
t.Fatal(err)
}
}
func TestApp_ID(t *testing.T) {
v := "123"
o := New(ID(v))
if !reflect.DeepEqual(v, o.ID()) {
t.Fatalf("o.ID():%s is not equal to v:%s", o.ID(), v)
}
}
func TestApp_Name(t *testing.T) {
v := "123"
o := New(Name(v))
if !reflect.DeepEqual(v, o.Name()) {
t.Fatalf("o.Name():%s is not equal to v:%s", o.Name(), v)
}
}
func TestApp_Version(t *testing.T) {
v := "123"
o := New(Version(v))
if !reflect.DeepEqual(v, o.Version()) {
t.Fatalf("o.Version():%s is not equal to v:%s", o.Version(), v)
}
}
func TestApp_Metadata(t *testing.T) {
v := map[string]string{
"a": "1",
"b": "2",
}
o := New(Metadata(v))
if !reflect.DeepEqual(v, o.Metadata()) {
t.Fatalf("o.Metadata():%s is not equal to v:%s", o.Metadata(), v)
}
}
func TestApp_Endpoint(t *testing.T) {
v := []string{"https://go-kratos.dev", "localhost"}
var endpoints []*url.URL
for _, urlStr := range v {
if endpoint, err := url.Parse(urlStr); err != nil {
t.Errorf("invalid endpoint:%v", urlStr)
} else {
endpoints = append(endpoints, endpoint)
}
}
o := New(Endpoint(endpoints...))
if instance, err := o.buildInstance(); err != nil {
t.Error("build instance failed")
} else {
o.instance = instance
}
if !reflect.DeepEqual(o.Endpoint(), v) {
t.Errorf("Endpoint() = %v, want %v", o.Endpoint(), v)
}
}
func TestApp_buildInstance(t *testing.T) {
want := struct {
id string
name string
version string
metadata map[string]string
endpoints []string
}{
id: "1",
name: "kratos",
version: "v1.0.0",
metadata: map[string]string{
"a": "1",
"b": "2",
},
endpoints: []string{"https://go-kratos.dev", "localhost"},
}
var endpoints []*url.URL
for _, urlStr := range want.endpoints {
if endpoint, err := url.Parse(urlStr); err != nil {
t.Errorf("invalid endpoint:%v", urlStr)
} else {
endpoints = append(endpoints, endpoint)
}
}
app := New(
ID(want.id),
Name(want.name),
Version(want.version),
Metadata(want.metadata),
Endpoint(endpoints...),
)
if got, err := app.buildInstance(); err != nil {
t.Error("build got failed")
} else {
if got.ID != want.id {
t.Errorf("ID() = %v, want %v", got.ID, want.id)
}
if got.Name != want.name {
t.Errorf("Name() = %v, want %v", got.Name, want.name)
}
if got.Version != want.version {
t.Errorf("Version() = %v, want %v", got.Version, want.version)
}
if !reflect.DeepEqual(got.Endpoints, want.endpoints) {
t.Errorf("Endpoint() = %v, want %v", got.Endpoints, want.endpoints)
}
if !reflect.DeepEqual(got.Metadata, want.metadata) {
t.Errorf("Metadata() = %v, want %v", got.Metadata, want.metadata)
}
}
}
func TestApp_Context(t *testing.T) {
type fields struct {
id string
version string
name string
instance *registry.ServiceInstance
metadata map[string]string
want struct {
id string
version string
name string
endpoint []string
metadata map[string]string
}
}
tests := []fields{
{
id: "1",
name: "kratos-v1",
instance: &registry.ServiceInstance{Endpoints: []string{"https://go-kratos.dev", "localhost"}},
metadata: map[string]string{},
version: "v1",
want: struct {
id string
version string
name string
endpoint []string
metadata map[string]string
}{
id: "1", version: "v1", name: "kratos-v1", endpoint: []string{"https://go-kratos.dev", "localhost"},
metadata: map[string]string{},
},
},
{
id: "2",
name: "kratos-v2",
instance: &registry.ServiceInstance{Endpoints: []string{"test"}},
metadata: map[string]string{"kratos": "https://github.com/go-kratos/kratos"},
version: "v2",
want: struct {
id string
version string
name string
endpoint []string
metadata map[string]string
}{
id: "2", version: "v2", name: "kratos-v2", endpoint: []string{"test"},
metadata: map[string]string{"kratos": "https://github.com/go-kratos/kratos"},
},
},
{
id: "3",
name: "kratos-v3",
instance: nil,
metadata: make(map[string]string),
version: "v3",
want: struct {
id string
version string
name string
endpoint []string
metadata map[string]string
}{
id: "3", version: "v3", name: "kratos-v3", endpoint: nil,
metadata: map[string]string{},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &App{
opts: options{id: tt.id, name: tt.name, metadata: tt.metadata, version: tt.version},
ctx: context.Background(),
cancel: nil,
instance: tt.instance,
}
ctx := NewContext(context.Background(), a)
if got, ok := FromContext(ctx); ok {
if got.ID() != tt.want.id {
t.Errorf("ID() = %v, want %v", got.ID(), tt.want.id)
}
if got.Name() != tt.want.name {
t.Errorf("Name() = %v, want %v", got.Name(), tt.want.name)
}
if got.Version() != tt.want.version {
t.Errorf("Version() = %v, want %v", got.Version(), tt.want.version)
}
if !reflect.DeepEqual(got.Endpoint(), tt.want.endpoint) {
t.Errorf("Endpoint() = %v, want %v", got.Endpoint(), tt.want.endpoint)
}
if !reflect.DeepEqual(got.Metadata(), tt.want.metadata) {
t.Errorf("Metadata() = %v, want %v", got.Metadata(), tt.want.metadata)
}
} else {
t.Errorf("ok() = %v, want %v", ok, true)
}
})
}
}

@ -0,0 +1,15 @@
module github.com/go-kratos/kratos/cmd/kratos/v2
go 1.16
require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/emicklei/proto v1.10.0
github.com/fatih/color v1.13.0
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/spf13/cobra v1.4.0
github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/text v0.4.0
gopkg.in/yaml.v3 v3.0.0 // indirect
)

@ -0,0 +1,79 @@
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/proto v1.10.0 h1:pDGyFRVV5RvV+nkBK9iy3q67FBy9Xa7vwrOTE+g5aGw=
github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

@ -0,0 +1,28 @@
//go:build go1.17
// +build go1.17
package base
import (
"fmt"
"os"
"os/exec"
"strings"
)
// GoInstall go get path.
func GoInstall(path ...string) error {
for _, p := range path {
if !strings.Contains(p, "@") {
p += "@latest"
}
fmt.Printf("go install %s\n", p)
cmd := exec.Command("go", "install", p)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return err
}
}
return nil
}

@ -0,0 +1,24 @@
//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
}

@ -0,0 +1,62 @@
package base
import (
"bufio"
"bytes"
"os"
"os/exec"
"path/filepath"
"strings"
"golang.org/x/mod/modfile"
)
// ModulePath returns go module path.
func ModulePath(filename string) (string, error) {
modBytes, err := os.ReadFile(filename)
if err != nil {
return "", err
}
return modfile.ModulePath(modBytes), nil
}
// ModuleVersion returns module version.
func ModuleVersion(path string) (string, error) {
stdout := &bytes.Buffer{}
fd := exec.Command("go", "mod", "graph")
fd.Stdout = stdout
fd.Stderr = stdout
if err := fd.Run(); err != nil {
return "", err
}
rd := bufio.NewReader(stdout)
for {
line, _, err := rd.ReadLine()
if err != nil {
return "", err
}
str := string(line)
i := strings.Index(str, "@")
if strings.Contains(str, path+"@") && i != -1 {
return path + str[i:], nil
}
}
}
// KratosMod returns kratos mod.
func KratosMod() string {
// go 1.15+ read from env GOMODCACHE
cacheOut, _ := exec.Command("go", "env", "GOMODCACHE").Output()
cachePath := strings.Trim(string(cacheOut), "\n")
pathOut, _ := exec.Command("go", "env", "GOPATH").Output()
gopath := strings.Trim(string(pathOut), "\n")
if cachePath == "" {
cachePath = filepath.Join(gopath, "pkg", "mod")
}
if path, err := ModuleVersion("github.com/go-kratos/kratos/v2"); err == nil {
// $GOPATH/pkg/mod/github.com/go-kratos/kratos@v2
return filepath.Join(cachePath, path)
}
// $GOPATH/src/github.com/go-kratos/kratos
return filepath.Join(gopath, "src", "github.com", "go-kratos", "kratos")
}

@ -0,0 +1,43 @@
package base
import (
"os"
"testing"
)
func TestModuleVersion(t *testing.T) {
v, err := ModuleVersion("golang.org/x/mod")
if err != nil {
t.Fatal(err)
}
t.Log(v)
}
func TestModulePath(t *testing.T) {
if err := os.Mkdir("/tmp/test_mod", os.ModePerm); err != nil {
t.Fatal(err)
}
f, err := os.Create("/tmp/test_mod/go.mod")
if err != nil {
t.Fatal(err)
}
mod := `module github.com/go-kratos/kratos/v2
go 1.16`
_, err = f.WriteString(mod)
if err != nil {
t.Fatal(err)
}
p, err := ModulePath("/tmp/test_mod/go.mod")
if err != nil {
t.Fatal(err)
}
if p != "github.com/go-kratos/kratos/v2" {
t.Fatalf("want: %s, got: %s", "github.com/go-kratos/kratos/v2", p)
}
t.Cleanup(func() { os.RemoveAll("/tmp/test_mod") })
}

@ -0,0 +1,108 @@
package base
import (
"bytes"
"fmt"
"log"
"os"
"path/filepath"
"strings"
"github.com/fatih/color"
)
func kratosHome() string {
dir, err := os.UserHomeDir()
if err != nil {
log.Fatal(err)
}
home := filepath.Join(dir, ".kratos")
if _, err := os.Stat(home); os.IsNotExist(err) {
if err := os.MkdirAll(home, 0o700); err != nil {
log.Fatal(err)
}
}
return home
}
func kratosHomeWithDir(dir string) string {
home := filepath.Join(kratosHome(), dir)
if _, err := os.Stat(home); os.IsNotExist(err) {
if err := os.MkdirAll(home, 0o700); err != nil {
log.Fatal(err)
}
}
return home
}
func copyFile(src, dst string, replaces []string) error {
srcinfo, err := os.Stat(src)
if err != nil {
return err
}
buf, err := os.ReadFile(src)
if err != nil {
return err
}
var old string
for i, next := range replaces {
if i%2 == 0 {
old = next
continue
}
buf = bytes.ReplaceAll(buf, []byte(old), []byte(next))
}
return os.WriteFile(dst, buf, srcinfo.Mode())
}
func copyDir(src, dst string, replaces, ignores []string) error {
srcinfo, err := os.Stat(src)
if err != nil {
return err
}
err = os.MkdirAll(dst, srcinfo.Mode())
if err != nil {
return err
}
fds, err := os.ReadDir(src)
if err != nil {
return err
}
for _, fd := range fds {
if hasSets(fd.Name(), ignores) {
continue
}
srcfp := filepath.Join(src, fd.Name())
dstfp := filepath.Join(dst, fd.Name())
var e error
if fd.IsDir() {
e = copyDir(srcfp, dstfp, replaces, ignores)
} else {
e = copyFile(srcfp, dstfp, replaces)
}
if e != nil {
return e
}
}
return nil
}
func hasSets(name string, sets []string) bool {
for _, ig := range sets {
if ig == name {
return true
}
}
return false
}
func Tree(path string, dir string) {
_ = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err == nil && info != nil && !info.IsDir() {
fmt.Printf("%s %s (%v bytes)\n", color.GreenString("CREATED"), strings.Replace(path, dir+"/", "", -1), info.Size())
}
return nil
})
}

@ -0,0 +1,126 @@
package base
import (
"context"
"fmt"
"net"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
)
var unExpandVarPath = []string{"~", ".", ".."}
// Repo is git repository manager.
type Repo struct {
url string
home string
branch string
}
func repoDir(url string) string {
vcsURL, err := ParseVCSUrl(url)
if err != nil {
return url
}
// check host contains port
host, _, err := net.SplitHostPort(vcsURL.Host)
if err != nil {
host = vcsURL.Host
}
for _, p := range unExpandVarPath {
host = strings.TrimLeft(host, p)
}
dir := path.Base(path.Dir(vcsURL.Path))
url = fmt.Sprintf("%s/%s", host, dir)
return url
}
// NewRepo new a repository manager.
func NewRepo(url string, branch string) *Repo {
return &Repo{
url: url,
home: kratosHomeWithDir("repo/" + repoDir(url)),
branch: branch,
}
}
// Path returns the repository cache path.
func (r *Repo) Path() string {
start := strings.LastIndex(r.url, "/")
end := strings.LastIndex(r.url, ".git")
if end == -1 {
end = len(r.url)
}
var branch string
if r.branch == "" {
branch = "@main"
} else {
branch = "@" + r.branch
}
return path.Join(r.home, r.url[start+1:end]+branch)
}
// Pull fetch the repository from remote url.
func (r *Repo) Pull(ctx context.Context) error {
cmd := exec.CommandContext(ctx, "git", "symbolic-ref", "HEAD")
cmd.Dir = r.Path()
_, err := cmd.CombinedOutput()
if err != nil {
return err
}
cmd = exec.CommandContext(ctx, "git", "pull")
cmd.Dir = r.Path()
out, err := cmd.CombinedOutput()
fmt.Println(string(out))
if err != nil {
return err
}
return err
}
// Clone clones the repository to cache path.
func (r *Repo) Clone(ctx context.Context) error {
if _, err := os.Stat(r.Path()); !os.IsNotExist(err) {
return r.Pull(ctx)
}
var cmd *exec.Cmd
if r.branch == "" {
cmd = exec.CommandContext(ctx, "git", "clone", r.url, r.Path())
} else {
cmd = exec.CommandContext(ctx, "git", "clone", "-b", r.branch, r.url, r.Path())
}
out, err := cmd.CombinedOutput()
fmt.Println(string(out))
if err != nil {
return err
}
return nil
}
// CopyTo copies the repository to project path.
func (r *Repo) CopyTo(ctx context.Context, to string, modPath string, ignores []string) error {
if err := r.Clone(ctx); err != nil {
return err
}
mod, err := ModulePath(filepath.Join(r.Path(), "go.mod"))
if err != nil {
return err
}
return copyDir(r.Path(), to, []string{mod, modPath}, ignores)
}
// CopyToV2 copies the repository to project path
func (r *Repo) CopyToV2(ctx context.Context, to string, modPath string, ignores, replaces []string) error {
if err := r.Clone(ctx); err != nil {
return err
}
mod, err := ModulePath(filepath.Join(r.Path(), "go.mod"))
if err != nil {
return err
}
replaces = append([]string{mod, modPath}, replaces...)
return copyDir(r.Path(), to, replaces, ignores)
}

@ -0,0 +1,51 @@
package base
import (
"context"
"os"
"testing"
)
func TestRepo(t *testing.T) {
urls := []string{
// ssh://[user@]host.xz[:port]/path/to/repo.git/
"ssh://git@github.com:7875/go-kratos/kratos.git",
// git://host.xz[:port]/path/to/repo.git/
"git://github.com:7875/go-kratos/kratos.git",
// http[s]://host.xz[:port]/path/to/repo.git/
"https://github.com:7875/go-kratos/kratos.git",
// ftp[s]://host.xz[:port]/path/to/repo.git/
"ftps://github.com:7875/go-kratos/kratos.git",
//[user@]host.xz:path/to/repo.git/
"git@github.com:go-kratos/kratos.git",
// ssh://[user@]host.xz[:port]/~[user]/path/to/repo.git/
"ssh://git@github.com:7875/go-kratos/kratos.git",
// git://host.xz[:port]/~[user]/path/to/repo.git/
"git://github.com:7875/go-kratos/kratos.git",
//[user@]host.xz:/~[user]/path/to/repo.git/
"git@github.com:go-kratos/kratos.git",
///path/to/repo.git/
"//github.com/go-kratos/kratos.git",
// file:///path/to/repo.git/
"file://./github.com/go-kratos/kratos.git",
}
for _, url := range urls {
dir := repoDir(url)
if dir != "github.com/go-kratos" && dir != "/go-kratos" {
t.Fatal(url, "repoDir test failed", dir)
}
}
}
func TestRepoClone(t *testing.T) {
r := NewRepo("https://github.com/go-kratos/service-layout.git", "")
if err := r.Clone(context.Background()); err != nil {
t.Fatal(err)
}
if err := r.CopyTo(context.Background(), "/tmp/test_repo", "github.com/go-kratos/kratos-layout", nil); err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
os.RemoveAll("/tmp/test_repo")
})
}

@ -0,0 +1,58 @@
package base
import (
"errors"
"net/url"
"regexp"
"strings"
)
var (
scpSyntaxRe = regexp.MustCompile(`^(\w+)@([\w.-]+):(.*)$`)
scheme = []string{"git", "https", "http", "git+ssh", "ssh", "file", "ftp", "ftps"}
)
// ParseVCSUrl ref https://github.com/golang/go/blob/master/src/cmd/go/internal/vcs/vcs.go
// see https://go-review.googlesource.com/c/go/+/12226/
// git url define https://git-scm.com/docs/git-clone#_git_urls
func ParseVCSUrl(repo string) (*url.URL, error) {
var (
repoURL *url.URL
err error
)
if m := scpSyntaxRe.FindStringSubmatch(repo); m != nil {
// Match SCP-like syntax and convert it to a URL.
// Eg, "git@github.com:user/repo" becomes
// "ssh://git@github.com/user/repo".
repoURL = &url.URL{
Scheme: "ssh",
User: url.User(m[1]),
Host: m[2],
Path: m[3],
}
} else {
if !strings.Contains(repo, "//") {
repo = "//" + repo
}
if strings.HasPrefix(repo, "//git@") {
repo = "ssh:" + repo
} else if strings.HasPrefix(repo, "//") {
repo = "https:" + repo
}
repoURL, err = url.Parse(repo)
if err != nil {
return nil, err
}
}
// Iterate over insecure schemes too, because this function simply
// reports the state of the repo. If we can't see insecure schemes then
// we can't report the actual repo URL.
for _, s := range scheme {
if repoURL.Scheme == s {
return repoURL, nil
}
}
return nil, errors.New("unable to parse repo url")
}

@ -0,0 +1,55 @@
package base
import (
"net"
"strings"
"testing"
)
func TestParseVCSUrl(t *testing.T) {
repos := []string{
// ssh://[user@]host.xz[:port]/path/to/repo.git/
"ssh://git@github.com:7875/go-kratos/kratos.git",
// git://host.xz[:port]/path/to/repo.git/
"git://github.com:7875/go-kratos/kratos.git",
// http[s]://host.xz[:port]/path/to/repo.git/
"https://github.com:7875/go-kratos/kratos.git",
// ftp[s]://host.xz[:port]/path/to/repo.git/
"ftps://github.com:7875/go-kratos/kratos.git",
//[user@]host.xz:path/to/repo.git/
"git@github.com:go-kratos/kratos.git",
// ssh://[user@]host.xz[:port]/~[user]/path/to/repo.git/
"ssh://git@github.com:7875/go-kratos/kratos.git",
// git://host.xz[:port]/~[user]/path/to/repo.git/
"git://github.com:7875/go-kratos/kratos.git",
//[user@]host.xz:/~[user]/path/to/repo.git/
"git@github.com:go-kratos/kratos.git",
///path/to/repo.git/
"~/go-kratos/kratos.git",
// file:///path/to/repo.git/
"file://~/go-kratos/kratos.git",
}
for _, repo := range repos {
url, err := ParseVCSUrl(repo)
if err != nil {
t.Fatal(repo, err)
}
urlPath := strings.TrimLeft(url.Path, "/")
if urlPath != "go-kratos/kratos.git" {
t.Fatal(repo, "parse url failed", urlPath)
}
}
}
func TestParseSsh(t *testing.T) {
repo := "ssh://git@github.com:7875/go-kratos/kratos.git"
url, err := ParseVCSUrl(repo)
if err != nil {
t.Fatal(err)
}
host, _, err := net.SplitHostPort(url.Host)
if err != nil {
host = url.Host
}
t.Log(host, url.Path)
}

@ -0,0 +1,45 @@
package change
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
// CmdChange is kratos change log tool
var CmdChange = &cobra.Command{
Use: "changelog",
Short: "Get a kratos change log",
Long: "Get a kratos release or commits info. Example: kratos changelog dev or kratos changelog {version}",
Run: run,
}
var (
token string
repoURL string
)
func init() {
if repoURL = os.Getenv("KRATOS_REPO"); repoURL == "" {
repoURL = "https://github.com/go-kratos/kratos.git"
}
CmdChange.Flags().StringVarP(&repoURL, "repo-url", "r", repoURL, "github repo")
token = os.Getenv("GITHUB_TOKEN")
}
func run(_ *cobra.Command, args []string) {
owner, repo := ParseGithubURL(repoURL)
api := GithubAPI{Owner: owner, Repo: repo, Token: token}
version := "latest"
if len(args) > 0 {
version = args[0]
}
if version == "dev" {
info := api.GetCommitsInfo()
fmt.Print(ParseCommitsInfo(info))
return
}
info := api.GetReleaseInfo(version)
fmt.Print(ParseReleaseInfo(info))
}

@ -0,0 +1,213 @@
package change
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"regexp"
"strings"
"time"
)
type ReleaseInfo struct {
Author struct {
Login string `json:"login"`
} `json:"author"`
PublishedAt string `json:"published_at"`
Body string `json:"body"`
HTMLURL string `json:"html_url"`
}
type CommitInfo struct {
Commit struct {
Message string `json:"message"`
} `json:"commit"`
}
type ErrorInfo struct {
Message string
}
type GithubAPI struct {
Owner string
Repo string
Token string
}
// GetReleaseInfo for getting kratos release info.
func (g *GithubAPI) GetReleaseInfo(version string) ReleaseInfo {
api := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", g.Owner, g.Repo)
if version != "latest" {
api = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/tags/%s", g.Owner, g.Repo, version)
}
resp, code := requestGithubAPI(api, http.MethodGet, nil, g.Token)
if code != http.StatusOK {
printGithubErrorInfo(resp)
}
releaseInfo := ReleaseInfo{}
err := json.Unmarshal(resp, &releaseInfo)
if err != nil {
fatal(err)
}
return releaseInfo
}
// GetCommitsInfo for getting kratos commits info.
func (g *GithubAPI) GetCommitsInfo() []CommitInfo {
info := g.GetReleaseInfo("latest")
page := 1
prePage := 100
var list []CommitInfo
for {
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/commits?pre_page=%d&page=%d&since=%s", g.Owner, g.Repo, prePage, page, info.PublishedAt)
resp, code := requestGithubAPI(url, http.MethodGet, nil, g.Token)
if code != http.StatusOK {
printGithubErrorInfo(resp)
}
var res []CommitInfo
err := json.Unmarshal(resp, &res)
if err != nil {
fatal(err)
}
list = append(list, res...)
if len(res) < prePage {
break
}
page++
}
return list
}
func printGithubErrorInfo(body []byte) {
errorInfo := &ErrorInfo{}
err := json.Unmarshal(body, errorInfo)
if err != nil {
fatal(err)
}
fatal(errors.New(errorInfo.Message))
}
func requestGithubAPI(url string, method string, body io.Reader, token string) ([]byte, int) {
cli := &http.Client{Timeout: 60 * time.Second}
request, err := http.NewRequest(method, url, body)
if err != nil {
fatal(err)
}
if token != "" {
request.Header.Add("Authorization", token)
}
resp, err := cli.Do(request)
if err != nil {
fatal(err)
}
defer resp.Body.Close()
resBody, err := io.ReadAll(resp.Body)
if err != nil {
fatal(err)
}
return resBody, resp.StatusCode
}
func ParseCommitsInfo(info []CommitInfo) string {
group := map[string][]string{
"fix": {},
"feat": {},
"deps": {},
"break": {},
"chore": {},
"other": {},
}
for _, commitInfo := range info {
msg := commitInfo.Commit.Message
index := strings.Index(fmt.Sprintf("%q", msg), `\n`)
if index != -1 {
msg = msg[:index-1]
}
prefix := []string{"fix", "feat", "deps", "break", "chore"}
var matched bool
for _, v := range prefix {
msg = strings.TrimPrefix(msg, " ")
if strings.HasPrefix(msg, v) {
group[v] = append(group[v], msg)
matched = true
}
}
if !matched {
group["other"] = append(group["other"], msg)
}
}
md := make(map[string]string)
for key, value := range group {
var text string
switch key {
case "break":
text = "### Breaking Changes\n"
case "deps":
text = "### Dependencies\n"
case "feat":
text = "### New Features\n"
case "fix":
text = "### Bug Fixes\n"
case "chore":
text = "### Chores\n"
case "other":
text = "### Others\n"
}
if len(value) == 0 {
continue
}
md[key] += text
for _, value := range value {
md[key] += fmt.Sprintf("- %s\n", value)
}
}
return fmt.Sprint(md["break"], md["deps"], md["feat"], md["fix"], md["chore"], md["other"])
}
func ParseReleaseInfo(info ReleaseInfo) string {
reg := regexp.MustCompile(`(?m)^\s*$[\r\n]*|[\r\n]+\s+\z|<[\S\s]+?>`)
body := reg.ReplaceAll([]byte(info.Body), []byte(""))
if string(body) == "" {
body = []byte("no release info")
}
splitters := "--------------------------------------------"
return fmt.Sprintf(
"Author: %s\nDate: %s\nUrl: %s\n\n%s\n\n%s\n\n%s\n",
info.Author.Login,
info.PublishedAt,
info.HTMLURL,
splitters,
body,
splitters,
)
}
func ParseGithubURL(url string) (owner string, repo string) {
var start int
start = strings.Index(url, "//")
if start == -1 {
start = strings.Index(url, ":") + 1
} else {
start += 2
}
end := strings.LastIndex(url, "/")
gitIndex := strings.LastIndex(url, ".git")
if gitIndex == -1 {
repo = url[strings.LastIndex(url, "/")+1:]
} else {
repo = url[strings.LastIndex(url, "/")+1 : gitIndex]
}
tmp := url[start:end]
owner = tmp[strings.Index(tmp, "/")+1:]
return
}
func fatal(err error) {
fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", err)
os.Exit(1)
}

@ -0,0 +1,25 @@
package change
import "testing"
func TestParseGithubURL(t *testing.T) {
urls := []struct {
url string
owner string
repo string
}{
{"https://github.com/go-kratos/kratos.git", "go-kratos", "kratos"},
{"https://github.com/go-kratos/kratos", "go-kratos", "kratos"},
{"git@github.com:go-kratos/kratos.git", "go-kratos", "kratos"},
{"https://github.com/go-kratos/go-kratos.dev.git", "go-kratos", "go-kratos.dev"},
}
for _, url := range urls {
owner, repo := ParseGithubURL(url.url)
if owner != url.owner {
t.Fatalf("owner want: %s, got: %s", owner, url.owner)
}
if repo != url.repo {
t.Fatalf("repo want: %s, got: %s", repo, url.repo)
}
}
}

@ -0,0 +1,67 @@
package project
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/AlecAivazis/survey/v2"
"github.com/fatih/color"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
var repoAddIgnores = []string{
".git", ".github", "api", "README.md", "LICENSE", "go.mod", "go.sum", "third_party", "openapi.yaml", ".gitignore",
}
func (p *Project) Add(ctx context.Context, dir string, layout string, branch string, mod string) error {
to := filepath.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.",
}
e := survey.AskOne(prompt, &override)
if e != nil {
return e
}
if !override {
return err
}
os.RemoveAll(to)
}
fmt.Printf("🚀 Add service %s, layout repo is %s, please wait a moment.\n\n", p.Name, layout)
repo := base.NewRepo(layout, branch)
if err := repo.CopyToV2(ctx, to, filepath.Join(mod, p.Path), repoAddIgnores, []string{filepath.Join(p.Path, "api"), "api"}); err != nil {
return err
}
e := os.Rename(
filepath.Join(to, "cmd", "server"),
filepath.Join(to, "cmd", p.Name),
)
if e != nil {
return e
}
base.Tree(to, dir)
fmt.Printf("\n🍺 Repository creation succeeded %s\n", color.GreenString(p.Name))
fmt.Print("💻 Use the following command to add a project 👇:\n\n")
fmt.Println(color.WhiteString("$ cd %s", p.Name))
fmt.Println(color.WhiteString("$ go generate ./..."))
fmt.Println(color.WhiteString("$ go build -o ./bin/ ./... "))
fmt.Println(color.WhiteString("$ ./bin/%s -conf ./configs\n", p.Name))
fmt.Println(" 🤝 Thanks for using Kratos")
fmt.Println(" 📚 Tutorial: https://go-kratos.dev/docs/getting-started/start")
return nil
}

@ -0,0 +1,64 @@
package project
import (
"context"
"fmt"
"os"
"path/filepath"
"github.com/AlecAivazis/survey/v2"
"github.com/fatih/color"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
// Project is a project template.
type Project struct {
Name string
Path string
}
// New new a project from remote repo.
func (p *Project) New(ctx context.Context, dir string, layout string, branch string) error {
to := filepath.Join(dir, p.Name)
if _, err := os.Stat(to); !os.IsNotExist(err) {
fmt.Printf("🚫 %s already exists\n", p.Name)
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
}
if !override {
return err
}
os.RemoveAll(to)
}
fmt.Printf("🚀 Creating service %s, layout repo is %s, please wait a moment.\n\n", p.Name, layout)
repo := base.NewRepo(layout, branch)
if err := repo.CopyTo(ctx, to, p.Name, []string{".git", ".github"}); err != nil {
return err
}
e := os.Rename(
filepath.Join(to, "cmd", "server"),
filepath.Join(to, "cmd", p.Name),
)
if e != nil {
return e
}
base.Tree(to, dir)
fmt.Printf("\n🍺 Project creation succeeded %s\n", color.GreenString(p.Name))
fmt.Print("💻 Use the following command to start the project 👇:\n\n")
fmt.Println(color.WhiteString("$ cd %s", p.Name))
fmt.Println(color.WhiteString("$ go generate ./..."))
fmt.Println(color.WhiteString("$ go build -o ./bin/ ./... "))
fmt.Println(color.WhiteString("$ ./bin/%s -conf ./configs\n", p.Name))
fmt.Println(" 🤝 Thanks for using Kratos")
fmt.Println(" 📚 Tutorial: https://go-kratos.dev/docs/getting-started/start")
return nil
}

@ -0,0 +1,149 @@
package project
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/AlecAivazis/survey/v2"
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
// CmdNew represents the new command.
var CmdNew = &cobra.Command{
Use: "new",
Short: "Create a service template",
Long: "Create a service project using the repository template. Example: kratos new helloworld",
Run: run,
}
var (
repoURL string
branch string
timeout string
nomod bool
)
func init() {
if repoURL = os.Getenv("KRATOS_LAYOUT_REPO"); repoURL == "" {
repoURL = "https://github.com/go-kratos/kratos-layout.git"
}
timeout = "60s"
CmdNew.Flags().StringVarP(&repoURL, "repo-url", "r", repoURL, "layout repo")
CmdNew.Flags().StringVarP(&branch, "branch", "b", branch, "repo branch")
CmdNew.Flags().StringVarP(&timeout, "timeout", "t", timeout, "time out")
CmdNew.Flags().BoolVarP(&nomod, "nomod", "", nomod, "retain go mod")
}
func run(_ *cobra.Command, args []string) {
wd, err := os.Getwd()
if err != nil {
panic(err)
}
t, err := time.ParseDuration(timeout)
if err != nil {
panic(err)
}
ctx, cancel := context.WithTimeout(context.Background(), t)
defer cancel()
name := ""
if len(args) == 0 {
prompt := &survey.Input{
Message: "What is project name ?",
Help: "Created project name.",
}
err = survey.AskOne(prompt, &name)
if err != nil || name == "" {
return
}
} else {
name = args[0]
}
projectName, workingDir := processProjectParams(name, wd)
p := &Project{Name: projectName}
done := make(chan error, 1)
go func() {
if !nomod {
done <- p.New(ctx, workingDir, repoURL, branch)
return
}
projectRoot := getgomodProjectRoot(workingDir)
if gomodIsNotExistIn(projectRoot) {
done <- fmt.Errorf("🚫 go.mod don't exists in %s", projectRoot)
return
}
p.Path, err = filepath.Rel(projectRoot, filepath.Join(workingDir, projectName))
if err != nil {
done <- fmt.Errorf("🚫 failed to get relative path: %v", err)
return
}
mod, e := base.ModulePath(filepath.Join(projectRoot, "go.mod"))
if e != nil {
done <- fmt.Errorf("🚫 failed to parse `go.mod`: %v", e)
return
}
// Get the relative path for adding a project based on Go modules
p.Path = filepath.Join(strings.TrimPrefix(workingDir, projectRoot+"/"), p.Name)
done <- p.Add(ctx, workingDir, repoURL, branch, mod)
}()
select {
case <-ctx.Done():
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
fmt.Fprint(os.Stderr, "\033[31mERROR: project creation timed out\033[m\n")
return
}
fmt.Fprintf(os.Stderr, "\033[31mERROR: failed to create project(%s)\033[m\n", ctx.Err().Error())
case err = <-done:
if err != nil {
fmt.Fprintf(os.Stderr, "\033[31mERROR: Failed to create project(%s)\033[m\n", err.Error())
}
}
}
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 _projectDir, _workingDir
}
_projectDir = filepath.Join(homeDir, projectName[2:])
}
// check path is relative
if !filepath.IsAbs(projectName) {
absPath, err := filepath.Abs(projectName)
if err != nil {
return _projectDir, _workingDir
}
_projectDir = absPath
}
return filepath.Base(_projectDir), filepath.Dir(_projectDir)
}
func getgomodProjectRoot(dir string) string {
if dir == filepath.Dir(dir) {
return dir
}
if gomodIsNotExistIn(dir) {
return getgomodProjectRoot(filepath.Dir(dir))
}
return dir
}
func gomodIsNotExistIn(dir string) bool {
_, e := os.Stat(filepath.Join(dir, "go.mod"))
return os.IsNotExist(e)
}

@ -0,0 +1,29 @@
//go:build linux
// +build linux
package project
import (
"testing"
)
func Test_processProjectParams(t *testing.T) {
type args struct {
projectName string
fallbackPlaceDir string
}
tests := []struct {
name string
args args
want string
}{
{"absLinux", args{projectName: "/home/kratos/awesome/go/demo", fallbackPlaceDir: ""}, "/home/kratos/awesome/go"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if _, got := processProjectParams(tt.args.projectName, tt.args.fallbackPlaceDir); got != tt.want {
t.Errorf("processProjectParams() = %v, want %v", got, tt.want)
}
})
}
}

@ -0,0 +1,144 @@
package project
import (
"fmt"
"go/parser"
"go/token"
"os"
"path/filepath"
"testing"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
// TestCmdNew tests the `kratos new` command.
func TestCmdNew(t *testing.T) {
cwd := changeCurrentDir(t)
projectName := "helloworld"
// create a new project
CmdNew.SetArgs([]string{projectName})
if err := CmdNew.Execute(); err != nil {
t.Fatalf("executing command: %v", err)
}
// check that the expected files were created
for _, file := range []string{
"go.mod",
"go.sum",
"README.md",
"cmd/helloworld/main.go",
} {
if _, err := os.Stat(filepath.Join(cwd, projectName, file)); err != nil {
t.Errorf("expected file %s to exist", file)
}
}
// check that the go.mod file contains the expected module name
assertGoMod(t, filepath.Join(cwd, projectName, "go.mod"), projectName)
assertImportsInclude(t, filepath.Join(cwd, projectName, "cmd", projectName, "wire.go"), fmt.Sprintf(`"%s/internal/biz"`, projectName))
}
// TestCmdNewNoMod tests the `kratos new` command with the --nomod flag.
func TestCmdNewNoMod(t *testing.T) {
cwd := changeCurrentDir(t)
// create a new project
CmdNew.SetArgs([]string{"project"})
if err := CmdNew.Execute(); err != nil {
t.Fatalf("executing command: %v", err)
}
// add new app with --nomod flag
CmdNew.SetArgs([]string{"--nomod", "project/app/user"})
if err := CmdNew.Execute(); err != nil {
t.Fatalf("executing command: %v", err)
}
// check that the expected files were created
for _, file := range []string{
"go.mod",
"go.sum",
"README.md",
"cmd/project/main.go",
"app/user/cmd/user/main.go",
} {
if _, err := os.Stat(filepath.Join(cwd, "project", file)); err != nil {
t.Errorf("expected file %s to exist", file)
}
}
assertImportsInclude(t, filepath.Join(cwd, "project/app/user/cmd/user/wire.go"), `"project/app/user/internal/biz"`)
}
// assertImportsInclude checks that the file at path contains the expected import.
func assertImportsInclude(t *testing.T, path, expected string) {
t.Helper()
got, err := imports(path)
if err != nil {
t.Fatalf("getting imports: %v", err)
}
for _, imp := range got {
if imp == expected {
return
}
}
t.Errorf("expected imports to include %s, got %v", expected, got)
}
// imports returns the imports in the file at path.
func imports(path string) ([]string, error) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
if err != nil {
return nil, err
}
imports := make([]string, 0, len(f.Imports))
for _, s := range f.Imports {
imports = append(imports, s.Path.Value)
}
return imports, nil
}
// assertGoMod checks that the go.mod file contains the expected module name.
func assertGoMod(t *testing.T, path, expected string) {
t.Helper()
got, err := base.ModulePath(path)
if err != nil {
t.Fatalf("getting module path: %v", err)
}
if got != expected {
t.Errorf("expected module name %s, got %s", expected, got)
}
}
// change the working directory to the tempdir
func changeCurrentDir(t *testing.T) string {
t.Helper()
tmp := t.TempDir()
oldCWD, err := os.Getwd()
if err != nil {
t.Fatalf("getting working directory: %v", err)
}
if err := os.Chdir(tmp); err != nil {
t.Fatalf("changing working directory: %v", err)
}
t.Cleanup(func() {
if err := os.Chdir(oldCWD); err != nil {
t.Fatalf("restoring working directory: %v", err)
}
})
return tmp
}

@ -0,0 +1,30 @@
//go:build windows
// +build windows
package project
import (
"testing"
)
func Test_processProjectParams(t *testing.T) {
type args struct {
projectName string
fallbackPlaceDir string
}
tests := []struct {
name string
args args
want string
}{
{"absWindows", args{projectName: "c:\\kratos\\awesome\\go\\demo", fallbackPlaceDir: ""}, "c:\\kratos\\awesome\\go"},
//{"relativeWindows", args{projectName: "/home/kratos/awesome/go/demo", fallbackPlaceDir: ""}, "/home/kratos/awesome/go"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if _, got := processProjectParams(tt.args.projectName, tt.args.fallbackPlaceDir); got != tt.want {
t.Errorf("getProjectPlaceDir() = %v, want %v", got, tt.want)
}
})
}
}

@ -0,0 +1,78 @@
package add
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"golang.org/x/mod/modfile"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
// CmdAdd represents the add command.
var CmdAdd = &cobra.Command{
Use: "add",
Short: "Add a proto API template",
Long: "Add a proto API template. Example: kratos proto add helloworld/v1/hello.proto",
Run: run,
}
func run(_ *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Println("Please enter the proto file or directory")
return
}
input := args[0]
n := strings.LastIndex(input, "/")
if n == -1 {
fmt.Println("The proto path needs to be hierarchical.")
return
}
path := input[:n]
fileName := input[n+1:]
pkgName := strings.ReplaceAll(path, "/", ".")
p := &Proto{
Name: fileName,
Path: path,
Package: pkgName,
GoPackage: goPackage(path),
JavaPackage: javaPackage(pkgName),
Service: serviceName(fileName),
}
if err := p.Generate(); err != nil {
fmt.Println(err)
return
}
}
func modName() string {
modBytes, err := os.ReadFile("go.mod")
if err != nil {
if modBytes, err = os.ReadFile("../go.mod"); err != nil {
return ""
}
}
return modfile.ModulePath(modBytes)
}
func goPackage(path string) string {
s := strings.Split(path, "/")
return modName() + "/" + path + ";" + s[len(s)-1]
}
func javaPackage(name string) string {
return name
}
func serviceName(name string) string {
return toUpperCamelCase(strings.Split(name, ".")[0])
}
func toUpperCamelCase(s string) string {
s = strings.ReplaceAll(s, "_", " ")
s = cases.Title(language.Und, cases.NoLower).String(s)
return strings.ReplaceAll(s, " ", "")
}

@ -0,0 +1,38 @@
package add
import "testing"
func TestUnderscoreToUpperCamelCase(t *testing.T) {
tests := []struct {
name string
want string
}{
{
name: "hello_world",
want: "HelloWorld",
},
{
name: "v2_kratos_dev",
want: "V2KratosDev",
},
{
name: "www_Google_com",
want: "WwwGoogleCom",
},
{
name: "wwwBaidu_com",
want: "WwwBaiduCom",
},
{
name: "HelloWorld",
want: "HelloWorld",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := toUpperCamelCase(tt.name); got != tt.want {
t.Errorf("toUpperCamelCase() = %v, want %v", got, tt.want)
}
})
}
}

@ -0,0 +1,40 @@
package add
import (
"fmt"
"os"
"path/filepath"
)
// Proto is a proto generator.
type Proto struct {
Name string
Path string
Service string
Package string
GoPackage string
JavaPackage string
}
// Generate generate a proto template.
func (p *Proto) Generate() error {
body, err := p.execute()
if err != nil {
return err
}
wd, err := os.Getwd()
if err != nil {
panic(err)
}
to := filepath.Join(wd, p.Path)
if _, err := os.Stat(to); os.IsNotExist(err) {
if err := os.MkdirAll(to, 0o700); err != nil {
return err
}
}
name := filepath.Join(to, p.Name)
if _, err := os.Stat(name); !os.IsNotExist(err) {
return fmt.Errorf("%s already exists", p.Name)
}
return os.WriteFile(name, body, 0o644)
}

@ -0,0 +1,52 @@
package add
import (
"bytes"
"strings"
"text/template"
)
const protoTemplate = `
syntax = "proto3";
package {{.Package}};
option go_package = "{{.GoPackage}}";
option java_multiple_files = true;
option java_package = "{{.JavaPackage}}";
service {{.Service}} {
rpc Create{{.Service}} (Create{{.Service}}Request) returns (Create{{.Service}}Reply);
rpc Update{{.Service}} (Update{{.Service}}Request) returns (Update{{.Service}}Reply);
rpc Delete{{.Service}} (Delete{{.Service}}Request) returns (Delete{{.Service}}Reply);
rpc Get{{.Service}} (Get{{.Service}}Request) returns (Get{{.Service}}Reply);
rpc List{{.Service}} (List{{.Service}}Request) returns (List{{.Service}}Reply);
}
message Create{{.Service}}Request {}
message Create{{.Service}}Reply {}
message Update{{.Service}}Request {}
message Update{{.Service}}Reply {}
message Delete{{.Service}}Request {}
message Delete{{.Service}}Reply {}
message Get{{.Service}}Request {}
message Get{{.Service}}Reply {}
message List{{.Service}}Request {}
message List{{.Service}}Reply {}
`
func (p *Proto) execute() ([]byte, error) {
buf := new(bytes.Buffer)
tmpl, err := template.New("proto").Parse(strings.TrimSpace(protoTemplate))
if err != nil {
return nil, err
}
if err := tmpl.Execute(buf, p); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

@ -0,0 +1,130 @@
package client
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
// CmdClient represents the source command.
var CmdClient = &cobra.Command{
Use: "client",
Short: "Generate the proto client code",
Long: "Generate the proto client code. Example: kratos proto client helloworld.proto",
Run: run,
}
var protoPath string
func init() {
if protoPath = os.Getenv("KRATOS_PROTO_PATH"); protoPath == "" {
protoPath = "./third_party"
}
CmdClient.Flags().StringVarP(&protoPath, "proto_path", "p", protoPath, "proto path")
}
func run(_ *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Println("Please enter the proto file or directory")
return
}
var (
err error
proto = strings.TrimSpace(args[0])
)
if err = look("protoc-gen-go", "protoc-gen-go-grpc", "protoc-gen-go-http", "protoc-gen-go-errors", "protoc-gen-openapi"); err != nil {
// update the kratos plugins
cmd := exec.Command("kratos", "upgrade")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err = cmd.Run(); err != nil {
fmt.Println(err)
return
}
}
if strings.HasSuffix(proto, ".proto") {
err = generate(proto, args)
} else {
err = walk(proto, args)
}
if err != nil {
fmt.Println(err)
}
}
func look(name ...string) error {
for _, n := range name {
if _, err := exec.LookPath(n); err != nil {
return err
}
}
return nil
}
func walk(dir string, args []string) error {
if dir == "" {
dir = "."
}
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if ext := filepath.Ext(path); ext != ".proto" || strings.HasPrefix(path, "third_party") {
return nil
}
return generate(path, args)
})
}
// generate is used to execute the generate command for the specified proto file
func generate(proto string, args []string) error {
input := []string{
"--proto_path=.",
}
if pathExists(protoPath) {
input = append(input, "--proto_path="+protoPath)
}
inputExt := []string{
"--proto_path=" + base.KratosMod(),
"--proto_path=" + filepath.Join(base.KratosMod(), "third_party"),
"--go_out=paths=source_relative:.",
"--go-grpc_out=paths=source_relative:.",
"--go-http_out=paths=source_relative:.",
"--go-errors_out=paths=source_relative:.",
"--openapi_out=paths=source_relative:.",
}
input = append(input, inputExt...)
protoBytes, err := os.ReadFile(proto)
if err == nil && len(protoBytes) > 0 {
if ok, _ := regexp.Match(`\n[^/]*(import)\s+"validate/validate.proto"`, protoBytes); ok {
input = append(input, "--validate_out=lang=go,paths=source_relative:.")
}
}
input = append(input, proto)
for _, a := range args {
if strings.HasPrefix(a, "-") {
input = append(input, a)
}
}
fd := exec.Command("protoc", input...)
fd.Stdout = os.Stdout
fd.Stderr = os.Stderr
fd.Dir = "."
if err := fd.Run(); err != nil {
return err
}
fmt.Printf("proto: %s\n", proto)
return nil
}
func pathExists(path string) bool {
_, err := os.Stat(path)
if err != nil {
return os.IsExist(err)
}
return true
}

@ -0,0 +1,22 @@
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"
)
// CmdProto represents the proto command.
var CmdProto = &cobra.Command{
Use: "proto",
Short: "Generate the proto files",
Long: "Generate the proto files.",
}
func init() {
CmdProto.AddCommand(add.CmdAdd)
CmdProto.AddCommand(client.CmdClient)
CmdProto.AddCommand(server.CmdServer)
}

@ -0,0 +1,120 @@
package server
import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"github.com/emicklei/proto"
"github.com/spf13/cobra"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
// CmdServer the service command.
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",
Run: run,
}
var targetDir string
func init() {
CmdServer.Flags().StringVarP(&targetDir, "target-dir", "t", "internal/service", "generate target directory")
}
func run(_ *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "Please specify the proto file. Example: kratos proto server api/xxx.proto")
return
}
reader, err := os.Open(args[0])
if err != nil {
log.Fatal(err)
}
defer reader.Close()
parser := proto.NewParser(reader)
definition, err := parser.Parse()
if err != nil {
log.Fatal(err)
}
var (
pkg string
res []*Service
)
proto.Walk(definition,
proto.WithOption(func(o *proto.Option) {
if o.Name == "go_package" {
pkg = strings.Split(o.Constant.Source, ";")[0]
}
}),
proto.WithService(func(s *proto.Service) {
cs := &Service{
Package: pkg,
Service: serviceName(s.Name),
}
for _, e := range s.Elements {
r, ok := e.(*proto.RPC)
if !ok {
continue
}
cs.Methods = append(cs.Methods, &Method{
Service: serviceName(s.Name), Name: serviceName(r.Name), Request: parametersName(r.RequestType),
Reply: parametersName(r.ReturnsType), Type: getMethodType(r.StreamsRequest, r.StreamsReturns),
})
}
res = append(res, cs)
}),
)
if _, err := os.Stat(targetDir); os.IsNotExist(err) {
fmt.Printf("Target directory: %s does not exsit\n", targetDir)
return
}
for _, s := range res {
to := filepath.Join(targetDir, strings.ToLower(s.Service)+".go")
if _, err := os.Stat(to); !os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "%s already exists: %s\n", s.Service, to)
continue
}
b, err := s.execute()
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile(to, b, 0o644); err != nil {
log.Fatal(err)
}
fmt.Println(to)
}
}
func getMethodType(streamsRequest, streamsReturns bool) MethodType {
if !streamsRequest && !streamsReturns {
return unaryType
} else if streamsRequest && streamsReturns {
return twoWayStreamsType
} else if streamsRequest {
return requestStreamsType
} else if streamsReturns {
return returnsStreamsType
}
return unaryType
}
func parametersName(name string) string {
return strings.ReplaceAll(name, ".", "_")
}
func serviceName(name string) string {
return toUpperCamelCase(strings.Split(name, ".")[0])
}
func toUpperCamelCase(s string) string {
s = strings.ReplaceAll(s, "_", " ")
s = cases.Title(language.Und, cases.NoLower).String(s)
return strings.ReplaceAll(s, " ", "")
}

@ -0,0 +1,102 @@
package server
import "testing"
func Test_serviceName(t *testing.T) {
type args struct {
str string
}
tests := []struct {
name string
args args
want string
}{
{
name: "serviceName on lowercase words",
args: args{str: "helloworld"},
want: "Helloworld",
},
{
name: "serviceName on uppercase words",
args: args{str: "HELLOWORLD"},
want: "HELLOWORLD",
},
{
name: "serviceName on lowercase words with spaces",
args: args{str: "hello world"},
want: "HelloWorld",
},
{
name: "serviceName on uppercase words with spaces",
args: args{str: "HELLO WORLD"},
want: "HELLOWORLD",
},
{
name: "serviceName on Lower Camel Case words",
args: args{str: "helloWorld"},
want: "HelloWorld",
},
{
name: "serviceName on Lower Camel Case words",
args: args{str: "helloWorld"},
want: "HelloWorld",
},
{
name: "serviceName on Upper Camel Case words",
args: args{str: "HelloWorld"},
want: "HelloWorld",
},
{
name: "serviceName on Upper Camel Case words",
args: args{str: "hello_world"},
want: "HelloWorld",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := serviceName(tt.args.str); got != tt.want {
t.Errorf("serviceName() = %v, want %v", got, tt.want)
}
})
}
}
func Test_parametersName(t *testing.T) {
type args struct {
name string
}
tests := []struct {
name string
args args
want string
}{
{
name: "parametersName on not nested",
args: args{
name: "MessageResponse",
},
want: "MessageResponse",
},
{
name: "parametersName on One layer of nesting",
args: args{
name: "Message.Response",
},
want: "Message_Response",
},
{
name: "parametersName on Two layer of nesting",
args: args{
name: "Message.Message2.Response",
},
want: "Message_Message2_Response",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := parametersName(tt.args.name); got != tt.want {
t.Errorf("parametersName() = %v, want %v", got, tt.want)
}
})
}
}

@ -0,0 +1,142 @@
package server
import (
"bytes"
"html/template"
)
//nolint:lll
var serviceTemplate = `
{{- /* delete empty line */ -}}
package service
import (
{{- if .UseContext }}
"context"
{{- end }}
{{- if .UseIO }}
"io"
{{- end }}
pb "{{ .Package }}"
{{- if .GoogleEmpty }}
"google.golang.org/protobuf/types/known/emptypb"
{{- end }}
)
type {{ .Service }}Service struct {
pb.Unimplemented{{ .Service }}Server
}
func New{{ .Service }}Service() *{{ .Service }}Service {
return &{{ .Service }}Service{}
}
{{- $s1 := "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
}
{{- else if eq .Type 2 }}
func (s *{{ .Service }}Service) {{ .Name }}(conn pb.{{ .Service }}_{{ .Name }}Server) error {
for {
req, err := conn.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
err = conn.Send(&pb.{{ .Reply }}{})
if err != nil {
return err
}
}
}
{{- else if eq .Type 3 }}
func (s *{{ .Service }}Service) {{ .Name }}(conn pb.{{ .Service }}_{{ .Name }}Server) error {
for {
req, err := conn.Recv()
if err == io.EOF {
return conn.SendAndClose(&pb.{{ .Reply }}{})
}
if err != nil {
return err
}
}
}
{{- 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
}
}
}
{{- end }}
{{- end }}
`
type MethodType uint8
const (
unaryType MethodType = 1
twoWayStreamsType MethodType = 2
requestStreamsType MethodType = 3
returnsStreamsType MethodType = 4
)
// Service is a proto service.
type Service struct {
Package string
Service string
Methods []*Method
GoogleEmpty bool
UseIO bool
UseContext bool
}
// Method is a proto method.
type Method struct {
Service string
Name string
Request string
Reply string
// type: unary or stream
Type MethodType
}
func (s *Service) execute() ([]byte, error) {
const empty = "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) {
s.GoogleEmpty = true
}
if method.Type == twoWayStreamsType || method.Type == requestStreamsType {
s.UseIO = true
}
if method.Type == unaryType {
s.UseContext = true
}
}
tmpl, err := template.New("service").Parse(serviceTemplate)
if err != nil {
return nil, err
}
if err := tmpl.Execute(buf, s); err != nil {
return nil, err
}
return buf.Bytes(), nil
}

@ -0,0 +1,145 @@
package run
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/spf13/cobra"
)
// CmdRun run project command.
var CmdRun = &cobra.Command{
Use: "run",
Short: "Run project",
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) {
var dir string
cmdArgs, programArgs := splitArgs(cmd, args)
if len(cmdArgs) > 0 {
dir = cmdArgs[0]
}
base, err := os.Getwd()
if err != nil {
fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", err)
return
}
if dir == "" {
// find the directory containing the cmd/*
cmdPath, err := findCMD(base)
if err != nil {
fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", err)
return
}
switch len(cmdPath) {
case 0:
fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", "The cmd directory cannot be found in the current directory")
return
case 1:
for _, v := range cmdPath {
dir = v
}
default:
var cmdPaths []string
for k := range cmdPath {
cmdPaths = append(cmdPaths, k)
}
prompt := &survey.Select{
Message: "Which directory do you want to run?",
Options: cmdPaths,
PageSize: 10,
}
e := survey.AskOne(prompt, &dir)
if e != nil || dir == "" {
return
}
dir = cmdPath[dir]
}
}
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
}
}
func splitArgs(cmd *cobra.Command, args []string) (cmdArgs, programArgs []string) {
dashAt := cmd.ArgsLenAtDash()
if dashAt >= 0 {
return args[:dashAt], args[dashAt:]
}
return args, []string{}
}
func findCMD(base string) (map[string]string, error) {
wd, err := os.Getwd()
if err != nil {
return nil, err
}
if !strings.HasSuffix(wd, "/") {
wd += "/"
}
var root bool
next := func(dir string) (map[string]string, error) {
cmdPath := make(map[string]string)
err := filepath.Walk(dir, func(walkPath string, info os.FileInfo, err error) error {
// multi level directory is not allowed under the cmdPath directory, so it is judged that the path ends with cmdPath.
if strings.HasSuffix(walkPath, "cmd") {
paths, err := os.ReadDir(walkPath)
if err != nil {
return err
}
for _, fileInfo := range paths {
if fileInfo.IsDir() {
abs := filepath.Join(walkPath, fileInfo.Name())
cmdPath[strings.TrimPrefix(abs, wd)] = abs
}
}
return nil
}
if info.Name() == "go.mod" {
root = true
}
return nil
})
return cmdPath, err
}
for i := 0; i < 5; i++ {
tmp := base
cmd, err := next(tmp)
if err != nil {
return nil, err
}
if len(cmd) > 0 {
return cmd, nil
}
if root {
break
}
_ = filepath.Join(base, "..")
}
return map[string]string{"": base}, nil
}
func changeWorkingDirectory(cmd *exec.Cmd, targetDir string) {
targetDir = strings.TrimSpace(targetDir)
if targetDir != "" {
cmd.Dir = targetDir
}
}

@ -0,0 +1,32 @@
package upgrade
import (
"fmt"
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
// CmdUpgrade represents the upgrade command.
var CmdUpgrade = &cobra.Command{
Use: "upgrade",
Short: "Upgrade the kratos tools",
Long: "Upgrade the kratos tools. Example: kratos upgrade",
Run: Run,
}
// Run upgrade the kratos tools.
func Run(_ *cobra.Command, _ []string) {
err := base.GoInstall(
"github.com/go-kratos/kratos/cmd/kratos/v2@latest",
"github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest",
"github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2@latest",
"google.golang.org/protobuf/cmd/protoc-gen-go@latest",
"google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest",
"github.com/google/gnostic/cmd/protoc-gen-openapi@latest",
)
if err != nil {
fmt.Println(err)
}
}

@ -0,0 +1,34 @@
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"
)
var rootCmd = &cobra.Command{
Use: "kratos",
Short: "Kratos: An elegant toolkit for Go microservices.",
Long: `Kratos: An elegant toolkit for Go microservices.`,
Version: release,
}
func init() {
rootCmd.AddCommand(project.CmdNew)
rootCmd.AddCommand(proto.CmdProto)
rootCmd.AddCommand(upgrade.CmdUpgrade)
rootCmd.AddCommand(change.CmdChange)
rootCmd.AddCommand(run.CmdRun)
}
func main() {
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
}
}

@ -0,0 +1,4 @@
package main
// release is the current kratos tool version.
const release = "v2.6.3"

@ -0,0 +1,135 @@
package main
import (
"fmt"
"strings"
"unicode"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/proto"
"github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2/errors"
)
const (
errorsPackage = protogen.GoImportPath("github.com/go-kratos/kratos/v2/errors")
fmtPackage = protogen.GoImportPath("fmt")
)
var enCases = cases.Title(language.AmericanEnglish, cases.NoLower)
// generateFile generates a _errors.pb.go file containing kratos errors definitions.
func generateFile(gen *protogen.Plugin, file *protogen.File) *protogen.GeneratedFile {
if len(file.Enums) == 0 {
return nil
}
filename := file.GeneratedFilenamePrefix + "_errors.pb.go"
g := gen.NewGeneratedFile(filename, file.GoImportPath)
g.P("// Code generated by protoc-gen-go-errors. DO NOT EDIT.")
g.P()
g.P("package ", file.GoPackageName)
g.P()
g.QualifiedGoIdent(fmtPackage.Ident(""))
generateFileContent(gen, file, g)
return g
}
// generateFileContent generates the kratos errors definitions, excluding the package statement.
func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile) {
if len(file.Enums) == 0 {
return
}
g.P("// This is a compile-time assertion to ensure that this generated file")
g.P("// is compatible with the kratos package it is being compiled against.")
g.P("const _ = ", errorsPackage.Ident("SupportPackageIsVersion1"))
g.P()
index := 0
for _, enum := range file.Enums {
if !genErrorsReason(gen, file, g, enum) {
index++
}
}
// If all enums do not contain 'errors.code', the current file is skipped
if index == 0 {
g.Skip()
}
}
func genErrorsReason(_ *protogen.Plugin, _ *protogen.File, g *protogen.GeneratedFile, enum *protogen.Enum) bool {
defaultCode := proto.GetExtension(enum.Desc.Options(), errors.E_DefaultCode)
code := 0
if ok := defaultCode.(int32); ok != 0 {
code = int(ok)
}
if code > 600 || code < 0 {
panic(fmt.Sprintf("Enum '%s' range must be greater than 0 and less than or equal to 600", string(enum.Desc.Name())))
}
var ew errorWrapper
for _, v := range enum.Values {
enumCode := code
eCode := proto.GetExtension(v.Desc.Options(), errors.E_Code)
if ok := eCode.(int32); ok != 0 {
enumCode = int(ok)
}
// If the current enumeration does not contain 'errors.code'
// or the code value exceeds the range, the current enum will be skipped
if enumCode > 600 || enumCode < 0 {
panic(fmt.Sprintf("Enum '%s' range must be greater than 0 and less than or equal to 600", string(v.Desc.Name())))
}
if enumCode == 0 {
continue
}
comment := v.Comments.Leading.String()
if comment == "" {
comment = v.Comments.Trailing.String()
}
err := &errorInfo{
Name: string(enum.Desc.Name()),
Value: string(v.Desc.Name()),
CamelValue: case2Camel(string(v.Desc.Name())),
HTTPCode: enumCode,
Comment: comment,
HasComment: len(comment) > 0,
}
ew.Errors = append(ew.Errors, err)
}
if len(ew.Errors) == 0 {
return true
}
g.P(ew.execute())
return false
}
func case2Camel(name string) string {
if !strings.Contains(name, "_") {
if name == strings.ToUpper(name) {
name = strings.ToLower(name)
}
return enCases.String(name)
}
strs := strings.Split(name, "_")
words := make([]string, 0, len(strs))
for _, w := range strs {
hasLower := false
for _, r := range w {
if unicode.IsLower(r) {
hasLower = true
break
}
}
if !hasLower {
w = strings.ToLower(w)
}
w = enCases.String(w)
words = append(words, w)
}
return strings.Join(words, "")
}

@ -0,0 +1,229 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.15.7
// source: errors.proto
package errors
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
descriptorpb "google.golang.org/protobuf/types/descriptorpb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Error struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"`
Reason string `protobuf:"bytes,2,opt,name=reason,proto3" json:"reason,omitempty"`
Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message,omitempty"`
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (x *Error) Reset() {
*x = Error{}
if protoimpl.UnsafeEnabled {
mi := &file_errors_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Error) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Error) ProtoMessage() {}
func (x *Error) ProtoReflect() protoreflect.Message {
mi := &file_errors_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Error.ProtoReflect.Descriptor instead.
func (*Error) Descriptor() ([]byte, []int) {
return file_errors_proto_rawDescGZIP(), []int{0}
}
func (x *Error) GetCode() int32 {
if x != nil {
return x.Code
}
return 0
}
func (x *Error) GetReason() string {
if x != nil {
return x.Reason
}
return ""
}
func (x *Error) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *Error) GetMetadata() map[string]string {
if x != nil {
return x.Metadata
}
return nil
}
var file_errors_proto_extTypes = []protoimpl.ExtensionInfo{
{
ExtendedType: (*descriptorpb.EnumOptions)(nil),
ExtensionType: (*int32)(nil),
Field: 1108,
Name: "errors.default_code",
Tag: "varint,1108,opt,name=default_code",
Filename: "errors.proto",
},
{
ExtendedType: (*descriptorpb.EnumValueOptions)(nil),
ExtensionType: (*int32)(nil),
Field: 1109,
Name: "errors.code",
Tag: "varint,1109,opt,name=code",
Filename: "errors.proto",
},
}
// Extension fields to descriptorpb.EnumOptions.
var (
// optional int32 default_code = 1108;
E_DefaultCode = &file_errors_proto_extTypes[0]
)
// Extension fields to descriptorpb.EnumValueOptions.
var (
// optional int32 code = 1109;
E_Code = &file_errors_proto_extTypes[1]
)
var File_errors_proto protoreflect.FileDescriptor
var file_errors_proto_rawDesc = []byte{
0x0a, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x01, 0x0a, 0x05, 0x45, 0x72, 0x72,
0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x18,
0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x65, 0x72, 0x72,
0x6f, 0x72, 0x73, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x40,
0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x1c,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd4, 0x08, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x64, 0x65,
0x3a, 0x36, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56,
0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd5, 0x08, 0x20, 0x01,
0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x59, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x73, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61,
0x74, 0x6f, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x3b, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x73, 0xa2, 0x02, 0x0c, 0x4b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x45, 0x72, 0x72,
0x6f, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_errors_proto_rawDescOnce sync.Once
file_errors_proto_rawDescData = file_errors_proto_rawDesc
)
func file_errors_proto_rawDescGZIP() []byte {
file_errors_proto_rawDescOnce.Do(func() {
file_errors_proto_rawDescData = protoimpl.X.CompressGZIP(file_errors_proto_rawDescData)
})
return file_errors_proto_rawDescData
}
var file_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_errors_proto_goTypes = []interface{}{
(*Error)(nil), // 0: errors.Error
nil, // 1: errors.Error.MetadataEntry
(*descriptorpb.EnumOptions)(nil), // 2: google.protobuf.EnumOptions
(*descriptorpb.EnumValueOptions)(nil), // 3: google.protobuf.EnumValueOptions
}
var file_errors_proto_depIdxs = []int32{
1, // 0: errors.Error.metadata:type_name -> errors.Error.MetadataEntry
2, // 1: errors.default_code:extendee -> google.protobuf.EnumOptions
3, // 2: errors.code:extendee -> google.protobuf.EnumValueOptions
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
1, // [1:3] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_errors_proto_init() }
func file_errors_proto_init() {
if File_errors_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_errors_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Error); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_errors_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 2,
NumServices: 0,
},
GoTypes: file_errors_proto_goTypes,
DependencyIndexes: file_errors_proto_depIdxs,
MessageInfos: file_errors_proto_msgTypes,
ExtensionInfos: file_errors_proto_extTypes,
}.Build()
File_errors_proto = out.File
file_errors_proto_rawDesc = nil
file_errors_proto_goTypes = nil
file_errors_proto_depIdxs = nil
}

@ -0,0 +1,25 @@
syntax = "proto3";
package errors;
option go_package = "github.com/go-kratos/kratos/v2/errors;errors";
option java_multiple_files = true;
option java_package = "com.github.kratos.errors";
option objc_class_prefix = "KratosErrors";
import "google/protobuf/descriptor.proto";
message Error {
int32 code = 1;
string reason = 2;
string message = 3;
map<string, string> metadata = 4;
};
extend google.protobuf.EnumOptions {
int32 default_code = 1108;
}
extend google.protobuf.EnumValueOptions {
int32 code = 1109;
}

@ -0,0 +1,17 @@
{{ range .Errors }}
{{ if .HasComment }}{{ .Comment }}{{ end -}}
func Is{{.CamelValue}}(err error) bool {
if err == nil {
return false
}
e := errors.FromError(err)
return e.Reason == {{ .Name }}_{{ .Value }}.String() && e.Code == {{ .HTTPCode }}
}
{{ if .HasComment }}{{ .Comment }}{{ end -}}
func Error{{ .CamelValue }}(format string, args ...interface{}) *errors.Error {
return errors.New({{ .HTTPCode }}, {{ .Name }}_{{ .Value }}.String(), fmt.Sprintf(format, args...))
}
{{- end }}

@ -0,0 +1,62 @@
package main
import "testing"
func Test_case2Camel(t *testing.T) {
type args struct {
name string
}
tests := []struct {
name string
args args
want string
}{
{
name: "snake1",
args: args{"SYSTEM_ERROR"},
want: "SystemError",
},
{
name: "snake2",
args: args{"System_Error"},
want: "SystemError",
},
{
name: "snake3",
args: args{"system_error"},
want: "SystemError",
},
{
name: "snake4",
args: args{"System_error"},
want: "SystemError",
},
{
name: "upper1",
args: args{"UNKNOWN"},
want: "Unknown",
},
{
name: "camel1",
args: args{"SystemError"},
want: "SystemError",
},
{
name: "camel2",
args: args{"systemError"},
want: "SystemError",
},
{
name: "lower1",
args: args{"system"},
want: "System",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := case2Camel(tt.args.name); got != tt.want {
t.Errorf("case2Camel() = %v, want %v", got, tt.want)
}
})
}
}

@ -0,0 +1,8 @@
module github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2
go 1.16
require (
golang.org/x/text v0.3.8
google.golang.org/protobuf v1.28.0
)

@ -0,0 +1,33 @@
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=

@ -0,0 +1,32 @@
package main
import (
"flag"
"fmt"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/types/pluginpb"
)
var showVersion = flag.Bool("version", false, "print the version and exit")
func main() {
flag.Parse()
if *showVersion {
fmt.Printf("protoc-gen-go-errors %v\n", release)
return
}
var flags flag.FlagSet
protogen.Options{
ParamFunc: flags.Set,
}.Run(func(gen *protogen.Plugin) error {
gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
for _, f := range gen.Files {
if !f.Generate {
continue
}
generateFile(gen, f)
}
return nil
})
}

@ -0,0 +1,35 @@
package main
import (
"bytes"
_ "embed"
"text/template"
)
//go:embed errorsTemplate.tpl
var errorsTemplate string
type errorInfo struct {
Name string
Value string
HTTPCode int
CamelValue string
Comment string
HasComment bool
}
type errorWrapper struct {
Errors []*errorInfo
}
func (e *errorWrapper) execute() string {
buf := new(bytes.Buffer)
tmpl, err := template.New("errors").Parse(errorsTemplate)
if err != nil {
panic(err)
}
if err := tmpl.Execute(buf, e); err != nil {
panic(err)
}
return buf.String()
}

@ -0,0 +1,4 @@
package main
// release is the current protoc-gen-go-errors version.
const release = "v2.6.3"

@ -0,0 +1,8 @@
module github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2
go 1.16
require (
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd
google.golang.org/protobuf v1.28.0
)

@ -0,0 +1,130 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd h1:e0TwkXOdbnH/1x5rc5MZ/VYyiZ4v+RdVfrGMqEwT68I=
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

@ -0,0 +1,334 @@
package main
import (
"fmt"
"net/http"
"os"
"regexp"
"strings"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/genproto/googleapis/api/annotations"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/descriptorpb"
)
const (
contextPackage = protogen.GoImportPath("context")
transportHTTPPackage = protogen.GoImportPath("github.com/go-kratos/kratos/v2/transport/http")
bindingPackage = protogen.GoImportPath("github.com/go-kratos/kratos/v2/transport/http/binding")
)
var methodSets = make(map[string]int)
// generateFile generates a _http.pb.go file containing kratos errors definitions.
func generateFile(gen *protogen.Plugin, file *protogen.File, omitempty bool, omitemptyPrefix string) *protogen.GeneratedFile {
if len(file.Services) == 0 || (omitempty && !hasHTTPRule(file.Services)) {
return nil
}
filename := file.GeneratedFilenamePrefix + "_http.pb.go"
g := gen.NewGeneratedFile(filename, file.GoImportPath)
g.P("// Code generated by protoc-gen-go-http. DO NOT EDIT.")
g.P("// versions:")
g.P(fmt.Sprintf("// - protoc-gen-go-http %s", release))
g.P("// - protoc ", protocVersion(gen))
if file.Proto.GetOptions().GetDeprecated() {
g.P("// ", file.Desc.Path(), " is a deprecated file.")
} else {
g.P("// source: ", file.Desc.Path())
}
g.P()
g.P("package ", file.GoPackageName)
g.P()
generateFileContent(gen, file, g, omitempty, omitemptyPrefix)
return g
}
// generateFileContent generates the kratos errors definitions, excluding the package statement.
func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, omitempty bool, omitemptyPrefix string) {
if len(file.Services) == 0 {
return
}
g.P("// This is a compile-time assertion to ensure that this generated file")
g.P("// is compatible with the kratos package it is being compiled against.")
g.P("var _ = new(", contextPackage.Ident("Context"), ")")
g.P("var _ = ", bindingPackage.Ident("EncodeURL"))
g.P("const _ = ", transportHTTPPackage.Ident("SupportPackageIsVersion1"))
g.P()
for _, service := range file.Services {
genService(gen, file, g, service, omitempty, omitemptyPrefix)
}
}
func genService(_ *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service, omitempty bool, omitemptyPrefix string) {
if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() {
g.P("//")
g.P(deprecationComment)
}
// HTTP Server.
sd := &serviceDesc{
ServiceType: service.GoName,
ServiceName: string(service.Desc.FullName()),
Metadata: file.Desc.Path(),
}
for _, method := range service.Methods {
if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {
continue
}
rule, ok := proto.GetExtension(method.Desc.Options(), annotations.E_Http).(*annotations.HttpRule)
if rule != nil && ok {
for _, bind := range rule.AdditionalBindings {
sd.Methods = append(sd.Methods, buildHTTPRule(g, service, method, bind, omitemptyPrefix))
}
sd.Methods = append(sd.Methods, buildHTTPRule(g, service, method, rule, omitemptyPrefix))
} else if !omitempty {
path := fmt.Sprintf("%s/%s/%s", omitemptyPrefix, service.Desc.FullName(), method.Desc.Name())
sd.Methods = append(sd.Methods, buildMethodDesc(g, method, http.MethodPost, path))
}
}
if len(sd.Methods) != 0 {
g.P(sd.execute())
}
}
func hasHTTPRule(services []*protogen.Service) bool {
for _, service := range services {
for _, method := range service.Methods {
if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() {
continue
}
rule, ok := proto.GetExtension(method.Desc.Options(), annotations.E_Http).(*annotations.HttpRule)
if rule != nil && ok {
return true
}
}
}
return false
}
func buildHTTPRule(g *protogen.GeneratedFile, service *protogen.Service, m *protogen.Method, rule *annotations.HttpRule, omitemptyPrefix string) *methodDesc {
var (
path string
method string
body string
responseBody string
)
switch pattern := rule.Pattern.(type) {
case *annotations.HttpRule_Get:
path = pattern.Get
method = http.MethodGet
case *annotations.HttpRule_Put:
path = pattern.Put
method = http.MethodPut
case *annotations.HttpRule_Post:
path = pattern.Post
method = http.MethodPost
case *annotations.HttpRule_Delete:
path = pattern.Delete
method = http.MethodDelete
case *annotations.HttpRule_Patch:
path = pattern.Patch
method = http.MethodPatch
case *annotations.HttpRule_Custom:
path = pattern.Custom.Path
method = pattern.Custom.Kind
}
if method == "" {
method = http.MethodPost
}
if path == "" {
path = fmt.Sprintf("%s/%s/%s", omitemptyPrefix, service.Desc.FullName(), m.Desc.Name())
}
body = rule.Body
responseBody = rule.ResponseBody
md := buildMethodDesc(g, m, method, path)
if method == http.MethodGet || method == http.MethodDelete {
if body != "" {
_, _ = fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: %s %s body should not be declared.\n", method, path)
}
} else {
if body == "" {
_, _ = fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: %s %s does not declare a body.\n", method, path)
}
}
if body == "*" {
md.HasBody = true
md.Body = ""
} else if body != "" {
md.HasBody = true
md.Body = "." + camelCaseVars(body)
} else {
md.HasBody = false
}
if responseBody == "*" {
md.ResponseBody = ""
} else if responseBody != "" {
md.ResponseBody = "." + camelCaseVars(responseBody)
}
return md
}
func buildMethodDesc(g *protogen.GeneratedFile, m *protogen.Method, method, path string) *methodDesc {
defer func() { methodSets[m.GoName]++ }()
vars := buildPathVars(path)
for v, s := range vars {
fields := m.Input.Desc.Fields()
if s != nil {
path = replacePath(v, *s, path)
}
for _, field := range strings.Split(v, ".") {
if strings.TrimSpace(field) == "" {
continue
}
if strings.Contains(field, ":") {
field = strings.Split(field, ":")[0]
}
fd := fields.ByName(protoreflect.Name(field))
if fd == nil {
fmt.Fprintf(os.Stderr, "\u001B[31mERROR\u001B[m: The corresponding field '%s' declaration in message could not be found in '%s'\n", v, path)
os.Exit(2)
}
if fd.IsMap() {
fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: The field in path:'%s' shouldn't be a map.\n", v)
} else if fd.IsList() {
fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: The field in path:'%s' shouldn't be a list.\n", v)
} else if fd.Kind() == protoreflect.MessageKind || fd.Kind() == protoreflect.GroupKind {
fields = fd.Message().Fields()
}
}
}
comment := m.Comments.Leading.String() + m.Comments.Trailing.String()
if comment != "" {
comment = "// " + m.GoName + strings.TrimPrefix(strings.TrimSuffix(comment, "\n"), "//")
}
return &methodDesc{
Name: m.GoName,
OriginalName: string(m.Desc.Name()),
Num: methodSets[m.GoName],
Request: g.QualifiedGoIdent(m.Input.GoIdent),
Reply: g.QualifiedGoIdent(m.Output.GoIdent),
Comment: comment,
Path: path,
Method: method,
HasVars: len(vars) > 0,
}
}
func buildPathVars(path string) (res map[string]*string) {
if strings.HasSuffix(path, "/") {
fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: Path %s should not end with \"/\" \n", path)
}
pattern := regexp.MustCompile(`(?i){([a-z.0-9_\s]*)=?([^{}]*)}`)
matches := pattern.FindAllStringSubmatch(path, -1)
res = make(map[string]*string, len(matches))
for _, m := range matches {
name := strings.TrimSpace(m[1])
if len(name) > 1 && len(m[2]) > 0 {
res[name] = &m[2]
} else {
res[name] = nil
}
}
return
}
func replacePath(name string, value string, path string) string {
pattern := regexp.MustCompile(fmt.Sprintf(`(?i){([\s]*%s[\s]*)=?([^{}]*)}`, name))
idx := pattern.FindStringIndex(path)
if len(idx) > 0 {
path = fmt.Sprintf("%s{%s:%s}%s",
path[:idx[0]], // The start of the match
name,
strings.ReplaceAll(value, "*", ".*"),
path[idx[1]:],
)
}
return path
}
func camelCaseVars(s string) string {
subs := strings.Split(s, ".")
vars := make([]string, 0, len(subs))
for _, sub := range subs {
vars = append(vars, camelCase(sub))
}
return strings.Join(vars, ".")
}
// camelCase returns the CamelCased name.
// If there is an interior underscore followed by a lower case letter,
// drop the underscore and convert the letter to upper case.
// There is a remote possibility of this rewrite causing a name collision,
// but it's so remote we're prepared to pretend it's nonexistent - since the
// C++ generator lowercase names, it's extremely unlikely to have two fields
// with different capitalization.
// In short, _my_field_name_2 becomes XMyFieldName_2.
func camelCase(s string) string {
if s == "" {
return ""
}
t := make([]byte, 0, 32)
i := 0
if s[0] == '_' {
// Need a capital letter; drop the '_'.
t = append(t, 'X')
i++
}
// Invariant: if the next letter is lower case, it must be converted
// to upper case.
// That is, we process a word at a time, where words are marked by _ or
// upper case letter. Digits are treated as words.
for ; i < len(s); i++ {
c := s[i]
if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
continue // Skip the underscore in s.
}
if isASCIIDigit(c) {
t = append(t, c)
continue
}
// Assume we have a letter now - if not, it's a bogus identifier.
// The next word is a sequence of characters that must start upper case.
if isASCIILower(c) {
c ^= ' ' // Make it a capital letter.
}
t = append(t, c) // Guaranteed not lower case.
// Accept lower case sequence that follows.
for i+1 < len(s) && isASCIILower(s[i+1]) {
i++
t = append(t, s[i])
}
}
return string(t)
}
// Is c an ASCII lower-case letter?
func isASCIILower(c byte) bool {
return 'a' <= c && c <= 'z'
}
// Is c an ASCII digit?
func isASCIIDigit(c byte) bool {
return '0' <= c && c <= '9'
}
func protocVersion(gen *protogen.Plugin) string {
v := gen.Request.GetCompilerVersion()
if v == nil {
return "(unknown)"
}
var suffix string
if s := v.GetSuffix(); s != "" {
suffix = "-" + s
}
return fmt.Sprintf("v%d.%d.%d%s", v.GetMajor(), v.GetMinor(), v.GetPatch(), suffix)
}
const deprecationComment = "// Deprecated: Do not use."

@ -0,0 +1,93 @@
{{$svrType := .ServiceType}}
{{$svrName := .ServiceName}}
{{- range .MethodSets}}
const Operation{{$svrType}}{{.OriginalName}} = "/{{$svrName}}/{{.OriginalName}}"
{{- end}}
type {{.ServiceType}}HTTPServer interface {
{{- range .MethodSets}}
{{- if ne .Comment ""}}
{{.Comment}}
{{- end}}
{{.Name}}(context.Context, *{{.Request}}) (*{{.Reply}}, error)
{{- end}}
}
func Register{{.ServiceType}}HTTPServer(s *http.Server, srv {{.ServiceType}}HTTPServer) {
r := s.Route("/")
{{- range .Methods}}
r.{{.Method}}("{{.Path}}", _{{$svrType}}_{{.Name}}{{.Num}}_HTTP_Handler(srv))
{{- end}}
}
{{range .Methods}}
func _{{$svrType}}_{{.Name}}{{.Num}}_HTTP_Handler(srv {{$svrType}}HTTPServer) func(ctx http.Context) error {
return func(ctx http.Context) error {
var in {{.Request}}
{{- if .HasBody}}
if err := ctx.Bind(&in{{.Body}}); err != nil {
return err
}
{{- if not (eq .Body "")}}
if err := ctx.BindQuery(&in); err != nil {
return err
}
{{- end}}
{{- else}}
if err := ctx.BindQuery(&in{{.Body}}); err != nil {
return err
}
{{- end}}
{{- if .HasVars}}
if err := ctx.BindVars(&in); err != nil {
return err
}
{{- end}}
http.SetOperation(ctx,Operation{{$svrType}}{{.OriginalName}})
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.{{.Name}}(ctx, req.(*{{.Request}}))
})
out, err := h(ctx, &in)
if err != nil {
return err
}
reply := out.(*{{.Reply}})
return ctx.Result(200, reply{{.ResponseBody}})
}
}
{{end}}
type {{.ServiceType}}HTTPClient interface {
{{- range .MethodSets}}
{{.Name}}(ctx context.Context, req *{{.Request}}, opts ...http.CallOption) (rsp *{{.Reply}}, err error)
{{- end}}
}
type {{.ServiceType}}HTTPClientImpl struct{
cc *http.Client
}
func New{{.ServiceType}}HTTPClient (client *http.Client) {{.ServiceType}}HTTPClient {
return &{{.ServiceType}}HTTPClientImpl{client}
}
{{range .MethodSets}}
func (c *{{$svrType}}HTTPClientImpl) {{.Name}}(ctx context.Context, in *{{.Request}}, opts ...http.CallOption) (*{{.Reply}}, error) {
var out {{.Reply}}
pattern := "{{.Path}}"
path := binding.EncodeURL(pattern, in, {{not .HasBody}})
opts = append(opts, http.Operation(Operation{{$svrType}}{{.OriginalName}}))
opts = append(opts, http.PathTemplate(pattern))
{{if .HasBody -}}
err := c.cc.Invoke(ctx, "{{.Method}}", path, in{{.Body}}, &out{{.ResponseBody}}, opts...)
{{else -}}
err := c.cc.Invoke(ctx, "{{.Method}}", path, nil, &out{{.ResponseBody}}, opts...)
{{end -}}
if err != nil {
return nil, err
}
return &out, err
}
{{end}}

@ -0,0 +1,87 @@
package main
import (
"reflect"
"testing"
)
func TestNoParameters(t *testing.T) {
path := "/test/noparams"
m := buildPathVars(path)
if !reflect.DeepEqual(m, map[string]*string{}) {
t.Fatalf("Map should be empty")
}
}
func TestSingleParam(t *testing.T) {
path := "/test/{message.id}"
m := buildPathVars(path)
if !reflect.DeepEqual(len(m), 1) {
t.Fatalf("len(m) not is 1")
}
if m["message.id"] != nil {
t.Fatalf(`m["message.id"] should be empty`)
}
}
func TestTwoParametersReplacement(t *testing.T) {
path := "/test/{message.id}/{message.name=messages/*}"
m := buildPathVars(path)
if len(m) != 2 {
t.Fatal("len(m) should be 2")
}
if m["message.id"] != nil {
t.Fatal(`m["message.id"] should be nil`)
}
if m["message.name"] == nil {
t.Fatal(`m["message.name"] should not be nil`)
}
if *m["message.name"] != "messages/*" {
t.Fatal(`m["message.name"] should be "messages/*"`)
}
}
func TestNoReplacePath(t *testing.T) {
path := "/test/{message.id=test}"
if !reflect.DeepEqual(replacePath("message.id", "test", path), "/test/{message.id:test}") {
t.Fatal(`replacePath("message.id", "test", path) should be "/test/{message.id:test}"`)
}
path = "/test/{message.id=test/*}"
if !reflect.DeepEqual(replacePath("message.id", "test/*", path), "/test/{message.id:test/.*}") {
t.Fatal(`replacePath("message.id", "test/*", path) should be "/test/{message.id:test/.*}"`)
}
}
func TestReplacePath(t *testing.T) {
path := "/test/{message.id}/{message.name=messages/*}"
newPath := replacePath("message.name", "messages/*", path)
if !reflect.DeepEqual("/test/{message.id}/{message.name:messages/.*}", newPath) {
t.Fatal(`replacePath("message.name", "messages/*", path) should be "/test/{message.id}/{message.name:messages/.*}"`)
}
}
func TestIteration(t *testing.T) {
path := "/test/{message.id}/{message.name=messages/*}"
vars := buildPathVars(path)
for v, s := range vars {
if s != nil {
path = replacePath(v, *s, path)
}
}
if !reflect.DeepEqual("/test/{message.id}/{message.name:messages/.*}", path) {
t.Fatal(`replacePath("message.name", "messages/*", path) should be "/test/{message.id}/{message.name:messages/.*}"`)
}
}
func TestIterationMiddle(t *testing.T) {
path := "/test/{message.name=messages/*}/books"
vars := buildPathVars(path)
for v, s := range vars {
if s != nil {
path = replacePath(v, *s, path)
}
}
if !reflect.DeepEqual("/test/{message.name:messages/.*}/books", path) {
t.Fatal(`replacePath("message.name", "messages/*", path) should be "/test/{message.name:messages/.*}/books"`)
}
}

@ -0,0 +1,35 @@
package main
import (
"flag"
"fmt"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/types/pluginpb"
)
var (
showVersion = flag.Bool("version", false, "print the version and exit")
omitempty = flag.Bool("omitempty", true, "omit if google.api is empty")
omitemptyPrefix = flag.String("omitempty_prefix", "", "omit if google.api is empty")
)
func main() {
flag.Parse()
if *showVersion {
fmt.Printf("protoc-gen-go-http %v\n", release)
return
}
protogen.Options{
ParamFunc: flag.CommandLine.Set,
}.Run(func(gen *protogen.Plugin) error {
gen.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)
for _, f := range gen.Files {
if !f.Generate {
continue
}
generateFile(gen, f, *omitempty, *omitemptyPrefix)
}
return nil
})
}

@ -0,0 +1,52 @@
package main
import (
"bytes"
_ "embed"
"strings"
"text/template"
)
//go:embed httpTemplate.tpl
var httpTemplate string
type serviceDesc struct {
ServiceType string // Greeter
ServiceName string // helloworld.Greeter
Metadata string // api/helloworld/helloworld.proto
Methods []*methodDesc
MethodSets map[string]*methodDesc
}
type methodDesc struct {
// method
Name string
OriginalName string // The parsed original name
Num int
Request string
Reply string
Comment string
// http_rule
Path string
Method string
HasVars bool
HasBody bool
Body string
ResponseBody string
}
func (s *serviceDesc) execute() string {
s.MethodSets = make(map[string]*methodDesc)
for _, m := range s.Methods {
s.MethodSets[m.Name] = m
}
buf := new(bytes.Buffer)
tmpl, err := template.New("http").Parse(strings.TrimSpace(httpTemplate))
if err != nil {
panic(err)
}
if err := tmpl.Execute(buf, s); err != nil {
panic(err)
}
return strings.Trim(buf.String(), "\r\n")
}

@ -0,0 +1,4 @@
package main
// release is the current protoc-gen-go-http version.
const release = "v2.6.3"

@ -0,0 +1,3 @@
ignore:
- "examples"
- "**/*.pb.go"

@ -0,0 +1,25 @@
# Config
## kubernetes
```shell
go get -u github.com/go-kratos/kratos/contrib/config/kubernetes/v2
```
## apollo
```shell
go get -u github.com/go-kratos/kratos/contrib/config/apollo/v2
```
## etcd
```shell
go get -u github.com/go-kratos/kratos/contrib/config/etcd/v2
```
## nacos
```shell
go get -u github.com/go-kratos/kratos/contrib/config/nacos/v2
```

@ -0,0 +1,158 @@
package config
import (
"context"
"errors"
"reflect"
"sync"
"time"
// init encoding
_ "github.com/go-kratos/kratos/v2/encoding/json"
_ "github.com/go-kratos/kratos/v2/encoding/proto"
_ "github.com/go-kratos/kratos/v2/encoding/xml"
_ "github.com/go-kratos/kratos/v2/encoding/yaml"
"github.com/go-kratos/kratos/v2/log"
)
var _ Config = (*config)(nil)
var (
// ErrNotFound is key not found.
ErrNotFound = errors.New("key not found")
// ErrTypeAssert is type assert error.
ErrTypeAssert = errors.New("type assert error")
)
// Observer is config observer.
type Observer func(string, Value)
// Config is a config interface.
type Config interface {
Load() error
Scan(v interface{}) error
Value(key string) Value
Watch(key string, o Observer) error
Close() error
}
type config struct {
opts options
reader Reader
cached sync.Map
observers sync.Map
watchers []Watcher
}
// New a config with options.
func New(opts ...Option) Config {
o := options{
decoder: defaultDecoder,
resolver: defaultResolver,
}
for _, opt := range opts {
opt(&o)
}
return &config{
opts: o,
reader: newReader(o),
}
}
func (c *config) watch(w Watcher) {
for {
kvs, err := w.Next()
if err != nil {
if errors.Is(err, context.Canceled) {
log.Infof("watcher's ctx cancel : %v", err)
return
}
time.Sleep(time.Second)
log.Errorf("failed to watch next config: %v", err)
continue
}
if err := c.reader.Merge(kvs...); err != nil {
log.Errorf("failed to merge next config: %v", err)
continue
}
if err := c.reader.Resolve(); err != nil {
log.Errorf("failed to resolve next config: %v", err)
continue
}
c.cached.Range(func(key, value interface{}) bool {
k := key.(string)
v := value.(Value)
if n, ok := c.reader.Value(k); ok && reflect.TypeOf(n.Load()) == reflect.TypeOf(v.Load()) && !reflect.DeepEqual(n.Load(), v.Load()) {
v.Store(n.Load())
if o, ok := c.observers.Load(k); ok {
o.(Observer)(k, v)
}
}
return true
})
}
}
func (c *config) Load() error {
for _, src := range c.opts.sources {
kvs, err := src.Load()
if err != nil {
return err
}
for _, v := range kvs {
log.Debugf("config loaded: %s format: %s", v.Key, v.Format)
}
if err = c.reader.Merge(kvs...); err != nil {
log.Errorf("failed to merge config source: %v", err)
return err
}
w, err := src.Watch()
if err != nil {
log.Errorf("failed to watch config source: %v", err)
return err
}
c.watchers = append(c.watchers, w)
go c.watch(w)
}
if err := c.reader.Resolve(); err != nil {
log.Errorf("failed to resolve config source: %v", err)
return err
}
return nil
}
func (c *config) Value(key string) Value {
if v, ok := c.cached.Load(key); ok {
return v.(Value)
}
if v, ok := c.reader.Value(key); ok {
c.cached.Store(key, v)
return v
}
return &errValue{err: ErrNotFound}
}
func (c *config) Scan(v interface{}) error {
data, err := c.reader.Source()
if err != nil {
return err
}
return unmarshalJSON(data, v)
}
func (c *config) Watch(key string, o Observer) error {
if v := c.Value(key); v.Load() == nil {
return ErrNotFound
}
c.observers.Store(key, o)
return nil
}
func (c *config) Close() error {
for _, w := range c.watchers {
if err := w.Stop(); err != nil {
return err
}
}
return nil
}

@ -0,0 +1,184 @@
package config
import (
"errors"
"testing"
)
const (
_testJSON = `
{
"server":{
"http":{
"addr":"0.0.0.0",
"port":80,
"timeout":0.5,
"enable_ssl":true
},
"grpc":{
"addr":"0.0.0.0",
"port":10080,
"timeout":0.2
}
},
"data":{
"database":{
"driver":"mysql",
"source":"root:root@tcp(127.0.0.1:3306)/karta_id?parseTime=true"
}
},
"endpoints":[
"www.aaa.com",
"www.bbb.org"
]
}`
)
type testConfigStruct struct {
Server struct {
HTTP struct {
Addr string `json:"addr"`
Port int `json:"port"`
Timeout float64 `json:"timeout"`
EnableSSL bool `json:"enable_ssl"`
} `json:"http"`
GRPC struct {
Addr string `json:"addr"`
Port int `json:"port"`
Timeout float64 `json:"timeout"`
} `json:"grpc"`
} `json:"server"`
Data struct {
Database struct {
Driver string `json:"driver"`
Source string `json:"source"`
} `json:"database"`
} `json:"data"`
Endpoints []string `json:"endpoints"`
}
type testJSONSource struct {
data string
sig chan struct{}
err chan struct{}
}
func newTestJSONSource(data string) *testJSONSource {
return &testJSONSource{data: data, sig: make(chan struct{}), err: make(chan struct{})}
}
func (p *testJSONSource) Load() ([]*KeyValue, error) {
kv := &KeyValue{
Key: "json",
Value: []byte(p.data),
Format: "json",
}
return []*KeyValue{kv}, nil
}
func (p *testJSONSource) Watch() (Watcher, error) {
return newTestWatcher(p.sig, p.err), nil
}
type testWatcher struct {
sig chan struct{}
err chan struct{}
exit chan struct{}
}
func newTestWatcher(sig, err chan struct{}) Watcher {
return &testWatcher{sig: sig, err: err, exit: make(chan struct{})}
}
func (w *testWatcher) Next() ([]*KeyValue, error) {
select {
case <-w.sig:
return nil, nil
case <-w.err:
return nil, errors.New("error")
case <-w.exit:
return nil, nil
}
}
func (w *testWatcher) Stop() error {
close(w.exit)
return nil
}
func TestConfig(t *testing.T) {
var (
err error
httpAddr = "0.0.0.0"
httpTimeout = 0.5
grpcPort = 10080
endpoint1 = "www.aaa.com"
databaseDriver = "mysql"
)
c := New(
WithSource(newTestJSONSource(_testJSON)),
WithDecoder(defaultDecoder),
WithResolver(defaultResolver),
)
err = c.Close()
if err != nil {
t.Fatal(err)
}
jSource := newTestJSONSource(_testJSON)
opts := options{
sources: []Source{jSource},
decoder: defaultDecoder,
resolver: defaultResolver,
}
cf := &config{}
cf.opts = opts
cf.reader = newReader(opts)
err = cf.Load()
if err != nil {
t.Fatal(err)
}
driver, err := cf.Value("data.database.driver").String()
if err != nil {
t.Fatal(err)
}
if databaseDriver != driver {
t.Fatal("databaseDriver is not equal to val")
}
err = cf.Watch("endpoints", func(key string, value Value) {
})
if err != nil {
t.Fatal(err)
}
jSource.sig <- struct{}{}
jSource.err <- struct{}{}
var testConf testConfigStruct
err = cf.Scan(&testConf)
if err != nil {
t.Fatal(err)
}
if httpAddr != testConf.Server.HTTP.Addr {
t.Errorf("testConf.Server.HTTP.Addr want: %s, got: %s", httpAddr, testConf.Server.HTTP.Addr)
}
if httpTimeout != testConf.Server.HTTP.Timeout {
t.Errorf("testConf.Server.HTTP.Timeout want: %.1f, got: %.1f", httpTimeout, testConf.Server.HTTP.Timeout)
}
if !testConf.Server.HTTP.EnableSSL {
t.Error("testConf.Server.HTTP.EnableSSL is not equal to true")
}
if grpcPort != testConf.Server.GRPC.Port {
t.Errorf("testConf.Server.GRPC.Port want: %d, got: %d", grpcPort, testConf.Server.GRPC.Port)
}
if endpoint1 != testConf.Endpoints[0] {
t.Errorf("testConf.Endpoints[0] want: %s, got: %s", endpoint1, testConf.Endpoints[0])
}
if len(testConf.Endpoints) != 2 {
t.Error("len(testConf.Endpoints) is not equal to 2")
}
}

67
config/env/env.go vendored

@ -0,0 +1,67 @@
package env
import (
"os"
"strings"
"github.com/go-kratos/kratos/v2/config"
)
type env struct {
prefixes []string
}
func NewSource(prefixes ...string) config.Source {
return &env{prefixes: prefixes}
}
func (e *env) Load() (kv []*config.KeyValue, err error) {
return e.load(os.Environ()), nil
}
func (e *env) load(envs []string) []*config.KeyValue {
var kv []*config.KeyValue
for _, env := range envs {
var k, v string
subs := strings.SplitN(env, "=", 2) //nolint:gomnd
k = subs[0]
if len(subs) > 1 {
v = subs[1]
}
if len(e.prefixes) > 0 {
p, ok := matchPrefix(e.prefixes, k)
if !ok || len(p) == len(k) {
continue
}
// trim prefix
k = strings.TrimPrefix(k, p)
k = strings.TrimPrefix(k, "_")
}
if len(k) != 0 {
kv = append(kv, &config.KeyValue{
Key: k,
Value: []byte(v),
})
}
}
return kv
}
func (e *env) Watch() (config.Watcher, error) {
w, err := NewWatcher()
if err != nil {
return nil, err
}
return w, nil
}
func matchPrefix(prefixes []string, s string) (string, bool) {
for _, p := range prefixes {
if strings.HasPrefix(s, p) {
return p, true
}
}
return "", false
}

@ -0,0 +1,429 @@
package env
import (
"os"
"path/filepath"
"reflect"
"testing"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/config/file"
)
const _testJSON = `
{
"test":{
"server":{
"name":"${SERVICE_NAME}",
"addr":"${ADDR:127.0.0.1}",
"port":"${PORT:8080}"
}
},
"foo":[
{
"name":"Tom",
"age":"${AGE}"
}
]
}`
func TestEnvWithPrefix(t *testing.T) {
var (
path = filepath.Join(t.TempDir(), "test_config")
filename = filepath.Join(path, "test.json")
data = []byte(_testJSON)
)
defer os.Remove(path)
if err := os.MkdirAll(path, 0o700); err != nil {
t.Error(err)
}
if err := os.WriteFile(filename, data, 0o666); err != nil {
t.Error(err)
}
// set env
prefix1, prefix2 := "KRATOS_", "FOO"
envs := map[string]string{
prefix1 + "SERVICE_NAME": "kratos_app",
prefix2 + "ADDR": "192.168.0.1",
prefix1 + "AGE": "20",
// only prefix
prefix2: "foo",
prefix2 + "_": "foo_",
}
for k, v := range envs {
os.Setenv(k, v)
}
c := config.New(config.WithSource(
file.NewSource(path),
NewSource(prefix1, prefix2),
))
if err := c.Load(); err != nil {
t.Fatal(err)
}
tests := []struct {
name string
path string
expect interface{}
}{
{
name: "test $KEY",
path: "test.server.name",
expect: "kratos_app",
},
{
name: "test ${KEY:DEFAULT} without default",
path: "test.server.addr",
expect: "192.168.0.1",
},
{
name: "test ${KEY:DEFAULT} with default",
path: "test.server.port",
expect: "8080",
},
{
name: "test ${KEY} in array",
path: "foo",
expect: []interface{}{
map[string]interface{}{
"name": "Tom",
"age": "20",
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var err error
v := c.Value(test.path)
if v.Load() != nil {
var actual interface{}
switch test.expect.(type) {
case int:
if actual, err = v.Int(); err == nil {
if !reflect.DeepEqual(test.expect.(int), int(actual.(int64))) {
t.Errorf("expect %v, actual %v", test.expect, actual)
}
}
case string:
if actual, err = v.String(); err == nil {
if !reflect.DeepEqual(test.expect.(string), actual.(string)) {
t.Errorf(`expect %v, actual %v`, test.expect, actual)
}
}
case bool:
if actual, err = v.Bool(); err == nil {
if !reflect.DeepEqual(test.expect.(bool), actual.(bool)) {
t.Errorf(`expect %v, actual %v`, test.expect, actual)
}
}
case float64:
if actual, err = v.Float(); err == nil {
if !reflect.DeepEqual(test.expect.(float64), actual.(float64)) {
t.Errorf(`expect %v, actual %v`, test.expect, actual)
}
}
default:
actual = v.Load()
if !reflect.DeepEqual(test.expect, actual) {
t.Logf("\nexpect: %#v\nactural: %#v", test.expect, actual)
t.Fail()
}
}
if err != nil {
t.Error(err)
}
} else {
t.Error("value path not found")
}
})
}
}
func TestEnvWithoutPrefix(t *testing.T) {
var (
path = filepath.Join(t.TempDir(), "test_config")
filename = filepath.Join(path, "test.json")
data = []byte(_testJSON)
)
defer os.Remove(path)
if err := os.MkdirAll(path, 0o700); err != nil {
t.Error(err)
}
if err := os.WriteFile(filename, data, 0o666); err != nil {
t.Error(err)
}
// set env
envs := map[string]string{
"SERVICE_NAME": "kratos_app",
"ADDR": "192.168.0.1",
"AGE": "20",
}
for k, v := range envs {
os.Setenv(k, v)
}
c := config.New(config.WithSource(
NewSource(),
file.NewSource(path),
))
if err := c.Load(); err != nil {
t.Fatal(err)
}
tests := []struct {
name string
path string
expect interface{}
}{
{
name: "test $KEY",
path: "test.server.name",
expect: "kratos_app",
},
{
name: "test ${KEY:DEFAULT} without default",
path: "test.server.addr",
expect: "192.168.0.1",
},
{
name: "test ${KEY:DEFAULT} with default",
path: "test.server.port",
expect: "8080",
},
{
name: "test ${KEY} in array",
path: "foo",
expect: []interface{}{
map[string]interface{}{
"name": "Tom",
"age": "20",
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var err error
v := c.Value(test.path)
if v.Load() != nil {
var actual interface{}
switch test.expect.(type) {
case int:
if actual, err = v.Int(); err == nil {
if !reflect.DeepEqual(test.expect.(int), int(actual.(int64))) {
t.Errorf("expect %v, actual %v", test.expect, actual)
}
}
case string:
if actual, err = v.String(); err == nil {
if !reflect.DeepEqual(test.expect.(string), actual.(string)) {
t.Errorf(`expect %v, actual %v`, test.expect, actual)
}
}
case bool:
if actual, err = v.Bool(); err == nil {
if !reflect.DeepEqual(test.expect.(bool), actual.(bool)) {
t.Errorf(`expect %v, actual %v`, test.expect, actual)
}
}
case float64:
if actual, err = v.Float(); err == nil {
if !reflect.DeepEqual(test.expect.(float64), actual.(float64)) {
t.Errorf(`expect %v, actual %v`, test.expect, actual)
}
}
default:
actual = v.Load()
if !reflect.DeepEqual(test.expect, actual) {
t.Logf("\nexpect: %#v\nactural: %#v", test.expect, actual)
t.Fail()
}
}
if err != nil {
t.Error(err)
}
} else {
t.Error("value path not found")
}
})
}
}
func Test_env_load(t *testing.T) {
type fields struct {
prefixes []string
}
type args struct {
envStrings []string
}
tests := []struct {
name string
fields fields
args args
want []*config.KeyValue
}{
{
name: "without prefixes",
fields: fields{
prefixes: nil,
},
args: args{
envStrings: []string{
"SERVICE_NAME=kratos_app",
"ADDR=192.168.0.1",
"AGE=20",
},
},
want: []*config.KeyValue{
{Key: "SERVICE_NAME", Value: []byte("kratos_app"), Format: ""},
{Key: "ADDR", Value: []byte("192.168.0.1"), Format: ""},
{Key: "AGE", Value: []byte("20"), Format: ""},
},
},
{
name: "empty prefix",
fields: fields{
prefixes: []string{""},
},
args: args{
envStrings: []string{
"__SERVICE_NAME=kratos_app",
"__ADDR=192.168.0.1",
"__AGE=20",
},
},
want: []*config.KeyValue{
{Key: "_SERVICE_NAME", Value: []byte("kratos_app"), Format: ""},
{Key: "_ADDR", Value: []byte("192.168.0.1"), Format: ""},
{Key: "_AGE", Value: []byte("20"), Format: ""},
},
},
{
name: "underscore prefix",
fields: fields{
prefixes: []string{"_"},
},
args: args{
envStrings: []string{
"__SERVICE_NAME=kratos_app",
"__ADDR=192.168.0.1",
"__AGE=20",
},
},
want: []*config.KeyValue{
{Key: "SERVICE_NAME", Value: []byte("kratos_app"), Format: ""},
{Key: "ADDR", Value: []byte("192.168.0.1"), Format: ""},
{Key: "AGE", Value: []byte("20"), Format: ""},
},
},
{
name: "with prefixes",
fields: fields{
prefixes: []string{"KRATOS_", "FOO"},
},
args: args{
envStrings: []string{
"KRATOS_SERVICE_NAME=kratos_app",
"KRATOS_ADDR=192.168.0.1",
"FOO_AGE=20",
},
},
want: []*config.KeyValue{
{Key: "SERVICE_NAME", Value: []byte("kratos_app"), Format: ""},
{Key: "ADDR", Value: []byte("192.168.0.1"), Format: ""},
{Key: "AGE", Value: []byte("20"), Format: ""},
},
},
{
name: "should not panic #1",
fields: fields{
prefixes: []string{"FOO"},
},
args: args{
envStrings: []string{
"FOO=123",
},
},
want: nil,
},
{
name: "should not panic #2",
fields: fields{
prefixes: []string{"FOO=1"},
},
args: args{
envStrings: []string{
"FOO=123",
},
},
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
e := &env{
prefixes: tt.fields.prefixes,
}
got := e.load(tt.args.envStrings)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("env.load() = %v, want %v", got, tt.want)
}
})
}
}
func Test_matchPrefix(t *testing.T) {
type args struct {
prefixes []string
s string
}
tests := []struct {
name string
args args
want string
wantOk bool
}{
{args: args{prefixes: nil, s: "foo=123"}, want: "", wantOk: false},
{args: args{prefixes: []string{""}, s: "foo=123"}, want: "", wantOk: true},
{args: args{prefixes: []string{"foo"}, s: "foo=123"}, want: "foo", wantOk: true},
{args: args{prefixes: []string{"foo=1"}, s: "foo=123"}, want: "foo=1", wantOk: true},
{args: args{prefixes: []string{"foo=1234"}, s: "foo=123"}, want: "", wantOk: false},
{args: args{prefixes: []string{"bar"}, s: "foo=123"}, want: "", wantOk: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, gotOk := matchPrefix(tt.args.prefixes, tt.args.s)
if got != tt.want {
t.Errorf("matchPrefix() got = %v, want %v", got, tt.want)
}
if gotOk != tt.wantOk {
t.Errorf("matchPrefix() gotOk = %v, wantOk %v", gotOk, tt.wantOk)
}
})
}
}
func Test_env_watch(t *testing.T) {
prefixes := []string{"BAR", "FOO"}
source := NewSource(prefixes...)
w, err := source.Watch()
if err != nil {
t.Errorf("expect no err, got %v", err)
}
_ = w.Stop()
}

@ -0,0 +1,30 @@
package env
import (
"context"
"github.com/go-kratos/kratos/v2/config"
)
var _ config.Watcher = (*watcher)(nil)
type watcher struct {
ctx context.Context
cancel context.CancelFunc
}
func NewWatcher() (config.Watcher, error) {
ctx, cancel := context.WithCancel(context.Background())
return &watcher{ctx: ctx, cancel: cancel}, nil
}
// Next will be blocked until the Stop method is called
func (w *watcher) Next() ([]*config.KeyValue, error) {
<-w.ctx.Done()
return nil, w.ctx.Err()
}
func (w *watcher) Stop() error {
w.cancel()
return nil
}

@ -0,0 +1,32 @@
package env
import (
"testing"
)
func Test_watcher_next(t *testing.T) {
t.Run("next after stop should return err", func(t *testing.T) {
w, err := NewWatcher()
if err != nil {
t.Errorf("expect no error, got %v", err)
}
_ = w.Stop()
_, err = w.Next()
if err == nil {
t.Error("expect error, actual nil")
}
})
}
func Test_watcher_stop(t *testing.T) {
t.Run("stop multiple times should not panic", func(t *testing.T) {
w, err := NewWatcher()
if err != nil {
t.Errorf("expect no error, got %v", err)
}
_ = w.Stop()
_ = w.Stop()
})
}

@ -0,0 +1,80 @@
package file
import (
"io"
"os"
"path/filepath"
"strings"
"github.com/go-kratos/kratos/v2/config"
)
var _ config.Source = (*file)(nil)
type file struct {
path string
}
// NewSource new a file source.
func NewSource(path string) config.Source {
return &file{path: path}
}
func (f *file) loadFile(path string) (*config.KeyValue, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
data, err := io.ReadAll(file)
if err != nil {
return nil, err
}
info, err := file.Stat()
if err != nil {
return nil, err
}
return &config.KeyValue{
Key: info.Name(),
Format: format(info.Name()),
Value: data,
}, nil
}
func (f *file) loadDir(path string) (kvs []*config.KeyValue, err error) {
files, err := os.ReadDir(path)
if err != nil {
return nil, err
}
for _, file := range files {
// ignore hidden files
if file.IsDir() || strings.HasPrefix(file.Name(), ".") {
continue
}
kv, err := f.loadFile(filepath.Join(path, file.Name()))
if err != nil {
return nil, err
}
kvs = append(kvs, kv)
}
return
}
func (f *file) Load() (kvs []*config.KeyValue, err error) {
fi, err := os.Stat(f.path)
if err != nil {
return nil, err
}
if fi.IsDir() {
return f.loadDir(f.path)
}
kv, err := f.loadFile(f.path)
if err != nil {
return nil, err
}
return []*config.KeyValue{kv}, nil
}
func (f *file) Watch() (config.Watcher, error) {
return newWatcher(f)
}

@ -0,0 +1,341 @@
package file
import (
"errors"
"os"
"path/filepath"
"reflect"
"sync"
"testing"
"time"
"github.com/go-kratos/kratos/v2/config"
)
const (
_testJSON = `
{
"test":{
"settings":{
"int_key":1000,
"float_key":1000.1,
"duration_key":10000,
"string_key":"string_value"
},
"server":{
"addr":"127.0.0.1",
"port":8000
}
},
"foo":[
{
"name":"nihao",
"age":18
},
{
"name":"nihao",
"age":18
}
]
}`
_testJSONUpdate = `
{
"test":{
"settings":{
"int_key":1000,
"float_key":1000.1,
"duration_key":10000,
"string_key":"string_value"
},
"server":{
"addr":"127.0.0.1",
"port":8000
}
},
"foo":[
{
"name":"nihao",
"age":18
},
{
"name":"nihao",
"age":18
}
],
"bar":{
"event":"update"
}
}`
// _testYaml = `
//Foo:
// bar :
// - {name: nihao,age: 1}
// - {name: nihao,age: 1}
//
//
//`
)
//func TestScan(t *testing.T) {
//
//}
func TestFile(t *testing.T) {
var (
path = filepath.Join(t.TempDir(), "test_config")
file = filepath.Join(path, "test.json")
data = []byte(_testJSON)
)
defer os.Remove(path)
if err := os.MkdirAll(path, 0o700); err != nil {
t.Error(err)
}
if err := os.WriteFile(file, data, 0o666); err != nil {
t.Error(err)
}
testSource(t, file, data)
testSource(t, path, data)
testWatchFile(t, file)
testWatchDir(t, path, file)
}
func testWatchFile(t *testing.T, path string) {
t.Log(path)
s := NewSource(path)
watch, err := s.Watch()
if err != nil {
t.Error(err)
}
f, err := os.OpenFile(path, os.O_RDWR, 0)
if err != nil {
t.Error(err)
}
defer f.Close()
_, err = f.WriteString(_testJSONUpdate)
if err != nil {
t.Error(err)
}
kvs, err := watch.Next()
if err != nil {
t.Errorf("watch.Next() error(%v)", err)
}
if !reflect.DeepEqual(string(kvs[0].Value), _testJSONUpdate) {
t.Errorf("string(kvs[0].Value(%v) is not equal to _testJSONUpdate(%v)", kvs[0].Value, _testJSONUpdate)
}
newFilepath := filepath.Join(filepath.Dir(path), "test1.json")
if err = os.Rename(path, newFilepath); err != nil {
t.Error(err)
}
kvs, err = watch.Next()
if err == nil {
t.Errorf("watch.Next() error(%v)", err)
}
if kvs != nil {
t.Errorf("watch.Next() error(%v)", err)
}
err = watch.Stop()
if err != nil {
t.Errorf("watch.Stop() error(%v)", err)
}
if err := os.Rename(newFilepath, path); err != nil {
t.Error(err)
}
}
func testWatchDir(t *testing.T, path, file string) {
t.Log(path)
t.Log(file)
s := NewSource(path)
watch, err := s.Watch()
if err != nil {
t.Error(err)
}
f, err := os.OpenFile(file, os.O_RDWR, 0)
if err != nil {
t.Error(err)
}
defer f.Close()
_, err = f.WriteString(_testJSONUpdate)
if err != nil {
t.Error(err)
}
kvs, err := watch.Next()
if err != nil {
t.Errorf("watch.Next() error(%v)", err)
}
if !reflect.DeepEqual(string(kvs[0].Value), _testJSONUpdate) {
t.Errorf("string(kvs[0].Value(%s) is not equal to _testJSONUpdate(%v)", kvs[0].Value, _testJSONUpdate)
}
}
func testSource(t *testing.T, path string, data []byte) {
t.Log(path)
s := NewSource(path)
kvs, err := s.Load()
if err != nil {
t.Error(err)
}
if string(kvs[0].Value) != string(data) {
t.Errorf("no expected: %s, but got: %s", kvs[0].Value, data)
}
}
func TestConfig(t *testing.T) {
path := filepath.Join(t.TempDir(), "test_config.json")
defer os.Remove(path)
if err := os.WriteFile(path, []byte(_testJSON), 0o666); err != nil {
t.Error(err)
}
c := config.New(config.WithSource(
NewSource(path),
))
testScan(t, c)
testConfig(t, c)
}
func testConfig(t *testing.T, c config.Config) {
expected := map[string]interface{}{
"test.settings.int_key": int64(1000),
"test.settings.float_key": 1000.1,
"test.settings.string_key": "string_value",
"test.settings.duration_key": time.Duration(10000),
"test.server.addr": "127.0.0.1",
"test.server.port": int64(8000),
}
if err := c.Load(); err != nil {
t.Error(err)
}
for key, value := range expected {
switch value.(type) {
case int64:
if v, err := c.Value(key).Int(); err != nil {
t.Error(key, value, err)
} else if v != value {
t.Errorf("no expect key: %s value: %v, but got: %v", key, value, v)
}
case float64:
if v, err := c.Value(key).Float(); err != nil {
t.Error(key, value, err)
} else if v != value {
t.Errorf("no expect key: %s value: %v, but got: %v", key, value, v)
}
case string:
if v, err := c.Value(key).String(); err != nil {
t.Error(key, value, err)
} else if v != value {
t.Errorf("no expect key: %s value: %v, but got: %v", key, value, v)
}
case time.Duration:
if v, err := c.Value(key).Duration(); err != nil {
t.Error(key, value, err)
} else if v != value {
t.Errorf("no expect key: %s value: %v, but got: %v", key, value, v)
}
}
}
// scan
var settings struct {
IntKey int64 `json:"int_key"`
FloatKey float64 `json:"float_key"`
StringKey string `json:"string_key"`
DurationKey time.Duration `json:"duration_key"`
}
if err := c.Value("test.settings").Scan(&settings); err != nil {
t.Error(err)
}
if v := expected["test.settings.int_key"]; settings.IntKey != v {
t.Errorf("no expect int_key value: %v, but got: %v", settings.IntKey, v)
}
if v := expected["test.settings.float_key"]; settings.FloatKey != v {
t.Errorf("no expect float_key value: %v, but got: %v", settings.FloatKey, v)
}
if v := expected["test.settings.string_key"]; settings.StringKey != v {
t.Errorf("no expect string_key value: %v, but got: %v", settings.StringKey, v)
}
if v := expected["test.settings.duration_key"]; settings.DurationKey != v {
t.Errorf("no expect duration_key value: %v, but got: %v", settings.DurationKey, v)
}
// not found
if _, err := c.Value("not_found_key").Bool(); errors.Is(err, config.ErrNotFound) {
t.Logf("not_found_key not match: %v", err)
}
}
func testScan(t *testing.T, c config.Config) {
type TestJSON struct {
Test struct {
Settings struct {
IntKey int `json:"int_key"`
FloatKey float64 `json:"float_key"`
DurationKey int `json:"duration_key"`
StringKey string `json:"string_key"`
} `json:"settings"`
Server struct {
Addr string `json:"addr"`
Port int `json:"port"`
} `json:"server"`
} `json:"test"`
Foo []struct {
Name string `json:"name"`
Age int `json:"age"`
} `json:"foo"`
}
var conf TestJSON
if err := c.Load(); err != nil {
t.Error(err)
}
if err := c.Scan(&conf); err != nil {
t.Error(err)
}
t.Log(conf)
}
func TestMergeDataRace(t *testing.T) {
path := filepath.Join(t.TempDir(), "test_config.json")
defer os.Remove(path)
if err := os.WriteFile(path, []byte(_testJSON), 0o666); err != nil {
t.Error(err)
}
c := config.New(config.WithSource(
NewSource(path),
))
const count = 80
wg := &sync.WaitGroup{}
wg.Add(2)
startCh := make(chan struct{})
go func() {
defer wg.Done()
<-startCh
for i := 0; i < count; i++ {
var conf struct{}
if err := c.Scan(&conf); err != nil {
t.Error(err)
}
}
}()
go func() {
defer wg.Done()
<-startCh
for i := 0; i < count; i++ {
if err := c.Load(); err != nil {
t.Error(err)
}
}
}()
close(startCh)
wg.Wait()
}

@ -0,0 +1,10 @@
package file
import "strings"
func format(name string) string {
if p := strings.Split(name, "."); len(p) > 1 {
return p[len(p)-1]
}
return ""
}

@ -0,0 +1,43 @@
package file
import (
"testing"
)
func TestFormat(t *testing.T) {
tests := []struct {
input string
expect string
}{
{
input: "",
expect: "",
},
{
input: " ",
expect: "",
},
{
input: ".",
expect: "",
},
{
input: "a.",
expect: "",
},
{
input: ".b",
expect: "b",
},
{
input: "a.b",
expect: "b",
},
}
for _, v := range tests {
content := format(v.input)
if got, want := content, v.expect; got != want {
t.Errorf("expect %v,got %v", want, got)
}
}
}

@ -0,0 +1,68 @@
package file
import (
"context"
"os"
"path/filepath"
"github.com/fsnotify/fsnotify"
"github.com/go-kratos/kratos/v2/config"
)
var _ config.Watcher = (*watcher)(nil)
type watcher struct {
f *file
fw *fsnotify.Watcher
ctx context.Context
cancel context.CancelFunc
}
func newWatcher(f *file) (config.Watcher, error) {
fw, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
}
if err := fw.Add(f.path); err != nil {
return nil, err
}
ctx, cancel := context.WithCancel(context.Background())
return &watcher{f: f, fw: fw, ctx: ctx, cancel: cancel}, nil
}
func (w *watcher) Next() ([]*config.KeyValue, error) {
select {
case <-w.ctx.Done():
return nil, w.ctx.Err()
case event := <-w.fw.Events:
if event.Op == fsnotify.Rename {
if _, err := os.Stat(event.Name); err == nil || os.IsExist(err) {
if err := w.fw.Add(event.Name); err != nil {
return nil, err
}
}
}
fi, err := os.Stat(w.f.path)
if err != nil {
return nil, err
}
path := w.f.path
if fi.IsDir() {
path = filepath.Join(w.f.path, filepath.Base(event.Name))
}
kv, err := w.f.loadFile(path)
if err != nil {
return nil, err
}
return []*config.KeyValue{kv}, nil
case err := <-w.fw.Errors:
return nil, err
}
}
func (w *watcher) Stop() error {
w.cancel()
return w.fw.Close()
}

@ -0,0 +1,133 @@
package config
import (
"fmt"
"regexp"
"strings"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
)
// Decoder is config decoder.
type Decoder func(*KeyValue, map[string]interface{}) error
// Resolver resolve placeholder in config.
type Resolver func(map[string]interface{}) error
// Option is config option.
type Option func(*options)
type options struct {
sources []Source
decoder Decoder
resolver Resolver
}
// WithSource with config source.
func WithSource(s ...Source) Option {
return func(o *options) {
o.sources = s
}
}
// WithDecoder with config decoder.
// DefaultDecoder behavior:
// If KeyValue.Format is non-empty, then KeyValue.Value will be deserialized into map[string]interface{}
// and stored in the config cache(map[string]interface{})
// if KeyValue.Format is empty,{KeyValue.Key : KeyValue.Value} will be stored in config cache(map[string]interface{})
func WithDecoder(d Decoder) Option {
return func(o *options) {
o.decoder = d
}
}
// WithResolver with config resolver.
func WithResolver(r Resolver) Option {
return func(o *options) {
o.resolver = r
}
}
// WithLogger with config logger.
// Deprecated: use global logger instead.
func WithLogger(_ log.Logger) Option {
return func(o *options) {}
}
// defaultDecoder decode config from source KeyValue
// to target map[string]interface{} using src.Format codec.
func defaultDecoder(src *KeyValue, target map[string]interface{}) error {
if src.Format == "" {
// expand key "aaa.bbb" into map[aaa]map[bbb]interface{}
keys := strings.Split(src.Key, ".")
for i, k := range keys {
if i == len(keys)-1 {
target[k] = src.Value
} else {
sub := make(map[string]interface{})
target[k] = sub
target = sub
}
}
return nil
}
if codec := encoding.GetCodec(src.Format); codec != nil {
return codec.Unmarshal(src.Value, &target)
}
return fmt.Errorf("unsupported key: %s format: %s", src.Key, src.Format)
}
// defaultResolver resolve placeholder in map value,
// placeholder format in ${key:default}.
func defaultResolver(input map[string]interface{}) error {
mapper := func(name string) string {
args := strings.SplitN(strings.TrimSpace(name), ":", 2) //nolint:gomnd
if v, has := readValue(input, args[0]); has {
s, _ := v.String()
return s
} else if len(args) > 1 { // default value
return args[1]
}
return ""
}
var resolve func(map[string]interface{}) error
resolve = func(sub map[string]interface{}) error {
for k, v := range sub {
switch vt := v.(type) {
case string:
sub[k] = expand(vt, mapper)
case map[string]interface{}:
if err := resolve(vt); err != nil {
return err
}
case []interface{}:
for i, iface := range vt {
switch it := iface.(type) {
case string:
vt[i] = expand(it, mapper)
case map[string]interface{}:
if err := resolve(it); err != nil {
return err
}
}
}
sub[k] = vt
}
}
return nil
}
return resolve(input)
}
func expand(s string, mapping func(string) string) string {
r := regexp.MustCompile(`\${(.*?)}`)
re := r.FindAllStringSubmatch(s, -1)
for _, i := range re {
if len(i) == 2 { //nolint:gomnd
s = strings.ReplaceAll(s, i[0], mapping(i[1]))
}
}
return s
}

@ -0,0 +1,228 @@
package config
import (
"reflect"
"strings"
"testing"
)
func TestDefaultDecoder(t *testing.T) {
src := &KeyValue{
Key: "service",
Value: []byte("config"),
Format: "",
}
target := make(map[string]interface{})
err := defaultDecoder(src, target)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(target, map[string]interface{}{"service": []byte("config")}) {
t.Fatal(`target is not equal to map[string]interface{}{"service": "config"}`)
}
src = &KeyValue{
Key: "service.name.alias",
Value: []byte("2233"),
Format: "",
}
target = make(map[string]interface{})
err = defaultDecoder(src, target)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(map[string]interface{}{
"service": map[string]interface{}{
"name": map[string]interface{}{
"alias": []byte("2233"),
},
},
}, target) {
t.Fatal(`target is not equal to map[string]interface{}{"service": map[string]interface{}{"name": map[string]interface{}{"alias": []byte("2233")}}}`)
}
}
func TestDefaultResolver(t *testing.T) {
var (
portString = "8080"
countInt = 10
rateFloat = 0.9
)
data := map[string]interface{}{
"foo": map[string]interface{}{
"bar": map[string]interface{}{
"notexist": "${NOTEXIST:100}",
"port": "${PORT:8081}",
"count": "${COUNT:0}",
"enable": "${ENABLE:false}",
"rate": "${RATE}",
"empty": "${EMPTY:foobar}",
"url": "${URL:http://example.com}",
"array": []interface{}{
"${PORT}",
map[string]interface{}{"foobar": "${NOTEXIST:8081}"},
},
"value1": "${test.value}",
"value2": "$PORT",
"value3": "abc${PORT}foo${COUNT}bar",
"value4": "${foo${bar}}",
},
},
"test": map[string]interface{}{
"value": "foobar",
},
"PORT": "8080",
"COUNT": "10",
"ENABLE": "true",
"RATE": "0.9",
"EMPTY": "",
}
tests := []struct {
name string
path string
expect interface{}
}{
{
name: "test not exist int env with default",
path: "foo.bar.notexist",
expect: 100,
},
{
name: "test string with default",
path: "foo.bar.port",
expect: portString,
},
{
name: "test int with default",
path: "foo.bar.count",
expect: countInt,
},
{
name: "test bool with default",
path: "foo.bar.enable",
expect: true,
},
{
name: "test float without default",
path: "foo.bar.rate",
expect: rateFloat,
},
{
name: "test empty value with default",
path: "foo.bar.empty",
expect: "",
},
{
name: "test url with default",
path: "foo.bar.url",
expect: "http://example.com",
},
{
name: "test array",
path: "foo.bar.array",
expect: []interface{}{portString, map[string]interface{}{"foobar": "8081"}},
},
{
name: "test ${test.value}",
path: "foo.bar.value1",
expect: "foobar",
},
{
name: "test $PORT",
path: "foo.bar.value2",
expect: "$PORT",
},
{
name: "test abc${PORT}foo${COUNT}bar",
path: "foo.bar.value3",
expect: "abc8080foo10bar",
},
{
name: "test ${foo${bar}}",
path: "foo.bar.value4",
expect: "}",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := defaultResolver(data)
if err != nil {
t.Fatal(err)
}
rd := reader{
values: data,
}
if v, ok := rd.Value(test.path); ok {
var actual interface{}
switch test.expect.(type) {
case int:
if actual, err = v.Int(); err == nil {
if !reflect.DeepEqual(test.expect.(int), int(actual.(int64))) {
t.Fatal("expect is not equal to actual")
}
}
case string:
if actual, err = v.String(); err == nil {
if !reflect.DeepEqual(test.expect, actual) {
t.Fatal("expect is not equal to actual")
}
}
case bool:
if actual, err = v.Bool(); err == nil {
if !reflect.DeepEqual(test.expect, actual) {
t.Fatal("expect is not equal to actual")
}
}
case float64:
if actual, err = v.Float(); err == nil {
if !reflect.DeepEqual(test.expect, actual) {
t.Fatal("expect is not equal to actual")
}
}
default:
actual = v.Load()
if !reflect.DeepEqual(test.expect, actual) {
t.Logf("expect: %#v, actural: %#v", test.expect, actual)
t.Fail()
}
}
if err != nil {
t.Error(err)
}
} else {
t.Error("value path not found")
}
})
}
}
func TestExpand(t *testing.T) {
tests := []struct {
input string
mapping func(string) string
want string
}{
{
input: "${a}",
mapping: func(s string) string {
return strings.ToUpper(s)
},
want: "A",
},
{
input: "a",
mapping: func(s string) string {
return strings.ToUpper(s)
},
want: "a",
},
}
for _, tt := range tests {
if got := expand(tt.input, tt.mapping); got != tt.want {
t.Errorf("expand() want: %s, got: %s", tt.want, got)
}
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save