Compare commits

...

164 Commits
cache ... 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
  1. 8
      .github/pull_request_template.md
  2. 12
      .github/stable.yml
  3. 21
      .github/workflows/go.yml
  4. 16
      .github/workflows/issue-translator.yml
  5. 2
      .golangci.yml
  6. 30
      Makefile
  7. 2
      README.md
  8. 8
      SECURITY.md
  9. 7
      api/metadata/server.go
  10. 37
      app.go
  11. 20
      app_test.go
  12. 10
      cmd/kratos/go.mod
  13. 38
      cmd/kratos/go.sum
  14. 6
      cmd/kratos/internal/base/mod_test.go
  15. 23
      cmd/kratos/internal/base/path.go
  16. 7
      cmd/kratos/internal/base/repo.go
  17. 2
      cmd/kratos/internal/base/vcs_url.go
  18. 2
      cmd/kratos/internal/change/change.go
  19. 4
      cmd/kratos/internal/change/get.go
  20. 10
      cmd/kratos/internal/project/add.go
  21. 16
      cmd/kratos/internal/project/new.go
  22. 70
      cmd/kratos/internal/project/project.go
  23. 29
      cmd/kratos/internal/project/project_linux_test.go
  24. 144
      cmd/kratos/internal/project/project_test.go
  25. 30
      cmd/kratos/internal/project/project_windows_test.go
  26. 7
      cmd/kratos/internal/proto/add/add.go
  27. 6
      cmd/kratos/internal/proto/add/proto.go
  28. 6
      cmd/kratos/internal/proto/client/client.go
  29. 4
      cmd/kratos/internal/proto/proto.go
  30. 18
      cmd/kratos/internal/proto/server/server.go
  31. 40
      cmd/kratos/internal/proto/server/server_test.go
  32. 18
      cmd/kratos/internal/run/run.go
  33. 6
      cmd/kratos/internal/upgrade/upgrade.go
  34. 4
      cmd/kratos/main.go
  35. 2
      cmd/kratos/version.go
  36. 2
      cmd/protoc-gen-go-errors/errors.go
  37. 17
      cmd/protoc-gen-go-errors/errorsTemplate.tpl
  38. 2
      cmd/protoc-gen-go-errors/go.mod
  39. 24
      cmd/protoc-gen-go-errors/go.sum
  40. 22
      cmd/protoc-gen-go-errors/template.go
  41. 2
      cmd/protoc-gen-go-errors/version.go
  42. 46
      cmd/protoc-gen-go-http/http.go
  43. 93
      cmd/protoc-gen-go-http/httpTemplate.tpl
  44. 7
      cmd/protoc-gen-go-http/main.go
  45. 96
      cmd/protoc-gen-go-http/template.go
  46. 2
      cmd/protoc-gen-go-http/version.go
  47. 14
      config/config.go
  48. 41
      config/config_test.go
  49. 6
      config/env/env.go
  50. 4
      config/env/watcher.go
  51. 14
      config/file/file_test.go
  52. 4
      config/file/format_test.go
  53. 4
      config/file/watcher.go
  54. 2
      config/options.go
  55. 14
      config/options_test.go
  56. 20
      config/reader.go
  57. 46
      config/reader_test.go
  58. 64
      config/value.go
  59. 71
      config/value_test.go
  60. 1
      contrib/config/apollo/README.md
  61. 60
      contrib/config/apollo/apollo.go
  62. 90
      contrib/config/apollo/apollo_test.go
  63. 9
      contrib/config/apollo/go.mod
  64. 992
      contrib/config/apollo/go.sum
  65. 9
      contrib/config/apollo/watcher.go
  66. 11
      contrib/config/consul/README.md
  67. 9
      contrib/config/consul/go.mod
  68. 1473
      contrib/config/consul/go.sum
  69. 2
      contrib/config/consul/watcher.go
  70. 15
      contrib/config/etcd/README.md
  71. 6
      contrib/config/etcd/go.mod
  72. 1460
      contrib/config/etcd/go.sum
  73. 4
      contrib/config/kubernetes/config_test.go
  74. 8
      contrib/config/kubernetes/go.mod
  75. 1229
      contrib/config/kubernetes/go.sum
  76. 3
      contrib/config/nacos/README.md
  77. 3
      contrib/config/nacos/go.mod
  78. 1462
      contrib/config/nacos/go.sum
  79. 29
      contrib/config/polaris/README.md
  80. 4
      contrib/config/polaris/config.go
  81. 6
      contrib/config/polaris/go.mod
  82. 1191
      contrib/config/polaris/go.sum
  83. 10
      contrib/config/polaris/watcher.go
  84. 2
      contrib/encoding/msgpack/go.mod
  85. 1460
      contrib/encoding/msgpack/go.sum
  86. 36
      contrib/log/aliyun/aliyun.go
  87. 62
      contrib/log/aliyun/aliyun_test.go
  88. 6
      contrib/log/aliyun/go.mod
  89. 1432
      contrib/log/aliyun/go.sum
  90. 21
      contrib/log/fluent/fluent_test.go
  91. 3
      contrib/log/fluent/go.mod
  92. 1442
      contrib/log/fluent/go.sum
  93. 2
      contrib/log/logrus/go.mod
  94. 1459
      contrib/log/logrus/go.sum
  95. 4
      contrib/log/tencent/go.mod
  96. 1462
      contrib/log/tencent/go.sum
  97. 37
      contrib/log/tencent/tencent.go
  98. 45
      contrib/log/tencent/tencent_test.go
  99. 2
      contrib/log/zap/go.mod
  100. 1440
      contrib/log/zap/go.sum
  101. Some files were not shown because too many files have changed in this diff Show More

@ -3,22 +3,20 @@
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
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 发送 PR!以下是一些提示:
如果这是你第一次为 Kratos 贡献,请阅读我们的贡献指南:https://go-kratos.dev/en/docs/community/contribution/
2、确保您已经为您的 PR 添加或运行了适当的测试和lint,请在提交PR之前使用“make lint”和“make test”,使用“make clean”整理您的 go.mod。
3、如果请购单未完成,您可能需要将其标记为 WIP(在制品)PR 或 draft PR
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):
<!--

@ -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

@ -13,7 +13,7 @@ jobs:
build:
strategy:
matrix:
go: [1.16, 1.17, 1.18, 1.19]
go: [1.19,1.20.x]
name: build & test
runs-on: ubuntu-latest
services:
@ -36,7 +36,7 @@ jobs:
- "8848:8848"
- "9848:9848"
polaris:
image: polarismesh/polaris-server-standalone:v1.9.0
image: polarismesh/polaris-standalone:latest
ports:
- 8090:8090
- 8091:8091
@ -44,10 +44,25 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3.3.0
uses: actions/setup-go@v4.0.1
with:
go-version: ${{ matrix.go }}
- name: Setup Environment
run: |
echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Module cache
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go
- name: Build
run: 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 }}

@ -68,4 +68,4 @@ linters-settings:
# recommend 10-20
min-complexity: 50
goimports:
local-prefixes: github.com/go-kratos/kratos # Put imports beginning with prefix after 3rd-party packages
local-prefixes: github.com/go-kratos # Put imports beginning with prefix after 3rd-party packages

@ -1,9 +1,27 @@
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"
@ -14,7 +32,7 @@ LINTER := bin/golangci-lint
ifneq ($(GOBIN),)
BIN=$(GOBIN)
else
# check GOPATH
# check GOPATH
ifneq ($(GOPATH),)
BIN=$(GOPATH)/bin
endif
@ -37,9 +55,9 @@ ifeq ($(user),root)
@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)
$(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
@ -71,7 +89,7 @@ test:
.PHONY: test-coverage
test-coverage:
@${TOOLS_SHELL} test_coverage
@echo "go test with coverage finished"
@echo "go test with coverage finished"
.PHONY: lint
lint: $(LINTER)
@ -81,4 +99,4 @@ lint: $(LINTER)
.PHONY: proto
proto:
protoc --proto_path=./api --proto_path=./third_party --go_out=paths=source_relative:./api --go-grpc_out=paths=source_relative:./api --go-http_out=paths=source_relative:./api metadata/metadata.proto
protoc --proto_path=./third_party --go_out=paths=source_relative:./ errors/errors.proto
protoc --proto_path=./third_party --go_out=paths=source_relative:./errors/errors.proto

@ -110,5 +110,5 @@ 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.
- [tal-tech/go-zero](https://github.com/tal-tech/go-zero) is a web and rpc framework with lots of builtin engineering practices.
- [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.

@ -5,10 +5,10 @@
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 2.0.rc1 | :white_check_mark: |
| < 2.0.beta3 | :x: |
| Version | Supported |
|-------------|--------------------|
| 2.0.rc1 | :white_check_mark: |
| < 2.0.beta3 | :x: |
## Reporting a Vulnerability

@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"io"
"sort"
"sync"
"google.golang.org/grpc"
@ -97,7 +98,7 @@ func (s *Server) load() error {
}
// ListServices return all services
func (s *Server) ListServices(ctx context.Context, in *ListServicesRequest) (*ListServicesReply, error) {
func (s *Server) ListServices(_ context.Context, _ *ListServicesRequest) (*ListServicesReply, error) {
s.lock.Lock()
defer s.lock.Unlock()
if err := s.load(); err != nil {
@ -115,11 +116,13 @@ func (s *Server) ListServices(ctx context.Context, in *ListServicesRequest) (*Li
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(ctx context.Context, in *GetServiceDescRequest) (*GetServiceDescReply, error) {
func (s *Server) GetServiceDesc(_ context.Context, in *GetServiceDescRequest) (*GetServiceDescReply, error) {
s.lock.Lock()
defer s.lock.Unlock()
if err := s.load(); err != nil {

@ -89,8 +89,15 @@ func (a *App) Run() error {
a.mu.Lock()
a.instance = instance
a.mu.Unlock()
eg, ctx := errgroup.WithContext(NewContext(a.ctx, a))
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 {
@ -102,17 +109,23 @@ func (a *App) Run() error {
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(NewContext(a.opts.ctx, a))
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 {
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 {
@ -123,28 +136,36 @@ func (a *App) Run() error {
return a.Stop()
}
})
if err := eg.Wait(); err != nil && !errors.Is(err, context.Canceled) {
if err = eg.Wait(); err != nil && !errors.Is(err, context.Canceled) {
return err
}
return nil
for _, fn := range a.opts.afterStop {
err = fn(sctx)
}
return err
}
// Stop gracefully stops the application.
func (a *App) Stop() error {
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 {
if err = a.opts.registrar.Deregister(ctx, instance); err != nil {
return err
}
}
if a.cancel != nil {
a.cancel()
}
return nil
return err
}
func (a *App) buildInstance() (*registry.ServiceInstance, error) {

@ -19,7 +19,7 @@ type mockRegistry struct {
service map[string]*registry.ServiceInstance
}
func (r *mockRegistry) Register(ctx context.Context, service *registry.ServiceInstance) error {
func (r *mockRegistry) Register(_ context.Context, service *registry.ServiceInstance) error {
if service == nil || service.ID == "" {
return errors.New("no service id")
}
@ -30,7 +30,7 @@ func (r *mockRegistry) Register(ctx context.Context, service *registry.ServiceIn
}
// Deregister the registration.
func (r *mockRegistry) Deregister(ctx context.Context, service *registry.ServiceInstance) error {
func (r *mockRegistry) Deregister(_ context.Context, service *registry.ServiceInstance) error {
r.lk.Lock()
defer r.lk.Unlock()
if r.service[service.ID] == nil {
@ -47,6 +47,22 @@ func TestApp(t *testing.T) {
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() {

@ -3,15 +3,13 @@ module github.com/go-kratos/kratos/cmd/kratos/v2
go 1.16
require (
github.com/AlecAivazis/survey/v2 v2.3.4
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.5.1
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/text v0.3.7
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // 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
)

@ -1,5 +1,5 @@
github.com/AlecAivazis/survey/v2 v2.3.4 h1:pchTU9rsLUSvWEl2Aq9Pv3k0IE2fkqtGxazskAMd9Ng=
github.com/AlecAivazis/survey/v2 v2.3.4/go.mod h1:hrV6Y/kQCLhIZXGcriDCUBtB3wnN7156gMXJ3+b23xM=
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=
@ -39,37 +39,41 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
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=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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=
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-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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=

@ -18,8 +18,6 @@ func TestModulePath(t *testing.T) {
t.Fatal(err)
}
defer os.RemoveAll("/tmp/test_mod")
f, err := os.Create("/tmp/test_mod/go.mod")
if err != nil {
t.Fatal(err)
@ -38,6 +36,8 @@ go 1.16`
t.Fatal(err)
}
if p != "github.com/go-kratos/kratos/v2" {
t.Fatalf("want: %s, got: %s", "module github.com/go-kratos/kratos/v2", p)
t.Fatalf("want: %s, got: %s", "github.com/go-kratos/kratos/v2", p)
}
t.Cleanup(func() { os.RemoveAll("/tmp/test_mod") })
}

@ -5,7 +5,6 @@ import (
"fmt"
"log"
"os"
"path"
"path/filepath"
"strings"
@ -17,7 +16,7 @@ func kratosHome() string {
if err != nil {
log.Fatal(err)
}
home := path.Join(dir, ".kratos")
home := filepath.Join(dir, ".kratos")
if _, err := os.Stat(home); os.IsNotExist(err) {
if err := os.MkdirAll(home, 0o700); err != nil {
log.Fatal(err)
@ -27,7 +26,7 @@ func kratosHome() string {
}
func kratosHomeWithDir(dir string) string {
home := path.Join(kratosHome(), dir)
home := filepath.Join(kratosHome(), dir)
if _, err := os.Stat(home); os.IsNotExist(err) {
if err := os.MkdirAll(home, 0o700); err != nil {
log.Fatal(err)
@ -37,7 +36,6 @@ func kratosHomeWithDir(dir string) string {
}
func copyFile(src, dst string, replaces []string) error {
var err error
srcinfo, err := os.Stat(src)
if err != nil {
return err
@ -58,27 +56,26 @@ func copyFile(src, dst string, replaces []string) error {
}
func copyDir(src, dst string, replaces, ignores []string) error {
var err error
var fds []os.DirEntry
var srcinfo os.FileInfo
if srcinfo, err = os.Stat(src); err != nil {
srcinfo, err := os.Stat(src)
if err != nil {
return err
}
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
err = os.MkdirAll(dst, srcinfo.Mode())
if err != nil {
return err
}
if fds, err = os.ReadDir(src); err != nil {
fds, err := os.ReadDir(src)
if err != nil {
return err
}
for _, fd := range fds {
if hasSets(fd.Name(), ignores) {
continue
}
srcfp := path.Join(src, fd.Name())
dstfp := path.Join(dst, fd.Name())
srcfp := filepath.Join(src, fd.Name())
dstfp := filepath.Join(dst, fd.Name())
var e error
if fd.IsDir() {
e = copyDir(srcfp, dstfp, replaces, ignores)

@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"strings"
)
@ -68,7 +69,7 @@ func (r *Repo) Pull(ctx context.Context) error {
cmd.Dir = r.Path()
_, err := cmd.CombinedOutput()
if err != nil {
return nil
return err
}
cmd = exec.CommandContext(ctx, "git", "pull")
cmd.Dir = r.Path()
@ -104,7 +105,7 @@ func (r *Repo) CopyTo(ctx context.Context, to string, modPath string, ignores []
if err := r.Clone(ctx); err != nil {
return err
}
mod, err := ModulePath(path.Join(r.Path(), "go.mod"))
mod, err := ModulePath(filepath.Join(r.Path(), "go.mod"))
if err != nil {
return err
}
@ -116,7 +117,7 @@ func (r *Repo) CopyToV2(ctx context.Context, to string, modPath string, ignores,
if err := r.Clone(ctx); err != nil {
return err
}
mod, err := ModulePath(path.Join(r.Path(), "go.mod"))
mod, err := ModulePath(filepath.Join(r.Path(), "go.mod"))
if err != nil {
return err
}

@ -8,7 +8,7 @@ import (
)
var (
scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
scpSyntaxRe = regexp.MustCompile(`^(\w+)@([\w.-]+):(.*)$`)
scheme = []string{"git", "https", "http", "git+ssh", "ssh", "file", "ftp", "ftps"}
)

@ -28,7 +28,7 @@ func init() {
token = os.Getenv("GITHUB_TOKEN")
}
func run(cmd *cobra.Command, args []string) {
func run(_ *cobra.Command, args []string) {
owner, repo := ParseGithubURL(repoURL)
api := GithubAPI{Owner: owner, Repo: repo, Token: token}
version := "latest"

@ -43,7 +43,7 @@ func (g *GithubAPI) GetReleaseInfo(version string) ReleaseInfo {
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, "GET", nil, g.Token)
resp, code := requestGithubAPI(api, http.MethodGet, nil, g.Token)
if code != http.StatusOK {
printGithubErrorInfo(resp)
}
@ -63,7 +63,7 @@ func (g *GithubAPI) GetCommitsInfo() []CommitInfo {
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, "GET", nil, g.Token)
resp, code := requestGithubAPI(url, http.MethodGet, nil, g.Token)
if code != http.StatusOK {
printGithubErrorInfo(resp)
}

@ -4,7 +4,7 @@ import (
"context"
"fmt"
"os"
"path"
"path/filepath"
"github.com/AlecAivazis/survey/v2"
"github.com/fatih/color"
@ -17,7 +17,7 @@ var repoAddIgnores = []string{
}
func (p *Project) Add(ctx context.Context, dir string, layout string, branch string, mod string) error {
to := path.Join(dir, p.Path)
to := filepath.Join(dir, p.Name)
if _, err := os.Stat(to); !os.IsNotExist(err) {
fmt.Printf("🚫 %s already exists\n", p.Name)
@ -40,13 +40,13 @@ func (p *Project) Add(ctx context.Context, dir string, layout string, branch str
repo := base.NewRepo(layout, branch)
if err := repo.CopyToV2(ctx, to, path.Join(mod, p.Path), repoAddIgnores, []string{path.Join(p.Path, "api"), "api"}); err != nil {
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(
path.Join(to, "cmd", "server"),
path.Join(to, "cmd", p.Name),
filepath.Join(to, "cmd", "server"),
filepath.Join(to, "cmd", p.Name),
)
if e != nil {
return e

@ -4,12 +4,12 @@ import (
"context"
"fmt"
"os"
"path"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
"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.
@ -20,14 +20,14 @@ type Project struct {
// New new a project from remote repo.
func (p *Project) New(ctx context.Context, dir string, layout string, branch string) error {
to := path.Join(dir, p.Name)
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.",
}
var override bool
e := survey.AskOne(prompt, &override)
if e != nil {
return e
@ -39,12 +39,12 @@ func (p *Project) New(ctx context.Context, dir string, layout string, branch str
}
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.Path, []string{".git", ".github"}); err != nil {
if err := repo.CopyTo(ctx, to, p.Name, []string{".git", ".github"}); err != nil {
return err
}
e := os.Rename(
path.Join(to, "cmd", "server"),
path.Join(to, "cmd", p.Name),
filepath.Join(to, "cmd", "server"),
filepath.Join(to, "cmd", p.Name),
)
if e != nil {
return e

@ -5,7 +5,8 @@ import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/AlecAivazis/survey/v2"
@ -40,7 +41,7 @@ func init() {
CmdNew.Flags().BoolVarP(&nomod, "nomod", "", nomod, "retain go mod")
}
func run(cmd *cobra.Command, args []string) {
func run(_ *cobra.Command, args []string) {
wd, err := os.Getwd()
if err != nil {
panic(err)
@ -64,23 +65,34 @@ func run(cmd *cobra.Command, args []string) {
} else {
name = args[0]
}
p := &Project{Name: path.Base(name), Path: name}
projectName, workingDir := processProjectParams(name, wd)
p := &Project{Name: projectName}
done := make(chan error, 1)
go func() {
if !nomod {
done <- p.New(ctx, wd, repoURL, branch)
done <- p.New(ctx, workingDir, repoURL, branch)
return
}
if _, e := os.Stat(path.Join(wd, "go.mod")); os.IsNotExist(e) {
done <- fmt.Errorf("🚫 go.mod don't exists in %s", wd)
projectRoot := getgomodProjectRoot(workingDir)
if gomodIsNotExistIn(projectRoot) {
done <- fmt.Errorf("🚫 go.mod don't exists in %s", projectRoot)
return
}
mod, e := base.ModulePath(path.Join(wd, "go.mod"))
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 {
panic(e)
done <- fmt.Errorf("🚫 failed to parse `go.mod`: %v", e)
return
}
done <- p.Add(ctx, wd, repoURL, branch, mod)
// 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():
@ -95,3 +107,43 @@ func run(cmd *cobra.Command, args []string) {
}
}
}
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)
}
})
}
}

@ -19,8 +19,11 @@ var CmdAdd = &cobra.Command{
Run: run,
}
func run(cmd *cobra.Command, args []string) {
// kratos proto add helloworld/v1/helloworld.proto
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 {

@ -3,7 +3,7 @@ package add
import (
"fmt"
"os"
"path"
"path/filepath"
)
// Proto is a proto generator.
@ -26,13 +26,13 @@ func (p *Proto) Generate() error {
if err != nil {
panic(err)
}
to := path.Join(wd, p.Path)
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 := path.Join(to, p.Name)
name := filepath.Join(to, p.Name)
if _, err := os.Stat(name); !os.IsNotExist(err) {
return fmt.Errorf("%s already exists", p.Name)
}

@ -8,9 +8,9 @@ import (
"regexp"
"strings"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
// CmdClient represents the source command.
@ -30,7 +30,7 @@ func init() {
CmdClient.Flags().StringVarP(&protoPath, "proto_path", "p", protoPath, "proto path")
}
func run(cmd *cobra.Command, args []string) {
func run(_ *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Println("Please enter the proto file or directory")
return

@ -1,11 +1,11 @@
package proto
import (
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/add"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/client"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/server"
"github.com/spf13/cobra"
)
// CmdProto represents the proto command.

@ -4,7 +4,7 @@ import (
"fmt"
"log"
"os"
"path"
"path/filepath"
"strings"
"github.com/emicklei/proto"
@ -16,8 +16,8 @@ import (
// 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",
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
@ -26,7 +26,7 @@ func init() {
CmdServer.Flags().StringVarP(&targetDir, "target-dir", "t", "internal/service", "generate target directory")
}
func run(cmd *cobra.Command, args []string) {
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
@ -64,8 +64,8 @@ func run(cmd *cobra.Command, args []string) {
continue
}
cs.Methods = append(cs.Methods, &Method{
Service: serviceName(s.Name), Name: serviceName(r.Name), Request: r.RequestType,
Reply: r.ReturnsType, Type: getMethodType(r.StreamsRequest, r.StreamsReturns),
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)
@ -76,7 +76,7 @@ func run(cmd *cobra.Command, args []string) {
return
}
for _, s := range res {
to := path.Join(targetDir, strings.ToLower(s.Service)+".go")
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
@ -105,6 +105,10 @@ func getMethodType(streamsRequest, streamsReturns bool) MethodType {
return unaryType
}
func parametersName(name string) string {
return strings.ReplaceAll(name, ".", "_")
}
func serviceName(name string) string {
return toUpperCamelCase(strings.Split(name, ".")[0])
}

@ -60,3 +60,43 @@ func Test_serviceName(t *testing.T) {
})
}
}
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)
}
})
}
}

@ -4,7 +4,6 @@ import (
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
@ -19,6 +18,11 @@ var CmdRun = &cobra.Command{
Long: "Run project. Example: kratos run",
Run: Run,
}
var targetDir string
func init() {
CmdRun.Flags().StringVarP(&targetDir, "work", "w", "", "target working directory")
}
// Run run project.
func Run(cmd *cobra.Command, args []string) {
@ -64,10 +68,11 @@ func Run(cmd *cobra.Command, args []string) {
dir = cmdPath[dir]
}
}
fd := exec.Command("go", append([]string{"run", "."}, programArgs...)...)
fd := exec.Command("go", append([]string{"run", dir}, programArgs...)...)
fd.Stdout = os.Stdout
fd.Stderr = os.Stderr
fd.Dir = dir
changeWorkingDirectory(fd, targetDir)
if err := fd.Run(); err != nil {
fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", err.Error())
return
@ -102,7 +107,7 @@ func findCMD(base string) (map[string]string, error) {
}
for _, fileInfo := range paths {
if fileInfo.IsDir() {
abs := path.Join(walkPath, fileInfo.Name())
abs := filepath.Join(walkPath, fileInfo.Name())
cmdPath[strings.TrimPrefix(abs, wd)] = abs
}
}
@ -131,3 +136,10 @@ func findCMD(base string) (map[string]string, error) {
}
return map[string]string{"": base}, nil
}
func changeWorkingDirectory(cmd *exec.Cmd, targetDir string) {
targetDir = strings.TrimSpace(targetDir)
if targetDir != "" {
cmd.Dir = targetDir
}
}

@ -3,9 +3,9 @@ package upgrade
import (
"fmt"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
// CmdUpgrade represents the upgrade command.
@ -17,7 +17,7 @@ var CmdUpgrade = &cobra.Command{
}
// Run upgrade the kratos tools.
func Run(cmd *cobra.Command, args []string) {
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",

@ -3,13 +3,13 @@ package main
import (
"log"
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/change"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/project"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/run"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/upgrade"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{

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

@ -59,7 +59,7 @@ func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.
}
}
func genErrorsReason(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, enum *protogen.Enum) bool {
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 {

@ -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 }}

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

@ -1,9 +1,31 @@
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=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
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=

@ -2,28 +2,12 @@ package main
import (
"bytes"
_ "embed"
"text/template"
)
var errorsTemplate = `
{{ 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 }}
`
//go:embed errorsTemplate.tpl
var errorsTemplate string
type errorInfo struct {
Name string

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

@ -2,6 +2,7 @@ package main
import (
"fmt"
"net/http"
"os"
"regexp"
"strings"
@ -23,7 +24,7 @@ const (
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) *protogen.GeneratedFile {
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
}
@ -41,12 +42,12 @@ func generateFile(gen *protogen.Plugin, file *protogen.File, omitempty bool) *pr
g.P()
g.P("package ", file.GoPackageName)
g.P()
generateFileContent(gen, file, g, omitempty)
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) {
func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, omitempty bool, omitemptyPrefix string) {
if len(file.Services) == 0 {
return
}
@ -58,11 +59,11 @@ func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.
g.P()
for _, service := range file.Services {
genService(gen, file, g, service, omitempty)
genService(gen, file, g, service, omitempty, omitemptyPrefix)
}
}
func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service, omitempty bool) {
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)
@ -80,12 +81,12 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated
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, method, bind))
sd.Methods = append(sd.Methods, buildHTTPRule(g, service, method, bind, omitemptyPrefix))
}
sd.Methods = append(sd.Methods, buildHTTPRule(g, method, rule))
sd.Methods = append(sd.Methods, buildHTTPRule(g, service, method, rule, omitemptyPrefix))
} else if !omitempty {
path := fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name())
sd.Methods = append(sd.Methods, buildMethodDesc(g, method, "POST", path))
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 {
@ -108,7 +109,7 @@ func hasHTTPRule(services []*protogen.Service) bool {
return false
}
func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotations.HttpRule) *methodDesc {
func buildHTTPRule(g *protogen.GeneratedFile, service *protogen.Service, m *protogen.Method, rule *annotations.HttpRule, omitemptyPrefix string) *methodDesc {
var (
path string
method string
@ -119,27 +120,33 @@ func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotati
switch pattern := rule.Pattern.(type) {
case *annotations.HttpRule_Get:
path = pattern.Get
method = "GET"
method = http.MethodGet
case *annotations.HttpRule_Put:
path = pattern.Put
method = "PUT"
method = http.MethodPut
case *annotations.HttpRule_Post:
path = pattern.Post
method = "POST"
method = http.MethodPost
case *annotations.HttpRule_Delete:
path = pattern.Delete
method = "DELETE"
method = http.MethodDelete
case *annotations.HttpRule_Patch:
path = pattern.Patch
method = "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 == "GET" || method == "DELETE" {
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)
}
@ -197,12 +204,17 @@ func buildMethodDesc(g *protogen.GeneratedFile, m *protogen.Method, method, path
}
}
}
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,
@ -213,7 +225,7 @@ 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]*)=?([^{}]*)}`)
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 {

@ -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}}

@ -9,8 +9,9 @@ import (
)
var (
showVersion = flag.Bool("version", false, "print the version and exit")
omitempty = flag.Bool("omitempty", true, "omit if google.api is empty")
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() {
@ -27,7 +28,7 @@ func main() {
if !f.Generate {
continue
}
generateFile(gen, f, *omitempty)
generateFile(gen, f, *omitempty, *omitemptyPrefix)
}
return nil
})

@ -2,102 +2,13 @@ package main
import (
"bytes"
_ "embed"
"strings"
"text/template"
)
var httpTemplate = `
{{$svrType := .ServiceType}}
{{$svrName := .ServiceName}}
{{- range .MethodSets}}
const Operation{{$svrType}}{{.OriginalName}} = "/{{$svrName}}/{{.OriginalName}}"
{{- end}}
type {{.ServiceType}}HTTPServer interface {
{{- range .MethodSets}}
{{.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}}
`
//go:embed httpTemplate.tpl
var httpTemplate string
type serviceDesc struct {
ServiceType string // Greeter
@ -114,6 +25,7 @@ type methodDesc struct {
Num int
Request string
Reply string
Comment string
// http_rule
Path string
Method string

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

@ -15,13 +15,13 @@ import (
"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")
_ Config = (*config)(nil)
)
// Observer is config observer.
@ -44,7 +44,7 @@ type config struct {
watchers []Watcher
}
// New new a config with options.
// New a config with options.
func New(opts ...Option) Config {
o := options{
decoder: defaultDecoder,
@ -62,11 +62,11 @@ func New(opts ...Option) Config {
func (c *config) watch(w Watcher) {
for {
kvs, err := w.Next()
if errors.Is(err, context.Canceled) {
log.Infof("watcher's ctx cancel : %v", err)
return
}
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

@ -2,7 +2,6 @@ package config
import (
"errors"
"reflect"
"testing"
)
@ -124,7 +123,7 @@ func TestConfig(t *testing.T) {
)
err = c.Close()
if err != nil {
t.Fatal("t is not nil")
t.Fatal(err)
}
jSource := newTestJSONSource(_testJSON)
@ -139,21 +138,21 @@ func TestConfig(t *testing.T) {
err = cf.Load()
if err != nil {
t.Fatal("t is not nil")
t.Fatal(err)
}
val, err := cf.Value("data.database.driver").String()
driver, err := cf.Value("data.database.driver").String()
if err != nil {
t.Fatal("t is not nil")
t.Fatal(err)
}
if !reflect.DeepEqual(databaseDriver, val) {
t.Fatal(`databaseDriver is not equal to val`)
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("t is not nil")
t.Fatal(err)
}
jSource.sig <- struct{}{}
@ -162,24 +161,24 @@ func TestConfig(t *testing.T) {
var testConf testConfigStruct
err = cf.Scan(&testConf)
if err != nil {
t.Fatal("t is not nil")
t.Fatal(err)
}
if !reflect.DeepEqual(httpAddr, testConf.Server.HTTP.Addr) {
t.Fatal(`httpAddr is not equal to testConf.Server.HTTP.Addr`)
if httpAddr != testConf.Server.HTTP.Addr {
t.Errorf("testConf.Server.HTTP.Addr want: %s, got: %s", httpAddr, testConf.Server.HTTP.Addr)
}
if !reflect.DeepEqual(httpTimeout, testConf.Server.HTTP.Timeout) {
t.Fatal(`httpTimeout is not equal to testConf.Server.HTTP.Timeout`)
if httpTimeout != testConf.Server.HTTP.Timeout {
t.Errorf("testConf.Server.HTTP.Timeout want: %.1f, got: %.1f", httpTimeout, testConf.Server.HTTP.Timeout)
}
if !reflect.DeepEqual(true, testConf.Server.HTTP.EnableSSL) {
t.Fatal(`testConf.Server.HTTP.EnableSSL is not equal to true`)
if !testConf.Server.HTTP.EnableSSL {
t.Error("testConf.Server.HTTP.EnableSSL is not equal to true")
}
if !reflect.DeepEqual(grpcPort, testConf.Server.GRPC.Port) {
t.Fatal(`grpcPort is not equal to testConf.Server.GRPC.Port`)
if grpcPort != testConf.Server.GRPC.Port {
t.Errorf("testConf.Server.GRPC.Port want: %d, got: %d", grpcPort, testConf.Server.GRPC.Port)
}
if !reflect.DeepEqual(endpoint1, testConf.Endpoints[0]) {
t.Fatal(`endpoint1 is not equal to testConf.Endpoints[0]`)
if endpoint1 != testConf.Endpoints[0] {
t.Errorf("testConf.Endpoints[0] want: %s, got: %s", endpoint1, testConf.Endpoints[0])
}
if !reflect.DeepEqual(len(testConf.Endpoints), 2) {
t.Fatal(`len(testConf.Endpoints) is not equal to 2`)
if len(testConf.Endpoints) != 2 {
t.Error("len(testConf.Endpoints) is not equal to 2")
}
}

6
config/env/env.go vendored

@ -19,11 +19,11 @@ func (e *env) Load() (kv []*config.KeyValue, err error) {
return e.load(os.Environ()), nil
}
func (e *env) load(envStrings []string) []*config.KeyValue {
func (e *env) load(envs []string) []*config.KeyValue {
var kv []*config.KeyValue
for _, envstr := range envStrings {
for _, env := range envs {
var k, v string
subs := strings.SplitN(envstr, "=", 2) //nolint:gomnd
subs := strings.SplitN(env, "=", 2) //nolint:gomnd
k = subs[0]
if len(subs) > 1 {
v = subs[1]

@ -6,13 +6,13 @@ import (
"github.com/go-kratos/kratos/v2/config"
)
var _ config.Watcher = (*watcher)(nil)
type watcher struct {
ctx context.Context
cancel context.CancelFunc
}
var _ config.Watcher = (*watcher)(nil)
func NewWatcher() (config.Watcher, error) {
ctx, cancel := context.WithCancel(context.Background())
return &watcher{ctx: ctx, cancel: cancel}, nil

@ -121,10 +121,10 @@ func testWatchFile(t *testing.T, path string) {
}
kvs, err := watch.Next()
if err != nil {
t.Errorf(`watch.Next() error(%v)`, err)
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)
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")
@ -133,15 +133,15 @@ func testWatchFile(t *testing.T, path string) {
}
kvs, err = watch.Next()
if err == nil {
t.Errorf(`watch.Next() error(%v)`, err)
t.Errorf("watch.Next() error(%v)", err)
}
if kvs != nil {
t.Errorf(`watch.Next() error(%v)`, err)
t.Errorf("watch.Next() error(%v)", err)
}
err = watch.Stop()
if err != nil {
t.Errorf(`watch.Stop() error(%v)`, err)
t.Errorf("watch.Stop() error(%v)", err)
}
if err := os.Rename(newFilepath, path); err != nil {
@ -171,10 +171,10 @@ func testWatchDir(t *testing.T, path, file string) {
kvs, err := watch.Next()
if err != nil {
t.Errorf(`watch.Next() error(%v)`, err)
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)
t.Errorf("string(kvs[0].Value(%s) is not equal to _testJSONUpdate(%v)", kvs[0].Value, _testJSONUpdate)
}
}

@ -1,6 +1,8 @@
package file
import "testing"
import (
"testing"
)
func TestFormat(t *testing.T) {
tests := []struct {

@ -10,6 +10,8 @@ import (
"github.com/go-kratos/kratos/v2/config"
)
var _ config.Watcher = (*watcher)(nil)
type watcher struct {
f *file
fw *fsnotify.Watcher
@ -18,8 +20,6 @@ type watcher struct {
cancel context.CancelFunc
}
var _ config.Watcher = (*watcher)(nil)
func newWatcher(f *file) (config.Watcher, error) {
fw, err := fsnotify.NewWatcher()
if err != nil {

@ -51,7 +51,7 @@ func WithResolver(r Resolver) Option {
// WithLogger with config logger.
// Deprecated: use global logger instead.
func WithLogger(l log.Logger) Option {
func WithLogger(_ log.Logger) Option {
return func(o *options) {}
}

@ -15,7 +15,7 @@ func TestDefaultDecoder(t *testing.T) {
target := make(map[string]interface{})
err := defaultDecoder(src, target)
if err != nil {
t.Fatal("err is not 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"}`)
@ -29,7 +29,7 @@ func TestDefaultDecoder(t *testing.T) {
target = make(map[string]interface{})
err = defaultDecoder(src, target)
if err != nil {
t.Fatal("err is not nil")
t.Fatal(err)
}
if !reflect.DeepEqual(map[string]interface{}{
"service": map[string]interface{}{
@ -150,7 +150,7 @@ func TestDefaultResolver(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
err := defaultResolver(data)
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
rd := reader{
values: data,
@ -161,25 +161,25 @@ func TestDefaultResolver(t *testing.T) {
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`)
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`)
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`)
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`)
t.Fatal("expect is not equal to actual")
}
}
default:

@ -8,11 +8,11 @@ import (
"strings"
"sync"
"github.com/go-kratos/kratos/v2/log"
"github.com/imdario/mergo"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"github.com/go-kratos/kratos/v2/log"
)
// Reader is config reader.
@ -38,9 +38,7 @@ func newReader(opts options) Reader {
}
func (r *reader) Merge(kvs ...*KeyValue) error {
r.lock.Lock()
merged, err := cloneMap(r.values)
r.lock.Unlock()
merged, err := r.cloneMap()
if err != nil {
return err
}
@ -79,6 +77,12 @@ func (r *reader) Resolve() error {
return r.opts.resolver(r.values)
}
func (r *reader) cloneMap() (map[string]interface{}, error) {
r.lock.Lock()
defer r.lock.Unlock()
return cloneMap(r.values)
}
func cloneMap(src map[string]interface{}) (map[string]interface{}, error) {
// https://gist.github.com/soroushjp/0ec92102641ddfc3ad5515ca76405f4d
var buf bytes.Buffer
@ -90,12 +94,12 @@ func cloneMap(src map[string]interface{}) (map[string]interface{}, error) {
if err != nil {
return nil, err
}
var copy map[string]interface{}
err = dec.Decode(&copy)
var clone map[string]interface{}
err = dec.Decode(&clone)
if err != nil {
return nil, err
}
return copy, nil
return clone, nil
}
func convertMap(src interface{}) interface{} {

@ -29,7 +29,7 @@ func TestReader_Merge(t *testing.T) {
Format: "json",
})
if err == nil {
t.Fatal(`err is nil`)
t.Fatal("err is nil")
}
err = r.Merge(&KeyValue{
@ -38,15 +38,15 @@ func TestReader_Merge(t *testing.T) {
Format: "json",
})
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
vv, ok := r.Value("nice")
if !ok {
t.Fatal(`ok is false`)
t.Fatal("ok is false")
}
vvv, err := vv.String()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if vvv != "boat" {
t.Fatal(`vvv is not equal to "boat"`)
@ -58,18 +58,18 @@ func TestReader_Merge(t *testing.T) {
Format: "json",
})
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
vv, ok = r.Value("x")
if !ok {
t.Fatal(`ok is false`)
t.Fatal("ok is false")
}
vvx, err := vv.Int()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if int64(2) != vvx {
t.Fatal(`vvx is not equal to 2`)
if vvx != 2 {
t.Fatal("vvx is not equal to 2")
}
}
@ -118,27 +118,27 @@ a:
r := newReader(opts)
err := r.Merge(&test.kv)
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
vv, ok := r.Value("a.b.X")
if !ok {
t.Fatal(`ok is false`)
t.Fatal("ok is false")
}
vvv, err := vv.Int()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if int64(1) != vvv {
t.Fatal(`vvv is not equal to 1`)
t.Fatal("vvv is not equal to 1")
}
vv, ok = r.Value("a.b.Y")
if !ok {
t.Fatal(`ok is false`)
t.Fatal("ok is false")
}
vvy, err := vv.String()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if vvy != "lol" {
t.Fatal(`vvy is not equal to "lol"`)
@ -146,29 +146,29 @@ a:
vv, ok = r.Value("a.b.z")
if !ok {
t.Fatal(`ok is false`)
t.Fatal("ok is false")
}
vvz, err := vv.Bool()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if !vvz {
t.Fatal(`vvz is not equal to true`)
t.Fatal("vvz is not equal to true")
}
_, ok = r.Value("aasasdg=234l.asdfk,")
if ok {
t.Fatal(`ok is true`)
t.Fatal("ok is true")
}
_, ok = r.Value("aas......asdg=234l.asdfk,")
if ok {
t.Fatal(`ok is true`)
t.Fatal("ok is true")
}
_, ok = r.Value("a.b.Y.")
if ok {
t.Fatal(`ok is true`)
t.Fatal("ok is true")
}
})
}
@ -192,11 +192,11 @@ func TestReader_Source(t *testing.T) {
Format: "json",
})
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
b, err := r.Source()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if !reflect.DeepEqual([]byte(`{"a":{"b":{"X":1}}}`), b) {
t.Fatal("[]byte(`{\"a\":{\"b\":{\"X\":1}}}`) is not equal to b")

@ -1,7 +1,7 @@
package config
import (
stdjson "encoding/json"
"encoding/json"
"fmt"
"reflect"
"strconv"
@ -10,7 +10,7 @@ import (
"google.golang.org/protobuf/proto"
"github.com/go-kratos/kratos/v2/encoding/json"
kratosjson "github.com/go-kratos/kratos/v2/encoding/json"
)
var (
@ -36,6 +36,10 @@ type atomicValue struct {
atomic.Value
}
func (v *atomicValue) typeAssertError() error {
return fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
}
func (v *atomicValue) Bool() (bool, error) {
switch val := v.Load().(type) {
case bool:
@ -43,7 +47,7 @@ func (v *atomicValue) Bool() (bool, error) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, string:
return strconv.ParseBool(fmt.Sprint(val))
}
return false, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
return false, v.typeAssertError()
}
func (v *atomicValue) Int() (int64, error) {
@ -73,35 +77,37 @@ func (v *atomicValue) Int() (int64, error) {
case float64:
return int64(val), nil
case string:
return strconv.ParseInt(val, 10, 64) //nolint:gomnd
return strconv.ParseInt(val, 10, 64)
}
return 0, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
return 0, v.typeAssertError()
}
func (v *atomicValue) Slice() ([]Value, error) {
if vals, ok := v.Load().([]interface{}); ok {
var slices []Value
for _, val := range vals {
a := &atomicValue{}
a.Store(val)
slices = append(slices, a)
}
return slices, nil
vals, ok := v.Load().([]interface{})
if !ok {
return nil, v.typeAssertError()
}
return nil, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
slices := make([]Value, 0, len(vals))
for _, val := range vals {
a := new(atomicValue)
a.Store(val)
slices = append(slices, a)
}
return slices, nil
}
func (v *atomicValue) Map() (map[string]Value, error) {
if vals, ok := v.Load().(map[string]interface{}); ok {
m := make(map[string]Value, len(vals))
for key, val := range vals {
a := new(atomicValue)
a.Store(val)
m[key] = a
}
return m, nil
vals, ok := v.Load().(map[string]interface{})
if !ok {
return nil, v.typeAssertError()
}
m := make(map[string]Value, len(vals))
for key, val := range vals {
a := new(atomicValue)
a.Store(val)
m[key] = a
}
return nil, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
return m, nil
}
func (v *atomicValue) Float() (float64, error) {
@ -131,9 +137,9 @@ func (v *atomicValue) Float() (float64, error) {
case float64:
return val, nil
case string:
return strconv.ParseFloat(val, 64) //nolint:gomnd
return strconv.ParseFloat(val, 64)
}
return 0.0, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
return 0.0, v.typeAssertError()
}
func (v *atomicValue) String() (string, error) {
@ -147,7 +153,7 @@ func (v *atomicValue) String() (string, error) {
case fmt.Stringer:
return val.String(), nil
}
return "", fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
return "", v.typeAssertError()
}
func (v *atomicValue) Duration() (time.Duration, error) {
@ -159,14 +165,14 @@ func (v *atomicValue) Duration() (time.Duration, error) {
}
func (v *atomicValue) Scan(obj interface{}) error {
data, err := stdjson.Marshal(v.Load())
data, err := json.Marshal(v.Load())
if err != nil {
return err
}
if pb, ok := obj.(proto.Message); ok {
return json.UnmarshalOptions.Unmarshal(data, pb)
return kratosjson.UnmarshalOptions.Unmarshal(data, pb)
}
return stdjson.Unmarshal(data, obj)
return json.Unmarshal(data, obj)
}
type errValue struct {

@ -6,17 +6,17 @@ import (
"time"
)
func Test_atomicValue_Bool(t *testing.T) {
func TestAtomicValue_Bool(t *testing.T) {
vlist := []interface{}{"1", "t", "T", "true", "TRUE", "True", true, 1, int32(1)}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.Bool()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if !b {
t.Fatal(`b is not equal to true`)
t.Fatal("b is not equal to true")
}
}
@ -26,10 +26,10 @@ func Test_atomicValue_Bool(t *testing.T) {
v.Store(x)
b, err := v.Bool()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b {
t.Fatal(`b is not equal to false`)
t.Fatal("b is not equal to false")
}
}
@ -39,22 +39,22 @@ func Test_atomicValue_Bool(t *testing.T) {
v.Store(x)
_, err := v.Bool()
if err == nil {
t.Fatal(`err is nil`)
t.Fatal("err is nil")
}
}
}
func Test_atomicValue_Int(t *testing.T) {
func TestAtomicValue_Int(t *testing.T) {
vlist := []interface{}{"123123", float64(123123), int64(123123), int32(123123), 123123}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.Int()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b != 123123 {
t.Fatal(`b is not equal to 123123`)
t.Fatal("b is not equal to 123123")
}
}
@ -64,22 +64,22 @@ func Test_atomicValue_Int(t *testing.T) {
v.Store(x)
_, err := v.Int()
if err == nil {
t.Fatal(`err is nil`)
t.Fatal("err is nil")
}
}
}
func Test_atomicValue_Float(t *testing.T) {
func TestAtomicValue_Float(t *testing.T) {
vlist := []interface{}{"123123.1", 123123.1}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.Float()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b != 123123.1 {
t.Fatal(`b is not equal to 123123.1`)
t.Fatal("b is not equal to 123123.1")
}
}
@ -89,7 +89,7 @@ func Test_atomicValue_Float(t *testing.T) {
v.Store(x)
_, err := v.Float()
if err == nil {
t.Fatal(`err is nil`)
t.Fatal("err is nil")
}
}
}
@ -103,17 +103,17 @@ func (t ts) String() string {
return fmt.Sprintf("%s%d", t.Name, t.Age)
}
func Test_atomicValue_String(t *testing.T) {
func TestAtomicValue_String(t *testing.T) {
vlist := []interface{}{"1", float64(1), int64(1), 1, int64(1)}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.String()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b != "1" {
t.Fatal(`b is not equal to 1`)
t.Fatal("b is not equal to 1")
}
}
@ -121,7 +121,7 @@ func Test_atomicValue_String(t *testing.T) {
v.Store(true)
b, err := v.String()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b != "true" {
t.Fatal(`b is not equal to "true"`)
@ -134,48 +134,48 @@ func Test_atomicValue_String(t *testing.T) {
})
b, err = v.String()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b != "test10" {
t.Fatal(`b is not equal to "test10"`)
}
}
func Test_atomicValue_Duration(t *testing.T) {
func TestAtomicValue_Duration(t *testing.T) {
vlist := []interface{}{int64(5)}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.Duration()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b != time.Duration(5) {
t.Fatal(`b is not equal to time.Duration(5)`)
t.Fatal("b is not equal to time.Duration(5)")
}
}
}
func Test_atomicValue_Slice(t *testing.T) {
func TestAtomicValue_Slice(t *testing.T) {
vlist := []interface{}{int64(5)}
v := atomicValue{}
v.Store(vlist)
slices, err := v.Slice()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
for _, v := range slices {
b, err := v.Duration()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b != time.Duration(5) {
t.Fatal(`b is not equal to time.Duration(5)`)
t.Fatal("b is not equal to time.Duration(5)")
}
}
}
func Test_atomicValue_Map(t *testing.T) {
func TestAtomicValue_Map(t *testing.T) {
vlist := make(map[string]interface{})
vlist["5"] = int64(5)
vlist["text"] = "text"
@ -183,21 +183,21 @@ func Test_atomicValue_Map(t *testing.T) {
v.Store(vlist)
m, err := v.Map()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
for k, v := range m {
if k == "5" {
b, err := v.Duration()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b != time.Duration(5) {
t.Fatal(`b is not equal to time.Duration(5)`)
t.Fatal("b is not equal to time.Duration(5)")
}
} else {
b, err := v.String()
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
if b != "text" {
t.Fatal(`b is not equal to "text"`)
@ -206,20 +206,19 @@ func Test_atomicValue_Map(t *testing.T) {
}
}
func Test_atomicValue_Scan(t *testing.T) {
var err error
func TestAtomicValue_Scan(t *testing.T) {
v := atomicValue{}
err = v.Scan(&struct {
err := v.Scan(&struct {
A string `json:"a"`
}{"a"})
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
err = v.Scan(&struct {
A string `json:"a"`
}{"a"})
if err != nil {
t.Fatal(`err is not nil`)
t.Fatal(err)
}
}

@ -97,5 +97,4 @@ config := map[string]interface{}{
}
}
}
_ = config
```

@ -3,15 +3,14 @@ package apollo
import (
"strings"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/log"
"github.com/apolloconfig/agollo/v4"
"github.com/apolloconfig/agollo/v4/constant"
apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
apolloconfig "github.com/apolloconfig/agollo/v4/env/config"
"github.com/apolloconfig/agollo/v4/extension"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
)
type apollo struct {
@ -26,6 +25,8 @@ const (
properties = "properties"
)
var formats map[string]struct{}
// Option is apollo option
type Option func(*options)
@ -111,8 +112,8 @@ func NewSource(opts ...Option) config.Source {
for _, o := range opts {
o(&op)
}
client, err := agollo.StartWithConfig(func() (*apolloConfig.AppConfig, error) {
return &apolloConfig.AppConfig{
client, err := agollo.StartWithConfig(func() (*apolloconfig.AppConfig, error) {
return &apolloconfig.AppConfig{
AppID: op.appid,
Cluster: op.cluster,
NamespaceName: op.namespace,
@ -130,10 +131,16 @@ func NewSource(opts ...Option) config.Source {
func format(ns string) string {
arr := strings.Split(ns, ".")
if len(arr) <= 1 || arr[len(arr)-1] == properties {
suffix := arr[len(arr)-1]
if len(arr) <= 1 || suffix == properties {
return json
}
return arr[len(arr)-1]
if _, ok := formats[suffix]; !ok {
// fallback
return json
}
return suffix
}
func (e *apollo) load() []*config.KeyValue {
@ -150,7 +157,7 @@ func (e *apollo) load() []*config.KeyValue {
kvs = append(kvs, kv)
continue
}
if strings.Contains(ns, ".") && !strings.Contains(ns, properties) &&
if strings.Contains(ns, ".") && !strings.HasSuffix(ns, "."+properties) &&
(format(ns) == yaml || format(ns) == yml || format(ns) == json) {
kv, err := e.getOriginConfig(ns)
if err != nil {
@ -159,14 +166,13 @@ func (e *apollo) load() []*config.KeyValue {
}
kvs = append(kvs, kv)
continue
} else {
kv, err := e.getConfig(ns)
if err != nil {
log.Errorf("apollo get config failed,err:%v", err)
continue
}
kvs = append(kvs, kv)
}
kv, err := e.getConfig(ns)
if err != nil {
log.Errorf("apollo get config failed,err:%v", err)
continue
}
kvs = append(kvs, kv)
}
return kvs
}
@ -253,16 +259,28 @@ func resolve(key string, value interface{}, target map[string]interface{}) {
// eg: namespace.ext with subKey got namespace.subKey
func genKey(ns, sub string) string {
arr := strings.Split(ns, ".")
if len(arr) < 1 {
return sub
}
if len(arr) == 1 {
if ns == "" {
return sub
}
return ns + "." + sub
}
return strings.Join(arr[:len(arr)-1], ".") + "." + sub
suffix := arr[len(arr)-1]
_, ok := formats[suffix]
if ok {
return strings.Join(arr[:len(arr)-1], ".") + "." + sub
}
return ns + "." + sub
}
func init() {
formats = make(map[string]struct{})
formats[yaml] = struct{}{}
formats[yml] = struct{}{}
formats[json] = struct{}{}
formats[properties] = struct{}{}
}

@ -0,0 +1,90 @@
package apollo
import (
"testing"
)
func Test_genKey(t *testing.T) {
type args struct {
ns string
sub string
}
tests := []struct {
name string
args args
want string
}{
{
name: "blank namespace",
args: args{
ns: "",
sub: "x.y",
},
want: "x.y",
},
{
name: "properties namespace",
args: args{
ns: "application",
sub: "x.y",
},
want: "application.x.y",
},
{
name: "namespace with format",
args: args{
ns: "app.yaml",
sub: "x.y",
},
want: "app.x.y",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := genKey(tt.args.ns, tt.args.sub); got != tt.want {
t.Errorf("genKey() = %v, want %v", got, tt.want)
}
})
}
}
func Test_format(t *testing.T) {
tests := []struct {
name string
namespace string
want string
}{
{
name: "properties namespace",
namespace: "application",
want: "json",
},
{
name: "properties namespace #1",
namespace: "app.setting",
want: "json",
},
{
name: "namespace with format[yaml]",
namespace: "app.yaml",
want: "yaml",
},
{
name: "namespace with format[yml]",
namespace: "app.yml",
want: "yml",
},
{
name: "namespace with format[json]",
namespace: "app.json",
want: "json",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := format(tt.namespace); got != tt.want {
t.Errorf("format() = %v, want %v", got, tt.want)
}
})
}
}

@ -3,13 +3,10 @@ module github.com/go-kratos/kratos/contrib/config/apollo/v2
go 1.16
require (
github.com/apolloconfig/agollo/v4 v4.2.0
github.com/go-kratos/kratos/v2 v2.4.0
github.com/apolloconfig/agollo/v4 v4.3.0
github.com/go-kratos/kratos/v2 v2.6.3
)
require (
github.com/spf13/viper v1.11.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
require github.com/spf13/viper v1.11.0 // indirect
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -4,12 +4,11 @@ import (
"context"
"strings"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/apolloconfig/agollo/v4/storage"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
"github.com/apolloconfig/agollo/v4/storage"
)
type watcher struct {
@ -26,7 +25,7 @@ type customChangeListener struct {
func (c *customChangeListener) onChange(namespace string, changes map[string]*storage.ConfigChange) []*config.KeyValue {
kv := make([]*config.KeyValue, 0, 2)
if strings.Contains(namespace, ".") && !strings.Contains(namespace, properties) &&
if strings.Contains(namespace, ".") && !strings.HasSuffix(namespace, "."+properties) &&
(format(namespace) == yaml || format(namespace) == yml || format(namespace) == json) {
value, err := c.apollo.client.GetConfigCache(namespace).Get("content")
if err != nil {
@ -73,7 +72,7 @@ func (c *customChangeListener) OnChange(changeEvent *storage.ChangeEvent) {
c.in <- change
}
func (c *customChangeListener) OnNewestChange(changeEvent *storage.FullChangeEvent) {}
func (c *customChangeListener) OnNewestChange(_ *storage.FullChangeEvent) {}
func newWatcher(a *apollo) (config.Watcher, error) {
changeCh := make(chan []*config.KeyValue)

@ -2,20 +2,21 @@
```go
import (
"github.com/go-kratos/kratos/contrib/config/consul/v2"
"github.com/hashicorp/consul/api"
"github.com/go-kratos/kratos/contrib/config/consul/v2"
)
func main() {
func main() {
consulClient, err := api.NewClient(&api.Config{
Address: "127.0.0.1:8500",
Address: "127.0.0.1:8500",
})
if err != nil {
panic(err)
}
cs, err := consul.New(consulClient, consul.WithPath("app/cart/configs/"))
//consul中需要标注文件后缀,kratos读取配置需要适配文件后缀
//The file suffix needs to be marked, and kratos needs to adapt the file suffix to read the configuration.
// consul中需要标注文件后缀,kratos读取配置需要适配文件后缀
// The file suffix needs to be marked, and kratos needs to adapt the file suffix to read the configuration.
if err != nil {
panic(err)
}

@ -3,8 +3,13 @@ module github.com/go-kratos/kratos/contrib/config/consul/v2
go 1.15
require (
github.com/go-kratos/kratos/v2 v2.4.0
github.com/hashicorp/consul/api v1.14.0
github.com/armon/go-metrics v0.3.10 // indirect
github.com/go-kratos/kratos/v2 v2.6.3
github.com/hashicorp/consul/api v1.20.0
github.com/hashicorp/go-hclog v0.14.1 // indirect
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
github.com/hashicorp/go-msgpack v0.5.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -18,7 +18,7 @@ type watcher struct {
cancel context.CancelFunc
}
func (w *watcher) handle(idx uint64, data interface{}) {
func (w *watcher) handle(_ uint64, data interface{}) {
if data == nil {
return
}

@ -4,10 +4,11 @@
import (
"log"
cfg "github.com/go-kratos/kratos/contrib/config/etcd/v2"
"github.com/go-kratos/kratos/v2/config"
clientv3 "go.etcd.io/etcd/client/v3"
"google.golang.org/grpc"
cfg "github.com/go-kratos/kratos/contrib/config/etcd/v2"
"github.com/go-kratos/kratos/v2/config"
)
// create an etcd client
@ -30,12 +31,16 @@ if err != nil {
c := config.New(config.WithSource(source))
defer c.Close()
// load sources before get
if err := c.Load(); err != nil {
log.Fatalln(err)
}
// acquire config value
foo, err := c.Value("/app-config").String()
if err != nil {
log.Println(err)
log.Fatalln(err)
}
println(foo)
log.Println(foo)
```

@ -3,9 +3,9 @@ module github.com/go-kratos/kratos/contrib/config/etcd/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.4.0
go.etcd.io/etcd/client/v3 v3.5.4
google.golang.org/grpc v1.46.2
github.com/go-kratos/kratos/v2 v2.6.3
go.etcd.io/etcd/client/v3 v3.5.8
google.golang.org/grpc v1.56.1
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -8,14 +8,14 @@ import (
"strings"
"testing"
"github.com/go-kratos/kratos/v2/config"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"github.com/go-kratos/kratos/v2/config"
)
const (

@ -3,10 +3,10 @@ module github.com/go-kratos/kratos/contrib/config/kubernetes/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.4.0
k8s.io/api v0.24.3
k8s.io/apimachinery v0.24.3
k8s.io/client-go v0.24.3
github.com/go-kratos/kratos/v2 v2.6.3
k8s.io/api v0.26.3
k8s.io/apimachinery v0.26.3
k8s.io/client-go v0.26.3
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -2,9 +2,10 @@
```go
import (
kconfig "github.com/go-kratos/kratos/v2/config"
"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/common/constant"
kconfig "github.com/go-kratos/kratos/v2/config"
)

@ -3,9 +3,8 @@ module github.com/go-kratos/kratos/contrib/config/nacos/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.4.0
github.com/go-kratos/kratos/v2 v2.6.3
github.com/nacos-group/nacos-sdk-go v1.0.9
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -2,24 +2,23 @@
```go
import (
"log"
"github.com/polarismesh/polaris-go"
"github.com/go-kratos/kratos/contrib/config/polaris/v2"
"log"
"github.com/polarismesh/polaris-go"
"github.com/go-kratos/kratos/contrib/config/polaris/v2"
)
func main() {
configApi, err := polaris.NewConfigAPI()
if err != nil {
log.Fatalln(err)
}
configApi, err := polaris.NewConfigAPI()
if err != nil {
log.Fatalln(err)
}
source, err := New(&configApi, WithNamespace("default"), WithFileGroup("default"), WithFileName("default.yaml"))
if err != nil {
log.Fatalln(err)
}
source.Load()
source, err := New(&configApi, WithNamespace("default"), WithFileGroup("default"), WithFileName("default.yaml"))
if err != nil {
log.Fatalln(err)
}
source.Load()
}
```

@ -6,9 +6,9 @@ import (
"path/filepath"
"strings"
"github.com/go-kratos/kratos/v2/config"
"github.com/polarismesh/polaris-go"
"github.com/go-kratos/kratos/v2/config"
)
// Option is polaris config option.

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/config/polaris/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.4.0
github.com/go-kratos/kratos/v2 v2.6.3
github.com/polarismesh/polaris-go v1.1.0
)
@ -14,10 +14,6 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -5,11 +5,11 @@ import (
"path/filepath"
"strings"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/log"
"github.com/polarismesh/polaris-go"
"github.com/polarismesh/polaris-go/pkg/model"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/log"
)
type Watcher struct {
@ -28,7 +28,7 @@ func getFullPath(namespace string, fileGroup string, fileName string) string {
return fmt.Sprintf("%s/%s/%s", namespace, fileGroup, fileName)
}
func recieve(event model.ConfigFileChangeEvent) {
func receive(event model.ConfigFileChangeEvent) {
meta := event.ConfigFileMetadata
ec := eventChanMap[getFullPath(meta.GetNamespace(), meta.GetFileGroup(), meta.GetFileName())]
defer func() {
@ -42,7 +42,7 @@ func recieve(event model.ConfigFileChangeEvent) {
}
func newWatcher(configFile polaris.ConfigFile) *Watcher {
configFile.AddChangeListener(recieve)
configFile.AddChangeListener(receive)
fullPath := getFullPath(configFile.GetNamespace(), configFile.GetFileGroup(), configFile.GetFileName())
if _, ok := eventChanMap[fullPath]; !ok {

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/encoding/msgpack/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.6.3
github.com/vmihailenco/msgpack/v5 v5.3.5
)

File diff suppressed because it is too large Load Diff

@ -16,6 +16,7 @@ import (
// Logger see more detail https://github.com/aliyun/aliyun-log-go-sdk
type Logger interface {
log.Logger
GetProducer() *producer.Producer
Close() error
}
@ -81,22 +82,16 @@ func (a *aliyunLog) Close() error {
}
func (a *aliyunLog) Log(level log.Level, keyvals ...interface{}) error {
buf := level.String()
levelTitle := "level"
contents := make([]*sls.LogContent, 0)
contents := make([]*sls.LogContent, 0, len(keyvals)/2+1)
contents = append(contents, &sls.LogContent{
Key: &levelTitle,
Value: &buf,
Key: newString(level.Key()),
Value: newString(level.String()),
})
for i := 0; i < len(keyvals); i += 2 {
key := toString(keyvals[i])
value := toString(keyvals[i+1])
contents = append(contents, &sls.LogContent{
Key: &key,
Value: &value,
Key: newString(toString(keyvals[i])),
Value: newString(toString(keyvals[i+1])),
})
}
@ -104,9 +99,7 @@ func (a *aliyunLog) Log(level log.Level, keyvals ...interface{}) error {
Time: proto.Uint32(uint32(time.Now().Unix())),
Contents: contents,
}
err := a.producer.SendLog(a.opts.project, a.opts.logstore, "", "", logInst)
return err
return a.producer.SendLog(a.opts.project, a.opts.logstore, "", "", logInst)
}
// NewAliyunLog new a aliyun logger with options.
@ -128,6 +121,11 @@ func NewAliyunLog(options ...Option) Logger {
}
}
// newString string convert to *string
func newString(s string) *string {
return &s
}
// toString convert any type to string
func toString(v interface{}) string {
var key string
@ -138,23 +136,23 @@ func toString(v interface{}) string {
case float64:
key = strconv.FormatFloat(v, 'f', -1, 64)
case float32:
key = strconv.FormatFloat(float64(v), 'f', -1, 64)
key = strconv.FormatFloat(float64(v), 'f', -1, 32)
case int:
key = strconv.Itoa(v)
case uint:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int8:
key = strconv.Itoa(int(v))
case uint8:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int16:
key = strconv.Itoa(int(v))
case uint16:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int32:
key = strconv.Itoa(int(v))
case uint32:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int64:
key = strconv.FormatInt(v, 10)
case uint64:

@ -2,6 +2,7 @@ package aliyun
import (
"math"
"reflect"
"testing"
"github.com/go-kratos/kratos/v2/log"
@ -57,7 +58,7 @@ func TestWithAccessSecret(t *testing.T) {
}
}
func TestLogger(t *testing.T) {
func TestLogger(_ *testing.T) {
project := "foo"
logger := NewAliyunLog(WithProject(project))
defer logger.Close()
@ -99,34 +100,45 @@ func TestLog(t *testing.T) {
}
}
func TestNewString(t *testing.T) {
ptr := newString("")
if kind := reflect.TypeOf(ptr).Kind(); kind != reflect.Ptr {
t.Errorf("want type: %v, got type: %v", reflect.Ptr, kind)
}
}
func TestToString(t *testing.T) {
tests := []struct {
in interface{}
out string
name string
in interface{}
out string
}{
{math.MaxFloat64, "17976931348623157000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000"},
{math.MaxFloat32, "340282346638528860000000000000000000000"},
{1<<((32<<(^uint(0)>>63))-1) - 1, "9223372036854775807"},
{uint(1<<(32<<(^uint(0)>>63)) - 1), "-1"},
{math.MaxInt8, "127"},
{math.MaxUint8, "255"},
{math.MaxInt16, "32767"},
{math.MaxUint16, "65535"},
{math.MaxInt32, "2147483647"},
{math.MaxUint32, "4294967295"},
{math.MaxInt64, "9223372036854775807"},
{uint64(math.MaxUint64), "18446744073709551615"},
{"abc", "abc"},
{false, "false"},
{[]byte("abc"), "abc"},
{"float64", 6.66, "6.66"},
{"max float64", math.MaxFloat64, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, //nolint:lll
{"float32", float32(6.66), "6.66"},
{"max float32", float32(math.MaxFloat32), "340282350000000000000000000000000000000"},
{"int", math.MaxInt64, "9223372036854775807"},
{"uint", uint(math.MaxUint64), "18446744073709551615"},
{"int8", int8(math.MaxInt8), "127"},
{"uint8", uint8(math.MaxUint8), "255"},
{"int16", int16(math.MaxInt16), "32767"},
{"uint16", uint16(math.MaxUint16), "65535"},
{"int32", int32(math.MaxInt32), "2147483647"},
{"uint32", uint32(math.MaxUint32), "4294967295"},
{"int64", int64(math.MaxInt64), "9223372036854775807"},
{"uint64", uint64(math.MaxUint64), "18446744073709551615"},
{"string", "abc", "abc"},
{"bool", false, "false"},
{"[]byte", []byte("abc"), "abc"},
{"struct", struct{ Name string }{}, `{"Name":""}`},
{"nil", nil, ""},
}
for _, test := range tests {
if toString(test.in) != test.out {
t.Fatalf("want: %s, got: %s", test.out, toString(test.in))
}
t.Run(test.name, func(t *testing.T) {
out := toString(test.in)
if test.out != out {
t.Fatalf("want: %s, got: %s", test.out, out)
}
})
}
}

@ -3,9 +3,9 @@ module github.com/go-kratos/kratos/contrib/log/aliyun/v2
go 1.16
require (
github.com/aliyun/aliyun-log-go-sdk v0.1.37
github.com/go-kratos/kratos/v2 v2.5.1
google.golang.org/protobuf v1.28.1
github.com/aliyun/aliyun-log-go-sdk v0.1.44
github.com/go-kratos/kratos/v2 v2.6.3
google.golang.org/protobuf v1.31.0
)
replace (

File diff suppressed because it is too large Load Diff

@ -11,18 +11,23 @@ import (
)
func TestMain(m *testing.M) {
listener := func(ln net.Listener) {
conn, err := ln.Accept()
if err != nil {
return
}
defer conn.Close()
_, err = io.ReadAll(conn)
if err != nil {
return
}
}
if ln, err := net.Listen("tcp", ":24224"); err == nil {
defer ln.Close()
go func() {
for {
conn, err := ln.Accept()
if err != nil {
return
}
defer conn.Close()
if _, err = io.ReadAll(conn); err != nil {
continue
}
listener(ln)
}
}()
}

@ -5,8 +5,7 @@ go 1.16
require (
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/fluent/fluent-logger-golang v1.9.0
github.com/go-kratos/kratos/v2 v2.5.1
github.com/kr/pretty v0.3.0 // indirect
github.com/go-kratos/kratos/v2 v2.6.3
github.com/tinylib/msgp v1.1.6 // indirect
)

File diff suppressed because it is too large Load Diff

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/logrus/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.6.3
github.com/sirupsen/logrus v1.8.1
)

File diff suppressed because it is too large Load Diff

@ -3,9 +3,9 @@ module github.com/go-kratos/kratos/contrib/log/tencent/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.6.3
github.com/tencentcloud/tencentcloud-cls-sdk-go v1.0.2
google.golang.org/protobuf v1.28.0
google.golang.org/protobuf v1.31.0
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -14,8 +14,8 @@ import (
type Logger interface {
log.Logger
GetProducer() *cls.AsyncProducerClient
GetProducer() *cls.AsyncProducerClient
Close() error
}
@ -66,25 +66,20 @@ func WithAccessSecret(as string) Option {
type Option func(cls *options)
func (log *tencentLog) Close() error {
err := log.producer.Close(5000)
return err
return log.producer.Close(5000)
}
func (log *tencentLog) Log(level log.Level, keyvals ...interface{}) error {
buf := level.String()
levelTitle := "level"
contents := make([]*cls.Log_Content, 0)
contents := make([]*cls.Log_Content, 0, len(keyvals)/2+1)
contents = append(contents, &cls.Log_Content{
Key: &levelTitle,
Value: &buf,
Key: newString(level.Key()),
Value: newString(level.String()),
})
for i := 0; i < len(keyvals); i += 2 {
key := toString(keyvals[i])
value := toString(keyvals[i+1])
contents = append(contents, &cls.Log_Content{
Key: &key,
Value: &value,
Key: newString(toString(keyvals[i])),
Value: newString(toString(keyvals[i+1])),
})
}
@ -92,8 +87,7 @@ func (log *tencentLog) Log(level log.Level, keyvals ...interface{}) error {
Time: proto.Int64(time.Now().Unix()),
Contents: contents,
}
err := log.producer.SendLog(log.opts.topicID, logInst, nil)
return err
return log.producer.SendLog(log.opts.topicID, logInst, nil)
}
func NewLogger(options ...Option) (Logger, error) {
@ -109,12 +103,17 @@ func NewLogger(options ...Option) (Logger, error) {
if err != nil {
return nil, err
}
producerInst.Start()
return &tencentLog{
producer: producerInst,
opts: opts,
}, nil
}
func newString(s string) *string {
return &s
}
// toString convert any type to string
func toString(v interface{}) string {
var key string
@ -125,23 +124,23 @@ func toString(v interface{}) string {
case float64:
key = strconv.FormatFloat(v, 'f', -1, 64)
case float32:
key = strconv.FormatFloat(float64(v), 'f', -1, 64)
key = strconv.FormatFloat(float64(v), 'f', -1, 32)
case int:
key = strconv.Itoa(v)
case uint:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int8:
key = strconv.Itoa(int(v))
case uint8:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int16:
key = strconv.Itoa(int(v))
case uint16:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int32:
key = strconv.Itoa(int(v))
case uint32:
key = strconv.Itoa(int(v))
key = strconv.FormatUint(uint64(v), 10)
case int64:
key = strconv.FormatInt(v, 10)
case uint64:

@ -1,6 +1,8 @@
package tencent
import (
"math"
"reflect"
"testing"
"github.com/go-kratos/kratos/v2/log"
@ -101,3 +103,46 @@ func TestLog(t *testing.T) {
t.Errorf("Log() returns error:%v", err)
}
}
func TestNewString(t *testing.T) {
ptr := newString("")
if kind := reflect.TypeOf(ptr).Kind(); kind != reflect.Ptr {
t.Errorf("want type: %v, got type: %v", reflect.Ptr, kind)
}
}
func TestToString(t *testing.T) {
tests := []struct {
name string
in interface{}
out string
}{
{"float64", 6.66, "6.66"},
{"max float64", math.MaxFloat64, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, //nolint:lll
{"float32", float32(6.66), "6.66"},
{"max float32", float32(math.MaxFloat32), "340282350000000000000000000000000000000"},
{"int", math.MaxInt64, "9223372036854775807"},
{"uint", uint(math.MaxUint64), "18446744073709551615"},
{"int8", int8(math.MaxInt8), "127"},
{"uint8", uint8(math.MaxUint8), "255"},
{"int16", int16(math.MaxInt16), "32767"},
{"uint16", uint16(math.MaxUint16), "65535"},
{"int32", int32(math.MaxInt32), "2147483647"},
{"uint32", uint32(math.MaxUint32), "4294967295"},
{"int64", int64(math.MaxInt64), "9223372036854775807"},
{"uint64", uint64(math.MaxUint64), "18446744073709551615"},
{"string", "abc", "abc"},
{"bool", false, "false"},
{"[]byte", []byte("abc"), "abc"},
{"struct", struct{ Name string }{}, `{"Name":""}`},
{"nil", nil, ""},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
out := toString(test.in)
if test.out != out {
t.Fatalf("want: %s, got: %s", test.out, out)
}
})
}
}

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/zap/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.5.1
github.com/go-kratos/kratos/v2 v2.6.3
go.uber.org/zap v1.23.0
)

File diff suppressed because it is too large Load Diff

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

Loading…
Cancel
Save