declastruct 1.8.0 → 1.9.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/dist/contract/cli/apply.js +34 -12
- package/dist/contract/cli/apply.js.map +1 -1
- package/dist/contract/cli/asApplyCommandFromArgv.d.ts +8 -0
- package/dist/contract/cli/asApplyCommandFromArgv.js +82 -0
- package/dist/contract/cli/asApplyCommandFromArgv.js.map +1 -0
- package/dist/contract/cli/invoke.js +24 -4
- package/dist/contract/cli/invoke.js.map +1 -1
- package/dist/contract/cli/plan.d.ts +2 -1
- package/dist/contract/cli/plan.js +55 -15
- package/dist/contract/cli/plan.js.map +1 -1
- package/dist/domain.objects/DeclastructSnapshot.d.ts +54 -0
- package/dist/domain.objects/DeclastructSnapshot.js +15 -0
- package/dist/domain.objects/DeclastructSnapshot.js.map +1 -0
- package/dist/domain.operations/apply/applyChanges.js +26 -7
- package/dist/domain.operations/apply/applyChanges.js.map +1 -1
- package/dist/domain.operations/plan/planChanges.d.ts +5 -1
- package/dist/domain.operations/plan/planChanges.js +48 -9
- package/dist/domain.operations/plan/planChanges.js.map +1 -1
- package/dist/infra/asIndentedLines.d.ts +8 -0
- package/dist/infra/asIndentedLines.js +15 -0
- package/dist/infra/asIndentedLines.js.map +1 -0
- package/dist/infra/initializeProviders.d.ts +15 -0
- package/dist/infra/initializeProviders.js +20 -0
- package/dist/infra/initializeProviders.js.map +1 -0
- package/package.json +8 -8
|
@@ -36,6 +36,7 @@ const path_1 = require("path");
|
|
|
36
36
|
const rhachet_artifact_git_1 = require("rhachet-artifact-git");
|
|
37
37
|
const DeclastructPlan_1 = require("../../domain.objects/DeclastructPlan");
|
|
38
38
|
const applyChanges_1 = require("../../domain.operations/apply/applyChanges");
|
|
39
|
+
const initializeProviders_1 = require("../../infra/initializeProviders");
|
|
39
40
|
const log = console;
|
|
40
41
|
/**
|
|
41
42
|
* .what = executes the apply command to apply infrastructure changes
|
|
@@ -50,12 +51,16 @@ const executeApplyCommand = async (input) => {
|
|
|
50
51
|
if (isYoloMode) {
|
|
51
52
|
// yolo mode requires --wish
|
|
52
53
|
if (!input.wishFilePath)
|
|
53
|
-
throw new helpful_errors_1.BadRequestError('--wish required when --plan yolo'
|
|
54
|
+
throw new helpful_errors_1.BadRequestError('--wish required when --plan yolo', {
|
|
55
|
+
hint: 'add --wish <file> to specify the wish file',
|
|
56
|
+
});
|
|
54
57
|
}
|
|
55
58
|
else {
|
|
56
59
|
// standard mode requires --plan (not "yolo")
|
|
57
60
|
if (!input.planFilePath)
|
|
58
|
-
throw new helpful_errors_1.BadRequestError('--plan required'
|
|
61
|
+
throw new helpful_errors_1.BadRequestError('--plan required', {
|
|
62
|
+
hint: 'add --plan <file> to specify the plan file',
|
|
63
|
+
});
|
|
59
64
|
}
|
|
60
65
|
// resolve plan path (null for yolo mode)
|
|
61
66
|
const resolvedPlanPath = isYoloMode
|
|
@@ -66,7 +71,10 @@ const executeApplyCommand = async (input) => {
|
|
|
66
71
|
if (!resolvedPlanPath)
|
|
67
72
|
return null;
|
|
68
73
|
if (!(0, fs_1.existsSync)(resolvedPlanPath))
|
|
69
|
-
throw new helpful_errors_1.BadRequestError(
|
|
74
|
+
throw new helpful_errors_1.BadRequestError('plan file not found', {
|
|
75
|
+
path: resolvedPlanPath,
|
|
76
|
+
hint: 'check that the --plan path points to an extant file',
|
|
77
|
+
});
|
|
70
78
|
const planJson = await (0, promises_1.readFile)(resolvedPlanPath, 'utf-8');
|
|
71
79
|
return new DeclastructPlan_1.DeclastructPlan(JSON.parse(planJson));
|
|
72
80
|
})();
|
|
@@ -76,7 +84,10 @@ const executeApplyCommand = async (input) => {
|
|
|
76
84
|
: plan.wish.uri;
|
|
77
85
|
// validate wish file exists
|
|
78
86
|
if (!(0, fs_1.existsSync)(resolvedWishPath))
|
|
79
|
-
throw new helpful_errors_1.BadRequestError(
|
|
87
|
+
throw new helpful_errors_1.BadRequestError('wish file not found', {
|
|
88
|
+
path: resolvedWishPath,
|
|
89
|
+
hint: 'check that the wish file path is correct',
|
|
90
|
+
});
|
|
80
91
|
// get git root for relative path display
|
|
81
92
|
const gitRoot = await (0, rhachet_artifact_git_1.getGitRepoRoot)({ from: process.cwd() });
|
|
82
93
|
const relativePlanPath = resolvedPlanPath
|
|
@@ -86,9 +97,14 @@ const executeApplyCommand = async (input) => {
|
|
|
86
97
|
// log header
|
|
87
98
|
log.info('');
|
|
88
99
|
log.info('🌊 declastruct apply');
|
|
89
|
-
if (relativePlanPath)
|
|
90
|
-
log.info(` plan: ${relativePlanPath}`);
|
|
91
|
-
|
|
100
|
+
if (relativePlanPath) {
|
|
101
|
+
log.info(` ├─ plan: ${relativePlanPath}`);
|
|
102
|
+
log.info(` └─ wish: ${relativeWishPath}`);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
log.info(` ├─ plan: (yolo)`);
|
|
106
|
+
log.info(` └─ wish: ${relativeWishPath}`);
|
|
107
|
+
}
|
|
92
108
|
log.info('');
|
|
93
109
|
// create cli context with passthrough args from plan
|
|
94
110
|
const cliContext = {
|
|
@@ -105,15 +121,20 @@ const executeApplyCommand = async (input) => {
|
|
|
105
121
|
const wish = await Promise.resolve(`${resolvedWishPath}`).then(s => __importStar(require(s)));
|
|
106
122
|
// validate exports
|
|
107
123
|
if (typeof wish.getResources !== 'function')
|
|
108
|
-
throw new helpful_errors_1.BadRequestError('
|
|
124
|
+
throw new helpful_errors_1.BadRequestError('wish file must export getResources() function', {
|
|
125
|
+
path: resolvedWishPath,
|
|
126
|
+
hint: 'add `export const getResources = () => [...]` to the wish file',
|
|
127
|
+
});
|
|
109
128
|
if (typeof wish.getProviders !== 'function')
|
|
110
|
-
throw new helpful_errors_1.BadRequestError('
|
|
129
|
+
throw new helpful_errors_1.BadRequestError('wish file must export getProviders() function', {
|
|
130
|
+
path: resolvedWishPath,
|
|
131
|
+
hint: 'add `export const getProviders = () => [...]` to the wish file',
|
|
132
|
+
});
|
|
111
133
|
// get resources and providers
|
|
112
134
|
const resources = await wish.getResources();
|
|
113
135
|
const providers = await wish.getProviders();
|
|
114
136
|
// initialize providers
|
|
115
|
-
|
|
116
|
-
await Promise.all(providers.map((p) => p.hooks.beforeAll()));
|
|
137
|
+
await (0, initializeProviders_1.initializeProviders)({ providers });
|
|
117
138
|
// create context with passthrough args
|
|
118
139
|
const context = {
|
|
119
140
|
bottleneck: new bottleneck_1.default({ maxConcurrent: 1 }),
|
|
@@ -132,7 +153,8 @@ const executeApplyCommand = async (input) => {
|
|
|
132
153
|
await Promise.all(providers.map((p) => p.hooks.afterAll()));
|
|
133
154
|
// log summary
|
|
134
155
|
log.info('');
|
|
135
|
-
log.info(
|
|
156
|
+
log.info('🌊 declastruct apply');
|
|
157
|
+
log.info(` └─ applied: ${result.appliedChanges.length}`);
|
|
136
158
|
log.info('');
|
|
137
159
|
};
|
|
138
160
|
exports.executeApplyCommand = executeApplyCommand;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/contract/cli/apply.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,4DAAoC;AACpC,2BAAgC;AAChC,0CAAuC;AACvC,mDAAiD;AACjD,+BAAyC;AACzC,+DAAsD;AAItD,yEAAsE;AACtE,4EAAyE;
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/contract/cli/apply.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .what = transforms a plan command argv into the equivalent apply command
|
|
3
|
+
* .why = shows users the exact command to run after plan, no syntax to remember
|
|
4
|
+
*/
|
|
5
|
+
export declare const asApplyCommandFromArgv: (input: {
|
|
6
|
+
argv: string[];
|
|
7
|
+
planFilePath: string;
|
|
8
|
+
}) => string;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.asApplyCommandFromArgv = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* .what = transforms a plan command argv into the equivalent apply command
|
|
6
|
+
* .why = shows users the exact command to run after plan, no syntax to remember
|
|
7
|
+
*/
|
|
8
|
+
const asApplyCommandFromArgv = (input) => {
|
|
9
|
+
const { argv, planFilePath } = input;
|
|
10
|
+
// detect invocation prefix (npx, pnpm dlx, yarn dlx, or bare)
|
|
11
|
+
const prefix = getInvocationPrefix({ argv });
|
|
12
|
+
// build the apply command
|
|
13
|
+
// convert: plan → apply, --into → --plan, remove --wish, --snap, and passthrough args
|
|
14
|
+
const applyArgs = asApplyArgsFromArgv({ argv, planFilePath });
|
|
15
|
+
return [prefix, 'declastruct apply', ...applyArgs].filter(Boolean).join(' ');
|
|
16
|
+
};
|
|
17
|
+
exports.asApplyCommandFromArgv = asApplyCommandFromArgv;
|
|
18
|
+
/**
|
|
19
|
+
* .what = extracts the invocation prefix from argv
|
|
20
|
+
* .why = preserves how user invoked the command (npx, pnpm dlx, yarn dlx, or bare)
|
|
21
|
+
*/
|
|
22
|
+
const getInvocationPrefix = (input) => {
|
|
23
|
+
const { argv } = input;
|
|
24
|
+
const execPath = argv[1] ?? '';
|
|
25
|
+
// detect package manager runners
|
|
26
|
+
if (execPath.includes('npx'))
|
|
27
|
+
return 'npx';
|
|
28
|
+
if (execPath.includes('pnpm'))
|
|
29
|
+
return 'pnpm dlx';
|
|
30
|
+
if (execPath.includes('yarn'))
|
|
31
|
+
return 'yarn dlx';
|
|
32
|
+
// check if invoked via node_modules/.bin (local install)
|
|
33
|
+
if (execPath.includes('node_modules/.bin'))
|
|
34
|
+
return 'npx';
|
|
35
|
+
// bare invocation (global install or direct path)
|
|
36
|
+
return '';
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* .what = converts plan argv into apply args
|
|
40
|
+
* .why = removes plan-specific flags and adds --plan flag
|
|
41
|
+
*/
|
|
42
|
+
const asApplyArgsFromArgv = (input) => {
|
|
43
|
+
const { argv, planFilePath } = input;
|
|
44
|
+
const result = [`--plan ${planFilePath}`];
|
|
45
|
+
// find where our CLI args start (after node and executable path)
|
|
46
|
+
const cliArgs = argv.slice(2);
|
|
47
|
+
// track which args to skip (flag + value pairs)
|
|
48
|
+
const skipFlags = new Set(['--wish', '--into', '--snap']);
|
|
49
|
+
let skipNext = false;
|
|
50
|
+
let hitPassthrough = false;
|
|
51
|
+
for (const arg of cliArgs) {
|
|
52
|
+
// stop at passthrough separator
|
|
53
|
+
if (arg === '--') {
|
|
54
|
+
hitPassthrough = true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
// skip everything after passthrough
|
|
58
|
+
if (hitPassthrough)
|
|
59
|
+
continue;
|
|
60
|
+
// skip the value of a flag we're removing
|
|
61
|
+
if (skipNext) {
|
|
62
|
+
skipNext = false;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
// check if this is a flag we're removing
|
|
66
|
+
if (skipFlags.has(arg)) {
|
|
67
|
+
skipNext = true;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
// check for --flag=value syntax
|
|
71
|
+
const [flag] = arg.split('=');
|
|
72
|
+
if (flag && skipFlags.has(flag))
|
|
73
|
+
continue;
|
|
74
|
+
// skip the 'plan' command itself
|
|
75
|
+
if (arg === 'plan')
|
|
76
|
+
continue;
|
|
77
|
+
// preserve all other args
|
|
78
|
+
result.push(arg);
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=asApplyCommandFromArgv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asApplyCommandFromArgv.js","sourceRoot":"","sources":["../../../src/contract/cli/asApplyCommandFromArgv.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACI,MAAM,sBAAsB,GAAG,CAAC,KAGtC,EAAU,EAAE;IACX,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC;IAErC,8DAA8D;IAC9D,MAAM,MAAM,GAAG,mBAAmB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IAE7C,0BAA0B;IAC1B,sFAAsF;IACtF,MAAM,SAAS,GAAG,mBAAmB,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;IAE9D,OAAO,CAAC,MAAM,EAAE,mBAAmB,EAAE,GAAG,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/E,CAAC,CAAC;AAdW,QAAA,sBAAsB,0BAcjC;AAEF;;;GAGG;AACH,MAAM,mBAAmB,GAAG,CAAC,KAAyB,EAAU,EAAE;IAChE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE/B,iCAAiC;IACjC,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,UAAU,CAAC;IACjD,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,UAAU,CAAC;IAEjD,yDAAyD;IACzD,IAAI,QAAQ,CAAC,QAAQ,CAAC,mBAAmB,CAAC;QAAE,OAAO,KAAK,CAAC;IAEzD,kDAAkD;IAClD,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,mBAAmB,GAAG,CAAC,KAG5B,EAAY,EAAE;IACb,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,KAAK,CAAC;IACrC,MAAM,MAAM,GAAa,CAAC,UAAU,YAAY,EAAE,CAAC,CAAC;IAEpD,iEAAiE;IACjE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE9B,gDAAgD;IAChD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC1D,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,gCAAgC;QAChC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,cAAc,GAAG,IAAI,CAAC;YACtB,SAAS;QACX,CAAC;QAED,oCAAoC;QACpC,IAAI,cAAc;YAAE,SAAS;QAE7B,0CAA0C;QAC1C,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,GAAG,KAAK,CAAC;YACjB,SAAS;QACX,CAAC;QAED,yCAAyC;QACzC,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,QAAQ,GAAG,IAAI,CAAC;YAChB,SAAS;QACX,CAAC;QAED,gCAAgC;QAChC,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAE1C,iCAAiC;QACjC,IAAI,GAAG,KAAK,MAAM;YAAE,SAAS;QAE7B,0BAA0B;QAC1B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -5,10 +5,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.invoke = void 0;
|
|
7
7
|
const commander_1 = require("commander");
|
|
8
|
+
const helpful_errors_1 = require("helpful-errors");
|
|
8
9
|
const package_json_1 = __importDefault(require("../../../package.json"));
|
|
9
10
|
const apply_1 = require("./apply");
|
|
10
11
|
const plan_1 = require("./plan");
|
|
11
12
|
const log = console;
|
|
13
|
+
/**
|
|
14
|
+
* .what = determines exit code based on error type
|
|
15
|
+
* .why = semantic exit codes let callers know if they can retry or must fix
|
|
16
|
+
*/
|
|
17
|
+
const getExitCodeForError = (error) => {
|
|
18
|
+
if (error instanceof helpful_errors_1.BadRequestError)
|
|
19
|
+
return 2;
|
|
20
|
+
return 1;
|
|
21
|
+
};
|
|
12
22
|
/**
|
|
13
23
|
* .what = invokes CLI commands based on user input
|
|
14
24
|
* .why = provides global entry point for declastruct CLI
|
|
@@ -25,6 +35,7 @@ const invoke = async ({ args }) => {
|
|
|
25
35
|
.description('Generate a change plan from a wish file')
|
|
26
36
|
.requiredOption('--wish <file>', 'Path to wish file')
|
|
27
37
|
.requiredOption('--into <file>', 'Path to output plan file')
|
|
38
|
+
.option('--snap <file>', 'Path to output snapshot file')
|
|
28
39
|
.usage('--wish <file> --into <file> [-- <wish-args>]')
|
|
29
40
|
.allowExcessArguments(true)
|
|
30
41
|
.configureOutput({
|
|
@@ -48,12 +59,17 @@ const invoke = async ({ args }) => {
|
|
|
48
59
|
await (0, plan_1.executePlanCommand)({
|
|
49
60
|
wishFilePath: options.wish,
|
|
50
61
|
planFilePath: options.into,
|
|
62
|
+
snapFilePath: options.snap ?? null,
|
|
51
63
|
passthroughArgs,
|
|
52
64
|
});
|
|
53
65
|
}
|
|
54
66
|
catch (error) {
|
|
55
|
-
|
|
56
|
-
|
|
67
|
+
// allowlist: BadRequestError (user must fix) and Error (malfunction)
|
|
68
|
+
// rethrow anything else (non-Error thrown = unexpected)
|
|
69
|
+
if (!(error instanceof Error))
|
|
70
|
+
throw error;
|
|
71
|
+
log.error('✖ plan failed:', error);
|
|
72
|
+
process.exit(getExitCodeForError(error));
|
|
57
73
|
}
|
|
58
74
|
});
|
|
59
75
|
program
|
|
@@ -70,8 +86,12 @@ const invoke = async ({ args }) => {
|
|
|
70
86
|
});
|
|
71
87
|
}
|
|
72
88
|
catch (error) {
|
|
73
|
-
|
|
74
|
-
|
|
89
|
+
// allowlist: BadRequestError (user must fix) and Error (malfunction)
|
|
90
|
+
// rethrow non-Error values (unexpected)
|
|
91
|
+
if (!(error instanceof Error))
|
|
92
|
+
throw error;
|
|
93
|
+
log.error('✖ apply failed:', error);
|
|
94
|
+
process.exit(getExitCodeForError(error));
|
|
75
95
|
}
|
|
76
96
|
});
|
|
77
97
|
await program.parseAsync(args, { from: 'user' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../../../src/contract/cli/invoke.ts"],"names":[],"mappings":";;;;;;AAAA,yCAAoC;
|
|
1
|
+
{"version":3,"file":"invoke.js","sourceRoot":"","sources":["../../../src/contract/cli/invoke.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* .why = provides CLI interface for planning infrastructure changes
|
|
5
5
|
* .note = requires wish file with getResources() and getProviders() exports
|
|
6
6
|
*/
|
|
7
|
-
export declare const executePlanCommand: ({ wishFilePath, planFilePath, passthroughArgs, }: {
|
|
7
|
+
export declare const executePlanCommand: ({ wishFilePath, planFilePath, snapFilePath, passthroughArgs, }: {
|
|
8
8
|
wishFilePath: string;
|
|
9
9
|
planFilePath: string;
|
|
10
|
+
snapFilePath: string | null;
|
|
10
11
|
passthroughArgs?: string[];
|
|
11
12
|
}) => Promise<void>;
|
|
@@ -35,28 +35,45 @@ const helpful_errors_1 = require("helpful-errors");
|
|
|
35
35
|
const path_1 = require("path");
|
|
36
36
|
const rhachet_artifact_git_1 = require("rhachet-artifact-git");
|
|
37
37
|
const planChanges_1 = require("../../domain.operations/plan/planChanges");
|
|
38
|
+
const initializeProviders_1 = require("../../infra/initializeProviders");
|
|
39
|
+
const asApplyCommandFromArgv_1 = require("./asApplyCommandFromArgv");
|
|
38
40
|
const log = console;
|
|
39
41
|
/**
|
|
40
42
|
* .what = executes the plan command to generate an infrastructure change plan
|
|
41
43
|
* .why = provides CLI interface for planning infrastructure changes
|
|
42
44
|
* .note = requires wish file with getResources() and getProviders() exports
|
|
43
45
|
*/
|
|
44
|
-
const executePlanCommand = async ({ wishFilePath, planFilePath, passthroughArgs = [], }) => {
|
|
46
|
+
const executePlanCommand = async ({ wishFilePath, planFilePath, snapFilePath, passthroughArgs = [], }) => {
|
|
47
|
+
// capture original argv before it gets modified for passthrough args
|
|
48
|
+
const argvOriginal = [...process.argv];
|
|
45
49
|
// resolve paths
|
|
46
50
|
const resolvedWishPath = (0, path_1.resolve)(process.cwd(), wishFilePath);
|
|
47
51
|
const resolvedPlanPath = (0, path_1.resolve)(process.cwd(), planFilePath);
|
|
52
|
+
const resolvedSnapPath = snapFilePath
|
|
53
|
+
? (0, path_1.resolve)(process.cwd(), snapFilePath)
|
|
54
|
+
: null;
|
|
48
55
|
// get git root for relative path display
|
|
49
56
|
const gitRoot = await (0, rhachet_artifact_git_1.getGitRepoRoot)({ from: process.cwd() });
|
|
50
57
|
const relativeWishPath = (0, path_1.relative)(gitRoot, resolvedWishPath);
|
|
51
58
|
const relativePlanPath = (0, path_1.relative)(gitRoot, resolvedPlanPath);
|
|
59
|
+
const relativeSnapPath = resolvedSnapPath
|
|
60
|
+
? (0, path_1.relative)(gitRoot, resolvedSnapPath)
|
|
61
|
+
: null;
|
|
52
62
|
// validate wish file exists
|
|
53
63
|
if (!(0, fs_1.existsSync)(resolvedWishPath)) {
|
|
54
|
-
throw new helpful_errors_1.BadRequestError(
|
|
64
|
+
throw new helpful_errors_1.BadRequestError('wish file not found', {
|
|
65
|
+
path: resolvedWishPath,
|
|
66
|
+
hint: 'check that the --wish path points to an extant file',
|
|
67
|
+
});
|
|
55
68
|
}
|
|
56
69
|
log.info('');
|
|
57
70
|
log.info('🌊 declastruct plan');
|
|
58
|
-
log.info(` wish: ${relativeWishPath}`);
|
|
59
|
-
log.info(` plan: ${relativePlanPath}`);
|
|
71
|
+
log.info(` ├─ wish: ${relativeWishPath}`);
|
|
72
|
+
log.info(` ├─ plan: ${relativePlanPath}`);
|
|
73
|
+
if (relativeSnapPath)
|
|
74
|
+
log.info(` └─ snap: ${relativeSnapPath}`);
|
|
75
|
+
else
|
|
76
|
+
log.info(` └─ snap: (none)`);
|
|
60
77
|
log.info('');
|
|
61
78
|
// create cli context with passthrough args
|
|
62
79
|
const cliContext = {
|
|
@@ -72,25 +89,30 @@ const executePlanCommand = async ({ wishFilePath, planFilePath, passthroughArgs
|
|
|
72
89
|
const wish = await Promise.resolve(`${resolvedWishPath}`).then(s => __importStar(require(s)));
|
|
73
90
|
// validate exports
|
|
74
91
|
if (typeof wish.getResources !== 'function') {
|
|
75
|
-
throw new helpful_errors_1.BadRequestError('
|
|
92
|
+
throw new helpful_errors_1.BadRequestError('wish file must export getResources() function', {
|
|
93
|
+
path: resolvedWishPath,
|
|
94
|
+
hint: 'add `export const getResources = () => [...]` to the wish file',
|
|
95
|
+
});
|
|
76
96
|
}
|
|
77
97
|
if (typeof wish.getProviders !== 'function') {
|
|
78
|
-
throw new helpful_errors_1.BadRequestError('
|
|
98
|
+
throw new helpful_errors_1.BadRequestError('wish file must export getProviders() function', {
|
|
99
|
+
path: resolvedWishPath,
|
|
100
|
+
hint: 'add `export const getProviders = () => [...]` to the wish file',
|
|
101
|
+
});
|
|
79
102
|
}
|
|
80
103
|
// get resources and providers
|
|
81
104
|
const resources = await wish.getResources();
|
|
82
105
|
const providers = await wish.getProviders();
|
|
83
106
|
// initialize providers
|
|
84
|
-
|
|
85
|
-
await Promise.all(providers.map((p) => p.hooks.beforeAll()));
|
|
107
|
+
await (0, initializeProviders_1.initializeProviders)({ providers });
|
|
86
108
|
// create context with passthrough args
|
|
87
109
|
const context = {
|
|
88
110
|
bottleneck: new bottleneck_1.default({ maxConcurrent: 1 }),
|
|
89
111
|
log,
|
|
90
112
|
passthrough: cliContext.passthrough,
|
|
91
113
|
};
|
|
92
|
-
// plan changes (
|
|
93
|
-
const plan = await (0, planChanges_1.planChanges)({
|
|
114
|
+
// plan changes (outputs emitted in real-time by planChanges)
|
|
115
|
+
const { plan, snapshot } = await (0, planChanges_1.planChanges)({
|
|
94
116
|
resources,
|
|
95
117
|
providers,
|
|
96
118
|
wishFilePath: resolvedWishPath,
|
|
@@ -100,14 +122,32 @@ const executePlanCommand = async ({ wishFilePath, planFilePath, passthroughArgs
|
|
|
100
122
|
await (0, promises_1.mkdir)(planDir, { recursive: true });
|
|
101
123
|
// write plan to file
|
|
102
124
|
await (0, promises_1.writeFile)(resolvedPlanPath, JSON.stringify(plan, null, 2), 'utf-8');
|
|
125
|
+
// write snapshot to file if requested
|
|
126
|
+
if (resolvedSnapPath) {
|
|
127
|
+
const snapDir = (0, path_1.dirname)(resolvedSnapPath);
|
|
128
|
+
await (0, promises_1.mkdir)(snapDir, { recursive: true });
|
|
129
|
+
await (0, promises_1.writeFile)(resolvedSnapPath, JSON.stringify(snapshot, null, 2), 'utf-8');
|
|
130
|
+
}
|
|
103
131
|
// cleanup providers
|
|
104
|
-
|
|
105
|
-
// log.info('✨ stop providers...');
|
|
106
|
-
await Promise.all(providers.map((p) => p.hooks.afterAll()));
|
|
132
|
+
await (0, initializeProviders_1.finalizeProviders)({ providers });
|
|
107
133
|
// log summary
|
|
108
134
|
log.info('');
|
|
109
|
-
log.info(
|
|
110
|
-
log.info(`
|
|
135
|
+
log.info('🌊 declastruct plan');
|
|
136
|
+
log.info(` ├─ resources: ${plan.changes.length}`);
|
|
137
|
+
log.info(` ├─ plan: ${relativePlanPath}`);
|
|
138
|
+
if (relativeSnapPath)
|
|
139
|
+
log.info(` └─ snap: ${relativeSnapPath}`);
|
|
140
|
+
else
|
|
141
|
+
log.info(` └─ snap: (none)`);
|
|
142
|
+
log.info('');
|
|
143
|
+
// log apply hint
|
|
144
|
+
const applyCommand = (0, asApplyCommandFromArgv_1.asApplyCommandFromArgv)({
|
|
145
|
+
argv: argvOriginal,
|
|
146
|
+
planFilePath: relativePlanPath,
|
|
147
|
+
});
|
|
148
|
+
log.info('🥥 did you know?');
|
|
149
|
+
log.info(' ├─ to apply, run');
|
|
150
|
+
log.info(` └─ ${applyCommand}`);
|
|
111
151
|
log.info('');
|
|
112
152
|
};
|
|
113
153
|
exports.executePlanCommand = executePlanCommand;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/contract/cli/plan.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,4DAAoC;AACpC,2BAAgC;AAChC,0CAA+C;AAC/C,mDAAiD;AACjD,+BAAkD;AAClD,+DAAsD;AAItD,yEAAsE;
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/contract/cli/plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { DomainLiteral } from 'domain-objects';
|
|
2
|
+
import type { IsoTimestamp } from './IsoTimestamp';
|
|
3
|
+
/**
|
|
4
|
+
* .what = a single entry in a snapshot, captures state for one resource
|
|
5
|
+
* .why = enables debug and audit of what declastruct observed for each resource
|
|
6
|
+
*/
|
|
7
|
+
export interface DeclastructSnapshotEntry {
|
|
8
|
+
/**
|
|
9
|
+
* which resource this entry is for
|
|
10
|
+
*/
|
|
11
|
+
forResource: {
|
|
12
|
+
/**
|
|
13
|
+
* class name of the resource
|
|
14
|
+
*/
|
|
15
|
+
class: string;
|
|
16
|
+
/**
|
|
17
|
+
* scannable identifier of this specific resource
|
|
18
|
+
*/
|
|
19
|
+
slug: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* serialized state of the resource
|
|
23
|
+
*
|
|
24
|
+
* .note = null if the resource does not exist remotely (for remote[])
|
|
25
|
+
* .note = contains _dobj stamp from serialize()
|
|
26
|
+
*/
|
|
27
|
+
state: Record<string, any> | null;
|
|
28
|
+
}
|
|
29
|
+
export declare class DeclastructSnapshotEntry extends DomainLiteral<DeclastructSnapshotEntry> implements DeclastructSnapshotEntry {
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* .what = snapshot of remote and wished state at plan time
|
|
33
|
+
* .why = enables debug and audit of what declastruct observed before diff
|
|
34
|
+
*/
|
|
35
|
+
export interface DeclastructSnapshot {
|
|
36
|
+
/**
|
|
37
|
+
* timestamp when the snapshot was taken
|
|
38
|
+
*/
|
|
39
|
+
observedAt: IsoTimestamp;
|
|
40
|
+
/**
|
|
41
|
+
* remote state for each resource (before omitReadonly)
|
|
42
|
+
*/
|
|
43
|
+
remote: DeclastructSnapshotEntry[];
|
|
44
|
+
/**
|
|
45
|
+
* wished state for each resource (what user declared)
|
|
46
|
+
*/
|
|
47
|
+
wished: DeclastructSnapshotEntry[];
|
|
48
|
+
}
|
|
49
|
+
export declare class DeclastructSnapshot extends DomainLiteral<DeclastructSnapshot> implements DeclastructSnapshot {
|
|
50
|
+
static nested: {
|
|
51
|
+
remote: typeof DeclastructSnapshotEntry;
|
|
52
|
+
wished: typeof DeclastructSnapshotEntry;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeclastructSnapshot = exports.DeclastructSnapshotEntry = void 0;
|
|
4
|
+
const domain_objects_1 = require("domain-objects");
|
|
5
|
+
class DeclastructSnapshotEntry extends domain_objects_1.DomainLiteral {
|
|
6
|
+
}
|
|
7
|
+
exports.DeclastructSnapshotEntry = DeclastructSnapshotEntry;
|
|
8
|
+
class DeclastructSnapshot extends domain_objects_1.DomainLiteral {
|
|
9
|
+
}
|
|
10
|
+
exports.DeclastructSnapshot = DeclastructSnapshot;
|
|
11
|
+
DeclastructSnapshot.nested = {
|
|
12
|
+
remote: DeclastructSnapshotEntry,
|
|
13
|
+
wished: DeclastructSnapshotEntry,
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=DeclastructSnapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeclastructSnapshot.js","sourceRoot":"","sources":["../../src/domain.objects/DeclastructSnapshot.ts"],"names":[],"mappings":";;;AAAA,mDAA+C;AAiC/C,MAAa,wBACX,SAAQ,8BAAuC;CACT;AAFxC,4DAEwC;AAuBxC,MAAa,mBACX,SAAQ,8BAAkC;;AAD5C,kDAQC;AAJe,0BAAM,GAAG;IACrB,MAAM,EAAE,wBAAwB;IAChC,MAAM,EAAE,wBAAwB;CACjC,CAAC"}
|
|
@@ -9,6 +9,25 @@ const validate_1 = require("../../domain.operations/plan/validate");
|
|
|
9
9
|
const colorizeAction_1 = require("../../infra/colorizeAction");
|
|
10
10
|
const withSpinner_1 = require("../../infra/withSpinner");
|
|
11
11
|
const applyChange_1 = require("./applyChange");
|
|
12
|
+
/**
|
|
13
|
+
* .what = checks if plan has any non-KEEP changes
|
|
14
|
+
* .why = determines whether apply phase should proceed
|
|
15
|
+
*/
|
|
16
|
+
const hasChangesToApply = (input) => {
|
|
17
|
+
return input.changes.some((change) => change.action !== DeclastructChange_1.DeclastructChangeAction.KEEP);
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* .what = finds resource that matches forResource identifier
|
|
21
|
+
* .why = locates the declared resource for a planned change
|
|
22
|
+
*/
|
|
23
|
+
const getOneResourceForChange = (input) => {
|
|
24
|
+
const resourceFound = input.resources.find((candidate) => candidate.constructor.name === input.forResource.class &&
|
|
25
|
+
(0, domain_objects_1.getUniqueIdentifierSlug)(candidate) === input.forResource.slug);
|
|
26
|
+
if (!resourceFound) {
|
|
27
|
+
helpful_errors_1.UnexpectedCodePathError.throw('could not find resource specified in plan. was it removed?', { forResource: input.forResource });
|
|
28
|
+
}
|
|
29
|
+
return resourceFound;
|
|
30
|
+
};
|
|
12
31
|
/**
|
|
13
32
|
* .what = applies changes to achieve desired state
|
|
14
33
|
* .why = executes infrastructure changes in a controlled, observable manner
|
|
@@ -18,18 +37,17 @@ const applyChange_1 = require("./applyChange");
|
|
|
18
37
|
*/
|
|
19
38
|
const applyChanges = async (input, context) => {
|
|
20
39
|
// replan to get current state
|
|
21
|
-
const currentPlan = await (0, planChanges_1.planChanges)({
|
|
40
|
+
const { plan: currentPlan } = await (0, planChanges_1.planChanges)({
|
|
22
41
|
resources: input.resources,
|
|
23
42
|
providers: input.providers,
|
|
24
43
|
wishFilePath: input.plan?.wish.uri ?? 'ignorable',
|
|
25
44
|
}, context);
|
|
26
45
|
// use current plan for apply (works for both modes)
|
|
27
46
|
const planToApply = currentPlan;
|
|
28
|
-
// check if there are any actionable changes (non-KEEP)
|
|
29
|
-
const hasActionableChanges = planToApply.changes.some((change) => change.action !== DeclastructChange_1.DeclastructChangeAction.KEEP);
|
|
30
47
|
// skip apply phase if everything is in sync
|
|
31
|
-
if (!
|
|
48
|
+
if (!hasChangesToApply({ changes: planToApply.changes })) {
|
|
32
49
|
return { appliedChanges: [] };
|
|
50
|
+
}
|
|
33
51
|
// validate plan matches current state (skip if no plan provided, i.e. yolo mode)
|
|
34
52
|
if (input.plan) {
|
|
35
53
|
(0, validate_1.assertPlanStillValid)({
|
|
@@ -56,9 +74,10 @@ const applyChanges = async (input, context) => {
|
|
|
56
74
|
continue;
|
|
57
75
|
}
|
|
58
76
|
// find the desired resource
|
|
59
|
-
const resourceFound =
|
|
60
|
-
|
|
61
|
-
|
|
77
|
+
const resourceFound = getOneResourceForChange({
|
|
78
|
+
resources: input.resources,
|
|
79
|
+
forResource: change.forResource,
|
|
80
|
+
});
|
|
62
81
|
// log the action line (stays fixed)
|
|
63
82
|
const actionLabel = (0, colorizeAction_1.colorizeAction)(change.action);
|
|
64
83
|
context.log.info(`○ ${actionLabel} ${change.forResource.slug}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/apply/applyChanges.ts"],"names":[],"mappings":";;;AAAA,mDAA4E;AAC5E,mDAAyD;AAKzD,6EAG+C;AAG/C,yEAAsE;AACtE,mEAA4E;AAC5E,8DAA2D;AAC3D,wDAAqD;AAErD,+CAA4C;AAE5C;;;;;;GAMG;AACI,MAAM,YAAY,GAAG,KAAK,EAC/B,KAIC,EACD,OAAqE,EACnB,EAAE;IACpD,8BAA8B;IAC9B,MAAM,WAAW,GAAG,MAAM,IAAA,yBAAW,
|
|
1
|
+
{"version":3,"file":"applyChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/apply/applyChanges.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ import type { ContextDeclastruct } from '../../domain.objects/ContextDeclastruct
|
|
|
4
4
|
import type { ContextDeclastructCli } from '../../domain.objects/ContextDeclastructCli';
|
|
5
5
|
import { DeclastructPlan } from '../../domain.objects/DeclastructPlan';
|
|
6
6
|
import type { DeclastructProvider } from '../../domain.objects/DeclastructProvider';
|
|
7
|
+
import { DeclastructSnapshot } from '../../domain.objects/DeclastructSnapshot';
|
|
7
8
|
/**
|
|
8
9
|
* .what = generates a plan of changes required to achieve desired state
|
|
9
10
|
* .why = enables users to review infrastructure changes before applying them
|
|
@@ -13,4 +14,7 @@ export declare const planChanges: (input: {
|
|
|
13
14
|
resources: DomainEntity<any>[];
|
|
14
15
|
providers: DeclastructProvider<any, any>[];
|
|
15
16
|
wishFilePath: string;
|
|
16
|
-
}, context: ContextLogTrail & ContextDeclastruct & ContextDeclastructCli) => Promise<
|
|
17
|
+
}, context: ContextLogTrail & ContextDeclastruct & ContextDeclastructCli) => Promise<{
|
|
18
|
+
plan: DeclastructPlan;
|
|
19
|
+
snapshot: DeclastructSnapshot;
|
|
20
|
+
}>;
|
|
@@ -2,15 +2,25 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.planChanges = void 0;
|
|
4
4
|
const domain_objects_1 = require("domain-objects");
|
|
5
|
+
const helpful_errors_1 = require("helpful-errors");
|
|
5
6
|
const DeclastructChange_1 = require("../../domain.objects/DeclastructChange");
|
|
6
7
|
const DeclastructPlan_1 = require("../../domain.objects/DeclastructPlan");
|
|
8
|
+
const DeclastructSnapshot_1 = require("../../domain.objects/DeclastructSnapshot");
|
|
7
9
|
const del_1 = require("../../domain.operations/del/del");
|
|
10
|
+
const asIndentedLines_1 = require("../../infra/asIndentedLines");
|
|
8
11
|
const asIsoTimestamp_1 = require("../../infra/asIsoTimestamp");
|
|
9
12
|
const colorizeAction_1 = require("../../infra/colorizeAction");
|
|
10
13
|
const withSpinner_1 = require("../../infra/withSpinner");
|
|
11
14
|
const computeChange_1 = require("./computeChange");
|
|
12
15
|
const getDaoByResource_1 = require("./getDaoByResource");
|
|
13
16
|
const hashChanges_1 = require("./hashChanges");
|
|
17
|
+
/**
|
|
18
|
+
* .what = checks if all changes are KEEP (no actions required)
|
|
19
|
+
* .why = determines whether to show "all in sync" message
|
|
20
|
+
*/
|
|
21
|
+
const isAllInSync = (input) => {
|
|
22
|
+
return input.changes.every((change) => change.action === DeclastructChange_1.DeclastructChangeAction.KEEP);
|
|
23
|
+
};
|
|
14
24
|
/**
|
|
15
25
|
* .what = generates a plan of changes required to achieve desired state
|
|
16
26
|
* .why = enables users to review infrastructure changes before applying them
|
|
@@ -24,8 +34,12 @@ const planChanges = async (input, context) => {
|
|
|
24
34
|
const bottleneck = 'onPlan' in context.bottleneck
|
|
25
35
|
? context.bottleneck.onPlan
|
|
26
36
|
: context.bottleneck;
|
|
27
|
-
//
|
|
37
|
+
// capture observation timestamp (before any API calls)
|
|
38
|
+
const observedAt = (0, asIsoTimestamp_1.asIsoTimestamp)(new Date());
|
|
39
|
+
// compute change for each resource with real-time output
|
|
28
40
|
const changes = [];
|
|
41
|
+
const snapshotRemote = [];
|
|
42
|
+
const snapshotWished = [];
|
|
29
43
|
for (const resource of input.resources) {
|
|
30
44
|
const change = await bottleneck.schedule(async () => {
|
|
31
45
|
// find DAO and provider context for this resource
|
|
@@ -45,6 +59,25 @@ const planChanges = async (input, context) => {
|
|
|
45
59
|
context.log.info(` ├─ ✔ done in ${durationSec}s`);
|
|
46
60
|
// determine desired state - null if marked for deletion
|
|
47
61
|
const desiredState = (0, del_1.isMarkedForDeletion)(resource) ? null : resource;
|
|
62
|
+
// collect snapshot entry BEFORE omitReadonly (for debug and audit)
|
|
63
|
+
const forResource = {
|
|
64
|
+
class: resource.constructor.name,
|
|
65
|
+
slug: helpful_errors_1.UnexpectedCodePathError.wrap(() => (0, domain_objects_1.getUniqueIdentifierSlug)(resource), {
|
|
66
|
+
message: 'failed to getUniqueIdentifierSlug for snapshot',
|
|
67
|
+
metadata: {
|
|
68
|
+
resource,
|
|
69
|
+
ctor: resource.constructor.name,
|
|
70
|
+
},
|
|
71
|
+
})(),
|
|
72
|
+
};
|
|
73
|
+
snapshotRemote.push(new DeclastructSnapshot_1.DeclastructSnapshotEntry({
|
|
74
|
+
forResource,
|
|
75
|
+
state: remoteState ? JSON.parse((0, domain_objects_1.serialize)(remoteState)) : null,
|
|
76
|
+
}));
|
|
77
|
+
snapshotWished.push(new DeclastructSnapshot_1.DeclastructSnapshotEntry({
|
|
78
|
+
forResource,
|
|
79
|
+
state: JSON.parse((0, domain_objects_1.serialize)(resource)), // always the declared resource, not desiredState
|
|
80
|
+
}));
|
|
48
81
|
// compute change
|
|
49
82
|
const computed = (0, computeChange_1.computeChange)({
|
|
50
83
|
desired: desiredState,
|
|
@@ -60,10 +93,10 @@ const planChanges = async (input, context) => {
|
|
|
60
93
|
context.log.info(` └─ decision ${(0, colorizeAction_1.colorizeAction)(computed.action)}`);
|
|
61
94
|
// and the diff too, indented to align with tree
|
|
62
95
|
if (computed.state.difference) {
|
|
63
|
-
const indentedDiff =
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
|
|
96
|
+
const indentedDiff = (0, asIndentedLines_1.asIndentedLines)({
|
|
97
|
+
text: computed.state.difference,
|
|
98
|
+
indent: ' ',
|
|
99
|
+
});
|
|
67
100
|
context.log.info(indentedDiff);
|
|
68
101
|
}
|
|
69
102
|
context.log.info('');
|
|
@@ -73,13 +106,12 @@ const planChanges = async (input, context) => {
|
|
|
73
106
|
changes.push(change);
|
|
74
107
|
}
|
|
75
108
|
// log success message if everything is in sync
|
|
76
|
-
|
|
77
|
-
if (allInSync) {
|
|
109
|
+
if (isAllInSync({ changes })) {
|
|
78
110
|
context.log.info('');
|
|
79
111
|
context.log.info('🎉 everything is in sync!');
|
|
80
112
|
}
|
|
81
|
-
//
|
|
82
|
-
|
|
113
|
+
// build plan
|
|
114
|
+
const plan = new DeclastructPlan_1.DeclastructPlan({
|
|
83
115
|
hash: (0, hashChanges_1.hashChanges)(changes),
|
|
84
116
|
createdAt: (0, asIsoTimestamp_1.asIsoTimestamp)(new Date()),
|
|
85
117
|
wish: {
|
|
@@ -88,6 +120,13 @@ const planChanges = async (input, context) => {
|
|
|
88
120
|
},
|
|
89
121
|
changes,
|
|
90
122
|
});
|
|
123
|
+
// build snapshot
|
|
124
|
+
const snapshot = new DeclastructSnapshot_1.DeclastructSnapshot({
|
|
125
|
+
observedAt,
|
|
126
|
+
remote: snapshotRemote,
|
|
127
|
+
wished: snapshotWished,
|
|
128
|
+
});
|
|
129
|
+
return { plan, snapshot };
|
|
91
130
|
};
|
|
92
131
|
exports.planChanges = planChanges;
|
|
93
132
|
//# sourceMappingURL=planChanges.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/plan/planChanges.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"planChanges.js","sourceRoot":"","sources":["../../../src/domain.operations/plan/planChanges.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.asIndentedLines = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* .what = indents each line of text with specified prefix
|
|
6
|
+
* .why = formats multi-line text to align with tree structure in logs
|
|
7
|
+
*/
|
|
8
|
+
const asIndentedLines = (input) => {
|
|
9
|
+
return input.text
|
|
10
|
+
.split('\n')
|
|
11
|
+
.map((line) => `${input.indent}${line}`)
|
|
12
|
+
.join('\n');
|
|
13
|
+
};
|
|
14
|
+
exports.asIndentedLines = asIndentedLines;
|
|
15
|
+
//# sourceMappingURL=asIndentedLines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asIndentedLines.js","sourceRoot":"","sources":["../../src/infra/asIndentedLines.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACI,MAAM,eAAe,GAAG,CAAC,KAG/B,EAAU,EAAE;IACX,OAAO,KAAK,CAAC,IAAI;SACd,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;SACvC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC,CAAC;AARW,QAAA,eAAe,mBAQ1B"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DeclastructProvider } from '../domain.objects/DeclastructProvider';
|
|
2
|
+
/**
|
|
3
|
+
* .what = initializes all providers via their beforeAll hooks
|
|
4
|
+
* .why = providers may need to establish connections or state before use
|
|
5
|
+
*/
|
|
6
|
+
export declare const initializeProviders: (input: {
|
|
7
|
+
providers: DeclastructProvider<any, any>[];
|
|
8
|
+
}) => Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* .what = finalizes all providers via their afterAll hooks
|
|
11
|
+
* .why = providers may need to close connections or cleanup state after use
|
|
12
|
+
*/
|
|
13
|
+
export declare const finalizeProviders: (input: {
|
|
14
|
+
providers: DeclastructProvider<any, any>[];
|
|
15
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.finalizeProviders = exports.initializeProviders = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* .what = initializes all providers via their beforeAll hooks
|
|
6
|
+
* .why = providers may need to establish connections or state before use
|
|
7
|
+
*/
|
|
8
|
+
const initializeProviders = async (input) => {
|
|
9
|
+
await Promise.all(input.providers.map((p) => p.hooks.beforeAll()));
|
|
10
|
+
};
|
|
11
|
+
exports.initializeProviders = initializeProviders;
|
|
12
|
+
/**
|
|
13
|
+
* .what = finalizes all providers via their afterAll hooks
|
|
14
|
+
* .why = providers may need to close connections or cleanup state after use
|
|
15
|
+
*/
|
|
16
|
+
const finalizeProviders = async (input) => {
|
|
17
|
+
await Promise.all(input.providers.map((p) => p.hooks.afterAll()));
|
|
18
|
+
};
|
|
19
|
+
exports.finalizeProviders = finalizeProviders;
|
|
20
|
+
//# sourceMappingURL=initializeProviders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initializeProviders.js","sourceRoot":"","sources":["../../src/infra/initializeProviders.ts"],"names":[],"mappings":";;;AAEA;;;GAGG;AACI,MAAM,mBAAmB,GAAG,KAAK,EAAE,KAEzC,EAAiB,EAAE;IAClB,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;AACrE,CAAC,CAAC;AAJW,QAAA,mBAAmB,uBAI9B;AAEF;;;GAGG;AACI,MAAM,iBAAiB,GAAG,KAAK,EAAE,KAEvC,EAAiB,EAAE;IAClB,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;AACpE,CAAC,CAAC;AAJW,QAAA,iBAAiB,qBAI5B"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "declastruct",
|
|
3
3
|
"author": "ehmpathy",
|
|
4
4
|
"description": "Add declarative control to any resource constructs. Declare, plan, and apply within an observable pit-of-success.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.9.1",
|
|
6
6
|
"repository": "ehmpathy/declastruct",
|
|
7
7
|
"homepage": "https://github.com/ehmpathy/declastruct",
|
|
8
8
|
"keywords": [
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"postversion": "git push origin HEAD --tags --no-verify",
|
|
55
55
|
"prepare:husky": "npx husky install && chmod ug+x .husky/*",
|
|
56
56
|
"prepare": "[ -e .git ] && npm run prepare:husky || exit 0 && npm run prepare:rhachet",
|
|
57
|
-
"prepare:rhachet": "rhachet init --hooks --roles mechanic behaver driver reviewer librarian ergonomist architect reflector dreamer dispatcher"
|
|
57
|
+
"prepare:rhachet": "npm run build && rhachet init --hooks --roles mechanic behaver driver reviewer librarian ergonomist architect reflector dreamer dispatcher"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"bottleneck": "2.19.5",
|
|
@@ -85,18 +85,18 @@
|
|
|
85
85
|
"cz-conventional-changelog": "3.3.0",
|
|
86
86
|
"declapract": "^0.13.1",
|
|
87
87
|
"declapract-typescript-ehmpathy": "0.45.3",
|
|
88
|
-
"declastruct": "
|
|
88
|
+
"declastruct": "link:.",
|
|
89
89
|
"declastruct-github": "1.0.7",
|
|
90
90
|
"depcheck": "1.4.3",
|
|
91
91
|
"esbuild-register": "3.6.0",
|
|
92
92
|
"husky": "8.0.3",
|
|
93
93
|
"jest": "30.2.0",
|
|
94
|
-
"rhachet": "1.
|
|
95
|
-
"rhachet-brains-anthropic": "0.4.
|
|
94
|
+
"rhachet": "1.41.2",
|
|
95
|
+
"rhachet-brains-anthropic": "0.4.1",
|
|
96
96
|
"rhachet-brains-xai": "0.3.3",
|
|
97
|
-
"rhachet-roles-bhrain": "0.
|
|
98
|
-
"rhachet-roles-bhuild": "0.
|
|
99
|
-
"rhachet-roles-ehmpathy": "1.
|
|
97
|
+
"rhachet-roles-bhrain": "0.27.5",
|
|
98
|
+
"rhachet-roles-bhuild": "0.21.3",
|
|
99
|
+
"rhachet-roles-ehmpathy": "1.35.0",
|
|
100
100
|
"test-fns": "1.7.2",
|
|
101
101
|
"tsc-alias": "1.8.10",
|
|
102
102
|
"tsx": "4.20.6",
|