biucingcli 0.9.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. biucingcli/__init__.py +5 -0
  2. biucingcli/cli.py +849 -0
  3. biucingcli/template_data/android/template/.editorconfig +9 -0
  4. biucingcli/template_data/android/template/.gitignore +26 -0
  5. biucingcli/template_data/android/template/.mise.toml +3 -0
  6. biucingcli/template_data/android/template/Brewfile +6 -0
  7. biucingcli/template_data/android/template/Makefile +103 -0
  8. biucingcli/template_data/android/template/README.md +163 -0
  9. biucingcli/template_data/android/template/app/build.gradle.kts +178 -0
  10. biucingcli/template_data/android/template/app/proguard-rules.pro +1 -0
  11. biucingcli/template_data/android/template/app/src/androidTest/java/app/HomeRouteUiTest.kt +21 -0
  12. biucingcli/template_data/android/template/app/src/main/AndroidManifest.xml +18 -0
  13. biucingcli/template_data/android/template/app/src/main/java/app/MainActivity.kt +36 -0
  14. biucingcli/template_data/android/template/app/src/main/res/values/strings.xml +4 -0
  15. biucingcli/template_data/android/template/app/src/main/res/values/themes.xml +8 -0
  16. biucingcli/template_data/android/template/app/src/test/java/app/AppSmokeTest.kt +19 -0
  17. biucingcli/template_data/android/template/build.gradle.kts +27 -0
  18. biucingcli/template_data/android/template/core/designsystem/build.gradle.kts +33 -0
  19. biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/Components.kt +75 -0
  20. biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/DesignTokens.kt +23 -0
  21. biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/Theme.kt +110 -0
  22. biucingcli/template_data/android/template/core/model/build.gradle.kts +26 -0
  23. biucingcli/template_data/android/template/core/model/src/main/java/model/Greeting.kt +6 -0
  24. biucingcli/template_data/android/template/core/model/src/test/java/model/GreetingTest.kt +16 -0
  25. biucingcli/template_data/android/template/core/network/build.gradle.kts +26 -0
  26. biucingcli/template_data/android/template/core/network/src/main/java/network/AppEnvironment.kt +17 -0
  27. biucingcli/template_data/android/template/core/testing/build.gradle.kts +27 -0
  28. biucingcli/template_data/android/template/core/testing/src/main/java/testing/FakeAppEnvironmentProvider.kt +13 -0
  29. biucingcli/template_data/android/template/docs/release-delivery.md +68 -0
  30. biucingcli/template_data/android/template/docs/release-signing.properties.example +20 -0
  31. biucingcli/template_data/android/template/fastlane/.env.example +22 -0
  32. biucingcli/template_data/android/template/fastlane/Appfile +1 -0
  33. biucingcli/template_data/android/template/fastlane/Fastfile +121 -0
  34. biucingcli/template_data/android/template/feature/home/build.gradle.kts +35 -0
  35. biucingcli/template_data/android/template/feature/home/src/main/java/home/HomeRoute.kt +38 -0
  36. biucingcli/template_data/android/template/feature/settings/build.gradle.kts +34 -0
  37. biucingcli/template_data/android/template/feature/settings/src/main/java/settings/SettingsRoute.kt +35 -0
  38. biucingcli/template_data/android/template/gradle/libs.versions.toml +35 -0
  39. biucingcli/template_data/android/template/gradle/verification-metadata.xml +3462 -0
  40. biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.jar +0 -0
  41. biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.jar.sha256 +1 -0
  42. biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.properties +10 -0
  43. biucingcli/template_data/android/template/gradle.properties +4 -0
  44. biucingcli/template_data/android/template/gradlew +252 -0
  45. biucingcli/template_data/android/template/gradlew.bat +94 -0
  46. biucingcli/template_data/android/template/scripts/artifact-info +11 -0
  47. biucingcli/template_data/android/template/scripts/bootstrap +17 -0
  48. biucingcli/template_data/android/template/scripts/doctor +133 -0
  49. biucingcli/template_data/android/template/scripts/setup-android-sdk +23 -0
  50. biucingcli/template_data/android/template/scripts/sync-gradle-wrapper +19 -0
  51. biucingcli/template_data/android/template/scripts/verify-gradle-supply-chain +61 -0
  52. biucingcli/template_data/android/template/scripts/verify-release-artifact +104 -0
  53. biucingcli/template_data/android/template/settings.gradle.kts +25 -0
  54. biucingcli/template_data/android/template.json +146 -0
  55. biucingcli/template_data/apple/template/.gitignore +28 -0
  56. biucingcli/template_data/apple/template/.mise.toml +4 -0
  57. biucingcli/template_data/apple/template/.swiftformat +10 -0
  58. biucingcli/template_data/apple/template/.swiftlint.yml +33 -0
  59. biucingcli/template_data/apple/template/App/Config/ProjectDescriptionHelpers/Module.swift +6 -0
  60. biucingcli/template_data/apple/template/App/Config/XCConfig/Base.xcconfig +4 -0
  61. biucingcli/template_data/apple/template/App/Project.swift +66 -0
  62. biucingcli/template_data/apple/template/App/Targets/App/Resources/.gitkeep +1 -0
  63. biucingcli/template_data/apple/template/App/Targets/App/Sources/AppEntry.swift +9 -0
  64. biucingcli/template_data/apple/template/App/Targets/App/Sources/HomeView.swift +18 -0
  65. biucingcli/template_data/apple/template/App/Targets/App/Sources/HomeViewModel.swift +38 -0
  66. biucingcli/template_data/apple/template/App/Targets/AppTests/Sources/AppTests.swift +59 -0
  67. biucingcli/template_data/apple/template/Brewfile +8 -0
  68. biucingcli/template_data/apple/template/Makefile +128 -0
  69. biucingcli/template_data/apple/template/Packages/AppServices/Package.swift +20 -0
  70. biucingcli/template_data/apple/template/Packages/AppServices/Sources/AppServices/StarterMetadata.swift +52 -0
  71. biucingcli/template_data/apple/template/Packages/DesignSystem/Package.swift +20 -0
  72. biucingcli/template_data/apple/template/Packages/DesignSystem/Sources/DesignSystem/Theme.swift +8 -0
  73. biucingcli/template_data/apple/template/README.md +133 -0
  74. biucingcli/template_data/apple/template/Tuist.swift +8 -0
  75. biucingcli/template_data/apple/template/Workspace.swift +11 -0
  76. biucingcli/template_data/apple/template/docs/release-delivery.md +55 -0
  77. biucingcli/template_data/apple/template/fastlane/.env.example +20 -0
  78. biucingcli/template_data/apple/template/fastlane/Appfile +3 -0
  79. biucingcli/template_data/apple/template/fastlane/Fastfile +126 -0
  80. biucingcli/template_data/apple/template/fastlane/Matchfile +7 -0
  81. biucingcli/template_data/apple/template/scripts/bootstrap +9 -0
  82. biucingcli/template_data/apple/template/scripts/doctor +163 -0
  83. biucingcli/template_data/apple/template/scripts/setup-xcode +6 -0
  84. biucingcli/template_data/apple/template/scripts/test-destination +42 -0
  85. biucingcli/template_data/apple/template/scripts/verify-release-identity +88 -0
  86. biucingcli/template_data/apple/template.json +110 -0
  87. biucingcli/template_data/frontend/template/.dockerignore +8 -0
  88. biucingcli/template_data/frontend/template/.env.example +1 -0
  89. biucingcli/template_data/frontend/template/.gitignore +7 -0
  90. biucingcli/template_data/frontend/template/.npmrc +1 -0
  91. biucingcli/template_data/frontend/template/.prettierignore +2 -0
  92. biucingcli/template_data/frontend/template/.prettierrc.json +4 -0
  93. biucingcli/template_data/frontend/template/Dockerfile +25 -0
  94. biucingcli/template_data/frontend/template/Dockerfile.dev +35 -0
  95. biucingcli/template_data/frontend/template/Dockerfile.dev.full +40 -0
  96. biucingcli/template_data/frontend/template/Makefile +137 -0
  97. biucingcli/template_data/frontend/template/README.md +146 -0
  98. biucingcli/template_data/frontend/template/compose.dev.yaml +29 -0
  99. biucingcli/template_data/frontend/template/eslint.config.js +27 -0
  100. biucingcli/template_data/frontend/template/index.html +12 -0
  101. biucingcli/template_data/frontend/template/nginx.conf +11 -0
  102. biucingcli/template_data/frontend/template/package.json +50 -0
  103. biucingcli/template_data/frontend/template/playwright.production.config.ts +21 -0
  104. biucingcli/template_data/frontend/template/playwright.smoke.config.ts +19 -0
  105. biucingcli/template_data/frontend/template/pnpm-lock.yaml +4054 -0
  106. biucingcli/template_data/frontend/template/public/.gitkeep +1 -0
  107. biucingcli/template_data/frontend/template/scripts/browser-smoke-production +55 -0
  108. biucingcli/template_data/frontend/template/scripts/doctor +46 -0
  109. biucingcli/template_data/frontend/template/src/App.test.tsx +18 -0
  110. biucingcli/template_data/frontend/template/src/App.tsx +5 -0
  111. biucingcli/template_data/frontend/template/src/components/MetricCard.tsx +14 -0
  112. biucingcli/template_data/frontend/template/src/components/TaskPanel.tsx +32 -0
  113. biucingcli/template_data/frontend/template/src/config/env.ts +3 -0
  114. biucingcli/template_data/frontend/template/src/hooks/useProjectOverview.ts +24 -0
  115. biucingcli/template_data/frontend/template/src/index.css +208 -0
  116. biucingcli/template_data/frontend/template/src/main.tsx +11 -0
  117. biucingcli/template_data/frontend/template/src/pages/HomePage.tsx +60 -0
  118. biucingcli/template_data/frontend/template/src/router/AppRouter.tsx +14 -0
  119. biucingcli/template_data/frontend/template/src/services/api/client.ts +33 -0
  120. biucingcli/template_data/frontend/template/src/services/projectOverview.ts +39 -0
  121. biucingcli/template_data/frontend/template/src/test/setup.ts +1 -0
  122. biucingcli/template_data/frontend/template/src/types/projectOverview.ts +22 -0
  123. biucingcli/template_data/frontend/template/src/vite-env.d.ts +9 -0
  124. biucingcli/template_data/frontend/template/tests/browser-smoke.spec.ts +16 -0
  125. biucingcli/template_data/frontend/template/tests/production-browser-smoke.spec.ts +22 -0
  126. biucingcli/template_data/frontend/template/tsconfig.json +21 -0
  127. biucingcli/template_data/frontend/template/vite.config.ts +12 -0
  128. biucingcli/template_data/frontend/template.json +81 -0
  129. biucingcli/template_data/harmonyos/template/.gitignore +21 -0
  130. biucingcli/template_data/harmonyos/template/.mise.toml +2 -0
  131. biucingcli/template_data/harmonyos/template/AppScope/app.json5 +10 -0
  132. biucingcli/template_data/harmonyos/template/AppScope/resources/base/element/string.json +8 -0
  133. biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/background.svg +3 -0
  134. biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/foreground.svg +4 -0
  135. biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/layered_image.json +6 -0
  136. biucingcli/template_data/harmonyos/template/Makefile +106 -0
  137. biucingcli/template_data/harmonyos/template/README.md +152 -0
  138. biucingcli/template_data/harmonyos/template/build-profile.json5 +36 -0
  139. biucingcli/template_data/harmonyos/template/code-linter.json5 +12 -0
  140. biucingcli/template_data/harmonyos/template/docs/release-signing.local.properties.example +14 -0
  141. biucingcli/template_data/harmonyos/template/entry/build-profile.json5 +9 -0
  142. biucingcli/template_data/harmonyos/template/entry/hvigorfile.ts +6 -0
  143. biucingcli/template_data/harmonyos/template/entry/oh-package.json5 +9 -0
  144. biucingcli/template_data/harmonyos/template/entry/src/main/ets/core/config/AppConfig.ets +10 -0
  145. biucingcli/template_data/harmonyos/template/entry/src/main/ets/core/designsystem/Tokens.ets +28 -0
  146. biucingcli/template_data/harmonyos/template/entry/src/main/ets/entryability/EntryAbility.ets +29 -0
  147. biucingcli/template_data/harmonyos/template/entry/src/main/ets/pages/Index.ets +47 -0
  148. biucingcli/template_data/harmonyos/template/entry/src/main/ets/pages/Settings.ets +96 -0
  149. biucingcli/template_data/harmonyos/template/entry/src/main/module.json5 +34 -0
  150. biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/element/color.json +24 -0
  151. biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/element/string.json +12 -0
  152. biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/media/app_icon.svg +5 -0
  153. biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/profile/main_pages.json +6 -0
  154. biucingcli/template_data/harmonyos/template/entry/src/test/List.test.ets +11 -0
  155. biucingcli/template_data/harmonyos/template/hvigor/hvigor-config.json5 +8 -0
  156. biucingcli/template_data/harmonyos/template/hvigorfile.ts +6 -0
  157. biucingcli/template_data/harmonyos/template/oh-package-lock.json5 +19 -0
  158. biucingcli/template_data/harmonyos/template/oh-package.json5 +13 -0
  159. biucingcli/template_data/harmonyos/template/scripts/artifact-info +31 -0
  160. biucingcli/template_data/harmonyos/template/scripts/bootstrap +38 -0
  161. biucingcli/template_data/harmonyos/template/scripts/doctor +147 -0
  162. biucingcli/template_data/harmonyos/template/scripts/lint +105 -0
  163. biucingcli/template_data/harmonyos/template/scripts/release-build +199 -0
  164. biucingcli/template_data/harmonyos/template/scripts/release-preflight +109 -0
  165. biucingcli/template_data/harmonyos/template/scripts/test +28 -0
  166. biucingcli/template_data/harmonyos/template/scripts/verify-release-artifact +173 -0
  167. biucingcli/template_data/harmonyos/template/scripts/verify-supply-chain +70 -0
  168. biucingcli/template_data/harmonyos/template.json +134 -0
  169. biucingcli/template_data/microservice/template/.air.toml +11 -0
  170. biucingcli/template_data/microservice/template/.dockerignore +5 -0
  171. biucingcli/template_data/microservice/template/.gitignore +4 -0
  172. biucingcli/template_data/microservice/template/.mise.toml +3 -0
  173. biucingcli/template_data/microservice/template/Brewfile +7 -0
  174. biucingcli/template_data/microservice/template/Dockerfile +44 -0
  175. biucingcli/template_data/microservice/template/Dockerfile.dev +50 -0
  176. biucingcli/template_data/microservice/template/Makefile +145 -0
  177. biucingcli/template_data/microservice/template/README.md +191 -0
  178. biucingcli/template_data/microservice/template/api/buf.gen.yaml +11 -0
  179. biucingcli/template_data/microservice/template/api/buf.yaml +11 -0
  180. biucingcli/template_data/microservice/template/api/proto/service/v1/service.proto +18 -0
  181. biucingcli/template_data/microservice/template/cmd/server/main.go +81 -0
  182. biucingcli/template_data/microservice/template/compose.dev.yaml +49 -0
  183. biucingcli/template_data/microservice/template/configs/config.yaml +18 -0
  184. biucingcli/template_data/microservice/template/deploy/compose.yaml +35 -0
  185. biucingcli/template_data/microservice/template/deploy/otel-collector.yaml +15 -0
  186. biucingcli/template_data/microservice/template/go.mod +53 -0
  187. biucingcli/template_data/microservice/template/go.sum +138 -0
  188. biucingcli/template_data/microservice/template/internal/config/config.go +112 -0
  189. biucingcli/template_data/microservice/template/internal/config/config_test.go +92 -0
  190. biucingcli/template_data/microservice/template/internal/handler/health.go +25 -0
  191. biucingcli/template_data/microservice/template/internal/handler/ping.go +25 -0
  192. biucingcli/template_data/microservice/template/internal/model/health.go +8 -0
  193. biucingcli/template_data/microservice/template/internal/model/ping.go +7 -0
  194. biucingcli/template_data/microservice/template/internal/repository/.gitkeep +1 -0
  195. biucingcli/template_data/microservice/template/internal/router/router.go +26 -0
  196. biucingcli/template_data/microservice/template/internal/runtime/server.go +116 -0
  197. biucingcli/template_data/microservice/template/internal/runtime/server_test.go +161 -0
  198. biucingcli/template_data/microservice/template/internal/service/health.go +26 -0
  199. biucingcli/template_data/microservice/template/internal/service/ping.go +23 -0
  200. biucingcli/template_data/microservice/template/internal/telemetry/telemetry.go +56 -0
  201. biucingcli/template_data/microservice/template/internal/transport/grpc.go +51 -0
  202. biucingcli/template_data/microservice/template/internal/transport/ping.go +28 -0
  203. biucingcli/template_data/microservice/template/scripts/bootstrap +29 -0
  204. biucingcli/template_data/microservice/template/scripts/doctor +115 -0
  205. biucingcli/template_data/microservice/template/tests/server_test.go +153 -0
  206. biucingcli/template_data/microservice/template.json +114 -0
  207. biucingcli/template_data/web-service/template/.air.toml +11 -0
  208. biucingcli/template_data/web-service/template/.dockerignore +5 -0
  209. biucingcli/template_data/web-service/template/.gitignore +5 -0
  210. biucingcli/template_data/web-service/template/.mise.toml +2 -0
  211. biucingcli/template_data/web-service/template/Brewfile +5 -0
  212. biucingcli/template_data/web-service/template/Dockerfile +41 -0
  213. biucingcli/template_data/web-service/template/Dockerfile.dev +45 -0
  214. biucingcli/template_data/web-service/template/Makefile +113 -0
  215. biucingcli/template_data/web-service/template/README.md +164 -0
  216. biucingcli/template_data/web-service/template/cmd/server/main.go +50 -0
  217. biucingcli/template_data/web-service/template/compose.dev.yaml +28 -0
  218. biucingcli/template_data/web-service/template/compose.yaml +14 -0
  219. biucingcli/template_data/web-service/template/configs/config.yaml +10 -0
  220. biucingcli/template_data/web-service/template/go.mod +36 -0
  221. biucingcli/template_data/web-service/template/go.sum +89 -0
  222. biucingcli/template_data/web-service/template/internal/config/config.go +84 -0
  223. biucingcli/template_data/web-service/template/internal/config/config_test.go +88 -0
  224. biucingcli/template_data/web-service/template/internal/handler/health.go +25 -0
  225. biucingcli/template_data/web-service/template/internal/handler/ping.go +25 -0
  226. biucingcli/template_data/web-service/template/internal/handler/user.go +40 -0
  227. biucingcli/template_data/web-service/template/internal/model/health.go +6 -0
  228. biucingcli/template_data/web-service/template/internal/model/ping.go +7 -0
  229. biucingcli/template_data/web-service/template/internal/model/user.go +7 -0
  230. biucingcli/template_data/web-service/template/internal/repository/.gitkeep +1 -0
  231. biucingcli/template_data/web-service/template/internal/repository/user.go +37 -0
  232. biucingcli/template_data/web-service/template/internal/router/router.go +28 -0
  233. biucingcli/template_data/web-service/template/internal/runtime/server.go +76 -0
  234. biucingcli/template_data/web-service/template/internal/runtime/server_test.go +139 -0
  235. biucingcli/template_data/web-service/template/internal/service/health.go +22 -0
  236. biucingcli/template_data/web-service/template/internal/service/ping.go +23 -0
  237. biucingcli/template_data/web-service/template/internal/service/user.go +27 -0
  238. biucingcli/template_data/web-service/template/scripts/bootstrap +23 -0
  239. biucingcli/template_data/web-service/template/scripts/doctor +83 -0
  240. biucingcli/template_data/web-service/template/tests/server_test.go +160 -0
  241. biucingcli/template_data/web-service/template.json +88 -0
  242. biucingcli/template_data/worker/template/.dockerignore +3 -0
  243. biucingcli/template_data/worker/template/.gitignore +2 -0
  244. biucingcli/template_data/worker/template/.mise.toml +2 -0
  245. biucingcli/template_data/worker/template/Brewfile +1 -0
  246. biucingcli/template_data/worker/template/Dockerfile +19 -0
  247. biucingcli/template_data/worker/template/Dockerfile.dev +9 -0
  248. biucingcli/template_data/worker/template/Makefile +105 -0
  249. biucingcli/template_data/worker/template/README.md +164 -0
  250. biucingcli/template_data/worker/template/cmd/worker/main.go +41 -0
  251. biucingcli/template_data/worker/template/compose.dev.yaml +29 -0
  252. biucingcli/template_data/worker/template/configs/config.json +11 -0
  253. biucingcli/template_data/worker/template/go.mod +3 -0
  254. biucingcli/template_data/worker/template/go.sum +1 -0
  255. biucingcli/template_data/worker/template/internal/config/config.go +108 -0
  256. biucingcli/template_data/worker/template/internal/config/config_test.go +86 -0
  257. biucingcli/template_data/worker/template/internal/runtime/runner.go +199 -0
  258. biucingcli/template_data/worker/template/internal/runtime/runner_test.go +215 -0
  259. biucingcli/template_data/worker/template/internal/task/heartbeat.go +19 -0
  260. biucingcli/template_data/worker/template/scripts/bootstrap +6 -0
  261. biucingcli/template_data/worker/template/scripts/doctor +41 -0
  262. biucingcli/template_data/worker/template/tests/worker_test.go +44 -0
  263. biucingcli/template_data/worker/template.json +100 -0
  264. biucingcli/templates.py +902 -0
  265. biucingcli-0.9.1.dist-info/METADATA +204 -0
  266. biucingcli-0.9.1.dist-info/RECORD +269 -0
  267. biucingcli-0.9.1.dist-info/WHEEL +5 -0
  268. biucingcli-0.9.1.dist-info/entry_points.txt +2 -0
  269. biucingcli-0.9.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,26 @@
1
+ package router
2
+
3
+ import "{{MODULE_NAME}}/internal/config"
4
+ import "{{MODULE_NAME}}/internal/handler"
5
+ import "{{MODULE_NAME}}/internal/service"
6
+
7
+ import "github.com/gin-gonic/gin"
8
+
9
+ func New(cfg config.Config) *gin.Engine {
10
+ engine := gin.Default()
11
+
12
+ healthService := service.NewHealthService(
13
+ cfg.Service.Name,
14
+ cfg.Service.GRPCPort,
15
+ cfg.Store.Driver,
16
+ )
17
+ healthHandler := handler.NewHealthHandler(healthService)
18
+ healthHandler.RegisterRoutes(engine)
19
+
20
+ apiGroup := engine.Group("/api/v1")
21
+ pingService := service.NewPingService(cfg.Service.Name, "{{PROTO_PACKAGE}}")
22
+ pingHandler := handler.NewPingHandler(pingService)
23
+ pingHandler.RegisterRoutes(apiGroup)
24
+
25
+ return engine
26
+ }
@@ -0,0 +1,116 @@
1
+ package runtime
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "fmt"
7
+ "net"
8
+ "net/http"
9
+ "time"
10
+
11
+ "{{MODULE_NAME}}/internal/config"
12
+
13
+ "google.golang.org/grpc"
14
+ )
15
+
16
+ type GRPCServer interface {
17
+ Serve(net.Listener) error
18
+ GracefulStop()
19
+ Stop()
20
+ SetServing(bool)
21
+ }
22
+
23
+ func NewHTTPServer(cfg config.Config, handler http.Handler) *http.Server {
24
+ return &http.Server{
25
+ Addr: ":" + cfg.Service.HTTPPort,
26
+ Handler: handler,
27
+ ReadTimeout: time.Duration(cfg.Server.ReadTimeoutSeconds) * time.Second,
28
+ ReadHeaderTimeout: time.Duration(cfg.Server.ReadHeaderTimeoutSeconds) * time.Second,
29
+ WriteTimeout: time.Duration(cfg.Server.WriteTimeoutSeconds) * time.Second,
30
+ IdleTimeout: time.Duration(cfg.Server.IdleTimeoutSeconds) * time.Second,
31
+ }
32
+ }
33
+
34
+ func CheckHealth(ctx context.Context, url string) error {
35
+ request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
36
+ if err != nil {
37
+ return err
38
+ }
39
+ response, err := http.DefaultClient.Do(request)
40
+ if err != nil {
41
+ return err
42
+ }
43
+ defer response.Body.Close()
44
+ if response.StatusCode != http.StatusOK {
45
+ return errors.New("health endpoint returned " + response.Status)
46
+ }
47
+ return nil
48
+ }
49
+
50
+ func Serve(
51
+ ctx context.Context,
52
+ httpServer *http.Server,
53
+ httpListener net.Listener,
54
+ grpcServer GRPCServer,
55
+ grpcListener net.Listener,
56
+ shutdownTimeout time.Duration,
57
+ ) error {
58
+ type result struct {
59
+ name string
60
+ err error
61
+ }
62
+ serveResults := make(chan result, 2)
63
+ go func() {
64
+ serveResults <- result{name: "HTTP", err: httpServer.Serve(httpListener)}
65
+ }()
66
+ go func() {
67
+ serveResults <- result{name: "gRPC", err: grpcServer.Serve(grpcListener)}
68
+ }()
69
+
70
+ var serveErr error
71
+ select {
72
+ case result := <-serveResults:
73
+ if !isExpectedServeError(result.err) {
74
+ serveErr = fmt.Errorf("%s server: %w", result.name, result.err)
75
+ }
76
+ case <-ctx.Done():
77
+ }
78
+
79
+ grpcServer.SetServing(false)
80
+ shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
81
+ defer cancel()
82
+
83
+ httpDone := make(chan error, 1)
84
+ go func() {
85
+ httpDone <- httpServer.Shutdown(shutdownCtx)
86
+ }()
87
+ grpcDone := make(chan struct{})
88
+ go func() {
89
+ grpcServer.GracefulStop()
90
+ close(grpcDone)
91
+ }()
92
+
93
+ var shutdownErr error
94
+ select {
95
+ case err := <-httpDone:
96
+ if err != nil {
97
+ shutdownErr = errors.Join(shutdownErr, fmt.Errorf("HTTP shutdown: %w", err))
98
+ }
99
+ case <-shutdownCtx.Done():
100
+ _ = httpServer.Close()
101
+ shutdownErr = errors.Join(shutdownErr, shutdownCtx.Err())
102
+ }
103
+
104
+ select {
105
+ case <-grpcDone:
106
+ case <-shutdownCtx.Done():
107
+ grpcServer.Stop()
108
+ shutdownErr = errors.Join(shutdownErr, shutdownCtx.Err())
109
+ }
110
+
111
+ return errors.Join(serveErr, shutdownErr)
112
+ }
113
+
114
+ func isExpectedServeError(err error) bool {
115
+ return err == nil || errors.Is(err, http.ErrServerClosed) || errors.Is(err, grpc.ErrServerStopped)
116
+ }
@@ -0,0 +1,161 @@
1
+ package runtime
2
+
3
+ import (
4
+ "context"
5
+ "net"
6
+ "net/http"
7
+ "net/http/httptest"
8
+ "sync"
9
+ "testing"
10
+ "time"
11
+
12
+ "{{MODULE_NAME}}/internal/config"
13
+
14
+ "google.golang.org/grpc"
15
+ )
16
+
17
+ func TestCheckHealthRequiresSuccessfulResponse(t *testing.T) {
18
+ healthServer := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
19
+ if request.URL.Path != "/healthz" {
20
+ writer.WriteHeader(http.StatusNotFound)
21
+ return
22
+ }
23
+ writer.WriteHeader(http.StatusOK)
24
+ }))
25
+ defer healthServer.Close()
26
+
27
+ if err := CheckHealth(context.Background(), healthServer.URL+"/healthz"); err != nil {
28
+ t.Fatal(err)
29
+ }
30
+ if err := CheckHealth(context.Background(), healthServer.URL+"/missing"); err == nil {
31
+ t.Fatal("expected a non-success status to fail the health check")
32
+ }
33
+ }
34
+
35
+ type fakeGRPCServer struct {
36
+ stopOnce sync.Once
37
+ stopped chan struct{}
38
+ servingChanges chan bool
39
+ blockGraceful bool
40
+ forcedStop chan struct{}
41
+ }
42
+
43
+ func newFakeGRPCServer(blockGraceful bool) *fakeGRPCServer {
44
+ return &fakeGRPCServer{
45
+ stopped: make(chan struct{}),
46
+ servingChanges: make(chan bool, 1),
47
+ blockGraceful: blockGraceful,
48
+ forcedStop: make(chan struct{}, 1),
49
+ }
50
+ }
51
+
52
+ func (server *fakeGRPCServer) Serve(net.Listener) error {
53
+ <-server.stopped
54
+ return grpc.ErrServerStopped
55
+ }
56
+
57
+ func (server *fakeGRPCServer) GracefulStop() {
58
+ if server.blockGraceful {
59
+ <-server.stopped
60
+ return
61
+ }
62
+ server.stopOnce.Do(func() { close(server.stopped) })
63
+ }
64
+
65
+ func (server *fakeGRPCServer) Stop() {
66
+ server.stopOnce.Do(func() { close(server.stopped) })
67
+ server.forcedStop <- struct{}{}
68
+ }
69
+
70
+ func (server *fakeGRPCServer) SetServing(serving bool) {
71
+ server.servingChanges <- serving
72
+ }
73
+
74
+ func TestNewHTTPServerAppliesTimeouts(t *testing.T) {
75
+ server := NewHTTPServer(config.Config{
76
+ Service: config.ServiceConfig{HTTPPort: "8080"},
77
+ Server: config.ServerConfig{
78
+ ReadTimeoutSeconds: 1,
79
+ ReadHeaderTimeoutSeconds: 2,
80
+ WriteTimeoutSeconds: 3,
81
+ IdleTimeoutSeconds: 4,
82
+ },
83
+ }, http.NewServeMux())
84
+
85
+ if server.ReadTimeout != time.Second || server.ReadHeaderTimeout != 2*time.Second {
86
+ t.Fatalf("unexpected read timeouts: %s, %s", server.ReadTimeout, server.ReadHeaderTimeout)
87
+ }
88
+ if server.WriteTimeout != 3*time.Second || server.IdleTimeout != 4*time.Second {
89
+ t.Fatalf("unexpected connection timeouts: %s, %s", server.WriteTimeout, server.IdleTimeout)
90
+ }
91
+ }
92
+
93
+ func TestServeMarksGRPCNotServingBeforeGracefulStop(t *testing.T) {
94
+ httpListener, grpcListener := testListeners(t)
95
+ grpcServer := newFakeGRPCServer(false)
96
+ ctx, cancel := context.WithCancel(context.Background())
97
+ cancel()
98
+
99
+ if err := Serve(
100
+ ctx,
101
+ &http.Server{Handler: http.NewServeMux()},
102
+ httpListener,
103
+ grpcServer,
104
+ grpcListener,
105
+ time.Second,
106
+ ); err != nil {
107
+ t.Fatal(err)
108
+ }
109
+
110
+ select {
111
+ case serving := <-grpcServer.servingChanges:
112
+ if serving {
113
+ t.Fatal("expected gRPC health to switch to NOT_SERVING")
114
+ }
115
+ default:
116
+ t.Fatal("expected a gRPC health status update")
117
+ }
118
+ }
119
+
120
+ func TestServeForcesGRPCStopAfterTimeout(t *testing.T) {
121
+ httpListener, grpcListener := testListeners(t)
122
+ grpcServer := newFakeGRPCServer(true)
123
+ ctx, cancel := context.WithCancel(context.Background())
124
+ cancel()
125
+
126
+ err := Serve(
127
+ ctx,
128
+ &http.Server{Handler: http.NewServeMux()},
129
+ httpListener,
130
+ grpcServer,
131
+ grpcListener,
132
+ 25*time.Millisecond,
133
+ )
134
+ if err == nil {
135
+ t.Fatal("expected the shutdown deadline to be reported")
136
+ }
137
+
138
+ select {
139
+ case <-grpcServer.forcedStop:
140
+ default:
141
+ t.Fatal("expected gRPC Stop after the graceful shutdown deadline")
142
+ }
143
+ }
144
+
145
+ func testListeners(t *testing.T) (net.Listener, net.Listener) {
146
+ t.Helper()
147
+ httpListener, err := net.Listen("tcp", "127.0.0.1:0")
148
+ if err != nil {
149
+ t.Fatal(err)
150
+ }
151
+ grpcListener, err := net.Listen("tcp", "127.0.0.1:0")
152
+ if err != nil {
153
+ _ = httpListener.Close()
154
+ t.Fatal(err)
155
+ }
156
+ t.Cleanup(func() {
157
+ _ = httpListener.Close()
158
+ _ = grpcListener.Close()
159
+ })
160
+ return httpListener, grpcListener
161
+ }
@@ -0,0 +1,26 @@
1
+ package service
2
+
3
+ import "{{MODULE_NAME}}/internal/model"
4
+
5
+ type HealthService struct {
6
+ serviceName string
7
+ grpcPort string
8
+ storeDriver string
9
+ }
10
+
11
+ func NewHealthService(serviceName string, grpcPort string, storeDriver string) HealthService {
12
+ return HealthService{
13
+ serviceName: serviceName,
14
+ grpcPort: grpcPort,
15
+ storeDriver: storeDriver,
16
+ }
17
+ }
18
+
19
+ func (service HealthService) Status() model.HealthResponse {
20
+ return model.HealthResponse{
21
+ Service: service.serviceName,
22
+ Status: "ok",
23
+ Store: service.storeDriver,
24
+ GRPCPort: service.grpcPort,
25
+ }
26
+ }
@@ -0,0 +1,23 @@
1
+ package service
2
+
3
+ import "{{MODULE_NAME}}/internal/model"
4
+
5
+ type PingService struct {
6
+ serviceName string
7
+ protoPackage string
8
+ }
9
+
10
+ func NewPingService(serviceName string, protoPackage string) PingService {
11
+ return PingService{
12
+ serviceName: serviceName,
13
+ protoPackage: protoPackage,
14
+ }
15
+ }
16
+
17
+ func (service PingService) Ping() model.PingResponse {
18
+ return model.PingResponse{
19
+ Message: "pong",
20
+ Service: service.serviceName,
21
+ ProtoPackage: service.protoPackage,
22
+ }
23
+ }
@@ -0,0 +1,56 @@
1
+ package telemetry
2
+
3
+ import (
4
+ "context"
5
+ "strings"
6
+
7
+ "go.opentelemetry.io/otel"
8
+ "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
9
+ "go.opentelemetry.io/otel/propagation"
10
+ "go.opentelemetry.io/otel/sdk/resource"
11
+ sdktrace "go.opentelemetry.io/otel/sdk/trace"
12
+ semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
13
+ )
14
+
15
+ func Setup(
16
+ ctx context.Context,
17
+ serviceName string,
18
+ endpoint string,
19
+ ) (func(context.Context) error, error) {
20
+ resourceAttributes := resource.NewWithAttributes(
21
+ semconv.SchemaURL,
22
+ semconv.ServiceName(serviceName),
23
+ )
24
+
25
+ options := []sdktrace.TracerProviderOption{
26
+ sdktrace.WithResource(resourceAttributes),
27
+ }
28
+
29
+ var setupErr error
30
+ if endpoint != "" {
31
+ exporterOptions := []otlptracehttp.Option{
32
+ otlptracehttp.WithEndpointURL(endpoint),
33
+ }
34
+ if strings.HasPrefix(endpoint, "http://") {
35
+ exporterOptions = append(exporterOptions, otlptracehttp.WithInsecure())
36
+ }
37
+
38
+ exporter, err := otlptracehttp.New(ctx, exporterOptions...)
39
+ if err != nil {
40
+ setupErr = err
41
+ } else {
42
+ options = append(options, sdktrace.WithBatcher(exporter))
43
+ }
44
+ }
45
+
46
+ provider := sdktrace.NewTracerProvider(options...)
47
+ otel.SetTracerProvider(provider)
48
+ otel.SetTextMapPropagator(
49
+ propagation.NewCompositeTextMapPropagator(
50
+ propagation.TraceContext{},
51
+ propagation.Baggage{},
52
+ ),
53
+ )
54
+
55
+ return provider.Shutdown, setupErr
56
+ }
@@ -0,0 +1,51 @@
1
+ package transport
2
+
3
+ import (
4
+ "net"
5
+
6
+ servicev1 "{{MODULE_NAME}}/api/gen/go/service/v1"
7
+ "{{MODULE_NAME}}/internal/service"
8
+
9
+ "google.golang.org/grpc"
10
+ "google.golang.org/grpc/health"
11
+ healthpb "google.golang.org/grpc/health/grpc_health_v1"
12
+ "google.golang.org/grpc/reflection"
13
+ )
14
+
15
+ type GRPCServer struct {
16
+ server *grpc.Server
17
+ health *health.Server
18
+ serviceName string
19
+ }
20
+
21
+ func NewGRPCServer(serviceName string, pingService service.PingService) *GRPCServer {
22
+ server := grpc.NewServer()
23
+ healthServer := health.NewServer()
24
+ healthServer.SetServingStatus(serviceName, healthpb.HealthCheckResponse_SERVING)
25
+ healthServer.SetServingStatus("", healthpb.HealthCheckResponse_SERVING)
26
+ healthpb.RegisterHealthServer(server, healthServer)
27
+ servicev1.Register{{SERVICE_TYPE_NAME}}ServiceServer(server, newPingServer(pingService))
28
+ reflection.Register(server)
29
+ return &GRPCServer{server: server, health: healthServer, serviceName: serviceName}
30
+ }
31
+
32
+ func (server *GRPCServer) Serve(listener net.Listener) error {
33
+ return server.server.Serve(listener)
34
+ }
35
+
36
+ func (server *GRPCServer) GracefulStop() {
37
+ server.server.GracefulStop()
38
+ }
39
+
40
+ func (server *GRPCServer) Stop() {
41
+ server.server.Stop()
42
+ }
43
+
44
+ func (server *GRPCServer) SetServing(serving bool) {
45
+ status := healthpb.HealthCheckResponse_NOT_SERVING
46
+ if serving {
47
+ status = healthpb.HealthCheckResponse_SERVING
48
+ }
49
+ server.health.SetServingStatus(server.serviceName, status)
50
+ server.health.SetServingStatus("", status)
51
+ }
@@ -0,0 +1,28 @@
1
+ package transport
2
+
3
+ import (
4
+ "context"
5
+
6
+ servicev1 "{{MODULE_NAME}}/api/gen/go/service/v1"
7
+ "{{MODULE_NAME}}/internal/service"
8
+ )
9
+
10
+ type pingServer struct {
11
+ servicev1.Unimplemented{{SERVICE_TYPE_NAME}}ServiceServer
12
+ service service.PingService
13
+ }
14
+
15
+ func newPingServer(pingService service.PingService) *pingServer {
16
+ return &pingServer{service: pingService}
17
+ }
18
+
19
+ func (server *pingServer) Ping(
20
+ _ context.Context,
21
+ _ *servicev1.PingRequest,
22
+ ) (*servicev1.PingResponse, error) {
23
+ response := server.service.Ping()
24
+ return &servicev1.PingResponse{
25
+ Message: response.Message,
26
+ Service: response.Service,
27
+ }, nil
28
+ }
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ if command -v brew >/dev/null 2>&1; then
5
+ brew bundle
6
+ else
7
+ echo "brew not found; skipping Brewfile install."
8
+ fi
9
+
10
+ if command -v mise >/dev/null 2>&1; then
11
+ mise install
12
+ else
13
+ echo "mise not found; skipping runtime install."
14
+ fi
15
+
16
+ if ! command -v go >/dev/null 2>&1; then
17
+ echo "go is not available on PATH."
18
+ echo "Install Go with Homebrew or activate it through mise, then rerun ./scripts/bootstrap."
19
+ exit 1
20
+ fi
21
+
22
+ if ! command -v buf >/dev/null 2>&1; then
23
+ echo "buf is not available on PATH."
24
+ echo "Install Buf with Homebrew or activate it through mise, then rerun ./scripts/bootstrap."
25
+ exit 1
26
+ fi
27
+
28
+ go mod tidy
29
+ ./scripts/doctor
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ if ! command -v go >/dev/null 2>&1; then
5
+ echo "go is not installed or not on PATH."
6
+ exit 1
7
+ fi
8
+
9
+ if ! command -v buf >/dev/null 2>&1; then
10
+ echo "buf is not installed or not on PATH."
11
+ exit 1
12
+ fi
13
+
14
+ go_version="$(go env GOVERSION)"
15
+ echo "Go toolchain: $go_version"
16
+ echo "Buf: available"
17
+
18
+ if [[ -z "${GOCACHE:-}" ]]; then
19
+ GOCACHE="$(pwd)/.cache/go-build"
20
+ export GOCACHE
21
+ fi
22
+ mkdir -p "$GOCACHE"
23
+
24
+ if [[ ! -f "./go.mod" ]]; then
25
+ echo "go.mod is missing."
26
+ exit 1
27
+ fi
28
+
29
+ if [[ ! -f "./configs/config.yaml" ]]; then
30
+ echo "configs/config.yaml is missing."
31
+ exit 1
32
+ fi
33
+
34
+ if [[ ! -f "./api/buf.yaml" ]]; then
35
+ echo "api/buf.yaml is missing."
36
+ exit 1
37
+ fi
38
+
39
+ if [[ ! -f "./api/buf.gen.yaml" ]]; then
40
+ echo "api/buf.gen.yaml is missing."
41
+ exit 1
42
+ fi
43
+
44
+ if [[ ! -f "./api/proto/service/v1/service.proto" ]]; then
45
+ echo "api/proto/service/v1/service.proto is missing."
46
+ exit 1
47
+ fi
48
+
49
+ if ! grep -q "name:" ./configs/config.yaml; then
50
+ echo "configs/config.yaml must define service.name."
51
+ exit 1
52
+ fi
53
+
54
+ if ! grep -q "http_port:" ./configs/config.yaml; then
55
+ echo "configs/config.yaml must define service.http_port."
56
+ exit 1
57
+ fi
58
+
59
+ if ! grep -q "grpc_port:" ./configs/config.yaml; then
60
+ echo "configs/config.yaml must define service.grpc_port."
61
+ exit 1
62
+ fi
63
+
64
+ service_name="$(sed -n 's/^ name: //p' ./configs/config.yaml | head -n 1)"
65
+ http_port="$(sed -n 's/^ http_port: //p' ./configs/config.yaml | head -n 1)"
66
+ grpc_port="$(sed -n 's/^ grpc_port: //p' ./configs/config.yaml | head -n 1)"
67
+
68
+ if [[ -z "$service_name" ]]; then
69
+ echo "configs/config.yaml service.name must not be empty."
70
+ exit 1
71
+ fi
72
+
73
+ if [[ ! "$http_port" =~ ^[0-9]+$ ]]; then
74
+ echo "configs/config.yaml service.http_port must be a numeric string."
75
+ exit 1
76
+ fi
77
+
78
+ if [[ ! "$grpc_port" =~ ^[0-9]+$ ]]; then
79
+ echo "configs/config.yaml service.grpc_port must be a numeric string."
80
+ exit 1
81
+ fi
82
+
83
+ if (( http_port < 1 || http_port > 65535 )); then
84
+ echo "configs/config.yaml service.http_port must be between 1 and 65535."
85
+ exit 1
86
+ fi
87
+
88
+ if (( grpc_port < 1 || grpc_port > 65535 )); then
89
+ echo "configs/config.yaml service.grpc_port must be between 1 and 65535."
90
+ exit 1
91
+ fi
92
+
93
+ if ! go list -m >/dev/null 2>&1; then
94
+ echo "go.mod does not define a valid module."
95
+ exit 1
96
+ fi
97
+
98
+ if ! CONFIG_FILE=./configs/config.yaml go test ./internal/config -run TestLoadDefaultConfig -count=1 >/dev/null; then
99
+ echo "config loader could not read configs/config.yaml successfully."
100
+ exit 1
101
+ fi
102
+
103
+ if command -v golangci-lint >/dev/null 2>&1; then
104
+ echo "golangci-lint: available"
105
+ else
106
+ echo "golangci-lint: not installed; make lint and make verify will be unavailable."
107
+ fi
108
+
109
+ if command -v docker >/dev/null 2>&1; then
110
+ echo "Docker: available"
111
+ else
112
+ echo "Docker: not installed; compose workflows will be unavailable."
113
+ fi
114
+
115
+ echo "Environment looks ready."