@tdk-landscape/tdk-cli-core 1.3.79 → 1.3.81
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/CHANGELOG.md +8 -0
- package/README.md +39 -206
- package/cli/dist/cli.js +2 -0
- package/cli/dist/commands/completion.js +15 -2
- package/cli/dist/commands/config.js +34 -6
- package/cli/dist/commands/doctor.js +103 -30
- package/cli/dist/commands/help.js +8 -2
- package/cli/dist/commands/networks.js +126 -101
- package/cli/dist/commands/resource.js +4 -1
- package/cli/dist/commands/resources.js +40 -9
- package/cli/dist/commands/runtime.js +74 -0
- package/cli/dist/commands/status.js +65 -7
- package/cli/dist/commands/up.js +12 -10
- package/cli/dist/generator/template-engine.js +29 -17
- package/cli/dist/utils/cold-preflight.js +12 -18
- package/cli/dist/utils/doctor-report.js +64 -0
- package/cli/dist/utils/doctor-runtime.js +4 -4
- package/cli/dist/utils/host-port-config.js +88 -0
- package/cli/dist/utils/host-port-plan.js +74 -0
- package/cli/dist/utils/machine-output.js +24 -0
- package/cli/dist/utils/service-manifest.js +1 -0
- package/cli/dist/utils/service-urls.js +10 -8
- package/cli/package.json +1 -1
- package/engine/schemas/project-schema.json +142 -0
- package/engine/topologies/platform/docker/compose/traefik_standalone.star +5 -3
- package/engine/topologies/tilt/resources/infra-loader.star +7 -32
- package/package.json +2 -2
|
@@ -15,22 +15,24 @@ export function getProjectName() {
|
|
|
15
15
|
}
|
|
16
16
|
return "tdk-project";
|
|
17
17
|
}
|
|
18
|
-
export function resolveSubdomainBases() {
|
|
18
|
+
export function resolveSubdomainBases(ingressPort) {
|
|
19
19
|
const projectName = getProjectName();
|
|
20
|
-
const raw = process.env.TDK_SERVICE_BASE_URL ??
|
|
20
|
+
const raw = process.env.TDK_SERVICE_BASE_URL ??
|
|
21
|
+
`http://${projectName}.localhost${ingressPort ? `:${ingressPort}` : ""}`;
|
|
21
22
|
try {
|
|
22
23
|
const u = new URL(raw.includes("://") ? raw : `http://${raw}`);
|
|
23
24
|
const host = u.hostname;
|
|
25
|
+
const port = u.port || (ingressPort ? String(ingressPort) : "");
|
|
24
26
|
if (host === "localhost" || /^\d+\.\d+\.\d+\.\d+$/.test(host)) {
|
|
25
27
|
return {
|
|
26
|
-
appBase: `${u.protocol}//${host}${
|
|
27
|
-
apiBase: `${u.protocol}//${host}${
|
|
28
|
+
appBase: `${u.protocol}//${host}${port ? `:${port}` : ""}`,
|
|
29
|
+
apiBase: `${u.protocol}//${host}${port ? `:${port}` : ""}`,
|
|
28
30
|
};
|
|
29
31
|
}
|
|
30
32
|
const bare = host.replace(/^(app|api)\./, "");
|
|
31
33
|
return {
|
|
32
|
-
appBase: `${u.protocol}//app.${bare}${
|
|
33
|
-
apiBase: `${u.protocol}//api.${bare}${
|
|
34
|
+
appBase: `${u.protocol}//app.${bare}${port ? `:${port}` : ""}`,
|
|
35
|
+
apiBase: `${u.protocol}//api.${bare}${port ? `:${port}` : ""}`,
|
|
34
36
|
};
|
|
35
37
|
}
|
|
36
38
|
catch {
|
|
@@ -56,8 +58,8 @@ export function resolveServicePath(resource) {
|
|
|
56
58
|
* Workers, libraries, SDKs and migrators have no Traefik route, so they are
|
|
57
59
|
* skipped rather than reported as unreachable.
|
|
58
60
|
*/
|
|
59
|
-
export function buildHealthTargets(resources) {
|
|
60
|
-
const { appBase, apiBase } = resolveSubdomainBases();
|
|
61
|
+
export function buildHealthTargets(resources, ingressPort) {
|
|
62
|
+
const { appBase, apiBase } = resolveSubdomainBases(ingressPort);
|
|
61
63
|
return resources
|
|
62
64
|
.filter((resource) => resource.config?.appType === "frontend" || resource.config?.appType === "backend")
|
|
63
65
|
.map((resource) => {
|
package/cli/package.json
CHANGED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/tdk-landscape/tdk-cli-core/main/engine/schemas/project-schema.json",
|
|
4
|
+
"title": "TDK Project Configuration",
|
|
5
|
+
"description": "Editor assistance for .tdk/project.json. TDK's CLI remains the runtime source of truth.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": true,
|
|
8
|
+
"required": [
|
|
9
|
+
"version",
|
|
10
|
+
"project",
|
|
11
|
+
"phases",
|
|
12
|
+
"optional_infra",
|
|
13
|
+
"discovery"
|
|
14
|
+
],
|
|
15
|
+
"properties": {
|
|
16
|
+
"version": {
|
|
17
|
+
"type": "string"
|
|
18
|
+
},
|
|
19
|
+
"project": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"additionalProperties": true,
|
|
22
|
+
"required": [
|
|
23
|
+
"name",
|
|
24
|
+
"version"
|
|
25
|
+
],
|
|
26
|
+
"properties": {
|
|
27
|
+
"name": {
|
|
28
|
+
"type": "string"
|
|
29
|
+
},
|
|
30
|
+
"version": {
|
|
31
|
+
"type": "string"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"phases": {
|
|
36
|
+
"type": "object",
|
|
37
|
+
"additionalProperties": true,
|
|
38
|
+
"required": [
|
|
39
|
+
"pre_alpha",
|
|
40
|
+
"alpha",
|
|
41
|
+
"beta",
|
|
42
|
+
"out_of_scope"
|
|
43
|
+
],
|
|
44
|
+
"properties": {
|
|
45
|
+
"pre_alpha": {
|
|
46
|
+
"$ref": "#/definitions/phase"
|
|
47
|
+
},
|
|
48
|
+
"alpha": {
|
|
49
|
+
"$ref": "#/definitions/phase"
|
|
50
|
+
},
|
|
51
|
+
"beta": {
|
|
52
|
+
"$ref": "#/definitions/phase"
|
|
53
|
+
},
|
|
54
|
+
"out_of_scope": {
|
|
55
|
+
"$ref": "#/definitions/phase"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"stacks": {
|
|
60
|
+
"type": "object",
|
|
61
|
+
"additionalProperties": true
|
|
62
|
+
},
|
|
63
|
+
"always_enabled_infra": {
|
|
64
|
+
"type": "array",
|
|
65
|
+
"items": {
|
|
66
|
+
"type": "string"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"optional_infra": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"additionalProperties": true,
|
|
72
|
+
"required": [
|
|
73
|
+
"monitoring",
|
|
74
|
+
"elk",
|
|
75
|
+
"debezium",
|
|
76
|
+
"golden_image",
|
|
77
|
+
"verdaccio"
|
|
78
|
+
],
|
|
79
|
+
"properties": {
|
|
80
|
+
"monitoring": {
|
|
81
|
+
"type": "boolean"
|
|
82
|
+
},
|
|
83
|
+
"elk": {
|
|
84
|
+
"type": "boolean"
|
|
85
|
+
},
|
|
86
|
+
"debezium": {
|
|
87
|
+
"type": "boolean"
|
|
88
|
+
},
|
|
89
|
+
"golden_image": {
|
|
90
|
+
"type": "boolean"
|
|
91
|
+
},
|
|
92
|
+
"verdaccio": {
|
|
93
|
+
"type": "boolean"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"discovery": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"additionalProperties": true,
|
|
100
|
+
"required": [
|
|
101
|
+
"paths"
|
|
102
|
+
],
|
|
103
|
+
"properties": {
|
|
104
|
+
"paths": {
|
|
105
|
+
"type": "array",
|
|
106
|
+
"items": {
|
|
107
|
+
"type": "string"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"overrides": {
|
|
113
|
+
"type": "object",
|
|
114
|
+
"additionalProperties": true
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"definitions": {
|
|
118
|
+
"phase": {
|
|
119
|
+
"type": "object",
|
|
120
|
+
"additionalProperties": true,
|
|
121
|
+
"required": [
|
|
122
|
+
"name",
|
|
123
|
+
"description",
|
|
124
|
+
"enabledStacks"
|
|
125
|
+
],
|
|
126
|
+
"properties": {
|
|
127
|
+
"name": {
|
|
128
|
+
"type": "string"
|
|
129
|
+
},
|
|
130
|
+
"description": {
|
|
131
|
+
"type": "string"
|
|
132
|
+
},
|
|
133
|
+
"enabledStacks": {
|
|
134
|
+
"type": "array",
|
|
135
|
+
"items": {
|
|
136
|
+
"type": "string"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -10,7 +10,7 @@ load("../config/healthcheck.star", "compose_healthcheck_timing")
|
|
|
10
10
|
load("../networking/traefik_static_routes.star", "normalize_abs_path")
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def generate_standalone_traefik_compose(sablier_enabled = False):
|
|
13
|
+
def generate_standalone_traefik_compose(sablier_enabled = False, http_host_port = "8080", https_host_port = "8443"):
|
|
14
14
|
"""Minimal Traefik that routes Docker labels on api.{project}.localhost.
|
|
15
15
|
|
|
16
16
|
The Sablier plugin, the sablier container and the wake gateway are only
|
|
@@ -48,8 +48,8 @@ services:
|
|
|
48
48
|
- "--entrypoints.websecure.address=:443"
|
|
49
49
|
- "--log.level=INFO"
|
|
50
50
|
{sablier_flags} ports:
|
|
51
|
-
- "
|
|
52
|
-
- "
|
|
51
|
+
- "{http_host_port}:80"
|
|
52
|
+
- "{https_host_port}:443"
|
|
53
53
|
volumes:
|
|
54
54
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
55
55
|
- ./{dynamic_dir_name}:/etc/traefik/dynamic:ro
|
|
@@ -65,6 +65,8 @@ services:
|
|
|
65
65
|
""".format(
|
|
66
66
|
name=name,
|
|
67
67
|
network=network,
|
|
68
|
+
http_host_port=http_host_port,
|
|
69
|
+
https_host_port=https_host_port,
|
|
68
70
|
healthcheck_timing=compose_healthcheck_timing(10),
|
|
69
71
|
traefik_depends_on=_SABLIER_DEPENDS_ON if sablier_enabled else "",
|
|
70
72
|
sablier_flags=_SABLIER_FLAGS if sablier_enabled else "",
|
|
@@ -70,7 +70,7 @@ services:
|
|
|
70
70
|
POSTGRES_PASSWORD: ${{DB_PASSWORD}}
|
|
71
71
|
POSTGRES_DB: postgres
|
|
72
72
|
ports:
|
|
73
|
-
- "
|
|
73
|
+
- "{host_port}:5432"
|
|
74
74
|
volumes:
|
|
75
75
|
- {name}_postgres_data:/var/lib/postgresql/data
|
|
76
76
|
networks:
|
|
@@ -88,7 +88,7 @@ networks:
|
|
|
88
88
|
|
|
89
89
|
volumes:
|
|
90
90
|
{name}_postgres_data:
|
|
91
|
-
""".format(name=name, database_network=database_network)
|
|
91
|
+
""".format(name=name, database_network=database_network, host_port=os.environ.get('TDK_POSTGRES_PORT', '15432'))
|
|
92
92
|
|
|
93
93
|
|
|
94
94
|
def _ensure_database_management_compose(root_prefix, write_fn):
|
|
@@ -174,43 +174,18 @@ def _load_infisical(should_enable, root_prefix="", env_file=None):
|
|
|
174
174
|
# 🌐 PROXY (Traefik)
|
|
175
175
|
# =============================================================================
|
|
176
176
|
|
|
177
|
-
def _stop_conflicting_traefik():
|
|
178
|
-
"""Auto-stop another TDK project's standalone Traefik if it already holds
|
|
179
|
-
host port 80/8080, so `tdk up` on a new project always wins over a stale
|
|
180
|
-
Traefik left running from a previous one.
|
|
181
|
-
|
|
182
|
-
Each standalone project gets its own container name and Docker network
|
|
183
|
-
(see PlatformDockerConstants.PROJECT_NAME), but the host ports are hardcoded
|
|
184
|
-
to 80/8080 so `api.{project}.localhost` works without a port suffix. That
|
|
185
|
-
means only one standalone project's Traefik can run at a time. Without this,
|
|
186
|
-
starting a second project while another's Traefik is still running fails
|
|
187
|
-
deep inside `docker compose up` with a cryptic "port is already allocated"
|
|
188
|
-
networking error instead of just taking over the port.
|
|
189
|
-
"""
|
|
190
|
-
own_container = PlatformDockerConstants.PROJECT_NAME + "_traefik"
|
|
191
|
-
result = str(local(
|
|
192
|
-
"docker ps --filter 'publish=80' --filter 'publish=8080' --format '{{.Names}}' 2>/dev/null || true",
|
|
193
|
-
quiet=True, echo_off=True,
|
|
194
|
-
)).strip()
|
|
195
|
-
for container in result.split("\n"):
|
|
196
|
-
container = container.strip()
|
|
197
|
-
if container and container != own_container:
|
|
198
|
-
print("🛑 Stopping Traefik from another TDK project ('{}') — it was holding host port 80/8080".format(container))
|
|
199
|
-
local(
|
|
200
|
-
"docker stop '{}' >/dev/null 2>&1 || true".format(container),
|
|
201
|
-
quiet=True, echo_off=True,
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
|
|
205
177
|
def _load_standalone_traefik(root_prefix, env_file, write_fn):
|
|
206
178
|
"""Generate and load a self-contained Traefik compose for standalone projects."""
|
|
207
|
-
_stop_conflicting_traefik()
|
|
208
179
|
compose_rel = ".tdk/.tdk-out/docker-compose.traefik.yml"
|
|
209
180
|
# The free-tier stub always reports "disabled"; the licensed module reports
|
|
210
181
|
# enabled for a manifest that opts in. Probing it keeps this file free of any
|
|
211
182
|
# license logic while starting the sablier containers only when they can work.
|
|
212
183
|
_, sablier_enabled = sablier_middleware_suffix({"sablier": {"enable": True}}, "probe")
|
|
213
|
-
content = generate_standalone_traefik_compose(
|
|
184
|
+
content = generate_standalone_traefik_compose(
|
|
185
|
+
sablier_enabled,
|
|
186
|
+
os.environ.get('TDK_HTTP_PORT', '8080'),
|
|
187
|
+
os.environ.get('TDK_HTTPS_PORT', '8443'),
|
|
188
|
+
)
|
|
214
189
|
if write_fn:
|
|
215
190
|
write_fn(compose_rel, content)
|
|
216
191
|
compose_file = root_prefix + compose_rel if root_prefix else compose_rel
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tdk-landscape/tdk-cli-core",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.3.81",
|
|
4
|
+
"description": "TDK runs many services on your laptop with Docker + Tilt. Helm still deploys the cluster.",
|
|
5
5
|
"homepage": "https://tdk-landscape.github.io/tdk-website",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|