@flisk-sh/flisk 1.4.0 → 1.4.1
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/cli/dist/commands/doctor.js +62 -0
- package/cli/dist/commands/runtime.js +6 -3
- package/cli/dist/generator/template-engine.js +7 -4
- package/cli/dist/utils/runtime-layout.js +7 -0
- package/cli/dist-bundle/chunk-7HR5PVOD.js +54 -0
- package/cli/dist-bundle/{chunk-PVBAGX5X.js → chunk-7IXBBU27.js} +1 -1
- package/cli/dist-bundle/{chunk-VHFFSBVJ.js → chunk-BB5BZ37Y.js} +1 -1
- package/cli/dist-bundle/{chunk-D7N2GGJH.js → chunk-DUNCELUK.js} +1 -1
- package/cli/dist-bundle/{chunk-36SOQVAL.js → chunk-KJOCVAMQ.js} +1 -1
- package/cli/dist-bundle/{chunk-VMB5673O.js → chunk-L6U555CJ.js} +30 -26
- package/cli/dist-bundle/{chunk-HEMPQKD6.js → chunk-M2R464RM.js} +1 -1
- package/cli/dist-bundle/{chunk-QQEV6D74.js → chunk-RX6O3PG4.js} +1 -1
- package/cli/dist-bundle/{chunk-ICXF6PXA.js → chunk-SRN64OPO.js} +2 -2
- package/cli/dist-bundle/{chunk-5EZ4EX6U.js → chunk-TZNXL3IO.js} +1 -1
- package/cli/dist-bundle/{chunk-B6Q5VKL7.js → chunk-UJXR6MZ2.js} +1 -1
- package/cli/dist-bundle/{chunk-BWK6MPCB.js → chunk-VRESY4NR.js} +1 -1
- package/cli/dist-bundle/cli.js +153 -153
- package/cli/dist-bundle/{cold-preflight-ABU26DYW.js → cold-preflight-BBDDHWRV.js} +1 -1
- package/cli/dist-bundle/{demo-stage-EBIUCJBX.js → demo-stage-HIHO4VV3.js} +1 -1
- package/cli/dist-bundle/{open-2KSAF6M2.js → open-W3QX35R6.js} +1 -1
- package/cli/dist-bundle/project-FW5LL2KM.js +2 -0
- package/cli/dist-bundle/{services-V6Q55JR5.js → services-RGTQ2LXC.js} +1 -1
- package/cli/dist-bundle/{tilt-port-owner-MWJ7P6NB.js → tilt-port-owner-6DO7OJRR.js} +1 -1
- package/cli/package.json +1 -1
- package/package.json +11 -2
- package/runtime/platform/services/platform/proxy/service.yaml +14 -0
- package/cli/dist/commands/__tests__/project-e2e-helpers.js +0 -49
- package/cli/dist/commands/__tests__/ui-loading-screen.test.js +0 -16
- package/cli/dist/generator/__tests__/golden-helpers.js +0 -43
- package/cli/dist-bundle/chunk-763VK575.js +0 -54
- package/cli/dist-bundle/project-YD3C4ZV3.js +0 -2
- package/runtime/discovery/test_resource_snapshot.py +0 -253
- package/runtime/engine/assets/docker/wake-gateway/decide.test.ts +0 -177
- package/runtime/engine/topologies/tilt/manifest/tests/test_integration.star +0 -278
- package/runtime/engine/topologies/tilt/manifest/tests/test_loader_parser.star +0 -475
- package/runtime/engine/topologies/tilt/manifest/tests/test_manifest.star +0 -319
- package/runtime/engine/topologies/tilt/manifest/tests/test_validator.star +0 -472
- package/runtime/ext/ide-components/shared/test_config_service.py +0 -328
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/bun-hoisted-symlink-fix.sh +0 -0
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/infisical-entrypoint.sh +0 -0
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/install-deps.sh +0 -0
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/prisma-bun-client-link-fix.sh +0 -0
- /package/{shared-platform-engineering → runtime/shared-platform-engineering}/docker-templates/prisma-normalize-client.sh +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{A as d,B as e,C as f,D as g,E as h,F as i,G as j,x as a,y as b,z as c}from"./chunk-
|
|
2
|
+
import{A as d,B as e,C as f,D as g,E as h,F as i,G as j,x as a,y as b,z as c}from"./chunk-L6U555CJ.js";import"./chunk-7HR5PVOD.js";import"./chunk-UJXR6MZ2.js";import"./chunk-K6SOCO6V.js";import"./chunk-3J6XI3NX.js";import"./chunk-DUNCELUK.js";import"./chunk-RX6O3PG4.js";import"./chunk-TZNXL3IO.js";import"./chunk-VRESY4NR.js";import"./chunk-BB5BZ37Y.js";import"./chunk-KJZUBHLO.js";export{c as MACHINE_CHECK_IDS,a as RUNTIME_CHECK_IDS,b as SCAFFOLD_CHECK_IDS,h as assertMachineReadyOrExit,i as detectRuntimePrerequisites,g as formatColdPreflight,j as formatRuntimeNextSteps,d as nodeTooOld,e as requireVerifiedDockerVersions,f as runColdPreflight};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{b as R}from"./chunk-
|
|
2
|
+
import{b as R}from"./chunk-KJOCVAMQ.js";import{b as c}from"./chunk-BB5BZ37Y.js";import"./chunk-KJZUBHLO.js";var v=12,_=24,F={plain:e=>e,bold:c.bold,dim:c.gray,ok:c.green,warn:c.yellow,err:c.red},S={pending:"\u25CB",active:"\u25D0",done:"\u2714",failed:"\u2716"},j={pending:"dim",active:"warn",done:"ok",failed:"err"};function o(e){return R(String(e)).replace(/[\n\r\t]/g," ")}function g(e){if(!Number.isFinite(e)||e<0)return"0.0s";if(e<1e4)return`${(e/1e3).toFixed(1)}s`;if(e<6e4)return`${Math.round(e/1e3)}s`;let n=Math.floor(e/6e4),i=Math.round(e%6e4/1e3);return`${n}m ${i}s`}function $(e){return e.reduce((n,i)=>n+i.text.length,0)}function k(e,n){if(n<=0)return[];let i=[],l=0;for(let s of e){if(l>=n)break;let t=n-l;if(s.text.length<=t){i.push(s),l+=s.text.length;continue}i.push({...s,text:`${s.text.slice(0,Math.max(0,t-1))}\u2026`}),l=n}return i}function w(e,n){let i=k(e,n),l=n-$(i);return l<=0?i:[...i,{text:" ".repeat(l),style:"plain"}]}function M(e,n,i){let l=$(n),s=i-l-1;if(s<4)return w(k([...e,...n],i),i);let t=k(e,s),r=i-$(t)-l;return[...t,{text:" ".repeat(Math.max(1,r)),style:"plain"},...n]}function b(e){return[{text:` ${"\u2500".repeat(Math.max(0,e-2))}`,style:"dim"}]}function P(e,n){return M([{text:" ",style:"plain"},{text:S[e.status],style:j[e.status]},{text:" ",style:"plain"},{text:o(e.label),style:e.status==="pending"?"dim":"plain"}],e.elapsedMs===void 0?[]:[{text:g(e.elapsedMs),style:"dim"}],n)}function Y(e){let n=Math.max(0,e.servicesTotal);if(n===0)return"no services found";let l=[`${Math.min(Math.max(0,e.servicesReady),n)} of ${n} services ready`];return e.servicesBuilding>0&&l.push(`${e.servicesBuilding} building`),l.join(" \xB7 ")}function E(e,n=80){let i=Number.isFinite(n)&&n>0?n:80,l=Math.max(_,Math.min(i-1,78)),s=[],t=a=>s.push(w(a,l)),r=()=>t([]);if(e.done){t(M([{text:" ",style:"plain"},{text:"\u2714",style:"ok"},{text:" Your stack is running",style:"ok"}],[{text:g(e.elapsedMs),style:"dim"}],l)),t([{text:" ",style:"plain"},{text:o(e.subtitle),style:"dim"}]),r();for(let a of e.done.urls.slice(0,2))t([{text:" ",style:"plain"},{text:o(a),style:"plain"}]);r(),t(b(l)),t([{text:" ",style:"plain"},{text:o(e.done.summary),style:"plain"}]),t([{text:" ",style:"plain"},{text:o(e.done.hint),style:"dim"}]),r(),t([{text:" ",style:"plain"},{text:`flisk ${o(e.done.version)}`,style:"dim"}])}else if(e.failure){let a=e.phases.find(p=>p.status==="failed");t(M([{text:" ",style:"plain"},{text:"\u2716",style:"err"},{text:" ",style:"plain"},{text:o(a?.label??"The demo stopped"),style:"err"}],[{text:g(e.elapsedMs),style:"dim"}],l)),r(),t([{text:" ",style:"plain"},{text:o(e.failure.message),style:"plain"}]),e.failure.fix&&t([{text:" ",style:"plain"},{text:o(e.failure.fix),style:"dim"}]),r(),t(b(l)),e.detail&&t([{text:" ",style:"plain"},{text:o(e.detail),style:"dim"}]),e.failure.logPath&&t([{text:" ",style:"plain"},{text:`log: ${o(e.failure.logPath)}`,style:"dim"}])}else{t([{text:" ",style:"plain"},{text:o(e.title),style:"bold"}]),t([{text:" ",style:"plain"},{text:o(e.subtitle),style:"dim"}]),r();let a=e.phases.slice(0,4);for(let p of a)t(P(p,l));for(let p=a.length;p<4;p+=1)r();r(),t(b(l)),t([{text:" ",style:"plain"},{text:o(e.detail??""),style:"dim"}]),t(M([{text:" ",style:"plain"},{text:Y(e),style:"plain"}],[{text:g(e.elapsedMs),style:"dim"}],l))}for(;s.length<v;)s.push(w([],l));return s.slice(0,v)}function A(e){return e.map(n=>n.map(i=>i.text).join(""))}function D(e){return e.map(n=>F[n.style](n.text)).join("")}function H(e,n=process.stderr,i=Date.now){let l=n.isTTY===!0,s=i(),t={...e},r=!1,a="",p="",f,T=()=>{let u=!!(t.done||t.failure);return{...t,elapsedMs:u?t.elapsedMs:i()-s}},x=()=>{let u=T(),m=E(u,n.columns??80),y=A(m);if(!l){let h=y.join(`
|
|
3
3
|
`);if(h===p)return;p=h,n.write(`${y.filter(L=>L.trim()!=="").join(`
|
|
4
4
|
`)}
|
|
5
5
|
`);return}let d=y.join(`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{d as a,e as b,f as c,g as d,h as e,i as f}from"./chunk-
|
|
2
|
+
import{d as a,e as b,f as c,g as d,h as e,i as f}from"./chunk-M2R464RM.js";import"./chunk-MINZ25AC.js";import"./chunk-DUNCELUK.js";import"./chunk-RX6O3PG4.js";import"./chunk-TZNXL3IO.js";import"./chunk-VRESY4NR.js";import"./chunk-BB5BZ37Y.js";import"./chunk-KJZUBHLO.js";export{d as findReadyFrontend,b as isFrontendReady,a as listFrontendTargets,f as openCommand,e as openFirstFrontend,c as pickReadyFrontend};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
+
import{g as a,h as b,i as c,j as d}from"./chunk-SRN64OPO.js";import"./chunk-YL56J2WX.js";import"./chunk-7HR5PVOD.js";import"./chunk-K6SOCO6V.js";import"./chunk-TZNXL3IO.js";import"./chunk-VRESY4NR.js";import"./chunk-BB5BZ37Y.js";import"./chunk-KJZUBHLO.js";export{c as cloneProjectTemplate,a as enableDiscoveredStacks,d as projectCommand,b as templateTargetDir};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{ca as a,da as b,ea as c,fa as d,ga as e,ha as f,ia as g,ja as h,ka as i,la as j,ma as k,na as l,oa as m,pa as n,qa as o}from"./chunk-
|
|
2
|
+
import{ca as a,da as b,ea as c,fa as d,ga as e,ha as f,ia as g,ja as h,ka as i,la as j,ma as k,na as l,oa as m,pa as n,qa as o}from"./chunk-VRESY4NR.js";import"./chunk-BB5BZ37Y.js";import"./chunk-KJZUBHLO.js";export{m as clearMetadataCache,f as discoverResources,e as discoverResourcesFromRoot,g as discoverResourcesStrict,c as discoverResourcesWithProblems,a as discoverServiceManifestPaths,h as discoverStackNames,j as discoverStacks,i as getAllStacks,n as getResourceMetadata,k as getResourcesForStack,o as getStackMetadata,b as resetPrintedServiceWarnings,l as stackExists,d as warnAboutSkippedFiles};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{a,b,c}from"./chunk-
|
|
2
|
+
import{a,b,c}from"./chunk-7IXBBU27.js";import"./chunk-UJXR6MZ2.js";import"./chunk-RX6O3PG4.js";import"./chunk-TZNXL3IO.js";import"./chunk-VRESY4NR.js";import"./chunk-BB5BZ37Y.js";import"./chunk-KJZUBHLO.js";export{c as classifyTiltPorts,a as findTiltPortOwner,b as isForeignTilt};
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flisk-sh/flisk",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Flisk CLI — start services on your machine.",
|
|
5
5
|
"homepage": "https://flisk.sh",
|
|
6
6
|
"repository": {
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"url": "https://github.com/flisk-sh/flisk/issues"
|
|
12
12
|
},
|
|
13
13
|
"private": false,
|
|
14
|
+
"type": "module",
|
|
14
15
|
"workspaces": [
|
|
15
16
|
"cli"
|
|
16
17
|
],
|
|
@@ -21,11 +22,19 @@
|
|
|
21
22
|
"runtime",
|
|
22
23
|
"!runtime/engine/docs",
|
|
23
24
|
"!runtime/ext/ide-components/code_executor",
|
|
24
|
-
"
|
|
25
|
+
"!runtime/**/__tests__/**",
|
|
26
|
+
"!runtime/**/tests/**",
|
|
27
|
+
"!runtime/**/*.test.*",
|
|
28
|
+
"!runtime/**/*.spec.*",
|
|
29
|
+
"!runtime/**/test_*.py",
|
|
30
|
+
"!runtime/**/*_test.py",
|
|
25
31
|
"examples/tdk-example",
|
|
26
32
|
"cli/bin",
|
|
27
33
|
"cli/dist/**/*.js",
|
|
28
34
|
"cli/dist-bundle/**/*.js",
|
|
35
|
+
"!cli/dist/**/__tests__/**",
|
|
36
|
+
"!cli/dist/**/*.test.js",
|
|
37
|
+
"!cli/dist/**/*.spec.js",
|
|
29
38
|
"cli/templates",
|
|
30
39
|
"cli/package.json",
|
|
31
40
|
"cli/shared-platform-engineering/docker-templates",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
appName: proxy
|
|
2
|
+
appType: infra
|
|
3
|
+
stack: platform
|
|
4
|
+
port: 80
|
|
5
|
+
description: Traefik reverse proxy with dynamic routing
|
|
6
|
+
features:
|
|
7
|
+
- traefik
|
|
8
|
+
healthCheck: False
|
|
9
|
+
dependsOn:
|
|
10
|
+
- database-management
|
|
11
|
+
runtime: docker
|
|
12
|
+
traefik:
|
|
13
|
+
host: traefik.flisk-project.localhost
|
|
14
|
+
pathPrefix: /dashboard
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2026 Flisk Landscape contributors
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
import { execFileSync, spawnSync } from "node:child_process";
|
|
4
|
-
import { cpSync, mkdtempSync } from "node:fs";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
|
-
import { dirname, join, resolve } from "node:path";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { expect } from "vitest";
|
|
9
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
export const repoRoot = resolve(__dirname, "../../../..");
|
|
11
|
-
export const cliBin = join(repoRoot, "cli", "bin", "flisk.js");
|
|
12
|
-
export function runFlisk(args, cwd, input) {
|
|
13
|
-
return execFileSync(process.execPath, [cliBin, ...args], {
|
|
14
|
-
cwd,
|
|
15
|
-
encoding: "utf-8",
|
|
16
|
-
input,
|
|
17
|
-
env: {
|
|
18
|
-
...process.env,
|
|
19
|
-
FLISK_EXTENSION_SOURCE: repoRoot,
|
|
20
|
-
},
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
/** `flisk doctor` exits non-zero on machines without Docker, so read its output either way. */
|
|
24
|
-
export function runFliskAllowFailure(args, cwd) {
|
|
25
|
-
const result = spawnSync(process.execPath, [cliBin, ...args], {
|
|
26
|
-
cwd,
|
|
27
|
-
encoding: "utf-8",
|
|
28
|
-
env: { ...process.env, FLISK_EXTENSION_SOURCE: repoRoot },
|
|
29
|
-
});
|
|
30
|
-
return `${result.stdout}${result.stderr}`;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Copies a project that `flisk project --yes` already generated into a fresh temp directory. Scaffolding costs
|
|
34
|
-
* several seconds per run, so a file generates one base project in `beforeAll` and each test copies it instead.
|
|
35
|
-
* Only use a copy for a test that starts from a generated project; a test that checks generation itself must
|
|
36
|
-
* generate its own.
|
|
37
|
-
*/
|
|
38
|
-
export function copyProject(source) {
|
|
39
|
-
const target = mkdtempSync(join(tmpdir(), "flisk-project-copy-"));
|
|
40
|
-
cpSync(source, target, { recursive: true });
|
|
41
|
-
return target;
|
|
42
|
-
}
|
|
43
|
-
export function starlarkSection(content, name) {
|
|
44
|
-
const start = content.indexOf(`${name} = {`);
|
|
45
|
-
expect(start).toBeGreaterThanOrEqual(0);
|
|
46
|
-
const end = content.indexOf("\n}", start);
|
|
47
|
-
expect(end).toBeGreaterThan(start);
|
|
48
|
-
return content.slice(start, end + 2);
|
|
49
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { renderToString } from "ink";
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
import { LoadingScreen } from "../ui.js";
|
|
5
|
-
describe("ui LoadingScreen", () => {
|
|
6
|
-
it("shows honest text with no percentage", () => {
|
|
7
|
-
const out = renderToString(_jsx(LoadingScreen, { animated: false }));
|
|
8
|
-
expect(out).toContain("Discovering resources...");
|
|
9
|
-
expect(out).not.toContain("%");
|
|
10
|
-
});
|
|
11
|
-
it("renders a spinner frame only when animated", () => {
|
|
12
|
-
expect(renderToString(_jsx(LoadingScreen, { animated: true }))).toMatch(/[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏] Discovering/);
|
|
13
|
-
expect(renderToString(_jsx(LoadingScreen, { animated: false }))).not.toMatch(/[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]/);
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
//# sourceMappingURL=ui-loading-screen.test.js.map
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2026 Flisk Landscape contributors
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
5
|
-
const normalize = (text) => text.replace(/\r\n/g, "\n");
|
|
6
|
-
export const UPDATE_COMMAND = "UPDATE_GOLDEN=1 bun run test -- golden-generated-output";
|
|
7
|
-
/**
|
|
8
|
-
* Compares generated files with the committed golden copies in `goldenDir`. Returns one problem per file that
|
|
9
|
-
* changed, is missing a golden, or has a golden nothing generates any more. With `update` it rewrites the goldens
|
|
10
|
-
* instead and returns nothing, which is how an intentional change is accepted.
|
|
11
|
-
*/
|
|
12
|
-
export function compareWithGolden(actual, goldenDir, update = false) {
|
|
13
|
-
if (update) {
|
|
14
|
-
for (const [name, content] of Object.entries(actual)) {
|
|
15
|
-
const target = join(goldenDir, name);
|
|
16
|
-
mkdirSync(dirname(target), { recursive: true });
|
|
17
|
-
writeFileSync(target, normalize(content));
|
|
18
|
-
}
|
|
19
|
-
for (const stale of staleGoldens(actual, goldenDir)) {
|
|
20
|
-
rmSync(join(goldenDir, stale), { force: true });
|
|
21
|
-
}
|
|
22
|
-
return [];
|
|
23
|
-
}
|
|
24
|
-
const problems = [];
|
|
25
|
-
for (const [name, content] of Object.entries(actual)) {
|
|
26
|
-
const path = join(goldenDir, name);
|
|
27
|
-
if (!existsSync(path)) {
|
|
28
|
-
problems.push(`${name}: no golden file yet`);
|
|
29
|
-
}
|
|
30
|
-
else if (normalize(readFileSync(path, "utf-8")) !== normalize(content)) {
|
|
31
|
-
problems.push(`${name}: generated output differs from its golden file`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
for (const stale of staleGoldens(actual, goldenDir)) {
|
|
35
|
-
problems.push(`${stale}: golden file that nothing generates any more`);
|
|
36
|
-
}
|
|
37
|
-
return problems;
|
|
38
|
-
}
|
|
39
|
-
function staleGoldens(actual, goldenDir) {
|
|
40
|
-
if (!existsSync(goldenDir))
|
|
41
|
-
return [];
|
|
42
|
-
return readdirSync(goldenDir).filter((name) => !(name in actual));
|
|
43
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{c as re,e as se}from"./chunk-K6SOCO6V.js";import{a as ie}from"./chunk-5EZ4EX6U.js";import{T as ee,U as te,ca as K,ga as ne,u as G}from"./chunk-BWK6MPCB.js";import{b as z,f as v,g as k,i as Q,j as I,k as C,l as U,m as Z,n as F,s as u,t as M}from"./chunk-VHFFSBVJ.js";import{a as O}from"./chunk-KJZUBHLO.js";import{appendFileSync as ke,existsSync as H,mkdirSync as ye,readFileSync as Ee,writeFileSync as oe}from"node:fs";import{dirname as Te,resolve as w}from"node:path";function yt(t,e,n){for(let[r,s]of e.entries())console.log(z.blue(`${s.emoji} ${s.description}...`)),s.type==="json"?be(t,s.filename,s.content):ve(t,s.filename,String(s.content)),n&&n(s,r,e.length)}function _e(t,e,n=2){let r=`${JSON.stringify(e,null,n)}
|
|
3
|
-
`;oe(t,r,"utf-8")}function be(t,e,n,r=2){let s=w(t,e);_e(s,n,r)}function q(t,e){oe(t,e,"utf-8")}function ve(t,e,n){let r=w(t,e);q(r,n)}function Et(t){H(t)||ye(t,{recursive:!0})}var we=[".env",".flisk/.flisk-out/",".flisk/.project-id",".flisk/smoke/","node_modules/"];function xe(t){let e=w(t,".gitignore"),n=H(e)?Ee(e,"utf-8"):"",r=new Set(n.split(`
|
|
4
|
-
`).map(d=>d.trim().replace(/\/$/,""))),s=we.filter(d=>!r.has(d.replace(/\/$/,"")));if(s.length===0)return[];let l=n&&!n.endsWith(`
|
|
5
|
-
`)?`
|
|
6
|
-
`:"";return ke(e,`${l}${n?`
|
|
7
|
-
# Flisk (generated files and secrets)
|
|
8
|
-
`:`# Flisk (generated files and secrets)
|
|
9
|
-
`}${s.join(`
|
|
10
|
-
`)}
|
|
11
|
-
`),s}function Ie(t){let e=w(t);for(;;){if(H(w(e,".git")))return!0;let n=Te(e);if(n===e)return!1;e=n}}function Tt(t){if(Ie(t))try{xe(t);return}catch(e){let n=e instanceof Error?e.message:String(e);return`Could not add .flisk/smoke/ to ${w(t,".gitignore")}: ${n}. Git may track the smoke response records.`}}import*as a from"node:fs";import*as i from"node:path";import{fileURLToPath as We}from"node:url";import _ from"handlebars";var Fe="1.0.0",$e={runtime:"bun",bundler:"vite",language:"typescript",framework:"hono",database:"postgresql",orm:"prisma",messaging:"nats",linting:"biome",testing:"vitest"},Re={frontend:{base:u.frontend.base,range:u.frontend.range,start:u.frontend.min,end:u.frontend.max},backend:{base:u.backend.base,range:u.backend.range,start:u.backend.min,end:u.backend.max},health:{base:u.health.base,range:u.health.range,start:u.health.min,end:u.health.max},worker:{base:u.worker.base,range:u.worker.range,start:u.worker.min,end:u.worker.max},migrator:{base:u.migrator.base,range:u.migrator.range,start:u.migrator.min,end:u.migrator.max},tiltUi:M.tiltUi,traefik:M.traefik},Ae={path:"/health",live:"/health/live",ready:"/health/ready",timeout:30,interval:5},je={frontend:"-frontend",backend:"-backend",worker:"-worker",migrator:"-migrator",library:"-lib",sdk:"-sdk",validSeparators:["-","_"],maxLength:63,minLength:3},Pe={entrypoint:"web",network:"traefik-public",defaultHost:"localhost",appHost:"app.localhost",apiHost:"api.localhost",appSubdomainPrefix:"app",apiSubdomainPrefix:"api",defaultPort:8080,tlsEnabled:!1,entrypoints:["web"],middlewares:[],tls:{enabled:!1},healthcheckPath:"/health",healthcheckInterval:"10s",healthcheckTimeout:"5s",frontendPriorityBase:100},De=["node_modules","dist","build",".git",".prisma",".turbo","coverage","tmp","temp","__tests__","test","tests"],Le={frontend:{suffix:"-frontend",portRange:"3000-3999"},backend:{suffix:"-backend",portRange:"4000-4999"},library:{suffix:"-library",portRange:null},sdk:{suffix:"-sdk",portRange:"3000-9999"},migrator:{suffix:"-migrator",portRange:"7000-7999"},worker:{suffix:"-worker",portRange:"6000-6999"}},Ne={prisma:"Database ORM with migrations",nats:"Event streaming via NATS",redis:"Caching layer",infisical:"Secrets management",vitest:"Testing framework",traefik:"HTTP routing",websocket:"Real-time connections",graphql:"GraphQL support",grpc:"gRPC support",viteNode:"Vite Node runtime",maintenance:"Maintenance mode"},Oe={services:"services/product",sharedPlatform:"shared-platform-engineering",sharedProduct:"shared-product-engineering",sharedDdd:"shared-ddd-layers"},Ce={scanIntervalSeconds:5,maxManifestsPerRoot:50,servicePatterns:["services/product/*","services/platform/*"]},Ue={dockerfile:"Dockerfile",context:"."},Me={backend:{command:"bun",args:["run","dev"],env:{NODE_ENV:"development"}},frontend:{command:"bun",args:["run","dev"],env:{NODE_ENV:"development"}}},S={version:Fe,tech:$e,ports:Re,health:Ae,naming:je,traefik:Pe,filewatchIgnores:De,serviceTypes:Le,features:Ne,paths:Oe,discovery:Ce,docker:Ue,runtime:Me};import{existsSync as Ge,lstatSync as Ke}from"node:fs";import{isAbsolute as ae,normalize as R,relative as He,sep as le}from"node:path";var Ft=[`${I}/**`,".flisk/.flisk-out/**","Tiltfile","TILT_*.star",k,`${F} (create only)`,"shared-platform-engineering/docker-templates/**","services/platform/database-management/docker-compose.yml","product_autogenerated_resource_manifests/**","product_autogenerated_services_list/**"];function qe(t){let e=R(t).split(le).join("/");return ae(t)||e===".."||e.startsWith("../")?!1:e.split("/").includes(I)||e.startsWith(".flisk/.flisk-out/")||e==="shared-platform-engineering/docker-templates"||e.startsWith("shared-platform-engineering/docker-templates/")||e.startsWith("product_autogenerated_resource_manifests/")||e.startsWith("product_autogenerated_services_list/")?!0:e==="Tiltfile"||/^TILT_[^/]+\.star$/.test(e)||e===k||e===F||e==="services/platform/database-management/docker-compose.yml"}function T(t,e){let n=ae(e)?R(e):R(`${t}/${e}`),r=He(t,n).split(le).join("/");if(!qe(r))throw new Error(`Refusing to write outside Flisk's generated-file allowlist: ${r}`);let s=t;for(let l of r.split("/"))if(s=R(`${s}/${l}`),Ge(s)&&Ke(s).isSymbolicLink())throw new Error(`Refusing to write through a symbolic link in generated path: ${r}`);return n}import{existsSync as A}from"node:fs";import{join as x}from"node:path";var V=["engine","discovery","specs","ext"],j="runtime";function ce(t,e){let n=x(t,j,e);return A(n)?n:x(t,e)}function fe(t){let e=x(t,j,"Tiltfile");return A(e)?e:x(t,"Tiltfile")}function P(t){let e=["Tiltfile",...V],n=e.filter(o=>A(x(t,j,o))),r=e.filter(o=>A(x(t,o)));if(n.length===0&&r.length===0)return{ok:!1,kind:"incomplete",missing:[...e],mixed:[]};if(n.length===e.length)return{ok:!0,kind:"nested",missing:[],mixed:[]};if(n.length===0){let o=e.filter(d=>!r.includes(d));return o.length===0?{ok:!0,kind:"flat",missing:o,mixed:[]}:{ok:!1,kind:"incomplete",missing:o,mixed:[]}}let s=e.filter(o=>!n.includes(o)),l=s.filter(o=>r.includes(o));return{ok:!1,kind:l.length>0?"mixed":"incomplete",missing:s,mixed:l}}function W(t,e=P(t)){if(e.ok)return`${t}: ${e.kind} layout`;let n=[];e.kind==="mixed"&&n.push(`mixes the nested ${j}/ layout with flat entries (${e.mixed.join(", ")} only at the root)`);let r=e.missing.filter(s=>!e.mixed.includes(s));return r.length>0&&n.push(`is missing ${r.join(", ")}`),`${t} ${n.join(" and ")}`}function D(t){return P(t).ok}var Ve={[v]:{name:v,description:"Generate and load the stack-level PostgreSQL docker-compose file",generatedFiles:["services/platform/database-management/docker-compose.yml"]}};function pe(t,e){return Ve[e]?["pre_alpha","alpha","beta"].some(n=>t[n]?.enabledStacks?.includes(e)):!1}var Je=We(new URL("../dist/generator/template-engine.js",import.meta.url).href),J=i.dirname(Je);function $(t){let e=[i.join(J,"..","..","templates"),i.join(J,"..","templates"),i.join(J,"..","..","..","templates"),i.join(process.cwd(),"node_modules","@flisk-sh","flisk","templates"),i.join(i.dirname(process.execPath),"flisk-cli","cli","templates")],n=[];for(let r of e){let s=i.join(r,t);n.push(s);try{return a.readFileSync(s,"utf-8")}catch{}}throw new Error(`Failed to load template ${t} from any of these paths: ${n.join(", ")}`)}var B=null;function Be(){return B||(B={[k]:$(".tiltignore.hbs"),[U]:$("TILT_RESOURCE_DEFAULTS.star.hbs"),[C]:$("TILT_TECH_STACK.star.hbs"),Tiltfile:$("Tiltfile.hbs"),"spec.master":$("spec.master.hbs")}),B}var Ye={proxy:"Traefik reverse proxy",verdaccio:"Private npm registry","database-management":"PostgreSQL database"},Xe={monitoring:"Signoz, SkyWalking (RAM intensive)",elk:"Elasticsearch/Logstash/Kibana",debezium:"CDC with Kafka/Zookeeper",golden_image:"Golden image rebuild (one-time)",verdaccio:"Premium local npm registry"},ue=["TILT_TECH_STACK.star","TILT_RESOURCE_DEFAULTS.star","spec.master","Tiltfile",".tiltignore"],L=class{templatesDir;constructor(e){let n=O("node:url").fileURLToPath(new URL("../dist/generator",import.meta.url))||i.dirname(new URL(new URL("../dist/generator/template-engine.js",import.meta.url).href).pathname);this.templatesDir=e||i.join(n,"..","..","templates"),this.registerHelpers()}quoteStarlarkString(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}"`}formatStarlarkValue(e){return e==null?"None":typeof e=="string"?this.quoteStarlarkString(e):typeof e=="boolean"?e?"True":"False":typeof e=="number"?String(e):Array.isArray(e)?`[${e.map(r=>this.formatStarlarkValue(r)).join(", ")}]`:typeof e=="object"?`{${Object.entries(e).map(([r,s])=>`${this.quoteStarlarkString(r)}: ${this.formatStarlarkValue(s)}`).join(", ")}}`:String(e)}registerHelpers(){_.registerHelper("starlark",e=>new _.SafeString(this.formatStarlarkValue(e))),_.registerHelper("starlarkArray",e=>{if(!Array.isArray(e))return new _.SafeString("[]");let n=e.map(r=>this.formatStarlarkValue(r));return new _.SafeString(`[${n.join(", ")}]`)}),_.registerHelper("json",e=>JSON.stringify(e))}buildContext(e){return{version:S.version,tech:S.tech,ports:S.ports,health:S.health,naming:S.naming,traefik:S.traefik,filewatchIgnores:[...S.filewatchIgnores],serviceTypes:S.serviceTypes,paths:S.paths,discovery:{scanIntervalSeconds:S.discovery.scanIntervalSeconds,maxManifestsPerRoot:S.discovery.maxManifestsPerRoot,paths:e.discovery.paths},docker:S.docker,runtime:S.runtime,project:e.project,phases:ze(e.phases),alwaysEnabledInfra:e.always_enabled_infra??[...ie],optionalInfra:e.optional_infra,serviceDescriptions:Ye,infraDescriptions:Xe}}loadTemplate(e){let n=i.join(this.templatesDir,`${e}.hbs`),r=a.existsSync(n)?a.readFileSync(n,"utf-8"):Be()[e];if(!r)throw new Error(`Template not found: ${n}`);return _.compile(r)}generateTechStack(e){return this.loadTemplate(C)(e)}generateServiceDefaults(e){return this.loadTemplate(U)(e)}generateSpecMaster(e){return this.loadTemplate("spec.master")(e)}generateTiltfile(e){return this.loadTemplate("Tiltfile")(e)}generateTiltIgnore(e){return this.loadTemplate(".tiltignore")(e)}generateAll(e){let n=this.buildContext(e);return{"TILT_TECH_STACK.star":this.generateTechStack(n),"TILT_RESOURCE_DEFAULTS.star":this.generateServiceDefaults(n),"spec.master":this.generateSpecMaster(n),Tiltfile:this.generateTiltfile(n),".tiltignore":this.generateTiltIgnore(n)}}};function ze(t){let e={...t};for(let n of Object.keys(e))e[n]={...e[n],enabledStacks:Array.from(new Set(e[n].enabledStacks))};return e}function Qe(t){return t.replace(/-/g,"_")}function Ze(t){let e=Qe(t.project.name||"flisk_project");return`###############################################################################
|
|
12
|
-
# SYSTEM-GENERATED - DO NOT EDIT
|
|
13
|
-
# Stack feature: database-management
|
|
14
|
-
# Source: .flisk/project.json phases.*.enabledStacks includes "database-management"
|
|
15
|
-
# Regenerate with: flisk config regenerate
|
|
16
|
-
###############################################################################
|
|
17
|
-
|
|
18
|
-
services:
|
|
19
|
-
postgres:
|
|
20
|
-
image: postgres:16-alpine
|
|
21
|
-
container_name: ${e}_postgres
|
|
22
|
-
restart: unless-stopped
|
|
23
|
-
environment:
|
|
24
|
-
POSTGRES_USER: ${e}
|
|
25
|
-
POSTGRES_PASSWORD: \${DB_PASSWORD}
|
|
26
|
-
POSTGRES_DB: postgres
|
|
27
|
-
ports:
|
|
28
|
-
- "\${FLISK_BIND_ADDRESS:-127.0.0.1}:\${FLISK_POSTGRES_PORT:-15432}:5432"
|
|
29
|
-
volumes:
|
|
30
|
-
- ${e}_postgres_data:/var/lib/postgresql/data
|
|
31
|
-
networks:
|
|
32
|
-
- database
|
|
33
|
-
healthcheck:
|
|
34
|
-
test: ["CMD-SHELL", "pg_isready -U ${e} -d postgres"]
|
|
35
|
-
interval: 5s
|
|
36
|
-
timeout: 5s
|
|
37
|
-
retries: 20
|
|
38
|
-
|
|
39
|
-
networks:
|
|
40
|
-
database:
|
|
41
|
-
name: ${e}_database
|
|
42
|
-
external: true
|
|
43
|
-
|
|
44
|
-
volumes:
|
|
45
|
-
${e}_postgres_data:
|
|
46
|
-
`}function de(t,e){if(!t||typeof t!="object")return!1;let n=t;for(let r of["pre_alpha","alpha","beta","out_of_scope"]){let s=n[r];if(!s||typeof s!="object"||!Array.isArray(s[e]))return!1}return!0}function et(t){if(!t||typeof t!="object")return null;let e=t;if(typeof e.version!="string"||!e.project||typeof e.project!="object")return null;let n=e.project;if(typeof n.name!="string"||typeof n.version!="string")return null;let r=null;if(de(e.phases,"enabledStacks"))r=e.phases;else if(de(e.stacks,"services")){let o=e.stacks;r={pre_alpha:{name:o.pre_alpha.name,description:o.pre_alpha.description,enabledStacks:o.pre_alpha.services},alpha:{name:o.alpha.name,description:o.alpha.description,enabledStacks:o.alpha.services},beta:{name:o.beta.name,description:o.beta.description,enabledStacks:o.beta.services},out_of_scope:{name:o.out_of_scope.name,description:o.out_of_scope.description,enabledStacks:o.out_of_scope.services}}}if(!r||!e.optional_infra||typeof e.optional_infra!="object")return null;let s=e.optional_infra;if(typeof s.monitoring!="boolean"||typeof s.elk!="boolean"||typeof s.debezium!="boolean"||typeof s.golden_image!="boolean"||typeof s.verdaccio!="boolean"||!e.discovery||typeof e.discovery!="object")return null;let l=e.discovery;return Array.isArray(l.paths)?{version:e.version,project:e.project,phases:r,always_enabled_infra:e.always_enabled_infra,optional_infra:e.optional_infra,discovery:e.discovery,overrides:e.overrides}:null}var Y=class extends Error{};function me(t){let e=i.join(t,".flisk",Z),n;try{n=a.readFileSync(e,"utf-8")}catch(l){if(l?.code==="ENOENT")throw new Y(`Project config not found: ${e}. Run 'flisk project --yes' first.`);let o=l instanceof Error?l.message:String(l);throw new Error(`Could not read project.json at ${e}: ${o}`)}let r;try{r=JSON.parse(n)}catch(l){let o=l instanceof Error?l.message:String(l);throw new Error(`Could not parse project.json at ${e}: ${o}`)}let s=et(r);if(!s)throw new Error("Invalid project.json: missing or invalid required fields. Expected: version (string), project (object with name/version), phases (object with pre_alpha/alpha/beta/out_of_scope enabledStacks), optional_infra (object with boolean flags), discovery (object with paths array)");return s}async function tt(t){let e=ne(t).filter(r=>r.config?.sablier?.enable===!0);e.length===0||await se(t)||console.warn(`\u26A0\uFE0F Sablier (on-demand scaling) is a Premium feature - no valid license key found. ${e.length} resource${e.length===1?" has":"s have"} a \`sablier\` block, but it will have no effect without a license. Set FLISK_LICENSE_KEY to a key that grants it, or remove the \`sablier\` block from the affected service.json file(s) to silence this warning.`)}function nt(t,e){let n=T(t,F);if(a.existsSync(n))return!1;let r={name:e.project.name||i.basename(t),version:e.project.version||"1.0.0",private:!0,type:"module",workspaces:e.discovery.paths};return q(n,`${JSON.stringify(r,null,2)}
|
|
47
|
-
`),!0}async function Bt(t,e={}){let n=me(t),r=K(t).flatMap(p=>ee(p,i.relative(t,p).split(i.sep).join("/")));if(r.length>0)throw new Error(`Refusing to generate config from unsafe service.json values:
|
|
48
|
-
${r.map(p=>` ${p}`).join(`
|
|
49
|
-
`)}`);await tt(t),nt(t,n)&&!e.quiet&&console.log("\u2713 Generated: package.json (workspace root)");let s=Object.values(n.phases).some(p=>p.enabledStacks.includes("verdaccio"));(n.optional_infra.verdaccio||s)&&(await re(t)||console.warn("\u26A0\uFE0F Verdaccio is a Premium feature - no valid license key found. It's enabled in this project's config, but will have no effect without a license. Set FLISK_LICENSE_KEY to a key that grants it, or run `flisk config disable-infra verdaccio` to silence this warning."));let l=i.join(t,".flisk",".flisk-out");a.existsSync(l)||a.mkdirSync(l,{recursive:!0});let d=new L().generateAll(n);for(let p of ue){let m=d[p],b=T(t,i.join(".flisk",".flisk-out",p));G(b,m),e.quiet||console.log(`\u2713 Generated: .flisk/.flisk-out/${p}`)}if(pe(n.phases,v)){let p=T(t,i.join("services","platform",v,Q)),m=i.dirname(p);a.mkdirSync(m,{recursive:!0}),G(p,Ze(n)),e.quiet||console.log("\u2713 Generated: services/platform/database-management/docker-compose.yml")}let f=i.join(l,k),c=T(t,k);if(a.existsSync(f)){if(!a.existsSync(c))a.copyFileSync(f,c),e.quiet||console.log("\u2713 Copied: .tiltignore \u2192 project root");else if(e.discardHandEdits){let p=a.readFileSync(c,"utf-8");p.includes(Se)&&p!==a.readFileSync(f,"utf-8")&&(a.copyFileSync(f,c),e.quiet||console.log("\u2713 Restored: .tiltignore \u2192 project root (hand edits discarded)"))}}let h=ct(t);if(!e.quiet)for(let p of h)console.log(`\u2713 Copied: ${p} \u2192 project root`);await ft(t,{quiet:e.quiet}),e.quiet||(console.log(""),console.log("\u{1F4A1} To start Tilt: flisk up"))}var rt=/\.(?:test|spec)\.[cm]?[jt]sx?$/;function he(t){return rt.test(t)}function ge(t){if(a.existsSync(t))for(let e of a.readdirSync(t,{withFileTypes:!0})){let n=i.join(t,e.name);e.isDirectory()?ge(n):he(n)&&a.rmSync(n,{force:!0})}}var st=V,it=[["shared-platform-engineering","docker-templates"]],ot=["install-deps.sh","bun-hoisted-symlink-fix.sh","prisma-bun-client-link-fix.sh","prisma-normalize-client.sh"];function at(){let t=O("node:url").fileURLToPath(new URL("../dist/generator",import.meta.url))||process.cwd();for(let e=0;e<6;e++){if(D(t))return t;let n=i.dirname(t);if(n===t)break;t=n}return null}function lt(){let t=O("node:url").fileURLToPath(new URL("../dist/generator",import.meta.url))||process.cwd();for(let r=0;r<8;r++){if(a.existsSync(i.join(t,"shared-platform-engineering","docker-templates")))return t;let s=i.dirname(t);if(s===t)break;t=s}let e=i.dirname(process.execPath);return[i.join(e,"flisk-cli"),i.join(process.cwd(),"node_modules","@flisk-sh","flisk")].find(r=>a.existsSync(i.join(r,"shared-platform-engineering","docker-templates")))??null}function ct(t){let e=lt(),n=[];if(!e)return console.warn("\u26A0\uFE0F Flisk runtime assets not found - generated Dockerfiles may fail. Reinstall or upgrade Flisk, then re-run `flisk project`."),n;for(let r of it){let s=i.join(e,...r),l=T(t,i.join(...r));a.existsSync(s)&&(a.mkdirSync(i.dirname(l),{recursive:!0}),a.cpSync(s,l,{recursive:!0}),n.push(r.join("/")))}for(let r of ot){let s=i.join(t,"shared-platform-engineering","docker-templates",r);a.existsSync(s)||console.warn(`\u26A0\uFE0F Missing runtime asset after copy: ${s}`)}return n}async function ft(t,e={}){let n=T(t,i.join(".flisk",".flisk-out","flisk-cli-ext")),r=[];process.env.FLISK_EXTENSION_SOURCE&&r.push(process.env.FLISK_EXTENSION_SOURCE);let s=at();s&&r.push(s);let l=i.dirname(process.execPath);r.push(i.join(l,"flisk-cli")),r.push(i.join(t,"..","flisk-cli"));let o=process.env.FLISK_EXTENSION_SOURCE;o&&a.existsSync(o)&&!D(o)&&console.warn(`\u26A0\uFE0F FLISK_EXTENSION_SOURCE is not a usable Flisk extension and is ignored:
|
|
50
|
-
${W(o)}`);let d="";for(let f of r)if(f&&D(f)){d=f;break}if(!d){let f=r.filter(c=>c&&a.existsSync(c)).map(c=>({candidate:c,report:P(c)})).filter(({report:c})=>c.kind==="mixed"||c.missing.length<5);console.warn("\u26A0\uFE0F Flisk extension not found - set FLISK_EXTENSION_SOURCE to its checkout path and re-run `flisk project` (or `flisk config regenerate`) to vendor it before `flisk up`."+f.map(({candidate:c,report:h})=>`
|
|
51
|
-
${W(c,h)}`).join(""));return}a.existsSync(n)||a.mkdirSync(n,{recursive:!0}),a.copyFileSync(fe(d),i.join(n,"Tiltfile"));for(let f of st)ge(i.join(n,f)),a.cpSync(ce(d,f),i.join(n,f),{recursive:!0,filter:c=>!he(c)});e.quiet||console.log("\u2713 Vendored Flisk extension \u2192 .flisk/.flisk-out/flisk-cli-ext/");try{let{applyPremiumOverlay:f}=await import("./extension-fetch-VEFSCG4B.js");await f(t,n)}catch(f){console.warn(`\u26A0\uFE0F Premium overlay skipped: ${f.message}`)}}var Se="SYSTEM-GENERATED BY Flisk CLI";function Yt(t,e){let n=[],r=[],s=[],l=[],o=(g,E,y)=>{E!==y&&(n.push(`${E===void 0?"Missing file":"Out of sync"}: ${g} (run 'flisk config regenerate')`),s.push({file:g,diff:pt(g,E??"",y)}))},d=me(t),c=new L().generateAll(d),h=i.join(t,".flisk",".flisk-out");for(let g of ue){let E=c[g],y=i.join(h,g);o(`.flisk/.flisk-out/${g}`,a.existsSync(y)?a.readFileSync(y,"utf-8"):void 0,E)}let p=i.join(t,k),m=a.existsSync(p)?a.readFileSync(p,"utf-8"):void 0;m!==void 0&&!m.includes(Se)?r.push(".tiltignore: not generated by Flisk, left as is"):o(k,m,c[k]);let b=e?.manifestPaths??K(t);for(let g of b){let E=i.relative(t,g).split(i.sep).join("/");if(!e?.skipManifestValidation){let X=te(g,E);n.push(...X.errors),r.push(...X.warnings)}let y=dt(t,g);n.push(...y.errors),l.push(...y.handEdited)}return{valid:n.length===0,errors:n,warnings:r,diffs:s,handEdited:l}}function pt(t,e,n){let r=e.replace(/\n$/,"").split(`
|
|
52
|
-
`),s=n.replace(/\n$/,"").split(`
|
|
53
|
-
`),l=[`--- a/${t}`,`+++ b/${t}`,`@@ -1,${r.length} +1,${s.length} @@`];for(let o of r)l.push(`-${o}`);for(let o of s)l.push(`+${o}`);return l.join(`
|
|
54
|
-
`)}function dt(t,e){let n=i.dirname(e),r=i.join(n,I);if(!a.existsSync(r))return{errors:[],handEdited:[]};let s=[],l=(h,p="")=>{for(let m of a.readdirSync(h,{withFileTypes:!0})){if(p===""&&m.name===".flisk-contract")continue;let b=i.join(p,m.name),g=i.join(h,m.name);m.isDirectory()?l(g,b):m.isFile()&&s.push({fullPath:g,relativeFile:b})}};if(l(r),s.length===0)return{errors:[],handEdited:[]};let o=i.join(r,".flisk-contract"),d=i.join(o,"service.json.source"),f=[],c=[];a.existsSync(d)?a.readFileSync(d,"utf-8")!==a.readFileSync(e,"utf-8")&&f.push(i.relative(t,e)+": service.json changed since generated outputs were written (run flisk up)"):f.push(i.relative(t,d)+": generated-file contract snapshot is missing (run flisk up to regenerate)");for(let h of s){if(h.relativeFile==="service.yaml")continue;let p=i.join(o,h.relativeFile),m=i.relative(t,h.fullPath);a.existsSync(p)?a.readFileSync(h.fullPath,"utf-8")!==a.readFileSync(p,"utf-8")&&(c.push(m.split(i.sep).join("/")),f.push(`${m}: generated file differs from its Flisk snapshot (run flisk up to regenerate)`)):f.push(`${m}: generated-file snapshot is missing (run flisk up to regenerate)`)}return{errors:f,handEdited:c}}import{stdin as ut,stdout as mt}from"node:process";import{createInterface as ht}from"node:readline/promises";async function N(t){let e=ht({input:ut,output:mt});try{return await new Promise((n,r)=>{e.once("close",()=>r(new Error("No input available to answer the prompt. Run this in a terminal."))),e.question(t).then(s=>n(s.trim()),r)})}finally{e.close()}}async function Zt(t){let e=t.initial?` (${t.initial})`:"";for(;;){let r=await N(`${t.message}${e} `)||t.initial||"",s=t.validate?.(r)??!0;if(s===!0)return r;console.log(s)}}async function en(t){let e=t.initial??!0,n=e?"Y/n":"y/N";for(;;){let r=(await N(`${t.message} (${n}) `)).toLowerCase();if(!r)return e;if(["y","yes"].includes(r))return!0;if(["n","no"].includes(r))return!1;console.log("Please answer yes or no.")}}async function tn(t){for(console.log(t.message),t.choices.forEach((e,n)=>{console.log(` ${n+1}. ${e.title}`)});;){let e=await N("Choose one: "),n=Number.parseInt(e,10)-1,r=t.choices[n];if(r)return r.value;console.log(`Enter a number from 1 to ${t.choices.length}.`)}}async function nn(t){let e=t.choices.map((r,s)=>r.selected?s+1:null).filter(r=>r!==null),n=e.length>0?` [${e.join(",")}]`:"";for(console.log(t.message),t.choices.forEach((r,s)=>{let l=r.selected?"*":" ";console.log(` ${l} ${s+1}. ${r.title}`)});;){let r=await N(`Choose one or more numbers, comma-separated${n}: `),s=e;if(r){let d=r.split(",").map(c=>c.trim()),f=d.find(c=>{if(!/^\d+$/.test(c))return!0;let h=Number.parseInt(c,10);return!t.choices[h-1]});if(f!==void 0){console.log(`"${f}" is not a valid choice (1-${t.choices.length})`);continue}s=d.map(c=>Number.parseInt(c,10))}let l=Array.from(new Set(s)).map(d=>t.choices[d-1]).filter(d=>!!d).map(d=>d.value),o=t.validate?.(l)??!0;if(o===!0)return l;console.log(o)}}export{yt as a,_e as b,Et as c,xe as d,Tt as e,V as f,ce as g,fe as h,P as i,W as j,$ as k,L as l,Y as m,me as n,Bt as o,lt as p,ct as q,Yt as r,Zt as s,en as t,tn as u,nn as v};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{g as a,h as b,i as c,j as d}from"./chunk-ICXF6PXA.js";import"./chunk-YL56J2WX.js";import"./chunk-763VK575.js";import"./chunk-K6SOCO6V.js";import"./chunk-5EZ4EX6U.js";import"./chunk-BWK6MPCB.js";import"./chunk-VHFFSBVJ.js";import"./chunk-KJZUBHLO.js";export{c as cloneProjectTemplate,a as enableDiscoveredStacks,d as projectCommand,b as templateTargetDir};
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# Copyright (c) 2026 Flisk Landscape contributors
|
|
3
|
-
# SPDX-License-Identifier: MIT
|
|
4
|
-
"""
|
|
5
|
-
🧪 Tests for resource_snapshot.py
|
|
6
|
-
|
|
7
|
-
Run with: python3 -m pytest test_resource_snapshot.py -v
|
|
8
|
-
Or: python3 test_resource_snapshot.py
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import json
|
|
12
|
-
import os
|
|
13
|
-
import sys
|
|
14
|
-
import tempfile
|
|
15
|
-
import shutil
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
import pytest
|
|
18
|
-
|
|
19
|
-
# Add parent directory to path
|
|
20
|
-
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
21
|
-
|
|
22
|
-
from resource_snapshot import (
|
|
23
|
-
save_snapshot,
|
|
24
|
-
load_snapshot,
|
|
25
|
-
diff_snapshots,
|
|
26
|
-
get_current_services,
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@pytest.fixture
|
|
31
|
-
def temp_workspace(tmp_path):
|
|
32
|
-
"""Provide a temporary workspace with automatic cleanup."""
|
|
33
|
-
original_dir = os.getcwd()
|
|
34
|
-
os.chdir(tmp_path)
|
|
35
|
-
yield tmp_path
|
|
36
|
-
os.chdir(original_dir)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class TestSaveSnapshot:
|
|
40
|
-
"""Tests for save_snapshot function."""
|
|
41
|
-
|
|
42
|
-
def test_save_creates_file(self, temp_workspace):
|
|
43
|
-
"""Test that save_snapshot creates the snapshot file."""
|
|
44
|
-
services = ["services/a/service.json", "services/b/service.json"]
|
|
45
|
-
save_snapshot(services)
|
|
46
|
-
|
|
47
|
-
snapshot_file = Path(".flisk/.flisk-out/snapshots/resource-snapshot.json")
|
|
48
|
-
assert snapshot_file.exists(), "Snapshot file should be created"
|
|
49
|
-
|
|
50
|
-
# Verify content
|
|
51
|
-
with open(snapshot_file) as f:
|
|
52
|
-
data = json.load(f)
|
|
53
|
-
assert data["count"] == 2
|
|
54
|
-
assert data["services"] == services
|
|
55
|
-
assert "timestamp" in data
|
|
56
|
-
|
|
57
|
-
def test_save_creates_directory(self, temp_workspace):
|
|
58
|
-
"""Test that save_snapshot creates the .flisk directory if needed."""
|
|
59
|
-
services = ["services/test/service.json"]
|
|
60
|
-
save_snapshot(services)
|
|
61
|
-
|
|
62
|
-
assert Path(".flisk/.flisk-out/snapshots").exists(), ".flisk/.flisk-out/snapshots directory should be created"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class TestLoadSnapshot:
|
|
66
|
-
"""Tests for load_snapshot function."""
|
|
67
|
-
|
|
68
|
-
def test_load_existing(self, temp_workspace):
|
|
69
|
-
"""Test loading an existing snapshot."""
|
|
70
|
-
# Create a snapshot first
|
|
71
|
-
services = ["services/a/service.json"]
|
|
72
|
-
save_snapshot(services)
|
|
73
|
-
|
|
74
|
-
# Load it
|
|
75
|
-
snapshot = load_snapshot()
|
|
76
|
-
|
|
77
|
-
assert snapshot["count"] == 1
|
|
78
|
-
assert snapshot["services"] == services
|
|
79
|
-
assert "timestamp" in snapshot
|
|
80
|
-
|
|
81
|
-
def test_load_nonexistent(self, temp_workspace):
|
|
82
|
-
"""Test loading when snapshot doesn't exist."""
|
|
83
|
-
snapshot = load_snapshot()
|
|
84
|
-
|
|
85
|
-
assert snapshot["count"] == 0
|
|
86
|
-
assert snapshot["services"] == []
|
|
87
|
-
assert snapshot["timestamp"] is None
|
|
88
|
-
|
|
89
|
-
def test_load_invalid_json(self, temp_workspace):
|
|
90
|
-
"""Test loading when snapshot has invalid JSON."""
|
|
91
|
-
# Create invalid snapshot
|
|
92
|
-
Path(".flisk/.flisk-out/snapshots").mkdir(parents=True, exist_ok=True)
|
|
93
|
-
with open(".flisk/.flisk-out/snapshots/resource-snapshot.json", "w") as f:
|
|
94
|
-
f.write("not valid json")
|
|
95
|
-
|
|
96
|
-
snapshot = load_snapshot()
|
|
97
|
-
|
|
98
|
-
# Should return empty snapshot on error
|
|
99
|
-
assert snapshot["count"] == 0
|
|
100
|
-
assert snapshot["services"] == []
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
class TestDiffSnapshots:
|
|
104
|
-
"""Tests for diff_snapshots function."""
|
|
105
|
-
|
|
106
|
-
def test_detect_added(self):
|
|
107
|
-
"""Test detecting added services."""
|
|
108
|
-
old = {"services": ["a/service.json", "b/service.json"]}
|
|
109
|
-
new = ["a/service.json", "b/service.json", "c/service.json"]
|
|
110
|
-
|
|
111
|
-
added, removed, modified = diff_snapshots(old, new)
|
|
112
|
-
|
|
113
|
-
assert added == {"c/service.json"}
|
|
114
|
-
assert removed == set()
|
|
115
|
-
assert modified == set()
|
|
116
|
-
|
|
117
|
-
def test_detect_removed(self):
|
|
118
|
-
"""Test detecting removed services."""
|
|
119
|
-
old = {"services": ["a/service.json", "b/service.json", "c/service.json"]}
|
|
120
|
-
new = ["a/service.json", "b/service.json"]
|
|
121
|
-
|
|
122
|
-
added, removed, modified = diff_snapshots(old, new)
|
|
123
|
-
|
|
124
|
-
assert added == set()
|
|
125
|
-
assert removed == {"c/service.json"}
|
|
126
|
-
assert modified == set()
|
|
127
|
-
|
|
128
|
-
def test_detect_both(self):
|
|
129
|
-
"""Test detecting both added and removed."""
|
|
130
|
-
old = {"services": ["a/service.json", "b/service.json"]}
|
|
131
|
-
new = ["b/service.json", "c/service.json"]
|
|
132
|
-
|
|
133
|
-
added, removed, modified = diff_snapshots(old, new)
|
|
134
|
-
|
|
135
|
-
assert added == {"c/service.json"}
|
|
136
|
-
assert removed == {"a/service.json"}
|
|
137
|
-
assert modified == set()
|
|
138
|
-
|
|
139
|
-
def test_no_changes(self):
|
|
140
|
-
"""Test when nothing changed."""
|
|
141
|
-
old = {"services": ["a/service.json", "b/service.json"]}
|
|
142
|
-
new = ["a/service.json", "b/service.json"]
|
|
143
|
-
|
|
144
|
-
added, removed, modified = diff_snapshots(old, new)
|
|
145
|
-
|
|
146
|
-
assert added == set()
|
|
147
|
-
assert removed == set()
|
|
148
|
-
assert modified == set()
|
|
149
|
-
|
|
150
|
-
def test_empty_old(self):
|
|
151
|
-
"""Test when old snapshot is empty."""
|
|
152
|
-
old = {"services": []}
|
|
153
|
-
new = ["a/service.json", "b/service.json"]
|
|
154
|
-
|
|
155
|
-
added, removed, modified = diff_snapshots(old, new)
|
|
156
|
-
|
|
157
|
-
assert added == {"a/service.json", "b/service.json"}
|
|
158
|
-
assert removed == set()
|
|
159
|
-
assert modified == set()
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
class TestGetCurrentServices:
|
|
163
|
-
"""Tests for get_current_services function."""
|
|
164
|
-
|
|
165
|
-
def test_finds_services(self, temp_workspace):
|
|
166
|
-
"""Test finding service.json files."""
|
|
167
|
-
# Create test directory structure
|
|
168
|
-
(Path("services/product/a") / "a-backend").mkdir(parents=True)
|
|
169
|
-
(Path("services/product/a") / "a-backend" / "service.json").touch()
|
|
170
|
-
|
|
171
|
-
(Path("services/product/b") / "b-backend").mkdir(parents=True)
|
|
172
|
-
(Path("services/product/b") / "b-backend" / "service.json").touch()
|
|
173
|
-
|
|
174
|
-
services = get_current_services("services/product")
|
|
175
|
-
|
|
176
|
-
assert len(services) == 2
|
|
177
|
-
assert all("service.json" in s for s in services)
|
|
178
|
-
|
|
179
|
-
def test_empty_result(self, temp_workspace):
|
|
180
|
-
"""Test when no services exist."""
|
|
181
|
-
# Create empty directory
|
|
182
|
-
Path("services/product").mkdir(parents=True)
|
|
183
|
-
|
|
184
|
-
services = get_current_services("services/product")
|
|
185
|
-
|
|
186
|
-
assert services == []
|
|
187
|
-
|
|
188
|
-
def test_nonexistent_root(self, temp_workspace):
|
|
189
|
-
"""Test when scan root doesn't exist."""
|
|
190
|
-
services = get_current_services("nonexistent/path")
|
|
191
|
-
|
|
192
|
-
assert services == []
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
def run_tests():
|
|
196
|
-
"""Run all tests with basic output."""
|
|
197
|
-
import tempfile
|
|
198
|
-
import inspect
|
|
199
|
-
|
|
200
|
-
print("🧪 Running resource_snapshot tests...")
|
|
201
|
-
print("=" * 50)
|
|
202
|
-
|
|
203
|
-
passed = 0
|
|
204
|
-
failed = 0
|
|
205
|
-
|
|
206
|
-
test_classes = [
|
|
207
|
-
TestSaveSnapshot,
|
|
208
|
-
TestLoadSnapshot,
|
|
209
|
-
TestDiffSnapshots,
|
|
210
|
-
TestGetCurrentServices,
|
|
211
|
-
]
|
|
212
|
-
|
|
213
|
-
for test_class in test_classes:
|
|
214
|
-
print(f"\n📦 {test_class.__name__}")
|
|
215
|
-
|
|
216
|
-
# Get all test methods
|
|
217
|
-
for method_name in dir(test_class):
|
|
218
|
-
if method_name.startswith("test_"):
|
|
219
|
-
test_method = getattr(test_class(), method_name)
|
|
220
|
-
|
|
221
|
-
# Check if method needs tmp_path parameter
|
|
222
|
-
sig = inspect.signature(test_method)
|
|
223
|
-
needs_tmp_path = len(sig.parameters) > 0
|
|
224
|
-
|
|
225
|
-
# Create temp directory for test
|
|
226
|
-
with tempfile.TemporaryDirectory() as tmp_dir:
|
|
227
|
-
try:
|
|
228
|
-
if needs_tmp_path:
|
|
229
|
-
test_method(Path(tmp_dir))
|
|
230
|
-
else:
|
|
231
|
-
test_method()
|
|
232
|
-
print(f" ✓ {method_name}")
|
|
233
|
-
passed += 1
|
|
234
|
-
except AssertionError as e:
|
|
235
|
-
print(f" ✗ {method_name}: {e}")
|
|
236
|
-
failed += 1
|
|
237
|
-
except Exception as e:
|
|
238
|
-
print(f" ✗ {method_name}: Exception - {e}")
|
|
239
|
-
failed += 1
|
|
240
|
-
|
|
241
|
-
print("\n" + "=" * 50)
|
|
242
|
-
print(f"📊 Results: {passed} passed, {failed} failed")
|
|
243
|
-
|
|
244
|
-
if failed == 0:
|
|
245
|
-
print("🎉 All tests passed!")
|
|
246
|
-
return 0
|
|
247
|
-
else:
|
|
248
|
-
print(f"⚠️ {failed} test(s) failed")
|
|
249
|
-
return 1
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if __name__ == "__main__":
|
|
253
|
-
sys.exit(run_tests())
|