@tdk-landscape/tdk-cli-core 1.3.14 → 1.3.22
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.
- package/README.md +3 -3
- package/Tiltfile +144 -0
- package/discovery/AGENTS.md +362 -0
- package/discovery/TILT_DISCOVERY.star +424 -0
- package/discovery/Tiltfile +58 -0
- package/discovery/config.star +258 -0
- package/discovery/constants.star +127 -0
- package/discovery/deterministic.star +211 -0
- package/discovery/discovery_daemon.star +191 -0
- package/discovery/discovery_orchestrator.star +460 -0
- package/discovery/filtering.star +5 -0
- package/discovery/identity-management-backend/service.yaml +26 -0
- package/discovery/identity-management-frontend/service.yaml +29 -0
- package/discovery/identity-sdk/service.yaml +9 -0
- package/discovery/incremental_discovery.star +213 -0
- package/discovery/indexing.star +7 -0
- package/discovery/json_manifest_scanner.star +51 -0
- package/discovery/libraries.star +46 -0
- package/discovery/loading.star +23 -0
- package/discovery/manifest/constants.star +104 -0
- package/discovery/manifest/loading.star +386 -0
- package/discovery/manifest/normalize.star +281 -0
- package/discovery/manifest/validation.star +108 -0
- package/discovery/normalization.star +11 -0
- package/discovery/registry.star +544 -0
- package/discovery/resource_snapshot.py +382 -0
- package/discovery/resource_snapshot.star +143 -0
- package/discovery/schemas.star +1 -0
- package/discovery/services/platform/cdc/debezium/nats-connector/service.yaml +9 -0
- package/discovery/services/platform/cdc/nats-http-bridge/service.yaml +9 -0
- package/discovery/services/platform/orchestrator/orchestrator-glue-backend/service.yaml +26 -0
- package/discovery/services/platform/synthetic-monitor/service.yaml +9 -0
- package/discovery/test_resource_snapshot.py +251 -0
- package/discovery/validation.star +78 -0
- package/discovery/versioning.star +1 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +11 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +1 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +36 -41
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/resource.d.ts.map +1 -1
- package/dist/commands/resource.js +51 -55
- package/dist/commands/resource.js.map +1 -1
- package/dist/commands/stack.d.ts.map +1 -1
- package/dist/commands/stack.js +22 -24
- package/dist/commands/stack.js.map +1 -1
- package/dist/commands/ui.d.ts.map +1 -1
- package/dist/commands/ui.js +1 -2
- package/dist/commands/ui.js.map +1 -1
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +1 -2
- package/dist/commands/up.js.map +1 -1
- package/dist/commands/upgrade.d.ts +8 -0
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +62 -21
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/generator/extension-fetch.d.ts +19 -0
- package/dist/generator/extension-fetch.d.ts.map +1 -1
- package/dist/generator/extension-fetch.js +71 -5
- package/dist/generator/extension-fetch.js.map +1 -1
- package/dist/generator/template-engine.d.ts +1 -0
- package/dist/generator/template-engine.d.ts.map +1 -1
- package/dist/generator/template-engine.js +50 -6
- package/dist/generator/template-engine.js.map +1 -1
- package/dist/utils/command-helpers.d.ts.map +1 -1
- package/dist/utils/command-helpers.js +7 -9
- package/dist/utils/command-helpers.js.map +1 -1
- package/dist/utils/constants.d.ts +1 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +1 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/errors.d.ts +2 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +6 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/paths.js +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/project-features.d.ts.map +1 -1
- package/dist/utils/project-features.js +1 -1
- package/dist/utils/project-features.js.map +1 -1
- package/dist/utils/resource-features.d.ts.map +1 -1
- package/dist/utils/resource-features.js +2 -2
- package/dist/utils/resource-features.js.map +1 -1
- package/dist/utils/tar.js +4 -4
- package/dist/utils/tar.js.map +1 -1
- package/dist/utils/validation.d.ts +7 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +9 -0
- package/dist/utils/validation.js.map +1 -1
- package/engine/AGENTS.md +705 -0
- package/engine/README.md +29 -0
- package/engine/REFACTORING_MANIFEST_SYSTEM.md +974 -0
- package/engine/Tiltfile +80 -0
- package/engine/assets/docker/golden-layers.Dockerfile +221 -0
- package/engine/assets/scripts/cleanup-completed-migrator-images.sh +37 -0
- package/engine/assets/scripts/cleanup-tilt-images.sh +120 -0
- package/engine/assets/scripts/mac-m1-resource-monitor.sh +121 -0
- package/engine/config.star +3 -0
- package/engine/docs/AUTODISCOVERY_TEST.md +182 -0
- package/engine/docs/C4-ARCHITECTURE-operations.md +396 -0
- package/engine/docs/C4-ARCHITECTURE-overview.md +284 -0
- package/engine/docs/C4-ARCHITECTURE.md +17 -0
- package/engine/docs/GOLDEN_IMAGE_INTEGRATION.md +349 -0
- package/engine/docs/MANIFEST_DRIVEN_ARCHITECTURE.md +357 -0
- package/engine/docs/README.md +284 -0
- package/engine/entrypoint.star +97 -0
- package/engine/lifecycle/orchestrator.star +260 -0
- package/engine/paths.star +717 -0
- package/engine/schemas/manifest-schema.json +301 -0
- package/engine/schemas/service-schema.json +301 -0
- package/engine/scripts/README.md +89 -0
- package/engine/scripts/build-and-publish-lib.sh +205 -0
- package/engine/scripts/check-lib-publish.sh +85 -0
- package/engine/scripts/debug-container.sh +258 -0
- package/engine/scripts/generate-manifest.sh +197 -0
- package/engine/spec.master +702 -0
- package/engine/spec.master.example +341 -0
- package/engine/topologies/README.md +34 -0
- package/engine/topologies/platform/docker/AGENTS.md +59 -0
- package/engine/topologies/platform/docker/auth/auth.star +167 -0
- package/engine/topologies/platform/docker/build/golden_image.star +37 -0
- package/engine/topologies/platform/docker/build/golden_image_build.star +82 -0
- package/engine/topologies/platform/docker/build/golden_image_constants.star +93 -0
- package/engine/topologies/platform/docker/build/golden_image_dockerfile.star +291 -0
- package/engine/topologies/platform/docker/compose/compose.star +636 -0
- package/engine/topologies/platform/docker/compose/compose_helpers.star +52 -0
- package/engine/topologies/platform/docker/compose/traefik_standalone.star +53 -0
- package/engine/topologies/platform/docker/config/bunignore.star +142 -0
- package/engine/topologies/platform/docker/config/dockerignore.star +150 -0
- package/engine/topologies/platform/docker/constants.star +170 -0
- package/engine/topologies/platform/docker/dockerfile/dockerfile.star +54 -0
- package/engine/topologies/platform/docker/generators/golden_docker_generator_v2.star +73 -0
- package/engine/topologies/platform/docker/index.star +27 -0
- package/engine/topologies/platform/docker/layers/bun_helpers.star +23 -0
- package/engine/topologies/platform/docker/layers/infisical/index.star +40 -0
- package/engine/topologies/platform/docker/layers/infisical/infisical_docker.star +262 -0
- package/engine/topologies/platform/docker/layers/l1_base_layers.star +87 -0
- package/engine/topologies/platform/docker/layers/l2_dependency_layers.star +125 -0
- package/engine/topologies/platform/docker/layers/l3_builder_layers.star +209 -0
- package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +214 -0
- package/engine/topologies/platform/docker/layers/prisma/constants.star +135 -0
- package/engine/topologies/platform/docker/layers/prisma/db_readiness.star +96 -0
- package/engine/topologies/platform/docker/layers/prisma/filesystem_setup.star +109 -0
- package/engine/topologies/platform/docker/layers/prisma/migrate_script.star +98 -0
- package/engine/topologies/platform/docker/layers/prisma/prisma_build.star +126 -0
- package/engine/topologies/platform/docker/layers/prisma/prisma_runtime.star +161 -0
- package/engine/topologies/platform/docker/layers/prisma/secret_resolution.star +119 -0
- package/engine/topologies/platform/docker/networking/api_path_constants.star +230 -0
- package/engine/topologies/platform/docker/networking/sablier_container_cycle.star +27 -0
- package/engine/topologies/platform/docker/networking/traefik.star +232 -0
- package/engine/topologies/platform/docker/networking/traefik_constants.star +146 -0
- package/engine/topologies/platform/docker/networking/traefik_helpers.star +160 -0
- package/engine/topologies/platform/docker/secrets/infisical.star +135 -0
- package/engine/topologies/platform/net/proxy.star +4 -0
- package/engine/topologies/platform/registries/local.star +4 -0
- package/engine/topologies/platform/security/secrets.star +239 -0
- package/engine/topologies/platform/state/relational.star +4 -0
- package/engine/topologies/tilt/common/AGENTS.md +59 -0
- package/engine/topologies/tilt/common/utils.star +364 -0
- package/engine/topologies/tilt/common/utils_debug.star +69 -0
- package/engine/topologies/tilt/common/utils_deterministic.star +168 -0
- package/engine/topologies/tilt/common/utils_docker_networks.star +46 -0
- package/engine/topologies/tilt/common/utils_env.star +43 -0
- package/engine/topologies/tilt/common/utils_output.star +97 -0
- package/engine/topologies/tilt/config/AGENTS.md +68 -0
- package/engine/topologies/tilt/config/defaults.star +3 -0
- package/engine/topologies/tilt/config/feature_flags.star +10 -0
- package/engine/topologies/tilt/config/global.star +55 -0
- package/engine/topologies/tilt/config/profiles.star +382 -0
- package/engine/topologies/tilt/generators/agents_md.star +62 -0
- package/engine/topologies/tilt/generators/api_gateway.star +145 -0
- package/engine/topologies/tilt/generators/index.star +124 -0
- package/engine/topologies/tilt/generators/infisical/README.md +424 -0
- package/engine/topologies/tilt/generators/infisical/examples.star +312 -0
- package/engine/topologies/tilt/generators/infisical/index.star +57 -0
- package/engine/topologies/tilt/generators/infisical/machine_identity.star +420 -0
- package/engine/topologies/tilt/generators/infisical/organization.star +534 -0
- package/engine/topologies/tilt/generators/infisical/path_manager.star +476 -0
- package/engine/topologies/tilt/generators/infisical/secrets_generator.star +420 -0
- package/engine/topologies/tilt/generators/nginx_conf.star +143 -0
- package/engine/topologies/tilt/generators/npmrc.star +111 -0
- package/engine/topologies/tilt/generators/tsconfig.star +23 -0
- package/engine/topologies/tilt/generators/typescript/backend_library_tsconfig.star +71 -0
- package/engine/topologies/tilt/generators/typescript/backend_tsconfig.star +124 -0
- package/engine/topologies/tilt/generators/typescript/common.star +7 -0
- package/engine/topologies/tilt/generators/typescript/frontend_library_tsconfig.star +76 -0
- package/engine/topologies/tilt/generators/typescript/frontend_tsconfig.star +110 -0
- package/engine/topologies/tilt/generators/typescript/include.star +23 -0
- package/engine/topologies/tilt/generators/typescript/playwright_config.star +40 -0
- package/engine/topologies/tilt/generators/typescript/prisma_config.star +49 -0
- package/engine/topologies/tilt/generators/validators.star +853 -0
- package/engine/topologies/tilt/generators/vite/backend.star +78 -0
- package/engine/topologies/tilt/generators/vite/frontend.star +98 -0
- package/engine/topologies/tilt/generators/vite/generators.star +43 -0
- package/engine/topologies/tilt/generators/vite/helpers.star +244 -0
- package/engine/topologies/tilt/generators/vite/library.star +65 -0
- package/engine/topologies/tilt/generators/vite/sdk.star +73 -0
- package/engine/topologies/tilt/generators/vite/templates.star +737 -0
- package/engine/topologies/tilt/generators/vite_config.star +22 -0
- package/engine/topologies/tilt/manifest/AGENTS.md +61 -0
- package/engine/topologies/tilt/manifest/README.md +693 -0
- package/engine/topologies/tilt/manifest/__init__.star +218 -0
- package/engine/topologies/tilt/manifest/constants.star +252 -0
- package/engine/topologies/tilt/manifest/errors.star +266 -0
- package/engine/topologies/tilt/manifest/integration.star +339 -0
- package/engine/topologies/tilt/manifest/json_to_yaml.py +54 -0
- package/engine/topologies/tilt/manifest/loader.star +214 -0
- package/engine/topologies/tilt/manifest/mapper.star +227 -0
- package/engine/topologies/tilt/manifest/parser.star +400 -0
- package/engine/topologies/tilt/manifest/schema.star +462 -0
- package/engine/topologies/tilt/manifest/tests/test_integration.star +276 -0
- package/engine/topologies/tilt/manifest/tests/test_loader_parser.star +397 -0
- package/engine/topologies/tilt/manifest/tests/test_manifest.star +316 -0
- package/engine/topologies/tilt/manifest/tests/test_validator.star +470 -0
- package/engine/topologies/tilt/manifest/validator.star +717 -0
- package/engine/topologies/tilt/manifest/yaml_to_json.py +18 -0
- package/engine/topologies/tilt/resources/AGENTS.md +71 -0
- package/engine/topologies/tilt/resources/conditions.star +3 -0
- package/engine/topologies/tilt/resources/databases.star +244 -0
- package/engine/topologies/tilt/resources/declaration.star +3 -0
- package/engine/topologies/tilt/resources/deps.star +3 -0
- package/engine/topologies/tilt/resources/infra-loader.star +437 -0
- package/engine/topologies/tilt/resources/libs.star +30 -0
- package/engine/topologies/tilt/resources/libs_discovery.star +102 -0
- package/engine/topologies/tilt/resources/libs_paths.star +79 -0
- package/engine/topologies/tilt/resources/libs_resource_definition.star +151 -0
- package/engine/topologies/tilt/resources/libs_setup.star +164 -0
- package/engine/topologies/tilt/resources/libs_tsconfig.star +37 -0
- package/engine/topologies/tilt/resources/orchestrator/apply.star +77 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +431 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_manifest_orchestration.star +81 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_migrator_orchestration.star +148 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_resource_validation.star +36 -0
- package/engine/topologies/tilt/resources/orchestrator/apply_runtime_flags.star +44 -0
- package/engine/topologies/tilt/resources/orchestrator/builders/typescript.star +164 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/AGENTS.md +75 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/index.star +21 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/resolver.star +134 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/env.star +258 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/frontend.star +169 -0
- package/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +524 -0
- package/engine/topologies/tilt/resources/orchestrator/helpers.star +33 -0
- package/engine/topologies/tilt/resources/orchestrator.star +54 -0
- package/engine/topologies/tilt/resources/ordering.star +3 -0
- package/engine/topologies/tilt/resources/triggers.star +3 -0
- package/engine/topologies/tilt/resources/watchers.star +299 -0
- package/engine/where-things-live.star +717 -0
- package/ext/Tiltfile +66 -0
- package/ext/ide-components/README.md +219 -0
- package/ext/ide-components/code_executor/server.py +268 -0
- package/ext/ide-components/code_viewer/server.py +206 -0
- package/ext/ide-components/config_inspector/server.py +1050 -0
- package/ext/ide-components/file_browser/server.py +285 -0
- package/ext/ide-components/shared/config_service.py +469 -0
- package/ext/ide-components/shared/file_utils.py +298 -0
- package/ext/ide-components/shared/http_utils.py +232 -0
- package/ext/ide-components/shared/static/styles.css +1334 -0
- package/ext/ide-components/shared/syntax_highlighter.py +140 -0
- package/ext/ide-components/shared/template_engine.py +123 -0
- package/ext/ide-components/shared/templates/base.html +121 -0
- package/ext/ide-components/shared/test_config_service.py +326 -0
- package/ext/ide-components/shared/tilt_integration.py +158 -0
- package/ext/ui-enhancements/cron-status-server.sh +49 -0
- package/ext/ui-enhancements/cron-status-tracker.sh +146 -0
- package/ext/ui-enhancements/extension.yaml +36 -0
- package/ext/ui-enhancements/tiltfile.py +99 -0
- package/ext/ui-enhancements/ui/cron-jobs-tab.css +396 -0
- package/ext/ui-enhancements/ui/help-panel.css +279 -0
- package/ext/ui-enhancements/ui/icons.css +125 -0
- package/ext/ui-enhancements/ui/tooltips.css +114 -0
- package/package.json +13 -9
- package/specs/specs/TILT_SERVICE_DEFAULTS.star +205 -0
- package/specs/specs/TILT_TECH_STACK.star +159 -0
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# 🐳 TILT SDK - DOCKER COMPOSE GENERATORS (modular)
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Path: .tilt/topologies/platform/docker/compose.star
|
|
5
|
+
# Purpose: docker-compose generation helpers extracted from .tilt/providers/docker.star
|
|
6
|
+
# =============================================================================
|
|
7
|
+
|
|
8
|
+
# === INLINED CONSTANTS for pure extension loading ===
|
|
9
|
+
BASE_PORT_FRONTEND = 3000
|
|
10
|
+
BASE_PORT_BACKEND = 4000
|
|
11
|
+
HEALTH_CHECK_PATH = "/health"
|
|
12
|
+
OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
|
|
13
|
+
# === END INLINED CONSTANTS ===
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
load("./compose_helpers.star", "with_runtime_image_tag", "compose_build_config")
|
|
17
|
+
load("../networking/traefik.star", "get_frontend_traefik_labels", "get_backend_traefik_labels")
|
|
18
|
+
load("../networking/api_path_constants.star", "get_api_path_for_domain")
|
|
19
|
+
load("../secrets/infisical.star", "get_infisical_environment_vars")
|
|
20
|
+
load("../auth/auth.star", "AuthConfig")
|
|
21
|
+
|
|
22
|
+
load("../constants.star", "PlatformDockerConstants")
|
|
23
|
+
|
|
24
|
+
# Load project name for dynamic host naming
|
|
25
|
+
# Use TDK_PROJECT_ROOT env var set by Tilt, fallback to current directory
|
|
26
|
+
def _load_project_name():
|
|
27
|
+
project_root = os.environ.get('TDK_PROJECT_ROOT', '')
|
|
28
|
+
project_json_path = '.tdk/project.json'
|
|
29
|
+
if project_root:
|
|
30
|
+
project_json_path = project_root + '/' + project_json_path
|
|
31
|
+
|
|
32
|
+
if os.path.exists(project_json_path):
|
|
33
|
+
_project_json = read_json(project_json_path)
|
|
34
|
+
return _project_json.get('project', {}).get('name', 'tdk-project')
|
|
35
|
+
return 'tdk-project'
|
|
36
|
+
|
|
37
|
+
_PROJECT_NAME = _load_project_name()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _compute_env_file_rel_path(resource_path, full_resource_path, env_filename):
|
|
41
|
+
"""
|
|
42
|
+
Compute the relative path from compose file location to env file.
|
|
43
|
+
|
|
44
|
+
The compose file is at: resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER/docker-compose.app.autogenerated.yml'
|
|
45
|
+
The env file is at: full_resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/' + env_filename
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
resource_path: The domain/service group path (e.g., 'services/product/users' or 'services/platform')
|
|
49
|
+
full_resource_path: The actual service path (e.g., 'services/product/users/user-management-backend' or 'shared-platform-engineering/my-lib/infra')
|
|
50
|
+
env_filename: The env file name (e.g., '.env.frontend.autogenerated' or '.env.backend.autogenerated')
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Relative path from compose file to env file
|
|
54
|
+
"""
|
|
55
|
+
# Count how many levels deep the compose file is
|
|
56
|
+
# resource_path like 'services/product/users' has 3 parts
|
|
57
|
+
# compose file is at resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/', so we need len(parts) + 1 levels of ../
|
|
58
|
+
resource_path_parts = resource_path.split('/')
|
|
59
|
+
num_dotdots = len(resource_path_parts) + 1 # +1 for the autogenerated directory
|
|
60
|
+
|
|
61
|
+
# Build the dotdot prefix
|
|
62
|
+
dotdot_prefix = '/'.join(['..'] * num_dotdots)
|
|
63
|
+
|
|
64
|
+
# The env file is at full_resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/' + env_filename
|
|
65
|
+
return dotdot_prefix + '/' + full_resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/' + env_filename
|
|
66
|
+
|
|
67
|
+
# =============================================================================
|
|
68
|
+
# 🚦 FRONTEND / BACKEND ENTRIES
|
|
69
|
+
# =============================================================================
|
|
70
|
+
|
|
71
|
+
def generate_frontend_compose(resource_path, resource_name, res, manifest=None):
|
|
72
|
+
"""Generate frontend docker-compose entry with Traefik routing."""
|
|
73
|
+
res_name = res['name']
|
|
74
|
+
image_name = with_runtime_image_tag(resource_name + '_' + res_name)
|
|
75
|
+
stack = manifest.get('stack', resource_name) if manifest else resource_name
|
|
76
|
+
|
|
77
|
+
target_path = res.get('target_path', manifest.get('target_path', '/usr/share/nginx/html'))
|
|
78
|
+
use_nginx = 'nginx' in target_path or target_path == '/usr/share/nginx/html'
|
|
79
|
+
# Read port from manifest (service.json), fallback to BASE_PORT_FRONTEND or 80 for nginx
|
|
80
|
+
port = manifest.get('port', 80 if use_nginx else BASE_PORT_FRONTEND)
|
|
81
|
+
|
|
82
|
+
# Base path for routing on {project}.localhost
|
|
83
|
+
base_path = '/' + manifest.get('basePath', stack + 's').lstrip('/')
|
|
84
|
+
|
|
85
|
+
traefik_cfg = manifest.get('traefik', {}) if manifest else {}
|
|
86
|
+
traefik_host = traefik_cfg.get('host')
|
|
87
|
+
# Use custom dockerfile from manifest if specified, otherwise use autogenerated default
|
|
88
|
+
dockerfile_path = res.get('dockerfile', OUTPUT.AUTOGENERATED_FOLDER + '/Dockerfile.app.autogenerated')
|
|
89
|
+
# Handle flat service structure (e.g., services/product/identity-management-frontend) vs nested (services/product/domain/service)
|
|
90
|
+
# Detect flat structure: services/product/{service} (3 path parts after root)
|
|
91
|
+
# vs nested: services/product/{domain}/{service} (4+ path parts)
|
|
92
|
+
full_resource_path = res.get('_resource_path', resource_path + '/' + res_name)
|
|
93
|
+
path_parts = full_resource_path.split('/')
|
|
94
|
+
# If path is like services/product/xxx (3 parts), it's flat - use path directly
|
|
95
|
+
# If path is like services/product/domain/xxx (4 parts), it's nested - use standard construction
|
|
96
|
+
if len(path_parts) <= 3:
|
|
97
|
+
# Flat structure: resource_path already includes res_name
|
|
98
|
+
build_config = compose_build_config(full_resource_path, '', dockerfile_path, 'production')
|
|
99
|
+
else:
|
|
100
|
+
# Nested structure: use resource_path and res_name separately
|
|
101
|
+
build_config = compose_build_config(resource_path, res_name, dockerfile_path, 'production')
|
|
102
|
+
|
|
103
|
+
# Calculate correct relative path to env_file from compose file location
|
|
104
|
+
# The compose file is at: resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER/docker-compose.app.autogenerated.yml'
|
|
105
|
+
# The env file is at: full_resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER/.env.frontend.autogenerated'
|
|
106
|
+
env_file_rel_path = _compute_env_file_rel_path(resource_path, full_resource_path, '.env.frontend.autogenerated')
|
|
107
|
+
|
|
108
|
+
traefik_labels = get_frontend_traefik_labels(
|
|
109
|
+
res_name,
|
|
110
|
+
stack,
|
|
111
|
+
base_path,
|
|
112
|
+
port,
|
|
113
|
+
traefik_host=traefik_host,
|
|
114
|
+
manifest=manifest,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return """ {res_name}:
|
|
118
|
+
image: {image_name}
|
|
119
|
+
{build_config}
|
|
120
|
+
<<: *frontend-memory-limit
|
|
121
|
+
env_file:
|
|
122
|
+
- {env_file_rel_path}
|
|
123
|
+
environment:
|
|
124
|
+
- VITE_APP_ENV=development
|
|
125
|
+
labels:
|
|
126
|
+
{traefik_labels}
|
|
127
|
+
networks:
|
|
128
|
+
- {network_traefik_public}
|
|
129
|
+
- {network_backend}
|
|
130
|
+
healthcheck:
|
|
131
|
+
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://127.0.0.1:{port}"]
|
|
132
|
+
interval: 10s
|
|
133
|
+
timeout: 5s
|
|
134
|
+
retries: 3
|
|
135
|
+
# STORY 4 FIX: 30s grace period to prevent 504 errors on startup
|
|
136
|
+
start_period: 30s
|
|
137
|
+
""".format(
|
|
138
|
+
res_name=res_name,
|
|
139
|
+
image_name=image_name,
|
|
140
|
+
build_config=build_config,
|
|
141
|
+
env_file_rel_path=env_file_rel_path,
|
|
142
|
+
traefik_labels=traefik_labels,
|
|
143
|
+
port=port,
|
|
144
|
+
network_traefik_public=PlatformDockerConstants.NETWORK_TRAEFIK_PUBLIC,
|
|
145
|
+
network_backend=PlatformDockerConstants.NETWORK_BACKEND,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _generate_single_backend_entry(resource_path, resource_name, res, manifest, instance_id=None):
|
|
150
|
+
"""
|
|
151
|
+
Generate a single backend docker-compose entry.
|
|
152
|
+
"""
|
|
153
|
+
res_name = res['name']
|
|
154
|
+
stack = manifest.get('stack', resource_name) if manifest else resource_name
|
|
155
|
+
|
|
156
|
+
# Get full service path from resource (for cross-root service support)
|
|
157
|
+
full_resource_path = res.get('_resource_path', resource_path + '/' + res_name)
|
|
158
|
+
|
|
159
|
+
# Calculate correct relative path to env_file from compose file location
|
|
160
|
+
env_file_rel_path = _compute_env_file_rel_path(resource_path, full_resource_path, '.env.backend.autogenerated')
|
|
161
|
+
|
|
162
|
+
internal_port = manifest.get('port', BASE_PORT_BACKEND) if manifest else BASE_PORT_BACKEND
|
|
163
|
+
dev_port = internal_port
|
|
164
|
+
# Use PROJECT_NAME from PlatformDockerConstants for portable database naming
|
|
165
|
+
_db_prefix = PlatformDockerConstants.PROJECT_NAME + "_"
|
|
166
|
+
db_name = manifest.get('databaseName', _db_prefix + stack) if manifest else _db_prefix + stack
|
|
167
|
+
|
|
168
|
+
# Compute database URLs using centralized constants
|
|
169
|
+
db_url_for_tilt = PlatformDockerConstants.get_database_url_for_env(db_name)
|
|
170
|
+
db_url_with_fallback = PlatformDockerConstants.get_compose_env_database_url(db_name)
|
|
171
|
+
|
|
172
|
+
health_path = manifest.get('healthCheckPath', HEALTH_CHECK_PATH) if manifest else HEALTH_CHECK_PATH
|
|
173
|
+
|
|
174
|
+
traefik_cfg = manifest.get('traefik', {}) if manifest else {}
|
|
175
|
+
traefik_host = traefik_cfg.get('host', stack + '.backend.' + _PROJECT_NAME + '.local')
|
|
176
|
+
# ALPHA: Use proper API v1 path with -management suffix via api_path_constants
|
|
177
|
+
# Old default: '/api/' + stack
|
|
178
|
+
# New default: get_api_path_for_domain → /api/v1/{stack}-management
|
|
179
|
+
traefik_path = traefik_cfg.get('pathPrefix', get_api_path_for_domain(stack, manifest))
|
|
180
|
+
|
|
181
|
+
nats_cfg = manifest.get('nats', {}) if manifest else {}
|
|
182
|
+
nats_queue = nats_cfg.get('queueGroup', stack + '_backend_svc')
|
|
183
|
+
nats_url = PlatformDockerConstants.NATS_URL
|
|
184
|
+
|
|
185
|
+
# Auth configuration - use centralized auth utilities
|
|
186
|
+
# Extract auth config from manifest to decouple auth.star from manifest structure
|
|
187
|
+
# Auto-detect identity-service mode if 'identity' is in dependsOn
|
|
188
|
+
internal_deps = manifest.get('dependsOn', []) if manifest else []
|
|
189
|
+
has_identity_dep = 'identity' in internal_deps
|
|
190
|
+
|
|
191
|
+
# If manifest has authMode, use it; otherwise auto-detect based on identity dependency
|
|
192
|
+
manifest_auth_mode = manifest.get('authMode') if manifest else None
|
|
193
|
+
if manifest_auth_mode:
|
|
194
|
+
auth_mode = manifest_auth_mode
|
|
195
|
+
elif has_identity_dep:
|
|
196
|
+
auth_mode = 'identity-service'
|
|
197
|
+
else:
|
|
198
|
+
auth_mode = None
|
|
199
|
+
|
|
200
|
+
auth_config = {
|
|
201
|
+
'authMode': auth_mode,
|
|
202
|
+
'jwtSecret': manifest.get('jwtSecret') if manifest else None,
|
|
203
|
+
'identityServiceUrl': manifest.get('envVars', {}).get('IDENTITY_RESOURCE_URL') if manifest else None,
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
# If we auto-detected identity-service mode but no URL is set, use default
|
|
207
|
+
if auth_mode == 'identity-service' and not auth_config['identityServiceUrl']:
|
|
208
|
+
auth_config['identityServiceUrl'] = AuthConfig.get_identity_resource_url(None)
|
|
209
|
+
|
|
210
|
+
auth_env = AuthConfig.generate_docker_compose_auth_env(auth_config)
|
|
211
|
+
|
|
212
|
+
# Use .autogenerated/Dockerfile.app.autogenerated by default for build config (primary only)
|
|
213
|
+
build_config = compose_build_config(resource_path, res_name)
|
|
214
|
+
|
|
215
|
+
# REMOVED: External port exposure - all services accessed via Traefik only
|
|
216
|
+
# Services are available at {project}.localhost/api/v1/{service}
|
|
217
|
+
# Internal port 3000 is accessible within Docker network for service-to-service communication
|
|
218
|
+
ports_section = "" # No external ports - Traefik-only access
|
|
219
|
+
|
|
220
|
+
# Determine service name based on instance
|
|
221
|
+
if instance_id:
|
|
222
|
+
# Replica instance: add instance suffix
|
|
223
|
+
resource_entry_name = res_name + '-' + str(instance_id)
|
|
224
|
+
instance_label = str(instance_id)
|
|
225
|
+
# Replicas should reuse the already-built image; avoid per-replica builds
|
|
226
|
+
build_config = ""
|
|
227
|
+
else:
|
|
228
|
+
# Primary instance
|
|
229
|
+
resource_entry_name = res_name
|
|
230
|
+
instance_label = '0'
|
|
231
|
+
|
|
232
|
+
# All instances share the same Traefik service for load balancing
|
|
233
|
+
traefik_resource_name = res_name # LB service name (shared)
|
|
234
|
+
|
|
235
|
+
traefik_labels = get_backend_traefik_labels(
|
|
236
|
+
resource_entry_name=resource_entry_name,
|
|
237
|
+
traefik_host=traefik_host,
|
|
238
|
+
traefik_path=traefik_path,
|
|
239
|
+
traefik_resource_name=traefik_resource_name,
|
|
240
|
+
internal_port=internal_port,
|
|
241
|
+
health_path=health_path,
|
|
242
|
+
manifest=manifest,
|
|
243
|
+
)
|
|
244
|
+
infisical_env = get_infisical_environment_vars(as_array=True, resource_name=res_name)
|
|
245
|
+
|
|
246
|
+
# Build auth environment variables section using centralized auth utilities
|
|
247
|
+
|
|
248
|
+
return """
|
|
249
|
+
{resource_entry_name}:
|
|
250
|
+
image: {image_name}
|
|
251
|
+
restart: unless-stopped
|
|
252
|
+
{build_config}
|
|
253
|
+
{ports_section}
|
|
254
|
+
env_file:
|
|
255
|
+
- {env_file_rel_path}
|
|
256
|
+
environment:
|
|
257
|
+
{infisical_env}
|
|
258
|
+
- RESOURCE_NAME={stack}
|
|
259
|
+
- PORT={port_anchor}
|
|
260
|
+
- INSTANCE_ID={instance_label}
|
|
261
|
+
- NATS_QUEUE_GROUP={nats_queue}
|
|
262
|
+
- TILT_DATABASE_URL={db_url_for_tilt}
|
|
263
|
+
- TILT_NATS_URL={nats_url}
|
|
264
|
+
- NODE_ENV=development
|
|
265
|
+
- DATABASE_URL={db_url_for_tilt}
|
|
266
|
+
{auth_env}
|
|
267
|
+
labels:
|
|
268
|
+
{traefik_labels}
|
|
269
|
+
networks:
|
|
270
|
+
- {network_traefik_public}
|
|
271
|
+
- {network_backend}
|
|
272
|
+
- {network_database}
|
|
273
|
+
- {network_infisical}
|
|
274
|
+
healthcheck:
|
|
275
|
+
test: ["CMD", "curl", "-f", "--max-time", "5", "http://localhost:{internal_port}{health_path}"]
|
|
276
|
+
interval: 10s
|
|
277
|
+
timeout: 5s
|
|
278
|
+
retries: 6
|
|
279
|
+
# STORY 4 FIX: 30s grace period to prevent 504 errors during startup
|
|
280
|
+
# Services get 30s to initialize before health checks begin
|
|
281
|
+
start_period: 30s
|
|
282
|
+
# Note: depends_on removed - Tilt manages service startup order
|
|
283
|
+
deploy:
|
|
284
|
+
resources:
|
|
285
|
+
limits:
|
|
286
|
+
cpus: '0.5'
|
|
287
|
+
memory: 512M
|
|
288
|
+
reservations:
|
|
289
|
+
cpus: '0.2'
|
|
290
|
+
memory: 256M
|
|
291
|
+
""".format(
|
|
292
|
+
resource_entry_name=resource_entry_name,
|
|
293
|
+
res_name=res_name,
|
|
294
|
+
resource_name=resource_name,
|
|
295
|
+
image_name=with_runtime_image_tag(resource_name + '_' + res_name),
|
|
296
|
+
build_config=build_config,
|
|
297
|
+
ports_section=ports_section,
|
|
298
|
+
env_file_rel_path=env_file_rel_path,
|
|
299
|
+
stack=stack,
|
|
300
|
+
internal_port=internal_port,
|
|
301
|
+
port_anchor=internal_port,
|
|
302
|
+
dev_port=dev_port,
|
|
303
|
+
db_name=db_name,
|
|
304
|
+
db_url_for_tilt=db_url_for_tilt,
|
|
305
|
+
db_url_with_fallback=db_url_with_fallback,
|
|
306
|
+
instance_label=instance_label,
|
|
307
|
+
health_path=health_path,
|
|
308
|
+
traefik_host=traefik_host,
|
|
309
|
+
traefik_path=traefik_path,
|
|
310
|
+
traefik_resource_name=traefik_resource_name,
|
|
311
|
+
nats_queue=nats_queue,
|
|
312
|
+
nats_url=nats_url,
|
|
313
|
+
traefik_labels=traefik_labels,
|
|
314
|
+
infisical_env=infisical_env,
|
|
315
|
+
auth_env=auth_env,
|
|
316
|
+
network_traefik_public=PlatformDockerConstants.NETWORK_TRAEFIK_PUBLIC,
|
|
317
|
+
network_backend=PlatformDockerConstants.NETWORK_BACKEND,
|
|
318
|
+
network_database=PlatformDockerConstants.NETWORK_DATABASE,
|
|
319
|
+
network_infisical=PlatformDockerConstants.NETWORK_INFISICAL,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def generate_backend_compose_entry(resource_path, resource_name, res, manifest=None):
|
|
324
|
+
"""
|
|
325
|
+
Generate backend docker-compose entries with TRUE multi-replica support.
|
|
326
|
+
"""
|
|
327
|
+
replicas = manifest.get('replicas', 1) if manifest else 1
|
|
328
|
+
|
|
329
|
+
if replicas <= 1:
|
|
330
|
+
# Single instance - simple case
|
|
331
|
+
return _generate_single_backend_entry(resource_path, resource_name, res, manifest, instance_id=None)
|
|
332
|
+
|
|
333
|
+
# Multi-replica: generate separate service entries
|
|
334
|
+
entries = []
|
|
335
|
+
|
|
336
|
+
# Primary instance (gets the port mapping)
|
|
337
|
+
entries.append(_generate_single_backend_entry(resource_path, resource_name, res, manifest, instance_id=None))
|
|
338
|
+
|
|
339
|
+
# Additional replicas (numbered, expose only)
|
|
340
|
+
for i in range(1, replicas):
|
|
341
|
+
entries.append(_generate_single_backend_entry(resource_path, resource_name, res, manifest, instance_id=i))
|
|
342
|
+
|
|
343
|
+
return ''.join(entries)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _generate_port_anchors(resource_entries):
|
|
347
|
+
"""Extract unique ports and generate YAML anchors for them."""
|
|
348
|
+
backend_port = None
|
|
349
|
+
frontend_port = None
|
|
350
|
+
sdk_port = None
|
|
351
|
+
has_backend = False
|
|
352
|
+
has_sdk = False
|
|
353
|
+
has_frontend = False
|
|
354
|
+
|
|
355
|
+
for entry in resource_entries:
|
|
356
|
+
# Check if this is an SDK (ends with -sdk)
|
|
357
|
+
if "-sdk:" in entry or entry.strip().startswith("identity-sdk:"):
|
|
358
|
+
has_sdk = True
|
|
359
|
+
# Extract SDK port from entry
|
|
360
|
+
if "loadbalancer.server.port=" in entry:
|
|
361
|
+
for line in entry.split("\n"):
|
|
362
|
+
if "loadbalancer.server.port=" in line:
|
|
363
|
+
# Safe parsing without try/except
|
|
364
|
+
port_str = line.split("loadbalancer.server.port=")[-1].split('"')[0]
|
|
365
|
+
if port_str.isdigit():
|
|
366
|
+
sdk_port = int(port_str)
|
|
367
|
+
break
|
|
368
|
+
# Check if this is a frontend (has frontend-memory-limit but not SDK)
|
|
369
|
+
elif "<<: *frontend-memory-limit" in entry and not ("-sdk:" in entry or entry.strip().startswith("identity-sdk:")):
|
|
370
|
+
has_frontend = True
|
|
371
|
+
# Extract frontend port from entry
|
|
372
|
+
if "loadbalancer.server.port=" in entry:
|
|
373
|
+
for line in entry.split("\n"):
|
|
374
|
+
if "loadbalancer.server.port=" in line:
|
|
375
|
+
# Safe parsing without try/except
|
|
376
|
+
port_str = line.split("loadbalancer.server.port=")[-1].split('"')[0]
|
|
377
|
+
if port_str.isdigit():
|
|
378
|
+
frontend_port = int(port_str)
|
|
379
|
+
break
|
|
380
|
+
# Check if this is a backend (has a port, not frontend, not SDK)
|
|
381
|
+
# Backend entries have "healthcheck:" section with backend port
|
|
382
|
+
elif "healthcheck:" in entry and "<<: *frontend-memory-limit" not in entry and not ("-sdk:" in entry or entry.strip().startswith("identity-sdk:")):
|
|
383
|
+
has_backend = True
|
|
384
|
+
# Extract backend port from entry
|
|
385
|
+
if "loadbalancer.server.port=" in entry:
|
|
386
|
+
for line in entry.split("\n"):
|
|
387
|
+
if "loadbalancer.server.port=" in line:
|
|
388
|
+
# Safe parsing without try/except
|
|
389
|
+
port_str = line.split("loadbalancer.server.port=")[-1].split('"')[0]
|
|
390
|
+
if port_str.isdigit():
|
|
391
|
+
backend_port = int(port_str)
|
|
392
|
+
break
|
|
393
|
+
|
|
394
|
+
# Build anchors - use extracted port or fall back to default
|
|
395
|
+
anchors = []
|
|
396
|
+
anchors.append("x-backend-port: &backend-port {}".format(backend_port if backend_port else BASE_PORT_BACKEND))
|
|
397
|
+
if has_frontend and frontend_port:
|
|
398
|
+
anchors.append("x-frontend-port: &frontend-port {}".format(frontend_port))
|
|
399
|
+
if has_sdk and sdk_port:
|
|
400
|
+
anchors.append("x-sdk-port: &sdk-port {}".format(sdk_port))
|
|
401
|
+
|
|
402
|
+
return "\n".join(anchors)
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def _detect_sdk_in_entries(resource_entries):
|
|
406
|
+
"""Check if any entry is an SDK."""
|
|
407
|
+
for entry in resource_entries:
|
|
408
|
+
if "-sdk:" in entry or entry.strip().startswith("identity-sdk:"):
|
|
409
|
+
return True
|
|
410
|
+
return False
|
|
411
|
+
|
|
412
|
+
def _detect_frontend_in_entries(resource_entries):
|
|
413
|
+
"""Check if any entry is a frontend."""
|
|
414
|
+
for entry in resource_entries:
|
|
415
|
+
if "<<: *frontend-memory-limit" in entry:
|
|
416
|
+
return True
|
|
417
|
+
return False
|
|
418
|
+
|
|
419
|
+
def _detect_backend_in_entries(resource_entries):
|
|
420
|
+
"""Check if any entry is a backend."""
|
|
421
|
+
for entry in resource_entries:
|
|
422
|
+
if _is_backend_entry(entry):
|
|
423
|
+
return True
|
|
424
|
+
return False
|
|
425
|
+
|
|
426
|
+
def _is_sdk_entry(entry):
|
|
427
|
+
"""Check if a specific entry is an SDK."""
|
|
428
|
+
return "-sdk:" in entry or entry.strip().startswith("identity-sdk:")
|
|
429
|
+
|
|
430
|
+
def _is_backend_entry(entry):
|
|
431
|
+
"""Check if a specific entry is a backend (not frontend, not SDK)."""
|
|
432
|
+
if "-sdk:" in entry or entry.strip().startswith("identity-sdk:"):
|
|
433
|
+
return False
|
|
434
|
+
if "<<: *frontend-memory-limit" in entry:
|
|
435
|
+
return False
|
|
436
|
+
# Backend entries have healthcheck with backend port pattern
|
|
437
|
+
if "healthcheck:" in entry and "curl" in entry:
|
|
438
|
+
return True
|
|
439
|
+
return False
|
|
440
|
+
|
|
441
|
+
def _replace_ports_with_anchors(entry, has_sdk=False, has_frontend=False, has_backend=False):
|
|
442
|
+
"""Replace hardcoded ports with YAML anchors in an entry."""
|
|
443
|
+
is_sdk = _is_sdk_entry(entry)
|
|
444
|
+
is_backend = _is_backend_entry(entry)
|
|
445
|
+
lines = entry.split("\n")
|
|
446
|
+
result = []
|
|
447
|
+
|
|
448
|
+
for line in lines:
|
|
449
|
+
new_line = line
|
|
450
|
+
# NOTE: We do NOT replace PORT=3000 with an anchor because YAML anchors
|
|
451
|
+
# in environment variable values are treated as literal strings, not resolved.
|
|
452
|
+
# The actual port value is already correctly set by _generate_single_backend_entry
|
|
453
|
+
# using the internal_port variable. Keep PORT=3000 as-is.
|
|
454
|
+
|
|
455
|
+
# YAML anchors do not resolve inside quoted Docker labels. Traefik must
|
|
456
|
+
# see a numeric loadbalancer.port (e.g. 4000), not `*backend-port`.
|
|
457
|
+
# NOTE: We do NOT replace healthcheck URLs with YAML anchors because anchors
|
|
458
|
+
# don't work inside quoted strings. The wget healthcheck URLs must use actual
|
|
459
|
+
# port numbers (e.g., http://127.0.0.1:3000), not anchor references.
|
|
460
|
+
# The correct port is already set by generate_frontend_compose.
|
|
461
|
+
# NOTE: We do NOT replace healthcheck URLs with anchors because YAML anchors
|
|
462
|
+
# don't work inside quoted strings. The healthcheck URL must use the actual
|
|
463
|
+
# port number (e.g., http://localhost:3000/health), not an anchor reference.
|
|
464
|
+
# The _generate_single_backend_entry function already uses the correct port
|
|
465
|
+
# via the internal_port variable in the healthcheck URL.
|
|
466
|
+
|
|
467
|
+
result.append(new_line)
|
|
468
|
+
|
|
469
|
+
return "\n".join(result)
|
|
470
|
+
|
|
471
|
+
def _process_entries_with_anchors(resource_entries, has_sdk, has_frontend, has_backend):
|
|
472
|
+
"""Replace ports with anchors in all entries."""
|
|
473
|
+
result = []
|
|
474
|
+
for entry in resource_entries:
|
|
475
|
+
result.append(_replace_ports_with_anchors(entry, has_sdk, has_frontend, has_backend))
|
|
476
|
+
return result
|
|
477
|
+
|
|
478
|
+
def generate_app_compose_from_entries(resource_path, resource_entries, write_fn=None):
|
|
479
|
+
"""Generate docker-compose.app.autogenerated.yml from service entries with port anchors.
|
|
480
|
+
|
|
481
|
+
Args:
|
|
482
|
+
resource_path: Path to the resource directory
|
|
483
|
+
resource_entries: List of docker-compose entries for services
|
|
484
|
+
write_fn: Optional write function for file output
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
str: Generated docker-compose YAML content
|
|
488
|
+
"""
|
|
489
|
+
|
|
490
|
+
# Detect service types
|
|
491
|
+
has_sdk = _detect_sdk_in_entries(resource_entries)
|
|
492
|
+
has_frontend = _detect_frontend_in_entries(resource_entries)
|
|
493
|
+
has_backend = _detect_backend_in_entries(resource_entries)
|
|
494
|
+
|
|
495
|
+
# Replace ports with anchors in entries
|
|
496
|
+
processed_entries = _process_entries_with_anchors(resource_entries, has_sdk, has_frontend, has_backend)
|
|
497
|
+
|
|
498
|
+
# Generate port anchors
|
|
499
|
+
port_anchors = _generate_port_anchors(resource_entries)
|
|
500
|
+
|
|
501
|
+
header = """###############################################################################
|
|
502
|
+
# 🛑 CRITICAL: SYSTEM-GENERATED FILE - DO NOT MODIFY DIRECTLY
|
|
503
|
+
#
|
|
504
|
+
# ANY MANUAL CHANGES MADE TO THIS FILE WILL BE WIPED ON THE NEXT 'tilt up'.
|
|
505
|
+
# Generation Source: .tilt/topologies/platform/docker/index.star
|
|
506
|
+
###############################################################################
|
|
507
|
+
|
|
508
|
+
# =============================================================================
|
|
509
|
+
# PORT DEFINITIONS - Change these to change ports everywhere
|
|
510
|
+
# =============================================================================
|
|
511
|
+
{port_anchors}
|
|
512
|
+
|
|
513
|
+
# =============================================================================
|
|
514
|
+
# MEMORY LIMITS
|
|
515
|
+
# =============================================================================
|
|
516
|
+
x-nix-any-m1-arm64-memory-limit: &nix-any-m1-arm64-memory-limit
|
|
517
|
+
deploy:
|
|
518
|
+
resources:
|
|
519
|
+
limits:
|
|
520
|
+
memory: 192M
|
|
521
|
+
reservations:
|
|
522
|
+
memory: 64M
|
|
523
|
+
|
|
524
|
+
x-frontend-memory-limit: &frontend-memory-limit
|
|
525
|
+
deploy:
|
|
526
|
+
resources:
|
|
527
|
+
limits:
|
|
528
|
+
memory: 64M
|
|
529
|
+
cpus: '0.15'
|
|
530
|
+
reservations:
|
|
531
|
+
memory: 32M
|
|
532
|
+
|
|
533
|
+
services:
|
|
534
|
+
""".format(port_anchors=port_anchors)
|
|
535
|
+
|
|
536
|
+
footer = """
|
|
537
|
+
networks:
|
|
538
|
+
{network_traefik_public}:
|
|
539
|
+
external: true
|
|
540
|
+
{network_backend}:
|
|
541
|
+
external: true
|
|
542
|
+
{network_database}:
|
|
543
|
+
external: true
|
|
544
|
+
{network_infisical}:
|
|
545
|
+
external: true
|
|
546
|
+
""".format(
|
|
547
|
+
network_traefik_public=PlatformDockerConstants.NETWORK_TRAEFIK_PUBLIC,
|
|
548
|
+
network_backend=PlatformDockerConstants.NETWORK_BACKEND,
|
|
549
|
+
network_database=PlatformDockerConstants.NETWORK_DATABASE,
|
|
550
|
+
network_infisical=PlatformDockerConstants.NETWORK_INFISICAL,
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
content = header + "\n".join(processed_entries) + footer
|
|
554
|
+
|
|
555
|
+
if write_fn:
|
|
556
|
+
compose_path = resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/docker-compose.app.autogenerated.yml'
|
|
557
|
+
print("DEBUG COMPOSE GEN: Writing {} bytes to {}".format(len(content), compose_path))
|
|
558
|
+
write_fn(compose_path, content)
|
|
559
|
+
print("DEBUG COMPOSE GEN: Write completed")
|
|
560
|
+
else:
|
|
561
|
+
print("DEBUG COMPOSE GEN: No write_fn provided!")
|
|
562
|
+
|
|
563
|
+
return content
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
def generate_migrator_compose(resource_path, resource_name, dockerfile_path=None, write_fn=None):
|
|
567
|
+
"""Generate docker-compose for database migrators.
|
|
568
|
+
|
|
569
|
+
Args:
|
|
570
|
+
resource_path: Path to the resource directory
|
|
571
|
+
resource_name: Name of the resource
|
|
572
|
+
dockerfile_path: Optional path to Dockerfile
|
|
573
|
+
write_fn: Optional write function for file output
|
|
574
|
+
|
|
575
|
+
Returns:
|
|
576
|
+
str: Generated docker-compose YAML content
|
|
577
|
+
"""
|
|
578
|
+
migrator_name = resource_name + '-db-migrator'
|
|
579
|
+
image_name = with_runtime_image_tag(resource_name + '-db-migrator')
|
|
580
|
+
|
|
581
|
+
# Use PROJECT_NAME from PlatformDockerConstants for portable database naming
|
|
582
|
+
db_name = PlatformDockerConstants.PROJECT_NAME + '_' + resource_name
|
|
583
|
+
default_db_url = PlatformDockerConstants.get_database_url_for_env(db_name)
|
|
584
|
+
|
|
585
|
+
dockerfile_ref = dockerfile_path if dockerfile_path else resource_path + "/" + OUTPUT.AUTOGENERATED_FOLDER + "/Dockerfile.migrator.autogenerated"
|
|
586
|
+
infisical_env = get_infisical_environment_vars(as_array=False)
|
|
587
|
+
|
|
588
|
+
content = """###############################################################################
|
|
589
|
+
# 🛑 CRITICAL: SYSTEM-GENERATED FILE - DO NOT MODIFY DIRECTLY
|
|
590
|
+
# Generation Source: .tilt/topologies/platform/docker/index.star
|
|
591
|
+
###############################################################################
|
|
592
|
+
# 🔐 Infisical Zero-Code Integration Enabled
|
|
593
|
+
# 🗃️ Database Virtualization: Connects to shared PostgreSQL instance
|
|
594
|
+
services:
|
|
595
|
+
{migrator_name}:
|
|
596
|
+
image: {image_name}
|
|
597
|
+
build:
|
|
598
|
+
context: ../../../../.
|
|
599
|
+
dockerfile: {dockerfile_ref}
|
|
600
|
+
target: migrator
|
|
601
|
+
environment:
|
|
602
|
+
{infisical_env}
|
|
603
|
+
RESOURCE_NAME: {resource_name}
|
|
604
|
+
TILT_DATABASE_URL: "{default_db_url}"
|
|
605
|
+
DATABASE_URL: ${{DATABASE_URL:-{default_db_url}}}
|
|
606
|
+
networks:
|
|
607
|
+
- {network_database}
|
|
608
|
+
- {network_backend}
|
|
609
|
+
- {network_infisical}
|
|
610
|
+
restart: "no"
|
|
611
|
+
|
|
612
|
+
networks:
|
|
613
|
+
{network_database}:
|
|
614
|
+
external: true
|
|
615
|
+
{network_backend}:
|
|
616
|
+
external: true
|
|
617
|
+
{network_infisical}:
|
|
618
|
+
external: true
|
|
619
|
+
""".format(
|
|
620
|
+
migrator_name=migrator_name,
|
|
621
|
+
image_name=image_name,
|
|
622
|
+
resource_path=resource_path,
|
|
623
|
+
dockerfile_ref=dockerfile_ref,
|
|
624
|
+
resource_name=resource_name,
|
|
625
|
+
db_name=db_name,
|
|
626
|
+
default_db_url=default_db_url,
|
|
627
|
+
infisical_env=infisical_env,
|
|
628
|
+
network_database=PlatformDockerConstants.NETWORK_DATABASE,
|
|
629
|
+
network_backend=PlatformDockerConstants.NETWORK_BACKEND,
|
|
630
|
+
network_infisical=PlatformDockerConstants.NETWORK_INFISICAL,
|
|
631
|
+
)
|
|
632
|
+
|
|
633
|
+
if write_fn:
|
|
634
|
+
write_fn(resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/docker-compose.migrator.autogenerated.yml', content)
|
|
635
|
+
|
|
636
|
+
return content
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# 🐳 TILT SDK - COMPOSE HELPERS
|
|
3
|
+
# =============================================================================
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# === INLINED CONSTANTS for pure extension loading ===
|
|
8
|
+
OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
|
|
9
|
+
# === END INLINED CONSTANTS ===
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def with_runtime_image_tag(image_name):
|
|
13
|
+
"""Apply stable local image tag (:dev)."""
|
|
14
|
+
tag = 'dev'
|
|
15
|
+
|
|
16
|
+
last_segment = image_name.split('/')[-1]
|
|
17
|
+
if ':' in last_segment:
|
|
18
|
+
return image_name[:image_name.rfind(':')] + ':' + tag
|
|
19
|
+
|
|
20
|
+
return image_name + ':' + tag
|
|
21
|
+
|
|
22
|
+
def compose_build_config(resource_path, res_name, dockerfile=OUTPUT.AUTOGENERATED_FOLDER + '/Dockerfile.app.autogenerated', target=None):
|
|
23
|
+
"""Generate build config for docker-compose."""
|
|
24
|
+
# Check if dockerfile is already a full path (contains resource_path)
|
|
25
|
+
if dockerfile.startswith(resource_path + '/'):
|
|
26
|
+
# dockerfile is already a full path, use it directly
|
|
27
|
+
full_dockerfile_path = dockerfile
|
|
28
|
+
elif res_name:
|
|
29
|
+
# Nested structure: construct path as resource_path/res_name/dockerfile
|
|
30
|
+
full_dockerfile_path = "{resource_path}/{res_name}/{dockerfile}".format(
|
|
31
|
+
resource_path=resource_path,
|
|
32
|
+
res_name=res_name,
|
|
33
|
+
dockerfile=dockerfile
|
|
34
|
+
)
|
|
35
|
+
else:
|
|
36
|
+
# Flat structure: construct path as resource_path/dockerfile
|
|
37
|
+
full_dockerfile_path = "{resource_path}/{dockerfile}".format(
|
|
38
|
+
resource_path=resource_path,
|
|
39
|
+
dockerfile=dockerfile
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
base_config = """ build:
|
|
43
|
+
context: ../../../../.
|
|
44
|
+
dockerfile: {full_dockerfile_path}""".format(
|
|
45
|
+
full_dockerfile_path=full_dockerfile_path
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if target:
|
|
49
|
+
base_config += """
|
|
50
|
+
target: {target}""".format(target=target)
|
|
51
|
+
|
|
52
|
+
return base_config
|