@tdk-landscape/tdk-cli-core 1.3.15 → 1.3.26
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
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# 📋 TILT SDK - MANIFEST LOADING (CEO Review: rename-service-manifest)
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Path: .tilt/topologies/tilt/discovery/manifest/loading.star
|
|
5
|
+
# Purpose: Load, synthesize, and apply defaults to manifests
|
|
6
|
+
#
|
|
7
|
+
# Manifest loading with synthesis-by-default
|
|
8
|
+
# Priority: service.json → synthesize from path
|
|
9
|
+
# =============================================================================
|
|
10
|
+
|
|
11
|
+
load('../../engine/topologies/tilt/manifest/constants.star',
|
|
12
|
+
'MANIFEST_DEFAULTS',
|
|
13
|
+
'DEFAULT_SYNCS',
|
|
14
|
+
'MANIFEST_FILENAME',
|
|
15
|
+
'BASE_PORT_FRONTEND',
|
|
16
|
+
'BASE_PORT_BACKEND',
|
|
17
|
+
'HEALTH_CHECK_PATH')
|
|
18
|
+
load('../../engine/topologies/tilt/common/utils.star', 'Utils')
|
|
19
|
+
load('../../engine/topologies/platform/docker/constants.star', 'PlatformDockerConstants')
|
|
20
|
+
|
|
21
|
+
def _check_prisma_folder(resource_path):
|
|
22
|
+
"""
|
|
23
|
+
Check if prisma/ directory exists in resource path (silent).
|
|
24
|
+
Used to auto-detect has_migrator when not in features.
|
|
25
|
+
"""
|
|
26
|
+
check_cmd = "test -d '{path}/prisma' && echo 'yes' || echo 'no'".format(path=resource_path)
|
|
27
|
+
result = str(local(check_cmd, quiet=True, echo_off=True)).strip()
|
|
28
|
+
return result == 'yes'
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def check_prisma_folder(resource_path):
|
|
32
|
+
return _check_prisma_folder(resource_path)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_default_syncs_for_type(app_type, features=None):
|
|
36
|
+
"""
|
|
37
|
+
Returns default sync paths based on app type and features.
|
|
38
|
+
"""
|
|
39
|
+
if features == None:
|
|
40
|
+
features = []
|
|
41
|
+
|
|
42
|
+
syncs = list(DEFAULT_SYNCS.get(app_type, ['src', 'package.json']))
|
|
43
|
+
|
|
44
|
+
# Add prisma to syncs if using prisma feature
|
|
45
|
+
if app_type == 'backend' and 'prisma' in features and 'prisma' not in syncs:
|
|
46
|
+
syncs.append('prisma')
|
|
47
|
+
|
|
48
|
+
return syncs
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _extract_stack_from_path(resource_path, app_name):
|
|
52
|
+
"""
|
|
53
|
+
Extract stack from resource path or app name.
|
|
54
|
+
|
|
55
|
+
Convention: services/product/{stack}/{resource-name}
|
|
56
|
+
Fallback: First segment of app_name before hyphen
|
|
57
|
+
|
|
58
|
+
Special handling: profile -> identity
|
|
59
|
+
"""
|
|
60
|
+
parts = resource_path.rstrip('/').split('/')
|
|
61
|
+
if len(parts) >= 4 and parts[-4] == 'services' and parts[-3] == 'product':
|
|
62
|
+
stack = parts[-2]
|
|
63
|
+
# Normalize profile to identity
|
|
64
|
+
if stack == 'profile':
|
|
65
|
+
return 'identity'
|
|
66
|
+
return stack
|
|
67
|
+
else:
|
|
68
|
+
return app_name.split('-')[0] if '-' in app_name else app_name
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def load_manifest(resource_path, persist_to_disk=False):
|
|
72
|
+
"""
|
|
73
|
+
Load manifest with synthesis-by-default.
|
|
74
|
+
|
|
75
|
+
Priority order:
|
|
76
|
+
1. service.json (manifest file)
|
|
77
|
+
2. Synthesize from directory structure (synthesis-by-default for standard resources)
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
resource_path: Path to resource directory
|
|
81
|
+
persist_to_disk: If True, sync _internalDeps back to the physical manifest file
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
Validated manifest dict with all defaults applied
|
|
85
|
+
"""
|
|
86
|
+
manifest = None
|
|
87
|
+
manifest_source = None
|
|
88
|
+
manifest_path = None
|
|
89
|
+
|
|
90
|
+
# Prepend project root to relative paths for correct resolution
|
|
91
|
+
project_root = os.environ.get('TDK_PROJECT_ROOT', '')
|
|
92
|
+
if project_root and not resource_path.startswith('/'):
|
|
93
|
+
base_path = project_root + '/' + resource_path
|
|
94
|
+
else:
|
|
95
|
+
base_path = resource_path
|
|
96
|
+
|
|
97
|
+
# Try to load manifest file
|
|
98
|
+
manifest_full_path = base_path + '/' + MANIFEST_FILENAME
|
|
99
|
+
content = read_file(manifest_full_path, default='')
|
|
100
|
+
|
|
101
|
+
if content and str(content).strip():
|
|
102
|
+
manifest = decode_json(content)
|
|
103
|
+
manifest_source = 'service.json'
|
|
104
|
+
manifest_path = manifest_full_path
|
|
105
|
+
else:
|
|
106
|
+
# Synthesize from directory structure if no manifest found
|
|
107
|
+
manifest = synthesize_manifest_from_path(resource_path)
|
|
108
|
+
manifest_source = 'synthesized'
|
|
109
|
+
manifest_path = resource_path # Virtual path
|
|
110
|
+
|
|
111
|
+
# Validate JSON parsed correctly
|
|
112
|
+
if manifest == None and manifest_source != 'synthesized':
|
|
113
|
+
fail("""
|
|
114
|
+
❌ ═══════════════════════════════════════════════════════════════════
|
|
115
|
+
❌ INVALID JSON IN MANIFEST FILE
|
|
116
|
+
❌ ═══════════════════════════════════════════════════════════════════
|
|
117
|
+
📁 File: {path}
|
|
118
|
+
Source: {source}
|
|
119
|
+
|
|
120
|
+
Common issues:
|
|
121
|
+
• Missing closing quote: "appName": "my-app
|
|
122
|
+
• Trailing comma: "port": 4000,}}
|
|
123
|
+
• Missing comma between properties
|
|
124
|
+
• Single quotes instead of double quotes
|
|
125
|
+
|
|
126
|
+
Fix the JSON syntax and run 'tilt up' again.
|
|
127
|
+
❌ ═══════════════════════════════════════════════════════════════════
|
|
128
|
+
""".format(path=manifest_path, source=manifest_source))
|
|
129
|
+
|
|
130
|
+
# Track manifest source for debugging
|
|
131
|
+
manifest['_manifestSource'] = manifest_source
|
|
132
|
+
manifest['_manifestPath'] = manifest_path
|
|
133
|
+
|
|
134
|
+
# Apply defaults and compute derived values
|
|
135
|
+
validated = apply_manifest_defaults(manifest, resource_path)
|
|
136
|
+
|
|
137
|
+
return validated
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def synthesize_manifest_from_path(resource_path):
|
|
141
|
+
return _synthesize_manifest_from_path(resource_path)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def apply_manifest_defaults(manifest, resource_path):
|
|
145
|
+
return _apply_manifest_defaults(manifest, resource_path)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _synthesize_manifest_from_path(resource_path):
|
|
149
|
+
"""
|
|
150
|
+
Create a manifest based on directory naming conventions.
|
|
151
|
+
Used when manifest.json doesn't exist (backward compatibility).
|
|
152
|
+
|
|
153
|
+
Convention: services/product/{stack}/{stack}-{component}-{type}
|
|
154
|
+
Example: services/product/{stack}/{app-name}-{type}
|
|
155
|
+
-> appName: {app-name}-{type}
|
|
156
|
+
-> appType: {type}
|
|
157
|
+
-> stack: {stack}
|
|
158
|
+
"""
|
|
159
|
+
parts = resource_path.rstrip('/').split('/')
|
|
160
|
+
dir_name = parts[-1] if parts else 'unknown-service'
|
|
161
|
+
|
|
162
|
+
# Determine appType from directory name suffix
|
|
163
|
+
app_type = 'backend'
|
|
164
|
+
if dir_name.endswith('-frontend'):
|
|
165
|
+
app_type = 'frontend'
|
|
166
|
+
elif dir_name.endswith('-backend'):
|
|
167
|
+
app_type = 'backend'
|
|
168
|
+
elif dir_name.endswith('-migrator'):
|
|
169
|
+
app_type = 'migrator'
|
|
170
|
+
elif dir_name.endswith('-sdk'):
|
|
171
|
+
app_type = 'sdk'
|
|
172
|
+
elif dir_name.endswith('-infra') or dir_name.endswith('-ui'):
|
|
173
|
+
app_type = 'library'
|
|
174
|
+
elif 'lib-' in dir_name or 'platform-' in dir_name:
|
|
175
|
+
app_type = 'library'
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
'appName': dir_name,
|
|
179
|
+
'appType': app_type,
|
|
180
|
+
'_synthesized': True,
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _apply_manifest_defaults(manifest, resource_path):
|
|
185
|
+
"""
|
|
186
|
+
🎯 SMART DEFAULTS: Expand slim manifest to full config.
|
|
187
|
+
|
|
188
|
+
CEO Review updates (rename-service-manifest):
|
|
189
|
+
- Port is constant per appType (3000 frontend, 4000 backend) — Traefik handles routing
|
|
190
|
+
- Custom dockerfile support via manifest["dockerfile"] field
|
|
191
|
+
- Developer manually provides features (no auto-detection per requirement)
|
|
192
|
+
|
|
193
|
+
Convention over Configuration:
|
|
194
|
+
- features: ["nats", "prisma"] -> usePrisma=True, useNats=True
|
|
195
|
+
- domain: "order" -> databaseName="TDK_order"
|
|
196
|
+
- domain: "order" -> traefik.host="order.backend.{project}.local"
|
|
197
|
+
- domain: "order" -> nats.queueGroup="order_backend_svc"
|
|
198
|
+
"""
|
|
199
|
+
result = dict(manifest)
|
|
200
|
+
|
|
201
|
+
# Normalize resource_path to be relative (strip leading / if present)
|
|
202
|
+
# Docker build context requires relative paths
|
|
203
|
+
if resource_path.startswith('/'):
|
|
204
|
+
resource_path = resource_path[1:]
|
|
205
|
+
|
|
206
|
+
# Track overrides for logging (task 4.8: override detection)
|
|
207
|
+
overrides = []
|
|
208
|
+
app_name = result.get('appName', '')
|
|
209
|
+
|
|
210
|
+
# Apply simple defaults
|
|
211
|
+
for key, default_value in MANIFEST_DEFAULTS.items():
|
|
212
|
+
if key not in result or result[key] == None:
|
|
213
|
+
result[key] = default_value
|
|
214
|
+
|
|
215
|
+
# 🎯 CEO REVIEW: Traefik-native port strategy
|
|
216
|
+
# Port is constant per appType, not dynamically assigned
|
|
217
|
+
# Traefik routes by hostname (e.g., booking.backend.{project}.local), not port
|
|
218
|
+
app_type = result.get('appType', 'backend')
|
|
219
|
+
|
|
220
|
+
# Set constant port per appType, but preserve explicit service.json ports.
|
|
221
|
+
computed_port = None
|
|
222
|
+
if app_type == 'frontend':
|
|
223
|
+
computed_port = BASE_PORT_FRONTEND
|
|
224
|
+
elif app_type == 'backend':
|
|
225
|
+
computed_port = BASE_PORT_BACKEND
|
|
226
|
+
elif app_type == 'migrator':
|
|
227
|
+
computed_port = 7000 # Migrator uses different range
|
|
228
|
+
|
|
229
|
+
if computed_port != None and ('port' not in manifest or manifest.get('port') == None):
|
|
230
|
+
result['port'] = computed_port
|
|
231
|
+
|
|
232
|
+
# 🎯 CEO REVIEW: Custom dockerfile support
|
|
233
|
+
# Validate custom dockerfile exists if specified
|
|
234
|
+
if 'dockerfile' in result:
|
|
235
|
+
custom_dockerfile = result['dockerfile']
|
|
236
|
+
dockerfile_path = resource_path + '/' + custom_dockerfile
|
|
237
|
+
# BUG FIX: Run check from project root since Tilt may run from .tdk/.tdk-out/
|
|
238
|
+
project_root = os.environ.get('TDK_PROJECT_ROOT', '')
|
|
239
|
+
if project_root:
|
|
240
|
+
dockerfile_exists = local("cd '{root}' && test -f '{path}' && echo 'yes' || echo 'no'".format(root=project_root, path=dockerfile_path), quiet=True, echo_off=True)
|
|
241
|
+
else:
|
|
242
|
+
dockerfile_exists = local("test -f '{path}' && echo 'yes' || echo 'no'".format(path=dockerfile_path), quiet=True, echo_off=True)
|
|
243
|
+
if str(dockerfile_exists).strip() != 'yes':
|
|
244
|
+
fail("""
|
|
245
|
+
❌ ═══════════════════════════════════════════════════════════════════
|
|
246
|
+
❌ CUSTOM DOCKERFILE NOT FOUND
|
|
247
|
+
❌ ═══════════════════════════════════════════════════════════════════
|
|
248
|
+
📁 Resource: {resource}
|
|
249
|
+
🐳 Dockerfile: {dockerfile}
|
|
250
|
+
|
|
251
|
+
Manifest specifies custom Dockerfile but it doesn't exist.
|
|
252
|
+
Either:
|
|
253
|
+
• Create {dockerfile} in resource directory
|
|
254
|
+
• Remove "dockerfile" field to use auto-generated Dockerfile
|
|
255
|
+
❌ ═══════════════════════════════════════════════════════════════════
|
|
256
|
+
""".format(resource=resource_path.split('/')[-1], dockerfile=custom_dockerfile))
|
|
257
|
+
|
|
258
|
+
# 🎯 FEATURE FLAGS -> BOOLEAN CONFIG
|
|
259
|
+
# NOTE: Developer manually provides features per CEO Review requirement
|
|
260
|
+
# No auto-detection from file existence (e.g., prisma/schema.prisma)
|
|
261
|
+
features = result.get('features', [])
|
|
262
|
+
result['usePrisma'] = 'prisma' in features
|
|
263
|
+
result['useNats'] = 'nats' in features
|
|
264
|
+
result['useTraefik'] = 'traefik' in features or app_type in ['backend', 'sdk']
|
|
265
|
+
|
|
266
|
+
# Extract stack from path if not set
|
|
267
|
+
if 'stack' not in result:
|
|
268
|
+
result['stack'] = _extract_stack_from_path(resource_path, app_name)
|
|
269
|
+
|
|
270
|
+
stack = result['stack']
|
|
271
|
+
|
|
272
|
+
# 🎯 SMART DATABASE NAME with override detection
|
|
273
|
+
computed_db_name = PlatformDockerConstants.get_db_name(stack)
|
|
274
|
+
if 'databaseName' not in result:
|
|
275
|
+
result['databaseName'] = computed_db_name
|
|
276
|
+
elif result['databaseName'] != computed_db_name:
|
|
277
|
+
overrides.append("databaseName: {} (auto: {})".format(result['databaseName'], computed_db_name))
|
|
278
|
+
|
|
279
|
+
# 🎯 SMART TRAEFIK CONFIG (Convention over Configuration)
|
|
280
|
+
# Apply to backends and SDKs that need Traefik routing
|
|
281
|
+
if result['useTraefik'] and app_type in ['backend', 'sdk']:
|
|
282
|
+
existing_traefik = result.get('traefik', {})
|
|
283
|
+
# Use apiPath from root level if available, otherwise use default pattern
|
|
284
|
+
root_api_path = result.get('apiPath')
|
|
285
|
+
default_path_prefix = root_api_path if root_api_path else '/api/' + stack
|
|
286
|
+
|
|
287
|
+
computed_traefik = {
|
|
288
|
+
'host': stack + '.backend.' + PlatformDockerConstants.PROJECT_NAME + '.local',
|
|
289
|
+
'pathPrefix': default_path_prefix,
|
|
290
|
+
'healthCheck': HEALTH_CHECK_PATH,
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
# Check for overrides
|
|
294
|
+
if existing_traefik.get('host') and existing_traefik.get('host') != computed_traefik['host']:
|
|
295
|
+
overrides.append("traefik.host: {} (auto: {})".format(existing_traefik['host'], computed_traefik['host']))
|
|
296
|
+
if existing_traefik.get('pathPrefix') and existing_traefik.get('pathPrefix') != computed_traefik['pathPrefix']:
|
|
297
|
+
overrides.append("traefik.pathPrefix: {} (auto: {})".format(existing_traefik['pathPrefix'], computed_traefik['pathPrefix']))
|
|
298
|
+
|
|
299
|
+
result['traefik'] = {
|
|
300
|
+
'host': existing_traefik.get('host', computed_traefik['host']),
|
|
301
|
+
'pathPrefix': existing_traefik.get('pathPrefix', computed_traefik['pathPrefix']),
|
|
302
|
+
'healthCheck': existing_traefik.get('healthCheck', computed_traefik['healthCheck']),
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
# 🎯 SMART NATS CONFIG
|
|
306
|
+
if result['useNats']:
|
|
307
|
+
existing_nats = result.get('nats', {})
|
|
308
|
+
result['nats'] = {
|
|
309
|
+
'queueGroup': existing_nats.get('queueGroup', stack + '_' + app_type + '_svc'),
|
|
310
|
+
'subjects': existing_nats.get('subjects', [stack + '.>']),
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
# Compute backend name for frontends with override detection
|
|
314
|
+
if app_type == 'frontend':
|
|
315
|
+
computed_backend = app_name.replace('-frontend', '-backend')
|
|
316
|
+
if 'backendName' not in result:
|
|
317
|
+
result['backendName'] = computed_backend
|
|
318
|
+
elif result['backendName'] != computed_backend:
|
|
319
|
+
overrides.append("backendName: {} (auto: {})".format(result['backendName'], computed_backend))
|
|
320
|
+
|
|
321
|
+
# 🎯 SMART BASEPATH for frontends (convention: /{stack}s)
|
|
322
|
+
computed_base_path = '/' + stack + 's'
|
|
323
|
+
if 'basePath' not in result:
|
|
324
|
+
result['basePath'] = computed_base_path
|
|
325
|
+
elif result['basePath'] != computed_base_path:
|
|
326
|
+
overrides.append("basePath: {} (auto: {})".format(result['basePath'], computed_base_path))
|
|
327
|
+
|
|
328
|
+
# 🎯 Always set _servicePath for all manifest types
|
|
329
|
+
result['_servicePath'] = resource_path
|
|
330
|
+
|
|
331
|
+
# 🎯 CENTRALIZED: Use Utils.get_internal_deps() for dependency extraction
|
|
332
|
+
internal_deps = Utils.get_internal_deps(resource_path)
|
|
333
|
+
result['_internalDeps'] = sorted(internal_deps)
|
|
334
|
+
|
|
335
|
+
# 🎯 CENTRALIZED: Use Utils.build_deps_mapping() for path resolution
|
|
336
|
+
result['_internalDepsMapping'] = Utils.build_deps_mapping(resource_path, internal_deps)
|
|
337
|
+
|
|
338
|
+
# 🎯 Log overrides if any were detected and verbose mode is enabled
|
|
339
|
+
if overrides and os.environ.get('TILT_LOG_LEVEL') == 'verbose':
|
|
340
|
+
print("📝 Override(s) detected for {}: {}".format(app_name, ', '.join(overrides)))
|
|
341
|
+
|
|
342
|
+
return result
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def load_related_manifest(frontend_manifest, backend_suffix='-backend'):
|
|
346
|
+
"""
|
|
347
|
+
Load the related backend manifest for a frontend resource.
|
|
348
|
+
|
|
349
|
+
CEO Review update: Supports dual-filename and synthesis-by-default.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
frontend_manifest: The loaded frontend manifest
|
|
353
|
+
backend_suffix: Suffix to replace '-frontend' with
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
Backend manifest dictionary, or None if not found
|
|
357
|
+
"""
|
|
358
|
+
if frontend_manifest.get('appType') != 'frontend':
|
|
359
|
+
return None
|
|
360
|
+
|
|
361
|
+
resource_path = frontend_manifest.get('_servicePath', '')
|
|
362
|
+
backend_path = resource_path.replace('-frontend', backend_suffix)
|
|
363
|
+
|
|
364
|
+
# Use load_manifest which handles dual-filename and synthesis
|
|
365
|
+
return load_manifest(backend_path)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def get_manifest_filename(resource_path):
|
|
369
|
+
"""
|
|
370
|
+
Determine which manifest filename is being used for a resource.
|
|
371
|
+
|
|
372
|
+
CEO Review addition: Utility for filename detection.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
resource_path: Path to resource directory
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
Filename string or None if neither exists (synthesis will be used)
|
|
379
|
+
"""
|
|
380
|
+
# Check for manifest file (service.json)
|
|
381
|
+
manifest_path = resource_path + '/' + MANIFEST_FILENAME
|
|
382
|
+
if local("test -f '{path}' && echo 'yes' || echo 'no'".format(path=manifest_path), quiet=True, echo_off=True) == 'yes':
|
|
383
|
+
return MANIFEST_FILENAME
|
|
384
|
+
|
|
385
|
+
# Manifest not found - synthesis will be used
|
|
386
|
+
return None
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# 📋 TILT SDK - MANIFEST NORMALIZATION & DISCOVERY
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Path: .tilt/topologies/tilt/discovery/manifest/normalize.star
|
|
5
|
+
# Purpose: Normalize manifests and provide helper accessors
|
|
6
|
+
# =============================================================================
|
|
7
|
+
|
|
8
|
+
load('./constants.star', 'MANIFEST_DEFAULTS', 'MANIFEST_FILENAME')
|
|
9
|
+
load('./loading.star', 'apply_manifest_defaults', 'check_prisma_folder', 'get_default_syncs_for_type')
|
|
10
|
+
load('./validation.star', 'validate_manifest')
|
|
11
|
+
load('../../engine/topologies/tilt/common/utils.star', 'Utils')
|
|
12
|
+
load('../../engine/topologies/platform/docker/constants.star', 'PlatformDockerConstants')
|
|
13
|
+
load('../../specs/specs/TILT_TECH_STACK.star', 'RUNTIME', 'MESSAGING')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _load_and_normalize(manifest_path, warn_only=True):
|
|
17
|
+
"""
|
|
18
|
+
🎯 MAIN ENTRY POINT: Load manifest and normalize to full resource config.
|
|
19
|
+
|
|
20
|
+
This function is the bridge between the discovery system (resource_registry.star)
|
|
21
|
+
and the manifest loading system. It:
|
|
22
|
+
|
|
23
|
+
1. Reads the JSON file
|
|
24
|
+
2. Validates the structure
|
|
25
|
+
3. Normalizes with smart defaults
|
|
26
|
+
4. Computes labels, syncs, has_migrator
|
|
27
|
+
5. Returns a resource-ready configuration
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
manifest_path: Full path to manifest file
|
|
31
|
+
warn_only: If True, return None on error instead of failing
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Normalized manifest dict or None on error (if warn_only=True)
|
|
35
|
+
"""
|
|
36
|
+
# Prepend project root to relative paths for correct resolution
|
|
37
|
+
project_root = os.environ.get('TDK_PROJECT_ROOT', '')
|
|
38
|
+
if project_root and not manifest_path.startswith('/'):
|
|
39
|
+
full_path = project_root + '/' + manifest_path
|
|
40
|
+
else:
|
|
41
|
+
full_path = manifest_path
|
|
42
|
+
|
|
43
|
+
# Read manifest file
|
|
44
|
+
content = read_file(full_path, default='')
|
|
45
|
+
|
|
46
|
+
if not content or not str(content).strip():
|
|
47
|
+
if warn_only:
|
|
48
|
+
print(" ⚠️ Empty or missing manifest: " + manifest_path)
|
|
49
|
+
return None
|
|
50
|
+
fail("Empty or missing manifest: " + manifest_path)
|
|
51
|
+
|
|
52
|
+
# Parse JSON
|
|
53
|
+
manifest = decode_json(content)
|
|
54
|
+
if manifest == None:
|
|
55
|
+
if warn_only:
|
|
56
|
+
print(" ⚠️ Invalid JSON in manifest: " + manifest_path)
|
|
57
|
+
return None
|
|
58
|
+
fail("Invalid JSON in manifest: " + manifest_path)
|
|
59
|
+
|
|
60
|
+
# Validate
|
|
61
|
+
issues = validate_manifest(manifest)
|
|
62
|
+
if issues:
|
|
63
|
+
if warn_only:
|
|
64
|
+
for issue in issues:
|
|
65
|
+
print(" ⚠️ " + manifest_path + ": " + issue)
|
|
66
|
+
return None
|
|
67
|
+
fail("Manifest validation failed:\n" + "\n".join(issues))
|
|
68
|
+
|
|
69
|
+
# Extract service path from manifest path
|
|
70
|
+
resource_path = manifest_path.rsplit('/', 1)[0]
|
|
71
|
+
|
|
72
|
+
# BUG FIX: Normalize various path patterns to project-relative paths
|
|
73
|
+
# Pattern 1: Worktrees - .worktrees/task1-dry/services/platform/...
|
|
74
|
+
# Pattern 2: TDK output - .tdk/.tdk-out/../.. or .tdk/.tdk-out/../../path
|
|
75
|
+
|
|
76
|
+
if resource_path.startswith('.worktrees/'):
|
|
77
|
+
# Extract the part after the worktree name
|
|
78
|
+
parts = resource_path.split('/')
|
|
79
|
+
if len(parts) >= 3:
|
|
80
|
+
resource_path = '/'.join(parts[2:])
|
|
81
|
+
elif '.worktrees/' in resource_path:
|
|
82
|
+
worktree_idx = resource_path.find('.worktrees/')
|
|
83
|
+
after_worktree = resource_path[worktree_idx:]
|
|
84
|
+
parts = after_worktree.split('/')
|
|
85
|
+
if len(parts) >= 3:
|
|
86
|
+
resource_path = '/'.join(parts[2:])
|
|
87
|
+
elif '.tdk/.tdk-out/../..' in resource_path:
|
|
88
|
+
# Handle TDK output paths like: /path/to/.tdk/.tdk-out/../.. or .tdk/.tdk-out/../../services/...
|
|
89
|
+
tdk_idx = resource_path.find('.tdk/.tdk-out/../..')
|
|
90
|
+
if tdk_idx != -1:
|
|
91
|
+
after_tdk = resource_path[tdk_idx + len('.tdk/.tdk-out/../..'):]
|
|
92
|
+
if after_tdk.startswith('/'):
|
|
93
|
+
after_tdk = after_tdk[1:]
|
|
94
|
+
resource_path = after_tdk
|
|
95
|
+
elif resource_path.endswith('.tdk/.tdk-out/../..'):
|
|
96
|
+
# Handle bare TDK output path that ends with just the resolution pattern
|
|
97
|
+
resource_path = ''
|
|
98
|
+
|
|
99
|
+
# Apply smart defaults
|
|
100
|
+
normalized = apply_manifest_defaults(manifest, resource_path)
|
|
101
|
+
|
|
102
|
+
# Compute additional fields for registry compatibility
|
|
103
|
+
app_name = normalized.get('appName', '')
|
|
104
|
+
app_type = normalized.get('appType', 'backend')
|
|
105
|
+
stack = normalized.get('stack', '')
|
|
106
|
+
features = normalized.get('features', [])
|
|
107
|
+
|
|
108
|
+
# 🎯 AUTO-COMPUTE labels from stack
|
|
109
|
+
normalized['labels'] = ['app.' + stack]
|
|
110
|
+
|
|
111
|
+
# 🎯 AUTO-DETECT has_migrator
|
|
112
|
+
has_migrator = 'prisma' in features
|
|
113
|
+
if not has_migrator:
|
|
114
|
+
has_migrator = check_prisma_folder(resource_path)
|
|
115
|
+
normalized['has_migrator'] = has_migrator
|
|
116
|
+
|
|
117
|
+
# 🎯 AUTO-COMPUTE syncs if not specified
|
|
118
|
+
if normalized.get('syncs') == None:
|
|
119
|
+
normalized['syncs'] = get_default_syncs_for_type(app_type, features)
|
|
120
|
+
|
|
121
|
+
# 🎯 COMPUTE dockerfile path
|
|
122
|
+
dockerfile = normalized.get('dockerfile', 'Dockerfile')
|
|
123
|
+
normalized['dockerfile_path'] = app_name + '/' + dockerfile
|
|
124
|
+
|
|
125
|
+
# 🎯 MARK as frontend if applicable
|
|
126
|
+
if app_type == 'frontend':
|
|
127
|
+
normalized['frontend'] = True
|
|
128
|
+
|
|
129
|
+
# 🎯 EXTRACT dependencies for registry
|
|
130
|
+
normalized['serviceDependencies'] = normalized.get('dependsOn', [])
|
|
131
|
+
|
|
132
|
+
return normalized
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _discover_manifests_in_path(root_path):
|
|
136
|
+
"""
|
|
137
|
+
Discover all manifest files under a root path.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
root_path: Directory to search (e.g., 'services/product')
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
List of manifest file paths
|
|
144
|
+
"""
|
|
145
|
+
find_cmd = "find {root} -name '{filename}' -type f 2>/dev/null | sort".format(
|
|
146
|
+
root=root_path,
|
|
147
|
+
filename=MANIFEST_FILENAME
|
|
148
|
+
)
|
|
149
|
+
result = str(local(find_cmd, quiet=True, echo_off=True))
|
|
150
|
+
|
|
151
|
+
manifests = []
|
|
152
|
+
if result:
|
|
153
|
+
for line in result.strip().split('\n'):
|
|
154
|
+
if line and line.strip():
|
|
155
|
+
manifests.append(line.strip())
|
|
156
|
+
|
|
157
|
+
return manifests
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _load_all_manifests(root_path, warn_only=True):
|
|
161
|
+
"""
|
|
162
|
+
Load and normalize all manifests under a root path.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
root_path: Directory to search (e.g., 'services/product')
|
|
166
|
+
warn_only: If True, skip invalid manifests with warnings
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
List of normalized manifest dicts
|
|
170
|
+
"""
|
|
171
|
+
manifest_paths = _discover_manifests_in_path(root_path)
|
|
172
|
+
manifests = []
|
|
173
|
+
|
|
174
|
+
for path in manifest_paths:
|
|
175
|
+
normalized = _load_and_normalize(path, warn_only=warn_only)
|
|
176
|
+
if normalized:
|
|
177
|
+
manifests.append(normalized)
|
|
178
|
+
|
|
179
|
+
return manifests
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _get_port(manifest):
|
|
183
|
+
"""Get the resource port from manifest."""
|
|
184
|
+
return manifest.get('port', MANIFEST_DEFAULTS['port'])
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _get_database_url(manifest, host='localhost', port=5432):
|
|
188
|
+
"""
|
|
189
|
+
Generate DATABASE_URL from manifest.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
manifest: Manifest dictionary
|
|
193
|
+
host: Database host (default: localhost)
|
|
194
|
+
port: Database port (default: 5432)
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
PostgreSQL connection string
|
|
198
|
+
"""
|
|
199
|
+
db_name = manifest.get('databaseName', PlatformDockerConstants.get_db_name(manifest.get('stack', 'app')))
|
|
200
|
+
return PlatformDockerConstants.get_tilt_database_url_template().format(
|
|
201
|
+
host=host,
|
|
202
|
+
port=port,
|
|
203
|
+
db=db_name,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def _print_summary(manifests):
|
|
208
|
+
"""
|
|
209
|
+
Print formatted summary of loaded manifests.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
manifests: List of manifest dictionaries
|
|
213
|
+
"""
|
|
214
|
+
print("")
|
|
215
|
+
print("📋 ═══════════════════════════════════════════════════════════════")
|
|
216
|
+
print("📋 LOADED MANIFESTS")
|
|
217
|
+
print("📋 ═══════════════════════════════════════════════════════════════")
|
|
218
|
+
|
|
219
|
+
for m in manifests:
|
|
220
|
+
status = "✅" if not m.get('_synthesized') else "⚡"
|
|
221
|
+
app_name = m.get('appName', 'unknown')
|
|
222
|
+
app_type = m.get('appType', 'unknown')
|
|
223
|
+
port = m.get('port', 0)
|
|
224
|
+
stack = m.get('stack', 'unknown')
|
|
225
|
+
|
|
226
|
+
print(" {status} {name} | {type} | Port: {port} | Stack: {stack}".format(
|
|
227
|
+
status=status,
|
|
228
|
+
name=app_name,
|
|
229
|
+
type=app_type,
|
|
230
|
+
port=port,
|
|
231
|
+
stack=stack,
|
|
232
|
+
))
|
|
233
|
+
|
|
234
|
+
print("📋 ═══════════════════════════════════════════════════════════════")
|
|
235
|
+
print("")
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _generate_manifest_template(app_name, stack, app_type='backend', port=4000):
|
|
239
|
+
"""
|
|
240
|
+
🎯 TEMPLATE GENERATOR: Returns a string with a standard manifest.
|
|
241
|
+
"""
|
|
242
|
+
template = {
|
|
243
|
+
"$schema": "https://" + PlatformDockerConstants.EMAIL_DOMAIN + "/schemas/manifest-schema.json",
|
|
244
|
+
"appName": app_name,
|
|
245
|
+
"appType": app_type,
|
|
246
|
+
"stack": stack,
|
|
247
|
+
"port": port,
|
|
248
|
+
"replicas": 1,
|
|
249
|
+
"features": [MESSAGING, "infisical"],
|
|
250
|
+
"dependsOn": [],
|
|
251
|
+
"runtime": RUNTIME
|
|
252
|
+
}
|
|
253
|
+
return Utils.encode_json(template)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def load_and_normalize(manifest_path, warn_only=True):
|
|
257
|
+
return _load_and_normalize(manifest_path, warn_only=warn_only)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def discover_manifests_in_path(root_path):
|
|
261
|
+
return _discover_manifests_in_path(root_path)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def load_all_manifests(root_path, warn_only=True):
|
|
265
|
+
return _load_all_manifests(root_path, warn_only=warn_only)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def get_port(manifest):
|
|
269
|
+
return _get_port(manifest)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def get_database_url(manifest, host='localhost', port=5432):
|
|
273
|
+
return _get_database_url(manifest, host=host, port=port)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def print_summary(manifests):
|
|
277
|
+
return _print_summary(manifests)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def generate_manifest_template(app_name, stack, app_type='backend', port=4000):
|
|
281
|
+
return _generate_manifest_template(app_name, stack, app_type=app_type, port=port)
|