@pulumix/core 0.9.0 → 0.10.0
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/dist/dev/env-compute.d.ts +15 -0
- package/dist/dev/env-compute.d.ts.map +1 -0
- package/dist/dev/env-compute.js +92 -0
- package/dist/dev/env-compute.js.map +1 -0
- package/dist/dev/index.d.ts +1 -9
- package/dist/dev/index.d.ts.map +1 -1
- package/dist/dev/index.js +91 -211
- package/dist/dev/index.js.map +1 -1
- package/dist/dev/local-runner.d.ts.map +1 -1
- package/dist/dev/local-runner.js +0 -1
- package/dist/dev/local-runner.js.map +1 -1
- package/dist/dev/port-forward.d.ts +1 -1
- package/dist/dev/port-forward.d.ts.map +1 -1
- package/dist/dev/port-forward.js +43 -28
- package/dist/dev/port-forward.js.map +1 -1
- package/dist/dev/types.d.ts +4 -22
- package/dist/dev/types.d.ts.map +1 -1
- package/dist/dev/types.js +1 -24
- package/dist/dev/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/k8s/client.d.ts +8 -0
- package/dist/k8s/client.d.ts.map +1 -0
- package/dist/k8s/client.js +48 -0
- package/dist/k8s/client.js.map +1 -0
- package/dist/k8s/index.d.ts +5 -0
- package/dist/k8s/index.d.ts.map +1 -0
- package/dist/k8s/index.js +12 -0
- package/dist/k8s/index.js.map +1 -0
- package/dist/k8s/inspect.d.ts +40 -0
- package/dist/k8s/inspect.d.ts.map +1 -0
- package/dist/k8s/inspect.js +133 -0
- package/dist/k8s/inspect.js.map +1 -0
- package/dist/orchestrator/index.d.ts +10 -0
- package/dist/orchestrator/index.d.ts.map +1 -1
- package/dist/orchestrator/index.js +247 -167
- package/dist/orchestrator/index.js.map +1 -1
- package/package.json +3 -2
|
@@ -65,9 +65,10 @@ const resolveBackendUrl = (rootPath, projectConfig, stackName) => {
|
|
|
65
65
|
switch (backend.type) {
|
|
66
66
|
case 'file': {
|
|
67
67
|
const backendPath = backend.path ?? 'dist/';
|
|
68
|
-
const
|
|
68
|
+
const base = path.isAbsolute(backendPath)
|
|
69
69
|
? backendPath
|
|
70
70
|
: path.join(rootPath, backendPath);
|
|
71
|
+
const absolutePath = path.join(base, stackName);
|
|
71
72
|
return `file://${absolutePath}`;
|
|
72
73
|
}
|
|
73
74
|
case 's3': {
|
|
@@ -90,7 +91,7 @@ const resolveBackendUrl = (rootPath, projectConfig, stackName) => {
|
|
|
90
91
|
return 'https://app.pulumi.com';
|
|
91
92
|
}
|
|
92
93
|
default: {
|
|
93
|
-
const defaultPath = path.join(rootPath, 'dist/');
|
|
94
|
+
const defaultPath = path.join(rootPath, 'dist/', stackName);
|
|
94
95
|
return `file://${defaultPath}`;
|
|
95
96
|
}
|
|
96
97
|
}
|
|
@@ -100,11 +101,12 @@ const resolveWorkDir = (rootPath, projectConfig, stackName) => {
|
|
|
100
101
|
const backend = stackConfig?.backend ?? projectConfig.backend ?? DEFAULT_BACKEND;
|
|
101
102
|
if (backend.type === 'file') {
|
|
102
103
|
const backendPath = backend.path ?? 'dist/';
|
|
103
|
-
|
|
104
|
+
const base = path.isAbsolute(backendPath)
|
|
104
105
|
? backendPath
|
|
105
106
|
: path.join(rootPath, backendPath);
|
|
107
|
+
return path.join(base, stackName);
|
|
106
108
|
}
|
|
107
|
-
return path.join(rootPath, 'dist/');
|
|
109
|
+
return path.join(rootPath, 'dist/', stackName);
|
|
108
110
|
};
|
|
109
111
|
const parseYamlFile = (filePath) => {
|
|
110
112
|
try {
|
|
@@ -444,150 +446,187 @@ class Orchestrator {
|
|
|
444
446
|
}
|
|
445
447
|
return (0, Either_1.Right)(undefined);
|
|
446
448
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
];
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
449
|
+
async prepareDeployment(config, liftEither, throwE) {
|
|
450
|
+
this.eventEmitter.emitPhaseStart('configuration');
|
|
451
|
+
const rootConfigPath = path.join(config.rootPath, 'pulumix.yaml');
|
|
452
|
+
const rawConfig = await liftEither(parseYamlFile(rootConfigPath));
|
|
453
|
+
const rootConfig = await liftEither((0, project_1.validateProjectConfig)(rawConfig, rootConfigPath));
|
|
454
|
+
const stacks = rootConfig.stacks ?? {};
|
|
455
|
+
const globalConfig = stacks[config.stackName] ?? {};
|
|
456
|
+
this.eventEmitter.emitPhaseComplete('configuration');
|
|
457
|
+
this.eventEmitter.emitPhaseStart('discovery');
|
|
458
|
+
const localServices = await liftEither(await (0, exports.discoverServices)(config.rootPath));
|
|
459
|
+
const allowlist = rootConfig.services?.allowed ?? [];
|
|
460
|
+
const publishedServices = await liftEither(await (0, exports.discoverPublishedServices)(config.rootPath, allowlist));
|
|
461
|
+
const localServiceNames = new Set(localServices.map(s => s.name));
|
|
462
|
+
const mergedServices = [
|
|
463
|
+
...localServices,
|
|
464
|
+
...publishedServices.filter(s => !localServiceNames.has(s.name))
|
|
465
|
+
];
|
|
466
|
+
const services = filterServices(mergedServices, config.servicesToDeploy);
|
|
467
|
+
for (let i = 0; i < services.length; i++) {
|
|
468
|
+
const service = services[i];
|
|
469
|
+
const isLast = i === services.length - 1;
|
|
470
|
+
const prefix = isLast ? '└─' : '├─';
|
|
471
|
+
const source = localServiceNames.has(service.name) ? 'local' : 'published';
|
|
472
|
+
this.eventEmitter.emitLog('info', `${prefix} ${service.name} (${source})`, undefined, 'Discovery');
|
|
473
|
+
}
|
|
474
|
+
this.eventEmitter.emitPhaseComplete('discovery');
|
|
475
|
+
this.eventEmitter.emitPhaseStart('dependency-analysis');
|
|
476
|
+
const sorted = (0, exports.sortByDependencies)(services);
|
|
477
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
478
|
+
const service = sorted[i];
|
|
479
|
+
const isLast = i === sorted.length - 1;
|
|
480
|
+
const prefix = isLast ? '└─' : '├─';
|
|
481
|
+
const deps = service.dependencies.length > 0
|
|
482
|
+
? ` (requires: ${service.dependencies.join(', ')})`
|
|
483
|
+
: '';
|
|
484
|
+
this.eventEmitter.emitLog('info', `${prefix} ${service.name}${deps}`, undefined, 'DependencyGraph');
|
|
485
|
+
}
|
|
486
|
+
this.eventEmitter.emitPhaseComplete('dependency-analysis');
|
|
487
|
+
const hostRegistry = getConfigValue(globalConfig, 'hostRegistry').orDefault('localhost:5001');
|
|
488
|
+
const clusterRegistry = getConfigValue(globalConfig, 'clusterRegistry').orDefault(hostRegistry);
|
|
489
|
+
const platformConfig = getConfigValue(globalConfig, 'platform').extract();
|
|
490
|
+
const platforms = platformConfig
|
|
491
|
+
? (Array.isArray(platformConfig) ? platformConfig : [platformConfig])
|
|
492
|
+
: undefined;
|
|
493
|
+
const hooks = (0, hooks_1.getHooksForStack)(rootConfig.hooks, config.stackName);
|
|
494
|
+
const servicesToBuild = sorted.filter(s => s.hasDockerfile);
|
|
495
|
+
const preBuildHooks = hooks.filter(h => h.stage === 'pre-build');
|
|
496
|
+
if (preBuildHooks.length > 0) {
|
|
497
|
+
this.eventEmitter.emitPhaseStart('bootstrap');
|
|
498
|
+
const hookResult = await (0, hooks_1.executeHooksForStage)('pre-build', hooks, config.rootPath, this.eventEmitter);
|
|
499
|
+
if (hookResult.isLeft()) {
|
|
500
|
+
this.eventEmitter.emitPhaseComplete('bootstrap', false);
|
|
501
|
+
throw throwE(hookResult.extract());
|
|
486
502
|
}
|
|
487
|
-
this.eventEmitter.emitPhaseComplete('
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
const
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
this.eventEmitter.emitPhaseComplete('bootstrap', false);
|
|
502
|
-
throw throwE(hookResult.extract());
|
|
503
|
-
}
|
|
504
|
-
this.eventEmitter.emitPhaseComplete('bootstrap');
|
|
503
|
+
this.eventEmitter.emitPhaseComplete('bootstrap');
|
|
504
|
+
}
|
|
505
|
+
const builtImages = {};
|
|
506
|
+
if (servicesToBuild.length > 0) {
|
|
507
|
+
this.eventEmitter.emitPhaseStart('image-build');
|
|
508
|
+
const preparedBuilds = await Promise.all(servicesToBuild.map(service => prepareBuild(service, hostRegistry, config.rootPath)));
|
|
509
|
+
const cachedBuilds = preparedBuilds.filter(b => b.cached);
|
|
510
|
+
const uncachedBuilds = preparedBuilds.filter(b => !b.cached);
|
|
511
|
+
for (const build of cachedBuilds) {
|
|
512
|
+
this.eventEmitter.emitTaskStart(build.service.name, build.service.name, 'image-build', build.contentHash);
|
|
513
|
+
this.eventEmitter.emitTaskUpdate(build.service.name, `unchanged (${build.contentHash})`);
|
|
514
|
+
const imageWithoutRegistry = (build.imageRef || build.imageTag).replace(`${hostRegistry}/`, '');
|
|
515
|
+
builtImages[build.service.name] = `${clusterRegistry}/${imageWithoutRegistry}`;
|
|
516
|
+
this.eventEmitter.emitTaskComplete(build.service.name, true, true, build.contentHash);
|
|
505
517
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
this.eventEmitter.emitPhaseStart('image-build');
|
|
509
|
-
const preparedBuilds = await Promise.all(servicesToBuild.map(service => prepareBuild(service, hostRegistry, config.rootPath)));
|
|
510
|
-
const cachedBuilds = preparedBuilds.filter(b => b.cached);
|
|
511
|
-
const uncachedBuilds = preparedBuilds.filter(b => !b.cached);
|
|
512
|
-
for (const build of cachedBuilds) {
|
|
518
|
+
if (uncachedBuilds.length > 0) {
|
|
519
|
+
for (const build of uncachedBuilds) {
|
|
513
520
|
this.eventEmitter.emitTaskStart(build.service.name, build.service.name, 'image-build', build.contentHash);
|
|
514
|
-
this.eventEmitter.emitTaskUpdate(build.service.name,
|
|
515
|
-
const imageWithoutRegistry = (build.imageRef || build.imageTag).replace(`${hostRegistry}/`, '');
|
|
516
|
-
builtImages[build.service.name] = `${clusterRegistry}/${imageWithoutRegistry}`;
|
|
517
|
-
this.eventEmitter.emitTaskComplete(build.service.name, true, true, build.contentHash);
|
|
521
|
+
this.eventEmitter.emitTaskUpdate(build.service.name, 'building');
|
|
518
522
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
+
const bakeServices = uncachedBuilds.map(build => ({
|
|
524
|
+
name: build.service.name,
|
|
525
|
+
contextPath: build.contextPath,
|
|
526
|
+
dockerfile: build.dockerfile,
|
|
527
|
+
tag: build.imageTag,
|
|
528
|
+
contentHash: build.contentHash,
|
|
529
|
+
platforms,
|
|
530
|
+
}));
|
|
531
|
+
const bakeConfig = (0, docker_1.generateBakeConfig)(bakeServices);
|
|
532
|
+
const bakeFilePath = path.join(config.rootPath, 'dist', 'docker-bake.json');
|
|
533
|
+
if (!fs.existsSync(path.dirname(bakeFilePath))) {
|
|
534
|
+
fs.mkdirSync(path.dirname(bakeFilePath), { recursive: true });
|
|
535
|
+
}
|
|
536
|
+
fs.writeFileSync(bakeFilePath, JSON.stringify(bakeConfig, null, 2));
|
|
537
|
+
const lastStepShown = new Map();
|
|
538
|
+
const completedTargets = new Set();
|
|
539
|
+
const buildHashMap = new Map(uncachedBuilds.map(b => [b.service.name, b.contentHash]));
|
|
540
|
+
const bakeResult = await (0, docker_1.runBake)(bakeFilePath, bakeServices, (progress) => {
|
|
541
|
+
if (!progress.target || progress.target.startsWith('_'))
|
|
542
|
+
return;
|
|
543
|
+
const isExportStep = progress.message.includes('exporting');
|
|
544
|
+
if (progress.done && isExportStep) {
|
|
545
|
+
completedTargets.add(progress.target);
|
|
546
|
+
const contentHash = buildHashMap.get(progress.target);
|
|
547
|
+
this.eventEmitter.emitTaskComplete(progress.target, !progress.error, false, contentHash);
|
|
548
|
+
return;
|
|
523
549
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
dockerfile: build.dockerfile,
|
|
528
|
-
tag: build.imageTag,
|
|
529
|
-
contentHash: build.contentHash,
|
|
530
|
-
platforms,
|
|
531
|
-
}));
|
|
532
|
-
const bakeConfig = (0, docker_1.generateBakeConfig)(bakeServices);
|
|
533
|
-
const bakeFilePath = path.join(config.rootPath, 'dist', 'docker-bake.json');
|
|
534
|
-
if (!fs.existsSync(path.dirname(bakeFilePath))) {
|
|
535
|
-
fs.mkdirSync(path.dirname(bakeFilePath), { recursive: true });
|
|
550
|
+
let message = progress.message;
|
|
551
|
+
if (progress.step) {
|
|
552
|
+
message = `[${progress.step.current}/${progress.step.total}] ${progress.message}`;
|
|
536
553
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
if (progress.done && isExportStep) {
|
|
546
|
-
completedTargets.add(progress.target);
|
|
547
|
-
const contentHash = buildHashMap.get(progress.target);
|
|
548
|
-
this.eventEmitter.emitTaskComplete(progress.target, !progress.error, false, contentHash);
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
let message = progress.message;
|
|
552
|
-
if (progress.step) {
|
|
553
|
-
message = `[${progress.step.current}/${progress.step.total}] ${progress.message}`;
|
|
554
|
-
}
|
|
555
|
-
const lastShown = lastStepShown.get(progress.target);
|
|
556
|
-
if (lastShown === message)
|
|
557
|
-
return;
|
|
558
|
-
lastStepShown.set(progress.target, message);
|
|
559
|
-
this.eventEmitter.emitTaskUpdate(progress.target, message);
|
|
560
|
-
});
|
|
561
|
-
if (bakeResult.isLeft()) {
|
|
562
|
-
const error = bakeResult.extract();
|
|
563
|
-
for (const build of uncachedBuilds) {
|
|
564
|
-
if (!completedTargets.has(build.service.name)) {
|
|
565
|
-
this.eventEmitter.emitTaskComplete(build.service.name, false, false, build.contentHash);
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
this.eventEmitter.emitLog('error', error.message, undefined, 'Build');
|
|
569
|
-
this.eventEmitter.emitPhaseComplete('image-build', false);
|
|
570
|
-
throw error;
|
|
571
|
-
}
|
|
572
|
-
const imageRefs = bakeResult.unsafeCoerce();
|
|
554
|
+
const lastShown = lastStepShown.get(progress.target);
|
|
555
|
+
if (lastShown === message)
|
|
556
|
+
return;
|
|
557
|
+
lastStepShown.set(progress.target, message);
|
|
558
|
+
this.eventEmitter.emitTaskUpdate(progress.target, message);
|
|
559
|
+
});
|
|
560
|
+
if (bakeResult.isLeft()) {
|
|
561
|
+
const error = bakeResult.extract();
|
|
573
562
|
for (const build of uncachedBuilds) {
|
|
574
|
-
const imageRef = imageRefs.get(build.service.name) || build.imageTag;
|
|
575
|
-
const imageWithoutRegistry = imageRef.replace(`${hostRegistry}/`, '');
|
|
576
|
-
builtImages[build.service.name] = `${clusterRegistry}/${imageWithoutRegistry}`;
|
|
577
563
|
if (!completedTargets.has(build.service.name)) {
|
|
578
|
-
this.eventEmitter.emitTaskComplete(build.service.name,
|
|
564
|
+
this.eventEmitter.emitTaskComplete(build.service.name, false, false, build.contentHash);
|
|
579
565
|
}
|
|
580
566
|
}
|
|
567
|
+
this.eventEmitter.emitLog('error', error.message, undefined, 'Build');
|
|
568
|
+
this.eventEmitter.emitPhaseComplete('image-build', false);
|
|
569
|
+
throw error;
|
|
570
|
+
}
|
|
571
|
+
const imageRefs = bakeResult.unsafeCoerce();
|
|
572
|
+
for (const build of uncachedBuilds) {
|
|
573
|
+
const imageRef = imageRefs.get(build.service.name) || build.imageTag;
|
|
574
|
+
const imageWithoutRegistry = imageRef.replace(`${hostRegistry}/`, '');
|
|
575
|
+
builtImages[build.service.name] = `${clusterRegistry}/${imageWithoutRegistry}`;
|
|
576
|
+
if (!completedTargets.has(build.service.name)) {
|
|
577
|
+
this.eventEmitter.emitTaskComplete(build.service.name, true, false, build.contentHash);
|
|
578
|
+
}
|
|
581
579
|
}
|
|
582
|
-
this.eventEmitter.emitPhaseComplete('image-build');
|
|
583
580
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
581
|
+
this.eventEmitter.emitPhaseComplete('image-build');
|
|
582
|
+
}
|
|
583
|
+
const postBuildHooks = hooks.filter(h => h.stage === 'post-build');
|
|
584
|
+
if (postBuildHooks.length > 0) {
|
|
585
|
+
const hookResult = await (0, hooks_1.executeHooksForStage)('post-build', hooks, config.rootPath, this.eventEmitter);
|
|
586
|
+
if (hookResult.isLeft()) {
|
|
587
|
+
throw throwE(hookResult.extract());
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
591
|
+
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
592
|
+
if (!fs.existsSync(workDir)) {
|
|
593
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
594
|
+
}
|
|
595
|
+
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
596
|
+
const outputs = {};
|
|
597
|
+
const program = async () => {
|
|
598
|
+
for (const service of sorted) {
|
|
599
|
+
const resolved = (0, exports.resolveStackConfig)(service, config.stackName);
|
|
600
|
+
const ctx = {
|
|
601
|
+
stackName: config.stackName,
|
|
602
|
+
serviceName: service.name,
|
|
603
|
+
metadata: service.metadata,
|
|
604
|
+
observability: service.observability,
|
|
605
|
+
security: service.security,
|
|
606
|
+
config: resolved.stackConfig,
|
|
607
|
+
globalConfig,
|
|
608
|
+
dependencies: outputs,
|
|
609
|
+
image: builtImages[service.name]
|
|
610
|
+
};
|
|
611
|
+
const deployFnResult = await loadDeployFunction(service);
|
|
612
|
+
if (deployFnResult.isLeft()) {
|
|
613
|
+
throw deployFnResult.extract();
|
|
614
|
+
}
|
|
615
|
+
const deployFn = deployFnResult.unsafeCoerce();
|
|
616
|
+
const result = await deployFn(ctx);
|
|
617
|
+
if (result?.outputs) {
|
|
618
|
+
outputs[service.name] = result.outputs;
|
|
589
619
|
}
|
|
590
620
|
}
|
|
621
|
+
return outputs;
|
|
622
|
+
};
|
|
623
|
+
return { sorted, builtImages, globalConfig, rootConfig, hooks, backendUrl, workDir, projectName, program, outputs };
|
|
624
|
+
}
|
|
625
|
+
deploy(config) {
|
|
626
|
+
const startTime = Date.now();
|
|
627
|
+
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither, throwE }) => {
|
|
628
|
+
await liftEither(this.validateEnvironment(config.stackName));
|
|
629
|
+
const { sorted, hooks, backendUrl, workDir, projectName, program, outputs } = await this.prepareDeployment(config, liftEither, throwE);
|
|
591
630
|
const preDeployHooks = hooks.filter(h => h.stage === 'pre-deploy');
|
|
592
631
|
if (preDeployHooks.length > 0) {
|
|
593
632
|
const hookResult = await (0, hooks_1.executeHooksForStage)('pre-deploy', hooks, config.rootPath, this.eventEmitter);
|
|
@@ -596,39 +635,6 @@ class Orchestrator {
|
|
|
596
635
|
}
|
|
597
636
|
}
|
|
598
637
|
this.eventEmitter.emitPhaseStart('deployment');
|
|
599
|
-
const outputs = {};
|
|
600
|
-
const program = async () => {
|
|
601
|
-
for (const service of sorted) {
|
|
602
|
-
const resolved = (0, exports.resolveStackConfig)(service, config.stackName);
|
|
603
|
-
const ctx = {
|
|
604
|
-
stackName: config.stackName,
|
|
605
|
-
serviceName: service.name,
|
|
606
|
-
metadata: service.metadata,
|
|
607
|
-
observability: service.observability,
|
|
608
|
-
security: service.security,
|
|
609
|
-
config: resolved.stackConfig,
|
|
610
|
-
globalConfig,
|
|
611
|
-
dependencies: outputs,
|
|
612
|
-
image: builtImages[service.name]
|
|
613
|
-
};
|
|
614
|
-
const deployFnResult = await loadDeployFunction(service);
|
|
615
|
-
if (deployFnResult.isLeft()) {
|
|
616
|
-
throw deployFnResult.extract();
|
|
617
|
-
}
|
|
618
|
-
const deployFn = deployFnResult.unsafeCoerce();
|
|
619
|
-
const result = await deployFn(ctx);
|
|
620
|
-
if (result?.outputs) {
|
|
621
|
-
outputs[service.name] = result.outputs;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
return outputs;
|
|
625
|
-
};
|
|
626
|
-
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
627
|
-
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
628
|
-
if (!fs.existsSync(workDir)) {
|
|
629
|
-
fs.mkdirSync(workDir, { recursive: true });
|
|
630
|
-
}
|
|
631
|
-
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
632
638
|
const stack = await automation_1.LocalWorkspace.createOrSelectStack({
|
|
633
639
|
stackName: config.stackName,
|
|
634
640
|
projectName,
|
|
@@ -673,6 +679,77 @@ class Orchestrator {
|
|
|
673
679
|
};
|
|
674
680
|
});
|
|
675
681
|
}
|
|
682
|
+
preview(config) {
|
|
683
|
+
const startTime = Date.now();
|
|
684
|
+
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither, throwE }) => {
|
|
685
|
+
await liftEither(this.validateEnvironment(config.stackName));
|
|
686
|
+
const { backendUrl, workDir, projectName, program } = await this.prepareDeployment(config, liftEither, throwE);
|
|
687
|
+
this.eventEmitter.emitPhaseStart('deployment');
|
|
688
|
+
const stack = await automation_1.LocalWorkspace.createOrSelectStack({ stackName: config.stackName, projectName, program }, { workDir, projectSettings: { name: projectName, runtime: 'nodejs', backend: { url: backendUrl } } });
|
|
689
|
+
try {
|
|
690
|
+
const previewResult = await stack.preview({
|
|
691
|
+
onOutput: config.onOutput || ((msg) => this.eventEmitter.emitLog('info', msg, undefined, 'Deploy')),
|
|
692
|
+
});
|
|
693
|
+
this.eventEmitter.emitPhaseComplete('deployment');
|
|
694
|
+
return {
|
|
695
|
+
success: true,
|
|
696
|
+
stack: config.stackName,
|
|
697
|
+
changeSummary: previewResult.changeSummary ?? {},
|
|
698
|
+
duration: Date.now() - startTime
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
catch (err) {
|
|
702
|
+
this.eventEmitter.emitPhaseComplete('deployment', false);
|
|
703
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
704
|
+
throw new Error(`Pulumi preview failed: ${message}`);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
status(config) {
|
|
709
|
+
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither }) => {
|
|
710
|
+
await liftEither(this.validateEnvironment(config.stackName));
|
|
711
|
+
const rootConfigPath = path.join(config.rootPath, 'pulumix.yaml');
|
|
712
|
+
const rawConfig = await liftEither(parseYamlFile(rootConfigPath));
|
|
713
|
+
const rootConfig = await liftEither((0, project_1.validateProjectConfig)(rawConfig, rootConfigPath));
|
|
714
|
+
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
715
|
+
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
716
|
+
if (!fs.existsSync(workDir)) {
|
|
717
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
718
|
+
}
|
|
719
|
+
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
720
|
+
const stack = await automation_1.LocalWorkspace.createOrSelectStack({ stackName: config.stackName, projectName, program: async () => { } }, { workDir, projectSettings: { name: projectName, runtime: 'nodejs', backend: { url: backendUrl } } });
|
|
721
|
+
const stackOutputs = await stack.outputs();
|
|
722
|
+
const outputs = Object.fromEntries(Object.entries(stackOutputs).map(([k, v]) => [k, v.value]));
|
|
723
|
+
return { success: true, stack: config.stackName, servicesDeployed: 0, duration: 0, outputs };
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
refresh(config) {
|
|
727
|
+
const startTime = Date.now();
|
|
728
|
+
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither }) => {
|
|
729
|
+
await liftEither(this.validateEnvironment(config.stackName));
|
|
730
|
+
const rootConfigPath = path.join(config.rootPath, 'pulumix.yaml');
|
|
731
|
+
const rawConfig = await liftEither(parseYamlFile(rootConfigPath));
|
|
732
|
+
const rootConfig = await liftEither((0, project_1.validateProjectConfig)(rawConfig, rootConfigPath));
|
|
733
|
+
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
734
|
+
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
735
|
+
if (!fs.existsSync(workDir)) {
|
|
736
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
737
|
+
}
|
|
738
|
+
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
739
|
+
const program = async () => { };
|
|
740
|
+
const stack = await automation_1.LocalWorkspace.createOrSelectStack({ stackName: config.stackName, projectName, program }, { workDir, projectSettings: { name: projectName, runtime: 'nodejs', backend: { url: backendUrl } } });
|
|
741
|
+
await stack.refresh({
|
|
742
|
+
onOutput: config.onOutput || ((msg) => this.eventEmitter.emitLog('info', msg, undefined, 'Deploy')),
|
|
743
|
+
});
|
|
744
|
+
return {
|
|
745
|
+
success: true,
|
|
746
|
+
stack: config.stackName,
|
|
747
|
+
servicesDeployed: 0,
|
|
748
|
+
duration: Date.now() - startTime,
|
|
749
|
+
outputs: {}
|
|
750
|
+
};
|
|
751
|
+
});
|
|
752
|
+
}
|
|
676
753
|
destroy(config) {
|
|
677
754
|
const startTime = Date.now();
|
|
678
755
|
return (0, EitherAsync_1.EitherAsync)(async ({ liftEither }) => {
|
|
@@ -682,6 +759,9 @@ class Orchestrator {
|
|
|
682
759
|
const rootConfig = await liftEither((0, project_1.validateProjectConfig)(rawConfig, rootConfigPath));
|
|
683
760
|
const backendUrl = resolveBackendUrl(config.rootPath, rootConfig, config.stackName);
|
|
684
761
|
const workDir = resolveWorkDir(config.rootPath, rootConfig, config.stackName);
|
|
762
|
+
if (!fs.existsSync(workDir)) {
|
|
763
|
+
fs.mkdirSync(workDir, { recursive: true });
|
|
764
|
+
}
|
|
685
765
|
const projectName = rootConfig.name ?? 'pulumix-project';
|
|
686
766
|
const program = async () => {
|
|
687
767
|
};
|