@tdk-landscape/tdk-cli-core 1.3.15 → 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/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 +59 -18
- 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/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
package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# 🧩 ORCHESTRATOR APPLY - COMPOSE RESOURCE REGISTRATION (Refactored)
|
|
3
|
+
# =============================================================================
|
|
4
|
+
|
|
5
|
+
# === INLINED CONSTANTS for pure extension loading ===
|
|
6
|
+
OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
|
|
7
|
+
# === END INLINED CONSTANTS ===
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
load('../../../platform/docker/index.star', 'Docker')
|
|
11
|
+
load('../../../platform/docker/constants.star', 'PlatformDockerConstants')
|
|
12
|
+
load('../../../tilt/manifest/constants.star', 'BASE_PORT_FRONTEND')
|
|
13
|
+
|
|
14
|
+
load('./builders/typescript.star', 'TypescriptBuilders')
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _env_file_if_exists(env_file):
|
|
18
|
+
""".env is gitignored (no .env.example shipped) across every TDK example repo, so a
|
|
19
|
+
fresh clone must not hard-require it: docker_compose()'s env_file kwarg type-checks as
|
|
20
|
+
path|string (rejects None), so only return a path when the file actually exists."""
|
|
21
|
+
exists = str(local("test -f '" + env_file + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes'
|
|
22
|
+
return env_file if exists else None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _docker_compose_app(compose_paths, project_name, env_file):
|
|
26
|
+
resolved_env_file = _env_file_if_exists(env_file)
|
|
27
|
+
if resolved_env_file:
|
|
28
|
+
docker_compose(compose_paths, project_name=project_name, env_file=resolved_env_file)
|
|
29
|
+
else:
|
|
30
|
+
docker_compose(compose_paths, project_name=project_name)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _build_infra_dependencies(resource_name, should_enable, ctx, has_backend=False):
|
|
34
|
+
infra_deps = []
|
|
35
|
+
if should_enable('database-management'):
|
|
36
|
+
infra_deps.append('postgres')
|
|
37
|
+
if has_backend:
|
|
38
|
+
infra_deps.append('provision-db-' + resource_name)
|
|
39
|
+
if should_enable(PlatformDockerConstants.VERDACCIO_RESOURCE_NAME):
|
|
40
|
+
project_root = ctx.get('project_root', '')
|
|
41
|
+
verdaccio_compose = ((project_root.rstrip('/') + '/') if project_root else '') + 'docker-compose.verdaccio.yml'
|
|
42
|
+
if str(local("test -f '" + verdaccio_compose + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes':
|
|
43
|
+
infra_deps.append(PlatformDockerConstants.VERDACCIO_RESOURCE_NAME)
|
|
44
|
+
if should_enable('golden-image') and ctx.get('golden_image_resource'):
|
|
45
|
+
infra_deps.append(ctx['golden_image_resource'])
|
|
46
|
+
return infra_deps
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _resolve_dependency_to_resource(dep_name, all_services_map):
|
|
50
|
+
"""
|
|
51
|
+
Resolve a short dependency name (e.g., 'identity') to the full YAML resource name.
|
|
52
|
+
|
|
53
|
+
The discovery registry creates YAML resources with names like:
|
|
54
|
+
- 'identity-management-backend-yaml' for identity backend
|
|
55
|
+
- 'api-gateway-yaml' for api-gateway
|
|
56
|
+
|
|
57
|
+
But manifests reference them as short names like 'identity' or 'api-gateway'.
|
|
58
|
+
"""
|
|
59
|
+
# Check if already a full YAML resource name
|
|
60
|
+
if dep_name in all_services_map:
|
|
61
|
+
return dep_name
|
|
62
|
+
|
|
63
|
+
# Try with -yaml suffix (for resources already resolved)
|
|
64
|
+
yaml_name = dep_name + '-yaml'
|
|
65
|
+
if yaml_name in all_services_map:
|
|
66
|
+
return yaml_name
|
|
67
|
+
|
|
68
|
+
# Try to find matching service by stack/short name
|
|
69
|
+
for resource_name, resource_info in all_services_map.items():
|
|
70
|
+
# Check if this service's stack matches the dependency
|
|
71
|
+
resource_domain = resource_info.get('stack', '')
|
|
72
|
+
if resource_domain == dep_name:
|
|
73
|
+
# Return the first resource of this service with -yaml suffix
|
|
74
|
+
resources = resource_info.get('resources', [])
|
|
75
|
+
if resources:
|
|
76
|
+
# Prefer backend resources over frontends
|
|
77
|
+
for res in resources:
|
|
78
|
+
if not res.get('frontend', False):
|
|
79
|
+
return res['name'] + '-yaml'
|
|
80
|
+
# Fallback to first resource
|
|
81
|
+
return resources[0]['name'] + '-yaml'
|
|
82
|
+
|
|
83
|
+
# Try pattern matching: identity -> identity-*-yaml
|
|
84
|
+
for resource_name in all_services_map.keys():
|
|
85
|
+
if resource_name.startswith(dep_name + '-') and resource_name.endswith('-yaml'):
|
|
86
|
+
return resource_name
|
|
87
|
+
|
|
88
|
+
# Return original with -yaml suffix as last resort
|
|
89
|
+
return dep_name + '-yaml'
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _build_resource_deps(res, res_name, manifest, resource_config, infra_deps, config_gen_resources, resource_manifests, runtime_flags, all_services_map=None):
|
|
93
|
+
res_deps = list(infra_deps)
|
|
94
|
+
if res_name in config_gen_resources:
|
|
95
|
+
res_deps.append(config_gen_resources[res_name])
|
|
96
|
+
if res.get('frontend', False):
|
|
97
|
+
backend_name = manifest.get('backendName', res_name.replace('frontend', 'backend'))
|
|
98
|
+
if backend_name != res_name and backend_name in resource_manifests:
|
|
99
|
+
res_deps.append(backend_name)
|
|
100
|
+
elif runtime_flags['enforce_migrator_deps'] and resource_config.get('has_migrator', False):
|
|
101
|
+
migrator_name = resource_config['name'] + '-db-migrator'
|
|
102
|
+
if migrator_name not in res_deps:
|
|
103
|
+
res_deps.append(migrator_name)
|
|
104
|
+
|
|
105
|
+
# NEW: Resolve dependsOn from manifest
|
|
106
|
+
internal_deps = manifest.get('dependsOn', [])
|
|
107
|
+
for dep in internal_deps:
|
|
108
|
+
resolved_dep = _resolve_dependency_to_resource(dep, all_services_map)
|
|
109
|
+
if resolved_dep and resolved_dep not in res_deps:
|
|
110
|
+
res_deps.append(resolved_dep)
|
|
111
|
+
|
|
112
|
+
return res_deps
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _register_replicas(config, auto_init_apps):
|
|
116
|
+
"""Register additional replica resources for high-availability services."""
|
|
117
|
+
replicas = config.get('replicas', 1)
|
|
118
|
+
if replicas <= 1:
|
|
119
|
+
return
|
|
120
|
+
# Docker compose generates replicas starting from 1 (e.g., service-1, service-2)
|
|
121
|
+
# Primary is the base name (service), replicas are service-1, service-2, etc.
|
|
122
|
+
for i in range(1, replicas):
|
|
123
|
+
replica_name = config['res_name'] + '-' + str(i)
|
|
124
|
+
dc_resource(
|
|
125
|
+
replica_name,
|
|
126
|
+
labels=config['labels'],
|
|
127
|
+
resource_deps=config['res_deps'],
|
|
128
|
+
auto_init=auto_init_apps,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _build_live_update_rules(res_path, full_res_path, syncs):
|
|
133
|
+
"""Build live update sync and run rules for a resource."""
|
|
134
|
+
live_update_rules = []
|
|
135
|
+
for sync_path in syncs:
|
|
136
|
+
full_sync_path = full_res_path + '/' + sync_path
|
|
137
|
+
dest = '/app/' + full_res_path + '/' + sync_path
|
|
138
|
+
live_update_rules.append(sync(full_sync_path, dest))
|
|
139
|
+
|
|
140
|
+
package_json_path = '/app/' + full_res_path + '/package.json'
|
|
141
|
+
bun_lock_path = '/app/' + full_res_path + '/bun.lock'
|
|
142
|
+
live_update_rules.append(run('cd /app/' + full_res_path + ' && bun install',
|
|
143
|
+
trigger=[package_json_path, bun_lock_path]))
|
|
144
|
+
return live_update_rules
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _register_docker_build(config, live_update_rules):
|
|
148
|
+
"""Register docker_build with live_update for hot-reload support."""
|
|
149
|
+
image_name = config['resource_name'] + '_' + config['res_name'] + ':dev'
|
|
150
|
+
project_root = config.get('project_root', '')
|
|
151
|
+
# Use custom dockerfile from config if specified, otherwise use autogenerated default
|
|
152
|
+
# The res_path is relative to project_root (e.g., 'services/product/...')
|
|
153
|
+
# The dockerfile config is relative to res_path (e.g., '.autogenerated/Dockerfile...')
|
|
154
|
+
rel_dockerfile = config.get('dockerfile', '')
|
|
155
|
+
if rel_dockerfile:
|
|
156
|
+
if rel_dockerfile.startswith('/'):
|
|
157
|
+
dockerfile = config['res_path'] + rel_dockerfile
|
|
158
|
+
else:
|
|
159
|
+
dockerfile = config['res_path'] + '/' + rel_dockerfile
|
|
160
|
+
else:
|
|
161
|
+
dockerfile = config['res_path'] + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/Dockerfile.app.autogenerated'
|
|
162
|
+
# Prepend project_root to make absolute path from the Tilt working directory
|
|
163
|
+
if project_root:
|
|
164
|
+
if dockerfile.startswith('/'):
|
|
165
|
+
dockerfile = project_root + dockerfile
|
|
166
|
+
else:
|
|
167
|
+
dockerfile = project_root + '/' + dockerfile
|
|
168
|
+
TypescriptBuilders.build_typescript_service(
|
|
169
|
+
image_name,
|
|
170
|
+
project_root or '.',
|
|
171
|
+
dockerfile,
|
|
172
|
+
live_update_rules,
|
|
173
|
+
config['res_deps'],
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _register_run_only_resource(config, resource_path, compose_project_name, auto_init_apps=True):
|
|
178
|
+
"""Register a run-only local resource for docker compose up."""
|
|
179
|
+
project_root = config.get('project_root', '')
|
|
180
|
+
compose_dir = resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER
|
|
181
|
+
compose_file = compose_dir + '/docker-compose.app.autogenerated.yml'
|
|
182
|
+
port_override = compose_dir + '/docker-compose.port-override.yml'
|
|
183
|
+
env_file = '.env'
|
|
184
|
+
if project_root:
|
|
185
|
+
root = project_root.rstrip('/')
|
|
186
|
+
compose_file = root + '/' + compose_file
|
|
187
|
+
port_override = root + '/' + port_override
|
|
188
|
+
env_file = root + '/.env'
|
|
189
|
+
compose_files = '-f ' + compose_file
|
|
190
|
+
if str(local("test -f '" + port_override + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes':
|
|
191
|
+
compose_files = compose_files + ' -f ' + port_override
|
|
192
|
+
# .env is gitignored (no .env.example shipped) across every TDK example repo, so a
|
|
193
|
+
# fresh clone must not hard-require it: only pass --env-file when it actually exists.
|
|
194
|
+
env_file_flag = ''
|
|
195
|
+
if str(local("test -f '" + env_file + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes':
|
|
196
|
+
env_file_flag = ' --env-file ' + env_file
|
|
197
|
+
local_resource(
|
|
198
|
+
name=config['res_name'] + '-run-only',
|
|
199
|
+
cmd='docker compose -p '
|
|
200
|
+
+ compose_project_name
|
|
201
|
+
+ ' '
|
|
202
|
+
+ compose_files
|
|
203
|
+
+ env_file_flag
|
|
204
|
+
+ ' up -d --no-build '
|
|
205
|
+
+ config['res_name'],
|
|
206
|
+
labels=config['labels'] + ['run-only'],
|
|
207
|
+
resource_deps=config['res_deps'],
|
|
208
|
+
auto_init=auto_init_apps,
|
|
209
|
+
allow_parallel=True,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _register_single_resource(config, resource_path, compose_project_name, auto_init_apps):
|
|
214
|
+
"""Register a single dc_resource with optional docker_build and run-only resource."""
|
|
215
|
+
app_type = config.get('app_type', 'backend')
|
|
216
|
+
res_name = config['res_name']
|
|
217
|
+
|
|
218
|
+
print("DEBUG REGISTER: Registering '{}' app_type='{}' auto_init={}".format(res_name, app_type, auto_init_apps))
|
|
219
|
+
|
|
220
|
+
# Skip docker_build for libraries and SDKs - they don't have Dockerfiles
|
|
221
|
+
if app_type not in ['library', 'sdk'] and config.get('syncs'):
|
|
222
|
+
print("DEBUG REGISTER: '{}' has syncs, calling docker_build".format(res_name))
|
|
223
|
+
live_update_rules = _build_live_update_rules(
|
|
224
|
+
config['res_path'],
|
|
225
|
+
config['res_path'],
|
|
226
|
+
config['syncs']
|
|
227
|
+
)
|
|
228
|
+
_register_docker_build(config, live_update_rules)
|
|
229
|
+
else:
|
|
230
|
+
print("DEBUG REGISTER: '{}' skipping docker_build (app_type='{}', syncs={})".format(res_name, app_type, config.get('syncs')))
|
|
231
|
+
|
|
232
|
+
print("DEBUG REGISTER: Calling dc_resource for '{}' with deps={}".format(res_name, config['res_deps']))
|
|
233
|
+
dc_resource(
|
|
234
|
+
config['res_name'],
|
|
235
|
+
labels=config['labels'],
|
|
236
|
+
resource_deps=config['res_deps'],
|
|
237
|
+
auto_init=auto_init_apps,
|
|
238
|
+
)
|
|
239
|
+
print("DEBUG REGISTER: dc_resource completed for '{}'".format(res_name))
|
|
240
|
+
|
|
241
|
+
_register_run_only_resource(config, resource_path, compose_project_name, auto_init_apps)
|
|
242
|
+
_register_replicas(config, auto_init_apps)
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _register_dc_resources(resource_configs, resource_path, compose_project_name, auto_init_apps):
|
|
246
|
+
"""Register all dc_resources for the service."""
|
|
247
|
+
for config in resource_configs:
|
|
248
|
+
_register_single_resource(config, resource_path, compose_project_name, auto_init_apps)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _has_backend_resource(resource_config, resource_manifests):
|
|
252
|
+
"""Check if service has a backend resource."""
|
|
253
|
+
for resource in resource_config.get('resources', []):
|
|
254
|
+
manifest = resource_manifests.get(resource['name'], {})
|
|
255
|
+
if manifest.get('appType') == 'backend':
|
|
256
|
+
return True
|
|
257
|
+
return False
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _should_skip_frontend(res, should_enable):
|
|
261
|
+
"""Check if frontend resource should be skipped (backends-only mode)."""
|
|
262
|
+
return res.get('frontend', False) and should_enable('backends-only')
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _process_frontend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable):
|
|
266
|
+
"""Process a frontend resource and return compose entry."""
|
|
267
|
+
target_path = res.get('target_path', manifest.get('target_path', '/usr/share/nginx/html'))
|
|
268
|
+
use_nginx = 'nginx' in target_path or target_path == '/usr/share/nginx/html'
|
|
269
|
+
port = res.get('port', manifest.get('port', BASE_PORT_FRONTEND))
|
|
270
|
+
Docker.frontend(
|
|
271
|
+
res_path=full_res_path,
|
|
272
|
+
resource_name=res['name'],
|
|
273
|
+
port=port,
|
|
274
|
+
target_path=target_path,
|
|
275
|
+
use_nginx=use_nginx,
|
|
276
|
+
use_golden=should_enable('golden-image'),
|
|
277
|
+
)
|
|
278
|
+
return Docker.frontend_compose(resource_path=resource_path, resource_name=resource_name, res=res, manifest=manifest)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _process_backend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable):
|
|
282
|
+
"""Process a backend resource and return compose entry."""
|
|
283
|
+
Docker.backend(
|
|
284
|
+
res_path=full_res_path,
|
|
285
|
+
resource_name=res['name'],
|
|
286
|
+
port=None, # Use default BASE_PORT_BACKEND
|
|
287
|
+
build_cmd=res.get('start_command', 'bun run build'),
|
|
288
|
+
use_golden=should_enable('golden-image'),
|
|
289
|
+
)
|
|
290
|
+
return Docker.backend_compose(resource_path=resource_path, resource_name=resource_name, res=res, manifest=manifest)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _build_resource_config(res, manifest, resource_config, full_res_path, infra_deps,
|
|
294
|
+
config_gen_resources, resource_manifests, runtime_flags, all_services_map=None, project_root=''):
|
|
295
|
+
"""Build configuration dict for a single resource."""
|
|
296
|
+
res_name = res['name']
|
|
297
|
+
res_deps = _build_resource_deps(
|
|
298
|
+
res, res_name, manifest, resource_config, infra_deps,
|
|
299
|
+
config_gen_resources, resource_manifests, runtime_flags, all_services_map,
|
|
300
|
+
)
|
|
301
|
+
replicas = manifest.get('replicas', 1)
|
|
302
|
+
if runtime_flags['disable_app_replicas']:
|
|
303
|
+
replicas = 1
|
|
304
|
+
|
|
305
|
+
# Extract environment variables from manifest params
|
|
306
|
+
env_vars = manifest.get('params', {})
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
'res_name': res_name,
|
|
310
|
+
'resource_name': resource_config['name'],
|
|
311
|
+
'res_deps': res_deps,
|
|
312
|
+
'labels': ['app.' + res_name],
|
|
313
|
+
'replicas': replicas,
|
|
314
|
+
'syncs': res.get('syncs', []),
|
|
315
|
+
'app_type': manifest.get('appType', 'backend'),
|
|
316
|
+
'dockerfile': res.get('dockerfile', OUTPUT.AUTOGENERATED_FOLDER + '/Dockerfile.app.autogenerated'),
|
|
317
|
+
'res_path': full_res_path,
|
|
318
|
+
'env': env_vars,
|
|
319
|
+
'project_root': project_root,
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def register_compose_resources(resource_config, ctx, runtime_flags, manifest_state):
|
|
324
|
+
"""Register all compose resources for a service."""
|
|
325
|
+
resource_name = resource_config.get('name', '')
|
|
326
|
+
resource_path = resource_config.get('path', '')
|
|
327
|
+
|
|
328
|
+
print("DEBUG COMPOSE: register_compose_resources called for '{}' path='{}'".format(resource_name, resource_path))
|
|
329
|
+
|
|
330
|
+
if not resource_name:
|
|
331
|
+
print("⚠️ Skipping service without name")
|
|
332
|
+
return {'compose_project_name': ''}
|
|
333
|
+
|
|
334
|
+
if not resource_path:
|
|
335
|
+
# Silently skip services without paths - these may be library references
|
|
336
|
+
# or incomplete manifests
|
|
337
|
+
print("DEBUG COMPOSE: SKIPPING '{}' - no path".format(resource_name))
|
|
338
|
+
return {'compose_project_name': ''}
|
|
339
|
+
|
|
340
|
+
print("DEBUG COMPOSE: Proceeding with '{}' - creating compose resources".format(resource_name))
|
|
341
|
+
should_enable = ctx['should_enable']
|
|
342
|
+
write_file = ctx['write_file']
|
|
343
|
+
compose_project_name = resource_name + '-autogenerated'
|
|
344
|
+
|
|
345
|
+
resource_manifests = manifest_state['resource_manifests']
|
|
346
|
+
config_gen_resources = manifest_state['config_gen_resources']
|
|
347
|
+
has_backend = _has_backend_resource(resource_config, resource_manifests)
|
|
348
|
+
infra_deps = _build_infra_dependencies(resource_name, should_enable, ctx, has_backend)
|
|
349
|
+
|
|
350
|
+
# Build map of all services for dependency resolution
|
|
351
|
+
# This maps short names like 'identity' to full resource names
|
|
352
|
+
all_services_map = {}
|
|
353
|
+
all_services = ctx.get('all_services', [])
|
|
354
|
+
for svc in all_services:
|
|
355
|
+
svc_name = svc.get('name', '')
|
|
356
|
+
if svc_name:
|
|
357
|
+
all_services_map[svc_name] = svc
|
|
358
|
+
# Also map resource names
|
|
359
|
+
for res in svc.get('resources', []):
|
|
360
|
+
res_name = res.get('name', '')
|
|
361
|
+
if res_name:
|
|
362
|
+
all_services_map[res_name] = svc
|
|
363
|
+
|
|
364
|
+
resource_entries = []
|
|
365
|
+
resource_configs = []
|
|
366
|
+
|
|
367
|
+
for res in resource_config.get('resources', []):
|
|
368
|
+
if _should_skip_frontend(res, should_enable):
|
|
369
|
+
continue
|
|
370
|
+
|
|
371
|
+
full_res_path = res.get('_resource_path', resource_path + '/' + res['name'])
|
|
372
|
+
manifest = resource_manifests.get(res['name'], {})
|
|
373
|
+
|
|
374
|
+
# Skip library/sdk type resources - they don't have Docker builds
|
|
375
|
+
app_type = manifest.get('appType', 'backend')
|
|
376
|
+
if app_type in ['library', 'sdk']:
|
|
377
|
+
continue
|
|
378
|
+
|
|
379
|
+
if res.get('frontend', False):
|
|
380
|
+
entry = _process_frontend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable)
|
|
381
|
+
else:
|
|
382
|
+
entry = _process_backend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable)
|
|
383
|
+
|
|
384
|
+
resource_entries.append(entry)
|
|
385
|
+
resource_configs.append(_build_resource_config(
|
|
386
|
+
res, manifest, resource_config, full_res_path, infra_deps,
|
|
387
|
+
config_gen_resources, resource_manifests, runtime_flags, all_services_map,
|
|
388
|
+
ctx.get('project_root', ''),
|
|
389
|
+
))
|
|
390
|
+
|
|
391
|
+
print("DEBUG COMPOSE: Calling Docker.app_compose for '{}' with write_fn={}".format(resource_name, write_file))
|
|
392
|
+
Docker.app_compose(resource_path, resource_entries, write_file)
|
|
393
|
+
|
|
394
|
+
print("DEBUG COMPOSE: {} resource_entries count = {}".format(resource_name, len(resource_entries)))
|
|
395
|
+
|
|
396
|
+
# Prepend project root to make path absolute from project root
|
|
397
|
+
project_root = ctx.get('project_root', '')
|
|
398
|
+
|
|
399
|
+
# Only register docker_compose if we have actual services (not just libraries)
|
|
400
|
+
if resource_entries:
|
|
401
|
+
compose_file_rel = resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/docker-compose.app.autogenerated.yml'
|
|
402
|
+
compose_file = project_root + '/' + compose_file_rel if project_root else compose_file_rel
|
|
403
|
+
# Load env file from project root for docker-compose variables (DB_PASSWORD, etc.)
|
|
404
|
+
env_file = project_root + '/.env' if project_root else '.env'
|
|
405
|
+
print("DEBUG COMPOSE: Calling docker_compose for '{}' with {} env_file={}".format(resource_name, compose_file, env_file))
|
|
406
|
+
_docker_compose_app(compose_file, compose_project_name, env_file)
|
|
407
|
+
port_override_rel = resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/docker-compose.port-override.yml'
|
|
408
|
+
port_override = project_root + '/' + port_override_rel if project_root else port_override_rel
|
|
409
|
+
if str(local("test -f '" + port_override + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes':
|
|
410
|
+
print("DEBUG COMPOSE: Applying port override {}".format(port_override))
|
|
411
|
+
_docker_compose_app(port_override, compose_project_name, env_file)
|
|
412
|
+
else:
|
|
413
|
+
print("DEBUG COMPOSE: SKIPPING docker_compose for '{}' - no resource_entries".format(resource_name))
|
|
414
|
+
|
|
415
|
+
for compose_file in resource_config.get('compose_files', []):
|
|
416
|
+
if compose_file != '.autogenerated/docker-compose.app.autogenerated.yml':
|
|
417
|
+
compose_file_full = project_root + '/' + resource_path + '/' + compose_file if project_root else resource_path + '/' + compose_file
|
|
418
|
+
env_file = project_root + '/.env' if project_root else '.env'
|
|
419
|
+
_docker_compose_app(compose_file_full, compose_project_name, env_file)
|
|
420
|
+
|
|
421
|
+
print("DEBUG COMPOSE: Calling _register_dc_resources for '{}' with {} configs, auto_init={}".format(resource_name, len(resource_configs), runtime_flags['auto_init_apps']))
|
|
422
|
+
_register_dc_resources(resource_configs, resource_path, compose_project_name, runtime_flags['auto_init_apps'])
|
|
423
|
+
|
|
424
|
+
return {'compose_project_name': compose_project_name}
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
ComposeResourceRegistration = struct(
|
|
428
|
+
register = register_compose_resources,
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
DEBUG = {}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# 📄 ORCHESTRATOR APPLY - MANIFEST ORCHESTRATION
|
|
3
|
+
# =============================================================================
|
|
4
|
+
|
|
5
|
+
# === INLINED CONSTANTS for pure extension loading ===
|
|
6
|
+
BASE_PORT_FRONTEND = 3000
|
|
7
|
+
BASE_PORT_BACKEND = 4000
|
|
8
|
+
# === END INLINED CONSTANTS ===
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
load('../../../../../discovery/loading.star', 'Manifest')
|
|
12
|
+
load('./generators/manifest_resource.star', 'ManifestResource')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def prepare_resource_manifests(resource_config, ctx):
|
|
17
|
+
resource_name = resource_config['name']
|
|
18
|
+
resource_manifests = {}
|
|
19
|
+
backend_manifest_cache = {}
|
|
20
|
+
config_gen_resources = {}
|
|
21
|
+
|
|
22
|
+
all_resources = resource_config.get('resources', [])
|
|
23
|
+
|
|
24
|
+
# First pass: load all manifests.
|
|
25
|
+
for resource in resource_config.get('resources', []):
|
|
26
|
+
# Use the resource's _resource_path if available (for services from different scan roots)
|
|
27
|
+
# Otherwise fall back to constructing path from resource_config path + resource name
|
|
28
|
+
resource_path = resource.get('_resource_path', resource_config['path'] + '/' + resource['name'])
|
|
29
|
+
|
|
30
|
+
# Load the manifest from the resource path
|
|
31
|
+
manifest = Manifest.load_manifest(resource_path)
|
|
32
|
+
resource_manifests[resource['name']] = manifest
|
|
33
|
+
|
|
34
|
+
app_name = manifest.get('appName', resource['name'])
|
|
35
|
+
stack = manifest.get('stack', resource_name)
|
|
36
|
+
port = manifest.get('port', BASE_PORT_FRONTEND)
|
|
37
|
+
app_type = manifest.get('appType', 'backend')
|
|
38
|
+
|
|
39
|
+
print(
|
|
40
|
+
" [Tilt] ✅ Loaded: " + app_name
|
|
41
|
+
+ " | Stack: " + stack
|
|
42
|
+
+ " | Port: " + str(port)
|
|
43
|
+
+ " | Type: " + app_type
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if manifest.get('appType') == 'backend':
|
|
47
|
+
backend_manifest_cache[manifest.get('appName')] = manifest
|
|
48
|
+
|
|
49
|
+
# Second pass: create config generation resources.
|
|
50
|
+
for resource in resource_config.get('resources', []):
|
|
51
|
+
manifest = resource_manifests.get(resource['name'], {})
|
|
52
|
+
backend_manifest = None
|
|
53
|
+
|
|
54
|
+
if resource.get('frontend', False) or manifest.get('appType') == 'frontend':
|
|
55
|
+
backend_name = manifest.get('backendName', resource['name'].replace('-frontend', '-backend'))
|
|
56
|
+
backend_manifest = backend_manifest_cache.get(backend_name)
|
|
57
|
+
if not backend_manifest:
|
|
58
|
+
backend_manifest = Manifest.load_related(manifest)
|
|
59
|
+
|
|
60
|
+
# Use the resource's actual service path for config generation
|
|
61
|
+
resource_path = resource.get('_resource_path', resource_config['path'] + '/' + resource['name'])
|
|
62
|
+
|
|
63
|
+
config_gen_resource = ManifestResource.create_config_resource(
|
|
64
|
+
resource_name,
|
|
65
|
+
resource,
|
|
66
|
+
resource_path, # Pass correct path instead of resource_config['path']
|
|
67
|
+
manifest,
|
|
68
|
+
backend_manifest,
|
|
69
|
+
ctx,
|
|
70
|
+
)
|
|
71
|
+
config_gen_resources[resource['name']] = config_gen_resource
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
'resource_manifests': resource_manifests,
|
|
75
|
+
'config_gen_resources': config_gen_resources,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
ManifestOrchestration = struct(
|
|
80
|
+
prepare = prepare_resource_manifests,
|
|
81
|
+
)
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# 🗃️ ORCHESTRATOR APPLY - MIGRATOR ORCHESTRATION
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# BLOCKER FIX #2: Sequential migration execution to prevent race conditions
|
|
5
|
+
# =============================================================================
|
|
6
|
+
|
|
7
|
+
# === INLINED CONSTANTS for pure extension loading ===
|
|
8
|
+
OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
|
|
9
|
+
# === END INLINED CONSTANTS ===
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
load('../../../platform/docker/index.star', 'Docker')
|
|
13
|
+
|
|
14
|
+
load('../../../platform/docker/generators/golden_docker_generator_v2.star', 'L4_generate_orchestrator')
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _find_backend_resource_path(resource_config):
|
|
18
|
+
resource_path = resource_config.get('path', '')
|
|
19
|
+
if not resource_path:
|
|
20
|
+
return None
|
|
21
|
+
backend_resource_path = None
|
|
22
|
+
|
|
23
|
+
for res in resource_config.get('resources', []):
|
|
24
|
+
if res.get('frontend', False):
|
|
25
|
+
continue
|
|
26
|
+
|
|
27
|
+
candidate = resource_path + '/' + res['name']
|
|
28
|
+
prisma_check = local("test -d " + candidate + "/prisma && echo yes || echo no", quiet=True)
|
|
29
|
+
prisma_check_stdout = getattr(prisma_check, "stdout", prisma_check)
|
|
30
|
+
has_prisma = str(prisma_check_stdout).strip() == 'yes'
|
|
31
|
+
|
|
32
|
+
if has_prisma:
|
|
33
|
+
return candidate
|
|
34
|
+
|
|
35
|
+
if backend_resource_path == None:
|
|
36
|
+
backend_resource_path = candidate
|
|
37
|
+
|
|
38
|
+
return backend_resource_path
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def register_migrators(resource_config, ctx, runtime_flags, compose_project_name):
|
|
42
|
+
should_enable = ctx['should_enable']
|
|
43
|
+
write_file = ctx['write_file']
|
|
44
|
+
resource_name = resource_config.get('name', '')
|
|
45
|
+
resource_path = resource_config.get('path', '')
|
|
46
|
+
|
|
47
|
+
if not resource_name:
|
|
48
|
+
print("⚠️ Skipping migrator registration for service without name")
|
|
49
|
+
return
|
|
50
|
+
|
|
51
|
+
if not resource_path:
|
|
52
|
+
# Silently skip migrator registration for services without paths
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
if not resource_config.get('has_migrator', False):
|
|
56
|
+
return
|
|
57
|
+
if not should_enable('database-management'):
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
backend_resource_path = _find_backend_resource_path(resource_config)
|
|
61
|
+
dockerfile_res_path = backend_resource_path if backend_resource_path else resource_path
|
|
62
|
+
|
|
63
|
+
df_contents = L4_generate_orchestrator(
|
|
64
|
+
dockerfile_res_path,
|
|
65
|
+
res_type='migrator',
|
|
66
|
+
resource_name=resource_name,
|
|
67
|
+
use_nginx=False,
|
|
68
|
+
port=3000,
|
|
69
|
+
target_path='/app/dist',
|
|
70
|
+
build_cmd='echo "No build needed for migrator"',
|
|
71
|
+
cmd='bun run db:migrate',
|
|
72
|
+
use_infisical=True,
|
|
73
|
+
use_shared_libs=True,
|
|
74
|
+
use_prisma=True,
|
|
75
|
+
use_golden=should_enable('golden-image'),
|
|
76
|
+
)
|
|
77
|
+
write_file(dockerfile_res_path + "/" + OUTPUT.AUTOGENERATED_FOLDER + "/Dockerfile.migrator.autogenerated", df_contents)
|
|
78
|
+
|
|
79
|
+
migrator_dockerignore_content = Docker.generate_dockerignore(dockerfile_res_path, 'migrator')
|
|
80
|
+
write_file(
|
|
81
|
+
dockerfile_res_path + "/" + OUTPUT.AUTOGENERATED_FOLDER + "/Dockerfile.migrator.autogenerated.dockerignore",
|
|
82
|
+
migrator_dockerignore_content,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
Docker.migrator_compose(
|
|
86
|
+
resource_path=resource_path,
|
|
87
|
+
resource_name=resource_name,
|
|
88
|
+
dockerfile_path=dockerfile_res_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/Dockerfile.migrator.autogenerated',
|
|
89
|
+
write_fn=write_file,
|
|
90
|
+
)
|
|
91
|
+
docker_compose(
|
|
92
|
+
resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/docker-compose.migrator.autogenerated.yml',
|
|
93
|
+
project_name=compose_project_name,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
migrator_names = resource_config.get('migrator_names', [resource_name + '-db-migrator'])
|
|
97
|
+
for migrator_name in migrator_names:
|
|
98
|
+
# =============================================================================
|
|
99
|
+
# BLOCKER FIX #2: Sequential migration dependencies prevent race conditions
|
|
100
|
+
# =============================================================================
|
|
101
|
+
# Each migrator depends on postgres, its own provisioned DB, golden image,
|
|
102
|
+
# AND the previous migrator to ensure sequential execution
|
|
103
|
+
migrator_db_deps = ['postgres', 'provision-db-' + resource_name]
|
|
104
|
+
if should_enable('golden-image') and ctx.get('golden_image_resource'):
|
|
105
|
+
migrator_db_deps.append(ctx['golden_image_resource'])
|
|
106
|
+
|
|
107
|
+
# Add sequential dependency on previous migrator to prevent parallel execution
|
|
108
|
+
# Use ctx to track sequence (mutable dict passed from caller)
|
|
109
|
+
migrator_index = ctx.setdefault('migrator_sequence', {})
|
|
110
|
+
previous_migrator = _get_previous_migrator(resource_name, migrator_index)
|
|
111
|
+
if previous_migrator:
|
|
112
|
+
migrator_db_deps.append(previous_migrator)
|
|
113
|
+
print("🔗 Sequential migration: " + migrator_name + " will run after " + previous_migrator)
|
|
114
|
+
|
|
115
|
+
dc_resource(
|
|
116
|
+
migrator_name,
|
|
117
|
+
labels=['app.' + resource_name, 'migrator'],
|
|
118
|
+
resource_deps=migrator_db_deps,
|
|
119
|
+
auto_init=runtime_flags['auto_init_migrators'],
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# =============================================================================
|
|
124
|
+
# BLOCKER FIX #2: Migration sequencing tracker
|
|
125
|
+
# =============================================================================
|
|
126
|
+
# Pass migrator sequence via ctx to avoid frozen module-level state
|
|
127
|
+
# The caller initializes ctx['migrator_sequence'] = {} before calling register_migrators
|
|
128
|
+
|
|
129
|
+
def _get_previous_migrator(current_service, migrator_index):
|
|
130
|
+
"""
|
|
131
|
+
Get the previous migrator in sequence for dependency chaining.
|
|
132
|
+
Returns the migrator name that should complete before this one starts.
|
|
133
|
+
"""
|
|
134
|
+
if current_service not in migrator_index:
|
|
135
|
+
migrator_index[current_service] = len(migrator_index)
|
|
136
|
+
|
|
137
|
+
idx = migrator_index[current_service]
|
|
138
|
+
if idx > 0:
|
|
139
|
+
# Find the service with index idx - 1
|
|
140
|
+
for svc, svc_idx in migrator_index.items():
|
|
141
|
+
if svc_idx == idx - 1:
|
|
142
|
+
return svc + '-db-migrator'
|
|
143
|
+
return None
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
MigratorOrchestration = struct(
|
|
147
|
+
register = register_migrators,
|
|
148
|
+
)
|