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.
- biucingcli/__init__.py +5 -0
- biucingcli/cli.py +849 -0
- biucingcli/template_data/android/template/.editorconfig +9 -0
- biucingcli/template_data/android/template/.gitignore +26 -0
- biucingcli/template_data/android/template/.mise.toml +3 -0
- biucingcli/template_data/android/template/Brewfile +6 -0
- biucingcli/template_data/android/template/Makefile +103 -0
- biucingcli/template_data/android/template/README.md +163 -0
- biucingcli/template_data/android/template/app/build.gradle.kts +178 -0
- biucingcli/template_data/android/template/app/proguard-rules.pro +1 -0
- biucingcli/template_data/android/template/app/src/androidTest/java/app/HomeRouteUiTest.kt +21 -0
- biucingcli/template_data/android/template/app/src/main/AndroidManifest.xml +18 -0
- biucingcli/template_data/android/template/app/src/main/java/app/MainActivity.kt +36 -0
- biucingcli/template_data/android/template/app/src/main/res/values/strings.xml +4 -0
- biucingcli/template_data/android/template/app/src/main/res/values/themes.xml +8 -0
- biucingcli/template_data/android/template/app/src/test/java/app/AppSmokeTest.kt +19 -0
- biucingcli/template_data/android/template/build.gradle.kts +27 -0
- biucingcli/template_data/android/template/core/designsystem/build.gradle.kts +33 -0
- biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/Components.kt +75 -0
- biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/DesignTokens.kt +23 -0
- biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/Theme.kt +110 -0
- biucingcli/template_data/android/template/core/model/build.gradle.kts +26 -0
- biucingcli/template_data/android/template/core/model/src/main/java/model/Greeting.kt +6 -0
- biucingcli/template_data/android/template/core/model/src/test/java/model/GreetingTest.kt +16 -0
- biucingcli/template_data/android/template/core/network/build.gradle.kts +26 -0
- biucingcli/template_data/android/template/core/network/src/main/java/network/AppEnvironment.kt +17 -0
- biucingcli/template_data/android/template/core/testing/build.gradle.kts +27 -0
- biucingcli/template_data/android/template/core/testing/src/main/java/testing/FakeAppEnvironmentProvider.kt +13 -0
- biucingcli/template_data/android/template/docs/release-delivery.md +68 -0
- biucingcli/template_data/android/template/docs/release-signing.properties.example +20 -0
- biucingcli/template_data/android/template/fastlane/.env.example +22 -0
- biucingcli/template_data/android/template/fastlane/Appfile +1 -0
- biucingcli/template_data/android/template/fastlane/Fastfile +121 -0
- biucingcli/template_data/android/template/feature/home/build.gradle.kts +35 -0
- biucingcli/template_data/android/template/feature/home/src/main/java/home/HomeRoute.kt +38 -0
- biucingcli/template_data/android/template/feature/settings/build.gradle.kts +34 -0
- biucingcli/template_data/android/template/feature/settings/src/main/java/settings/SettingsRoute.kt +35 -0
- biucingcli/template_data/android/template/gradle/libs.versions.toml +35 -0
- biucingcli/template_data/android/template/gradle/verification-metadata.xml +3462 -0
- biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.jar +0 -0
- biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.jar.sha256 +1 -0
- biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.properties +10 -0
- biucingcli/template_data/android/template/gradle.properties +4 -0
- biucingcli/template_data/android/template/gradlew +252 -0
- biucingcli/template_data/android/template/gradlew.bat +94 -0
- biucingcli/template_data/android/template/scripts/artifact-info +11 -0
- biucingcli/template_data/android/template/scripts/bootstrap +17 -0
- biucingcli/template_data/android/template/scripts/doctor +133 -0
- biucingcli/template_data/android/template/scripts/setup-android-sdk +23 -0
- biucingcli/template_data/android/template/scripts/sync-gradle-wrapper +19 -0
- biucingcli/template_data/android/template/scripts/verify-gradle-supply-chain +61 -0
- biucingcli/template_data/android/template/scripts/verify-release-artifact +104 -0
- biucingcli/template_data/android/template/settings.gradle.kts +25 -0
- biucingcli/template_data/android/template.json +146 -0
- biucingcli/template_data/apple/template/.gitignore +28 -0
- biucingcli/template_data/apple/template/.mise.toml +4 -0
- biucingcli/template_data/apple/template/.swiftformat +10 -0
- biucingcli/template_data/apple/template/.swiftlint.yml +33 -0
- biucingcli/template_data/apple/template/App/Config/ProjectDescriptionHelpers/Module.swift +6 -0
- biucingcli/template_data/apple/template/App/Config/XCConfig/Base.xcconfig +4 -0
- biucingcli/template_data/apple/template/App/Project.swift +66 -0
- biucingcli/template_data/apple/template/App/Targets/App/Resources/.gitkeep +1 -0
- biucingcli/template_data/apple/template/App/Targets/App/Sources/AppEntry.swift +9 -0
- biucingcli/template_data/apple/template/App/Targets/App/Sources/HomeView.swift +18 -0
- biucingcli/template_data/apple/template/App/Targets/App/Sources/HomeViewModel.swift +38 -0
- biucingcli/template_data/apple/template/App/Targets/AppTests/Sources/AppTests.swift +59 -0
- biucingcli/template_data/apple/template/Brewfile +8 -0
- biucingcli/template_data/apple/template/Makefile +128 -0
- biucingcli/template_data/apple/template/Packages/AppServices/Package.swift +20 -0
- biucingcli/template_data/apple/template/Packages/AppServices/Sources/AppServices/StarterMetadata.swift +52 -0
- biucingcli/template_data/apple/template/Packages/DesignSystem/Package.swift +20 -0
- biucingcli/template_data/apple/template/Packages/DesignSystem/Sources/DesignSystem/Theme.swift +8 -0
- biucingcli/template_data/apple/template/README.md +133 -0
- biucingcli/template_data/apple/template/Tuist.swift +8 -0
- biucingcli/template_data/apple/template/Workspace.swift +11 -0
- biucingcli/template_data/apple/template/docs/release-delivery.md +55 -0
- biucingcli/template_data/apple/template/fastlane/.env.example +20 -0
- biucingcli/template_data/apple/template/fastlane/Appfile +3 -0
- biucingcli/template_data/apple/template/fastlane/Fastfile +126 -0
- biucingcli/template_data/apple/template/fastlane/Matchfile +7 -0
- biucingcli/template_data/apple/template/scripts/bootstrap +9 -0
- biucingcli/template_data/apple/template/scripts/doctor +163 -0
- biucingcli/template_data/apple/template/scripts/setup-xcode +6 -0
- biucingcli/template_data/apple/template/scripts/test-destination +42 -0
- biucingcli/template_data/apple/template/scripts/verify-release-identity +88 -0
- biucingcli/template_data/apple/template.json +110 -0
- biucingcli/template_data/frontend/template/.dockerignore +8 -0
- biucingcli/template_data/frontend/template/.env.example +1 -0
- biucingcli/template_data/frontend/template/.gitignore +7 -0
- biucingcli/template_data/frontend/template/.npmrc +1 -0
- biucingcli/template_data/frontend/template/.prettierignore +2 -0
- biucingcli/template_data/frontend/template/.prettierrc.json +4 -0
- biucingcli/template_data/frontend/template/Dockerfile +25 -0
- biucingcli/template_data/frontend/template/Dockerfile.dev +35 -0
- biucingcli/template_data/frontend/template/Dockerfile.dev.full +40 -0
- biucingcli/template_data/frontend/template/Makefile +137 -0
- biucingcli/template_data/frontend/template/README.md +146 -0
- biucingcli/template_data/frontend/template/compose.dev.yaml +29 -0
- biucingcli/template_data/frontend/template/eslint.config.js +27 -0
- biucingcli/template_data/frontend/template/index.html +12 -0
- biucingcli/template_data/frontend/template/nginx.conf +11 -0
- biucingcli/template_data/frontend/template/package.json +50 -0
- biucingcli/template_data/frontend/template/playwright.production.config.ts +21 -0
- biucingcli/template_data/frontend/template/playwright.smoke.config.ts +19 -0
- biucingcli/template_data/frontend/template/pnpm-lock.yaml +4054 -0
- biucingcli/template_data/frontend/template/public/.gitkeep +1 -0
- biucingcli/template_data/frontend/template/scripts/browser-smoke-production +55 -0
- biucingcli/template_data/frontend/template/scripts/doctor +46 -0
- biucingcli/template_data/frontend/template/src/App.test.tsx +18 -0
- biucingcli/template_data/frontend/template/src/App.tsx +5 -0
- biucingcli/template_data/frontend/template/src/components/MetricCard.tsx +14 -0
- biucingcli/template_data/frontend/template/src/components/TaskPanel.tsx +32 -0
- biucingcli/template_data/frontend/template/src/config/env.ts +3 -0
- biucingcli/template_data/frontend/template/src/hooks/useProjectOverview.ts +24 -0
- biucingcli/template_data/frontend/template/src/index.css +208 -0
- biucingcli/template_data/frontend/template/src/main.tsx +11 -0
- biucingcli/template_data/frontend/template/src/pages/HomePage.tsx +60 -0
- biucingcli/template_data/frontend/template/src/router/AppRouter.tsx +14 -0
- biucingcli/template_data/frontend/template/src/services/api/client.ts +33 -0
- biucingcli/template_data/frontend/template/src/services/projectOverview.ts +39 -0
- biucingcli/template_data/frontend/template/src/test/setup.ts +1 -0
- biucingcli/template_data/frontend/template/src/types/projectOverview.ts +22 -0
- biucingcli/template_data/frontend/template/src/vite-env.d.ts +9 -0
- biucingcli/template_data/frontend/template/tests/browser-smoke.spec.ts +16 -0
- biucingcli/template_data/frontend/template/tests/production-browser-smoke.spec.ts +22 -0
- biucingcli/template_data/frontend/template/tsconfig.json +21 -0
- biucingcli/template_data/frontend/template/vite.config.ts +12 -0
- biucingcli/template_data/frontend/template.json +81 -0
- biucingcli/template_data/harmonyos/template/.gitignore +21 -0
- biucingcli/template_data/harmonyos/template/.mise.toml +2 -0
- biucingcli/template_data/harmonyos/template/AppScope/app.json5 +10 -0
- biucingcli/template_data/harmonyos/template/AppScope/resources/base/element/string.json +8 -0
- biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/background.svg +3 -0
- biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/foreground.svg +4 -0
- biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/layered_image.json +6 -0
- biucingcli/template_data/harmonyos/template/Makefile +106 -0
- biucingcli/template_data/harmonyos/template/README.md +152 -0
- biucingcli/template_data/harmonyos/template/build-profile.json5 +36 -0
- biucingcli/template_data/harmonyos/template/code-linter.json5 +12 -0
- biucingcli/template_data/harmonyos/template/docs/release-signing.local.properties.example +14 -0
- biucingcli/template_data/harmonyos/template/entry/build-profile.json5 +9 -0
- biucingcli/template_data/harmonyos/template/entry/hvigorfile.ts +6 -0
- biucingcli/template_data/harmonyos/template/entry/oh-package.json5 +9 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/core/config/AppConfig.ets +10 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/core/designsystem/Tokens.ets +28 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/entryability/EntryAbility.ets +29 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/pages/Index.ets +47 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/pages/Settings.ets +96 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/module.json5 +34 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/element/color.json +24 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/element/string.json +12 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/media/app_icon.svg +5 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/profile/main_pages.json +6 -0
- biucingcli/template_data/harmonyos/template/entry/src/test/List.test.ets +11 -0
- biucingcli/template_data/harmonyos/template/hvigor/hvigor-config.json5 +8 -0
- biucingcli/template_data/harmonyos/template/hvigorfile.ts +6 -0
- biucingcli/template_data/harmonyos/template/oh-package-lock.json5 +19 -0
- biucingcli/template_data/harmonyos/template/oh-package.json5 +13 -0
- biucingcli/template_data/harmonyos/template/scripts/artifact-info +31 -0
- biucingcli/template_data/harmonyos/template/scripts/bootstrap +38 -0
- biucingcli/template_data/harmonyos/template/scripts/doctor +147 -0
- biucingcli/template_data/harmonyos/template/scripts/lint +105 -0
- biucingcli/template_data/harmonyos/template/scripts/release-build +199 -0
- biucingcli/template_data/harmonyos/template/scripts/release-preflight +109 -0
- biucingcli/template_data/harmonyos/template/scripts/test +28 -0
- biucingcli/template_data/harmonyos/template/scripts/verify-release-artifact +173 -0
- biucingcli/template_data/harmonyos/template/scripts/verify-supply-chain +70 -0
- biucingcli/template_data/harmonyos/template.json +134 -0
- biucingcli/template_data/microservice/template/.air.toml +11 -0
- biucingcli/template_data/microservice/template/.dockerignore +5 -0
- biucingcli/template_data/microservice/template/.gitignore +4 -0
- biucingcli/template_data/microservice/template/.mise.toml +3 -0
- biucingcli/template_data/microservice/template/Brewfile +7 -0
- biucingcli/template_data/microservice/template/Dockerfile +44 -0
- biucingcli/template_data/microservice/template/Dockerfile.dev +50 -0
- biucingcli/template_data/microservice/template/Makefile +145 -0
- biucingcli/template_data/microservice/template/README.md +191 -0
- biucingcli/template_data/microservice/template/api/buf.gen.yaml +11 -0
- biucingcli/template_data/microservice/template/api/buf.yaml +11 -0
- biucingcli/template_data/microservice/template/api/proto/service/v1/service.proto +18 -0
- biucingcli/template_data/microservice/template/cmd/server/main.go +81 -0
- biucingcli/template_data/microservice/template/compose.dev.yaml +49 -0
- biucingcli/template_data/microservice/template/configs/config.yaml +18 -0
- biucingcli/template_data/microservice/template/deploy/compose.yaml +35 -0
- biucingcli/template_data/microservice/template/deploy/otel-collector.yaml +15 -0
- biucingcli/template_data/microservice/template/go.mod +53 -0
- biucingcli/template_data/microservice/template/go.sum +138 -0
- biucingcli/template_data/microservice/template/internal/config/config.go +112 -0
- biucingcli/template_data/microservice/template/internal/config/config_test.go +92 -0
- biucingcli/template_data/microservice/template/internal/handler/health.go +25 -0
- biucingcli/template_data/microservice/template/internal/handler/ping.go +25 -0
- biucingcli/template_data/microservice/template/internal/model/health.go +8 -0
- biucingcli/template_data/microservice/template/internal/model/ping.go +7 -0
- biucingcli/template_data/microservice/template/internal/repository/.gitkeep +1 -0
- biucingcli/template_data/microservice/template/internal/router/router.go +26 -0
- biucingcli/template_data/microservice/template/internal/runtime/server.go +116 -0
- biucingcli/template_data/microservice/template/internal/runtime/server_test.go +161 -0
- biucingcli/template_data/microservice/template/internal/service/health.go +26 -0
- biucingcli/template_data/microservice/template/internal/service/ping.go +23 -0
- biucingcli/template_data/microservice/template/internal/telemetry/telemetry.go +56 -0
- biucingcli/template_data/microservice/template/internal/transport/grpc.go +51 -0
- biucingcli/template_data/microservice/template/internal/transport/ping.go +28 -0
- biucingcli/template_data/microservice/template/scripts/bootstrap +29 -0
- biucingcli/template_data/microservice/template/scripts/doctor +115 -0
- biucingcli/template_data/microservice/template/tests/server_test.go +153 -0
- biucingcli/template_data/microservice/template.json +114 -0
- biucingcli/template_data/web-service/template/.air.toml +11 -0
- biucingcli/template_data/web-service/template/.dockerignore +5 -0
- biucingcli/template_data/web-service/template/.gitignore +5 -0
- biucingcli/template_data/web-service/template/.mise.toml +2 -0
- biucingcli/template_data/web-service/template/Brewfile +5 -0
- biucingcli/template_data/web-service/template/Dockerfile +41 -0
- biucingcli/template_data/web-service/template/Dockerfile.dev +45 -0
- biucingcli/template_data/web-service/template/Makefile +113 -0
- biucingcli/template_data/web-service/template/README.md +164 -0
- biucingcli/template_data/web-service/template/cmd/server/main.go +50 -0
- biucingcli/template_data/web-service/template/compose.dev.yaml +28 -0
- biucingcli/template_data/web-service/template/compose.yaml +14 -0
- biucingcli/template_data/web-service/template/configs/config.yaml +10 -0
- biucingcli/template_data/web-service/template/go.mod +36 -0
- biucingcli/template_data/web-service/template/go.sum +89 -0
- biucingcli/template_data/web-service/template/internal/config/config.go +84 -0
- biucingcli/template_data/web-service/template/internal/config/config_test.go +88 -0
- biucingcli/template_data/web-service/template/internal/handler/health.go +25 -0
- biucingcli/template_data/web-service/template/internal/handler/ping.go +25 -0
- biucingcli/template_data/web-service/template/internal/handler/user.go +40 -0
- biucingcli/template_data/web-service/template/internal/model/health.go +6 -0
- biucingcli/template_data/web-service/template/internal/model/ping.go +7 -0
- biucingcli/template_data/web-service/template/internal/model/user.go +7 -0
- biucingcli/template_data/web-service/template/internal/repository/.gitkeep +1 -0
- biucingcli/template_data/web-service/template/internal/repository/user.go +37 -0
- biucingcli/template_data/web-service/template/internal/router/router.go +28 -0
- biucingcli/template_data/web-service/template/internal/runtime/server.go +76 -0
- biucingcli/template_data/web-service/template/internal/runtime/server_test.go +139 -0
- biucingcli/template_data/web-service/template/internal/service/health.go +22 -0
- biucingcli/template_data/web-service/template/internal/service/ping.go +23 -0
- biucingcli/template_data/web-service/template/internal/service/user.go +27 -0
- biucingcli/template_data/web-service/template/scripts/bootstrap +23 -0
- biucingcli/template_data/web-service/template/scripts/doctor +83 -0
- biucingcli/template_data/web-service/template/tests/server_test.go +160 -0
- biucingcli/template_data/web-service/template.json +88 -0
- biucingcli/template_data/worker/template/.dockerignore +3 -0
- biucingcli/template_data/worker/template/.gitignore +2 -0
- biucingcli/template_data/worker/template/.mise.toml +2 -0
- biucingcli/template_data/worker/template/Brewfile +1 -0
- biucingcli/template_data/worker/template/Dockerfile +19 -0
- biucingcli/template_data/worker/template/Dockerfile.dev +9 -0
- biucingcli/template_data/worker/template/Makefile +105 -0
- biucingcli/template_data/worker/template/README.md +164 -0
- biucingcli/template_data/worker/template/cmd/worker/main.go +41 -0
- biucingcli/template_data/worker/template/compose.dev.yaml +29 -0
- biucingcli/template_data/worker/template/configs/config.json +11 -0
- biucingcli/template_data/worker/template/go.mod +3 -0
- biucingcli/template_data/worker/template/go.sum +1 -0
- biucingcli/template_data/worker/template/internal/config/config.go +108 -0
- biucingcli/template_data/worker/template/internal/config/config_test.go +86 -0
- biucingcli/template_data/worker/template/internal/runtime/runner.go +199 -0
- biucingcli/template_data/worker/template/internal/runtime/runner_test.go +215 -0
- biucingcli/template_data/worker/template/internal/task/heartbeat.go +19 -0
- biucingcli/template_data/worker/template/scripts/bootstrap +6 -0
- biucingcli/template_data/worker/template/scripts/doctor +41 -0
- biucingcli/template_data/worker/template/tests/worker_test.go +44 -0
- biucingcli/template_data/worker/template.json +100 -0
- biucingcli/templates.py +902 -0
- biucingcli-0.9.1.dist-info/METADATA +204 -0
- biucingcli-0.9.1.dist-info/RECORD +269 -0
- biucingcli-0.9.1.dist-info/WHEEL +5 -0
- biucingcli-0.9.1.dist-info/entry_points.txt +2 -0
- biucingcli-0.9.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
package tests
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"encoding/json"
|
|
6
|
+
"net"
|
|
7
|
+
"net/http"
|
|
8
|
+
"net/http/httptest"
|
|
9
|
+
"testing"
|
|
10
|
+
"time"
|
|
11
|
+
|
|
12
|
+
servicev1 "{{MODULE_NAME}}/api/gen/go/service/v1"
|
|
13
|
+
"{{MODULE_NAME}}/internal/config"
|
|
14
|
+
"{{MODULE_NAME}}/internal/model"
|
|
15
|
+
"{{MODULE_NAME}}/internal/router"
|
|
16
|
+
"{{MODULE_NAME}}/internal/service"
|
|
17
|
+
"{{MODULE_NAME}}/internal/transport"
|
|
18
|
+
|
|
19
|
+
"google.golang.org/grpc"
|
|
20
|
+
"google.golang.org/grpc/credentials/insecure"
|
|
21
|
+
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
|
22
|
+
"google.golang.org/grpc/test/bufconn"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
func TestHealthz(t *testing.T) {
|
|
26
|
+
engine := router.New(config.Config{
|
|
27
|
+
Service: config.ServiceConfig{
|
|
28
|
+
Name: "{{SERVICE_NAME}}",
|
|
29
|
+
HTTPPort: "{{HTTP_PORT}}",
|
|
30
|
+
GRPCPort: "{{GRPC_PORT}}",
|
|
31
|
+
},
|
|
32
|
+
Store: config.StoreConfig{
|
|
33
|
+
Driver: "{{DEPENDENCY_STORE}}",
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
request := httptest.NewRequest(http.MethodGet, "/healthz", nil)
|
|
38
|
+
recorder := httptest.NewRecorder()
|
|
39
|
+
|
|
40
|
+
engine.ServeHTTP(recorder, request)
|
|
41
|
+
|
|
42
|
+
if recorder.Code != http.StatusOK {
|
|
43
|
+
t.Fatalf("expected status %d, got %d", http.StatusOK, recorder.Code)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
var response model.HealthResponse
|
|
47
|
+
if err := json.Unmarshal(recorder.Body.Bytes(), &response); err != nil {
|
|
48
|
+
t.Fatal(err)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if response.Service != "{{SERVICE_NAME}}" {
|
|
52
|
+
t.Fatalf("expected service %q, got %q", "{{SERVICE_NAME}}", response.Service)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if response.Store != "{{DEPENDENCY_STORE}}" {
|
|
56
|
+
t.Fatalf("expected store %q, got %q", "{{DEPENDENCY_STORE}}", response.Store)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func TestPing(t *testing.T) {
|
|
61
|
+
engine := router.New(config.Config{
|
|
62
|
+
Service: config.ServiceConfig{
|
|
63
|
+
Name: "{{SERVICE_NAME}}",
|
|
64
|
+
HTTPPort: "{{HTTP_PORT}}",
|
|
65
|
+
GRPCPort: "{{GRPC_PORT}}",
|
|
66
|
+
},
|
|
67
|
+
Store: config.StoreConfig{
|
|
68
|
+
Driver: "{{DEPENDENCY_STORE}}",
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
request := httptest.NewRequest(http.MethodGet, "/api/v1/ping", nil)
|
|
73
|
+
recorder := httptest.NewRecorder()
|
|
74
|
+
|
|
75
|
+
engine.ServeHTTP(recorder, request)
|
|
76
|
+
|
|
77
|
+
if recorder.Code != http.StatusOK {
|
|
78
|
+
t.Fatalf("expected status %d, got %d", http.StatusOK, recorder.Code)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
var response model.PingResponse
|
|
82
|
+
if err := json.Unmarshal(recorder.Body.Bytes(), &response); err != nil {
|
|
83
|
+
t.Fatal(err)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if response.Message != "pong" {
|
|
87
|
+
t.Fatalf("expected message %q, got %q", "pong", response.Message)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if response.ProtoPackage != "{{PROTO_PACKAGE}}" {
|
|
91
|
+
t.Fatalf("expected proto package %q, got %q", "{{PROTO_PACKAGE}}", response.ProtoPackage)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
func TestGRPCPingContract(t *testing.T) {
|
|
96
|
+
listener := bufconn.Listen(1024 * 1024)
|
|
97
|
+
pingService := service.NewPingService("{{SERVICE_NAME}}", "{{PROTO_PACKAGE}}")
|
|
98
|
+
server := transport.NewGRPCServer("{{SERVICE_NAME}}", pingService)
|
|
99
|
+
|
|
100
|
+
go func() {
|
|
101
|
+
_ = server.Serve(listener)
|
|
102
|
+
}()
|
|
103
|
+
t.Cleanup(func() {
|
|
104
|
+
server.Stop()
|
|
105
|
+
_ = listener.Close()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
connection, err := grpc.NewClient(
|
|
109
|
+
"passthrough:///bufnet",
|
|
110
|
+
grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) {
|
|
111
|
+
return listener.Dial()
|
|
112
|
+
}),
|
|
113
|
+
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
114
|
+
)
|
|
115
|
+
if err != nil {
|
|
116
|
+
t.Fatalf("create gRPC client: %v", err)
|
|
117
|
+
}
|
|
118
|
+
t.Cleanup(func() { _ = connection.Close() })
|
|
119
|
+
|
|
120
|
+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
121
|
+
defer cancel()
|
|
122
|
+
|
|
123
|
+
client := servicev1.New{{SERVICE_TYPE_NAME}}ServiceClient(connection)
|
|
124
|
+
healthClient := healthpb.NewHealthClient(connection)
|
|
125
|
+
healthResponse, err := healthClient.Check(ctx, &healthpb.HealthCheckRequest{Service: "{{SERVICE_NAME}}"})
|
|
126
|
+
if err != nil {
|
|
127
|
+
t.Fatalf("check gRPC health: %v", err)
|
|
128
|
+
}
|
|
129
|
+
if healthResponse.GetStatus() != healthpb.HealthCheckResponse_SERVING {
|
|
130
|
+
t.Fatalf("expected gRPC health status SERVING, got %s", healthResponse.GetStatus())
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
response, err := client.Ping(ctx, &servicev1.PingRequest{RequestId: "contract-test"})
|
|
134
|
+
if err != nil {
|
|
135
|
+
t.Fatalf("call Ping: %v", err)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if response.GetMessage() != "pong" {
|
|
139
|
+
t.Fatalf("expected message %q, got %q", "pong", response.GetMessage())
|
|
140
|
+
}
|
|
141
|
+
if response.GetService() != "{{SERVICE_NAME}}" {
|
|
142
|
+
t.Fatalf("expected service %q, got %q", "{{SERVICE_NAME}}", response.GetService())
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
expectedMethod := "/{{PROTO_PACKAGE}}.{{SERVICE_TYPE_NAME}}Service/Ping"
|
|
146
|
+
if servicev1.{{SERVICE_TYPE_NAME}}Service_Ping_FullMethodName != expectedMethod {
|
|
147
|
+
t.Fatalf(
|
|
148
|
+
"expected full method %q, got %q",
|
|
149
|
+
expectedMethod,
|
|
150
|
+
servicev1.{{SERVICE_TYPE_NAME}}Service_Ping_FullMethodName,
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "microservice",
|
|
3
|
+
"description": "Go microservice starter with Protobuf, Buf, Compose, and OpenTelemetry",
|
|
4
|
+
"category": "backend",
|
|
5
|
+
"stack": ["Go", "Gin", "Protobuf", "Buf", "Docker Compose", "OpenTelemetry"],
|
|
6
|
+
"tags": ["grpc", "otel", "protobuf", "docker", "service"],
|
|
7
|
+
"platforms": ["linux", "container"],
|
|
8
|
+
"maturity": {
|
|
9
|
+
"level": "validated",
|
|
10
|
+
"summary": "Containerized microservice starter with coordinated HTTP/gRPC shutdown, bounded timeouts, health checks, protobuf, and observability."
|
|
11
|
+
},
|
|
12
|
+
"validation": {
|
|
13
|
+
"status": "real-build-verified",
|
|
14
|
+
"verification_tier": "real-build",
|
|
15
|
+
"evidence": [
|
|
16
|
+
"python unittest template rendering coverage",
|
|
17
|
+
"generated-project HTTP and gRPC shutdown tests",
|
|
18
|
+
"HTTP and gRPC health checks",
|
|
19
|
+
"real docker runtime image builds",
|
|
20
|
+
"real docker development image builds"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"operating_assumptions": [
|
|
24
|
+
"The starter assumes a contract-first backend workflow with Buf and local dependency orchestration.",
|
|
25
|
+
"Generated projects are expected to validate protobuf, service runtime, and container packaging together."
|
|
26
|
+
],
|
|
27
|
+
"workflow_labels": ["bootstrap", "dev", "verify", "build", "runtime"],
|
|
28
|
+
"commands": {
|
|
29
|
+
"bootstrap": "make bootstrap",
|
|
30
|
+
"doctor": "make doctor",
|
|
31
|
+
"lint": "make lint",
|
|
32
|
+
"test": "make test",
|
|
33
|
+
"verify": "make verify",
|
|
34
|
+
"build": "make build",
|
|
35
|
+
"clean": "make clean",
|
|
36
|
+
"help": "make help"
|
|
37
|
+
},
|
|
38
|
+
"worktree": {
|
|
39
|
+
"support_level": "worktree-ready",
|
|
40
|
+
"isolation_dimensions": [
|
|
41
|
+
"runtime-names",
|
|
42
|
+
"ports",
|
|
43
|
+
"dependency-stores",
|
|
44
|
+
"caches",
|
|
45
|
+
"generated-output",
|
|
46
|
+
"cleanup",
|
|
47
|
+
"diagnostics"
|
|
48
|
+
],
|
|
49
|
+
"diagnostics": [
|
|
50
|
+
"make worktree-info",
|
|
51
|
+
"make worktree-doctor"
|
|
52
|
+
],
|
|
53
|
+
"cleanup": [
|
|
54
|
+
"make clean-worktree"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"variables": [
|
|
58
|
+
{
|
|
59
|
+
"name": "project_name",
|
|
60
|
+
"required": true,
|
|
61
|
+
"validator": "project-name"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "module_name",
|
|
65
|
+
"required": true,
|
|
66
|
+
"prompt": "Go module name: ",
|
|
67
|
+
"validator": "go-module"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "service_name",
|
|
71
|
+
"required": false,
|
|
72
|
+
"default_from": "project_name",
|
|
73
|
+
"validator": "slug"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "proto_package",
|
|
77
|
+
"required": true,
|
|
78
|
+
"prompt": "Proto package: ",
|
|
79
|
+
"validator": "protobuf-package"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"name": "http_port",
|
|
83
|
+
"required": false,
|
|
84
|
+
"default": "8080",
|
|
85
|
+
"validator": "port"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "grpc_port",
|
|
89
|
+
"required": false,
|
|
90
|
+
"default": "9090",
|
|
91
|
+
"validator": "port"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"name": "dependency_store",
|
|
95
|
+
"required": false,
|
|
96
|
+
"default": "postgres",
|
|
97
|
+
"validator": "choice",
|
|
98
|
+
"choices": ["postgres", "redis"]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "otel_exporter_endpoint",
|
|
102
|
+
"required": false,
|
|
103
|
+
"default": "http://localhost:4318",
|
|
104
|
+
"validator": "url"
|
|
105
|
+
}
|
|
106
|
+
],
|
|
107
|
+
"next_steps": [
|
|
108
|
+
"make bootstrap",
|
|
109
|
+
"make dev",
|
|
110
|
+
"make verify",
|
|
111
|
+
"make up",
|
|
112
|
+
"make docker-build"
|
|
113
|
+
]
|
|
114
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
ARG BUILDER_IMAGE=golang:1.26-alpine
|
|
2
|
+
ARG RUNTIME_IMAGE=alpine:3.20
|
|
3
|
+
|
|
4
|
+
FROM ${BUILDER_IMAGE} AS builder
|
|
5
|
+
|
|
6
|
+
WORKDIR /app
|
|
7
|
+
|
|
8
|
+
ARG GOPROXY=https://proxy.golang.org,direct
|
|
9
|
+
ARG GOSUMDB=sum.golang.org
|
|
10
|
+
ENV GOPROXY=${GOPROXY}
|
|
11
|
+
ENV GOSUMDB=${GOSUMDB}
|
|
12
|
+
|
|
13
|
+
COPY go.mod ./
|
|
14
|
+
RUN set -eux; \
|
|
15
|
+
attempt=1; \
|
|
16
|
+
until go mod download; do \
|
|
17
|
+
if [ "$attempt" -ge 3 ]; then \
|
|
18
|
+
exit 1; \
|
|
19
|
+
fi; \
|
|
20
|
+
attempt=$((attempt + 1)); \
|
|
21
|
+
sleep 5; \
|
|
22
|
+
done
|
|
23
|
+
|
|
24
|
+
COPY . .
|
|
25
|
+
RUN CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH:-amd64} go build -o /out/server ./cmd/server
|
|
26
|
+
|
|
27
|
+
FROM ${RUNTIME_IMAGE}
|
|
28
|
+
|
|
29
|
+
WORKDIR /app
|
|
30
|
+
|
|
31
|
+
COPY --from=builder /out/server /app/server
|
|
32
|
+
COPY configs/config.yaml /app/configs/config.yaml
|
|
33
|
+
|
|
34
|
+
EXPOSE {{HTTP_PORT}}
|
|
35
|
+
|
|
36
|
+
ENV CONFIG_FILE=/app/configs/config.yaml
|
|
37
|
+
|
|
38
|
+
HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=3 \
|
|
39
|
+
CMD ["/app/server", "healthcheck", "http://127.0.0.1:{{HTTP_PORT}}/healthz"]
|
|
40
|
+
|
|
41
|
+
CMD ["/app/server"]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
FROM golang:1.26-bookworm
|
|
2
|
+
|
|
3
|
+
WORKDIR /workspace
|
|
4
|
+
|
|
5
|
+
ARG AIR_VERSION=1.65.3
|
|
6
|
+
ARG GOLANGCI_LINT_VERSION=2.12.2
|
|
7
|
+
ARG GOPROXY=https://proxy.golang.org,direct
|
|
8
|
+
ARG GOSUMDB=sum.golang.org
|
|
9
|
+
ARG TARGETARCH
|
|
10
|
+
|
|
11
|
+
RUN apt-get update \
|
|
12
|
+
&& apt-get install -y --no-install-recommends bash ca-certificates curl git make tar \
|
|
13
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
14
|
+
|
|
15
|
+
RUN set -eux; \
|
|
16
|
+
case "${TARGETARCH}" in \
|
|
17
|
+
arm64) air_arch="arm64"; golangci_arch="arm64" ;; \
|
|
18
|
+
amd64) air_arch="amd64"; golangci_arch="amd64" ;; \
|
|
19
|
+
*) echo "Unsupported TARGETARCH: ${TARGETARCH}"; exit 1 ;; \
|
|
20
|
+
esac; \
|
|
21
|
+
curl -fsSL "https://github.com/air-verse/air/releases/download/v${AIR_VERSION}/air_${AIR_VERSION}_linux_${air_arch}.tar.gz" \
|
|
22
|
+
| tar -xz -C /usr/local/bin air; \
|
|
23
|
+
curl -fsSL "https://github.com/golangci/golangci-lint/releases/download/v${GOLANGCI_LINT_VERSION}/golangci-lint-${GOLANGCI_LINT_VERSION}-linux-${golangci_arch}.tar.gz" \
|
|
24
|
+
| tar -xz -C /tmp; \
|
|
25
|
+
mv "/tmp/golangci-lint-${GOLANGCI_LINT_VERSION}-linux-${golangci_arch}/golangci-lint" /usr/local/bin/golangci-lint; \
|
|
26
|
+
rm -rf /tmp/golangci-lint-${GOLANGCI_LINT_VERSION}-linux-${golangci_arch}
|
|
27
|
+
|
|
28
|
+
COPY go.mod go.sum ./
|
|
29
|
+
ENV GOPROXY=${GOPROXY}
|
|
30
|
+
ENV GOSUMDB=${GOSUMDB}
|
|
31
|
+
RUN set -eux; \
|
|
32
|
+
attempt=1; \
|
|
33
|
+
until go mod download; do \
|
|
34
|
+
if [ "$attempt" -ge 3 ]; then \
|
|
35
|
+
exit 1; \
|
|
36
|
+
fi; \
|
|
37
|
+
attempt=$((attempt + 1)); \
|
|
38
|
+
sleep 5; \
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
ENV PATH="/go/bin:${PATH}"
|
|
42
|
+
ENV GOCACHE=/workspace/.cache/go-build
|
|
43
|
+
ENV GOLANGCI_LINT_CACHE=/workspace/.cache/golangci-lint
|
|
44
|
+
|
|
45
|
+
CMD ["air", "-c", ".air.toml"]
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
APP_NAME={{SERVICE_NAME}}
|
|
2
|
+
WORKTREE_ROOT ?=$(shell git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
3
|
+
WORKTREE_LABEL ?=$(shell basename "$(WORKTREE_ROOT)" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-//; s/-$$//')
|
|
4
|
+
WORKTREE_ID ?=$(shell printf '%s' "$(WORKTREE_ROOT)" | shasum | cut -c1-8)
|
|
5
|
+
WORKTREE_SLUG ?=$(APP_NAME)-$(WORKTREE_ID)
|
|
6
|
+
COMPOSE_PROJECT_NAME ?=$(WORKTREE_SLUG)
|
|
7
|
+
IMAGE ?=$(WORKTREE_SLUG)
|
|
8
|
+
TAG ?=dev
|
|
9
|
+
IMAGE_REF := $(IMAGE):$(TAG)
|
|
10
|
+
COMPOSE ?=COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT_NAME) docker compose
|
|
11
|
+
CONTAINER_PORT ?={{HTTP_PORT}}
|
|
12
|
+
HOST_PORT ?={{HTTP_PORT}}
|
|
13
|
+
DEV_COMPOSE_FILE ?=compose.dev.yaml
|
|
14
|
+
DEV_SERVICE ?=app-dev
|
|
15
|
+
DOCKER_VARIANT ?=alpine
|
|
16
|
+
DOCKER_PLATFORM ?=linux/arm64
|
|
17
|
+
GOPROXY ?=https://proxy.golang.org,direct
|
|
18
|
+
GOSUMDB ?=sum.golang.org
|
|
19
|
+
GOCACHE ?= $(CURDIR)/.cache/go-build
|
|
20
|
+
GOMODCACHE ?= $(CURDIR)/.cache/go-mod
|
|
21
|
+
GOLANGCI_LINT_CACHE ?= $(CURDIR)/.cache/golangci-lint
|
|
22
|
+
export COMPOSE_PROJECT_NAME
|
|
23
|
+
export IMAGE
|
|
24
|
+
export TAG
|
|
25
|
+
export HOST_PORT
|
|
26
|
+
export CONTAINER_PORT
|
|
27
|
+
export GOCACHE
|
|
28
|
+
export GOMODCACHE
|
|
29
|
+
export GOLANGCI_LINT_CACHE
|
|
30
|
+
|
|
31
|
+
ifeq ($(DOCKER_VARIANT),ubuntu)
|
|
32
|
+
BUILDER_IMAGE ?= public.ecr.aws/docker/library/golang:1.26
|
|
33
|
+
RUNTIME_IMAGE ?= public.ecr.aws/docker/library/ubuntu:26.04
|
|
34
|
+
else
|
|
35
|
+
BUILDER_IMAGE ?= golang:1.26-alpine
|
|
36
|
+
RUNTIME_IMAGE ?= alpine:3.20
|
|
37
|
+
endif
|
|
38
|
+
|
|
39
|
+
.PHONY: worktree-info worktree-doctor worktree-compose-config clean-worktree bootstrap doctor dev dev-shell tidy lint test verify run build clean help docker-build docker-run docker-push
|
|
40
|
+
|
|
41
|
+
worktree-info:
|
|
42
|
+
@printf '%s\n' "Worktree root: $(WORKTREE_ROOT)"
|
|
43
|
+
@printf '%s\n' "Worktree label: $(WORKTREE_LABEL)"
|
|
44
|
+
@printf '%s\n' "Worktree ID: $(WORKTREE_ID)"
|
|
45
|
+
@printf '%s\n' "Worktree slug: $(WORKTREE_SLUG)"
|
|
46
|
+
@printf '%s\n' "Compose project: $(COMPOSE_PROJECT_NAME)"
|
|
47
|
+
@printf '%s\n' "HTTP URL: http://127.0.0.1:$(HOST_PORT)"
|
|
48
|
+
@printf '%s\n' "Image ref: $(IMAGE_REF)"
|
|
49
|
+
@printf '%s\n' "Go cache: $(GOCACHE)"
|
|
50
|
+
@printf '%s\n' "Go module cache: $(GOMODCACHE)"
|
|
51
|
+
@printf '%s\n' "golangci-lint cache: $(GOLANGCI_LINT_CACHE)"
|
|
52
|
+
|
|
53
|
+
worktree-doctor:
|
|
54
|
+
@$(MAKE) --no-print-directory worktree-info
|
|
55
|
+
@case "$(GOCACHE)" in "$(WORKTREE_ROOT)"/*) ;; *) printf '%s\n' "GOCACHE should stay inside this worktree: $(GOCACHE)"; exit 1;; esac
|
|
56
|
+
@case "$(GOMODCACHE)" in "$(WORKTREE_ROOT)"/*) ;; *) printf '%s\n' "GOMODCACHE should stay inside this worktree: $(GOMODCACHE)"; exit 1;; esac
|
|
57
|
+
@case "$(GOLANGCI_LINT_CACHE)" in "$(WORKTREE_ROOT)"/*) ;; *) printf '%s\n' "GOLANGCI_LINT_CACHE should stay inside this worktree: $(GOLANGCI_LINT_CACHE)"; exit 1;; esac
|
|
58
|
+
@if [ "$(HOST_PORT)" = "{{HTTP_PORT}}" ]; then printf '%s\n' "Warning: HOST_PORT uses the generated default {{HTTP_PORT}}; override it when another worktree is running."; fi
|
|
59
|
+
@if ! command -v lsof >/dev/null 2>&1; then printf '%s\n' "Port occupancy checks skipped: lsof is not available."; else \
|
|
60
|
+
if lsof -nP -iTCP:$(HOST_PORT) -sTCP:LISTEN >/dev/null 2>&1; then printf '%s\n%s\n' "Warning: HOST_PORT $(HOST_PORT) is already in use." "Suggested override: HOST_PORT=$$(( $(HOST_PORT) + 10000 )) make dev"; fi; \
|
|
61
|
+
fi
|
|
62
|
+
@printf '%s\n' "Compose config check: make worktree-compose-config"
|
|
63
|
+
|
|
64
|
+
worktree-compose-config:
|
|
65
|
+
@if ! command -v docker >/dev/null 2>&1; then printf '%s\n' "Docker is not available; cannot render Compose config."; exit 1; fi
|
|
66
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) config
|
|
67
|
+
|
|
68
|
+
clean-worktree:
|
|
69
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) down --remove-orphans --volumes
|
|
70
|
+
|
|
71
|
+
bootstrap:
|
|
72
|
+
GOPROXY=$(GOPROXY) GOSUMDB=$(GOSUMDB) $(COMPOSE) -f $(DEV_COMPOSE_FILE) build $(DEV_SERVICE)
|
|
73
|
+
|
|
74
|
+
doctor:
|
|
75
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) ./scripts/doctor
|
|
76
|
+
|
|
77
|
+
dev:
|
|
78
|
+
GOPROXY=$(GOPROXY) GOSUMDB=$(GOSUMDB) $(COMPOSE) -f $(DEV_COMPOSE_FILE) up $(DEV_SERVICE)
|
|
79
|
+
|
|
80
|
+
dev-shell:
|
|
81
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) bash
|
|
82
|
+
|
|
83
|
+
tidy:
|
|
84
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) go mod tidy
|
|
85
|
+
|
|
86
|
+
lint:
|
|
87
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) golangci-lint run --disable-all --enable=errcheck --enable=govet --enable=ineffassign --enable=staticcheck --enable=unused ./...
|
|
88
|
+
|
|
89
|
+
test:
|
|
90
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) go test ./...
|
|
91
|
+
|
|
92
|
+
verify: doctor lint test build
|
|
93
|
+
|
|
94
|
+
run:
|
|
95
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm --service-ports $(DEV_SERVICE)
|
|
96
|
+
|
|
97
|
+
build:
|
|
98
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) go build -o bin/$(APP_NAME) ./cmd/server
|
|
99
|
+
|
|
100
|
+
clean:
|
|
101
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) down --remove-orphans
|
|
102
|
+
|
|
103
|
+
help:
|
|
104
|
+
@printf '%s\n' "Common commands:" " make bootstrap Prepare the development environment" " make doctor Check required tools and project configuration" " make lint Run static analysis" " make test Run tests" " make verify Run the complete local verification contract" " make build Build the application" " make clean Remove generated runtime state" " make help Show this command summary"
|
|
105
|
+
|
|
106
|
+
docker-build:
|
|
107
|
+
docker build --platform $(DOCKER_PLATFORM) --build-arg BUILDER_IMAGE=$(BUILDER_IMAGE) --build-arg RUNTIME_IMAGE=$(RUNTIME_IMAGE) --build-arg GOPROXY=$(GOPROXY) --build-arg GOSUMDB=$(GOSUMDB) -t $(IMAGE_REF) .
|
|
108
|
+
|
|
109
|
+
docker-run:
|
|
110
|
+
docker run --rm -p $(HOST_PORT):$(CONTAINER_PORT) $(IMAGE_REF)
|
|
111
|
+
|
|
112
|
+
docker-push:
|
|
113
|
+
docker push $(IMAGE_REF)
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# {{SERVICE_NAME}}
|
|
2
|
+
|
|
3
|
+
This project was generated by BiucingCLI.
|
|
4
|
+
|
|
5
|
+
## Stack
|
|
6
|
+
|
|
7
|
+
- Go
|
|
8
|
+
- Gin
|
|
9
|
+
- Docker
|
|
10
|
+
|
|
11
|
+
## Project Layout
|
|
12
|
+
|
|
13
|
+
- `cmd/server`: application entrypoint
|
|
14
|
+
- `internal/config`: config loading
|
|
15
|
+
- `internal/handler`: HTTP handlers
|
|
16
|
+
- `internal/service`: business logic
|
|
17
|
+
- `internal/model`: response models
|
|
18
|
+
- `internal/router`: route wiring
|
|
19
|
+
- `internal/runtime`: bounded HTTP serving and graceful shutdown
|
|
20
|
+
- `configs`: local config files
|
|
21
|
+
- `tests`: integration-style HTTP tests
|
|
22
|
+
|
|
23
|
+
## Docker Workflow
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
make bootstrap
|
|
27
|
+
make dev
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The starter is designed to run development, checks, and runtime packaging inside Docker by default.
|
|
31
|
+
|
|
32
|
+
## Available Commands
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
make bootstrap
|
|
36
|
+
make dev
|
|
37
|
+
make dev-shell
|
|
38
|
+
make doctor
|
|
39
|
+
make lint
|
|
40
|
+
make test
|
|
41
|
+
make verify
|
|
42
|
+
make build
|
|
43
|
+
make docker-build
|
|
44
|
+
make docker-run
|
|
45
|
+
make clean
|
|
46
|
+
make help
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The service reads configuration from `configs/config.yaml` by default.
|
|
50
|
+
|
|
51
|
+
## Runtime Safety
|
|
52
|
+
|
|
53
|
+
- `SIGINT` and `SIGTERM` stop accepting new connections and drain in-flight HTTP requests.
|
|
54
|
+
- HTTP read, read-header, write, and idle timeouts are configured under `server` in `configs/config.yaml`.
|
|
55
|
+
- Graceful shutdown is bounded by `server.shutdown_timeout_seconds`; after the deadline, open connections are force-closed and the process exits non-zero.
|
|
56
|
+
- The runtime image checks `GET /healthz` every 10 seconds. Compose allows 15 seconds for the default 10-second shutdown window.
|
|
57
|
+
|
|
58
|
+
## Environment
|
|
59
|
+
|
|
60
|
+
- `Brewfile`: optional host workstation tool installation
|
|
61
|
+
- `.mise.toml`: pinned Go version for host workflows
|
|
62
|
+
- `Dockerfile.dev`: Go development image with `air` and `golangci-lint`
|
|
63
|
+
- `compose.dev.yaml`: local Docker development workflow
|
|
64
|
+
- `.air.toml`: hot reload config for the development container
|
|
65
|
+
- `scripts/bootstrap`: host-oriented setup helper when you do not use Docker
|
|
66
|
+
- `scripts/doctor`: local environment checks
|
|
67
|
+
- `make lint`: baseline static analysis with `golangci-lint`
|
|
68
|
+
- `make verify`: run doctor, lint, and tests together inside Docker
|
|
69
|
+
- the development image prewarms `go mod download` so the first Docker-based dev shell and verification flow spend less time resolving modules
|
|
70
|
+
- `GOPROXY` and `GOSUMDB` can be overridden on `make bootstrap`, `make dev`, and `make docker-build` when your network needs a different module proxy or checksum policy
|
|
71
|
+
|
|
72
|
+
## Example Endpoints
|
|
73
|
+
|
|
74
|
+
- `GET /healthz`: lightweight health check
|
|
75
|
+
- `GET /api/v1/ping`: sample versioned API endpoint
|
|
76
|
+
- `GET /api/v1/users`: list sample users from an in-memory repository
|
|
77
|
+
- `GET /api/v1/users/:id`: fetch a sample user by ID
|
|
78
|
+
|
|
79
|
+
## Docker
|
|
80
|
+
|
|
81
|
+
Start the hot-reload development container:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
make dev
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Open a shell in the development container:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
make dev-shell
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Build the runtime image:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
make docker-build
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Build with the Ubuntu runtime path:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
make docker-build DOCKER_VARIANT=ubuntu
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Build and run the Ubuntu variant end to end:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
make docker-build DOCKER_VARIANT=ubuntu IMAGE={{SERVICE_NAME}}-ubuntu TAG=dev
|
|
109
|
+
make docker-run IMAGE={{SERVICE_NAME}}-ubuntu TAG=dev HOST_PORT={{HTTP_PORT}}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Run the container:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
make docker-run
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
`make docker-run` starts whatever image tag you last built or specify explicitly through `IMAGE` and `TAG`.
|
|
119
|
+
|
|
120
|
+
## Worktree Workflow
|
|
121
|
+
|
|
122
|
+
This starter is safe to run from parallel Git worktrees when each worktree keeps its own identity and host port.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
make worktree-info
|
|
126
|
+
make worktree-doctor
|
|
127
|
+
make worktree-compose-config
|
|
128
|
+
HOST_PORT=8081 make dev
|
|
129
|
+
HOST_PORT=8081 make docker-run
|
|
130
|
+
make clean-worktree
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- `WORKTREE_LABEL` is derived from the worktree directory name for display.
|
|
134
|
+
- `WORKTREE_ID` is derived from the current worktree path by default and can be overridden.
|
|
135
|
+
- `COMPOSE_PROJECT_NAME` defaults to `{{SERVICE_NAME}}-$(WORKTREE_ID)`, so Compose containers, networks, and volumes stay scoped to the worktree.
|
|
136
|
+
- `IMAGE` defaults to the worktree slug and `TAG` defaults to `dev`, so runtime image tags do not overwrite another worktree by default.
|
|
137
|
+
- `GOCACHE`, `GOMODCACHE`, and `GOLANGCI_LINT_CACHE` stay under the current worktree's `.cache/` directory.
|
|
138
|
+
- The Docker dev workflow mounts Go build, module, and lint caches as Compose-scoped volumes, so dependency versions and downloads do not bleed across worktrees.
|
|
139
|
+
- `make worktree-doctor` checks whether `HOST_PORT` is already in use and prints a suggested override.
|
|
140
|
+
- `make worktree-compose-config` renders the current worktree's Compose config without starting containers.
|
|
141
|
+
- `make clean-worktree` removes only the current worktree's Compose containers, networks, and volumes.
|
|
142
|
+
|
|
143
|
+
Push a tagged image:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
make docker-push IMAGE=registry.example.com/{{SERVICE_NAME}} TAG=0.1.0
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Run with Docker Compose:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
docker compose up --build
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The Docker defaults are:
|
|
156
|
+
|
|
157
|
+
- `DOCKER_VARIANT=alpine`: `golang:1.26-alpine` + `alpine:3.20`
|
|
158
|
+
- `DOCKER_VARIANT=ubuntu`: `public.ecr.aws/docker/library/golang:1.26` + `public.ecr.aws/docker/library/ubuntu:26.04`
|
|
159
|
+
|
|
160
|
+
You can also override the exact images directly:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
make docker-build BUILDER_IMAGE=public.ecr.aws/docker/library/golang:1.26 RUNTIME_IMAGE=public.ecr.aws/docker/library/ubuntu:26.04
|
|
164
|
+
```
|