@go-to-k/cdkd 0.147.2 → 0.148.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/README.md +2 -0
- package/dist/cli.js +145 -2
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -306,6 +306,8 @@ cdkd state info --state-bucket my-bucket # explicit bucket; reports Source: --s
|
|
|
306
306
|
cdkd state list
|
|
307
307
|
cdkd state ls --long # include resource count, last-modified, lock status
|
|
308
308
|
cdkd state list --json # JSON output (alone, or combined with --long)
|
|
309
|
+
cdkd state list --tree # parent → child stack tree (nested stacks; #555 A3)
|
|
310
|
+
cdkd state list --tree --json # tree as nested JSON
|
|
309
311
|
|
|
310
312
|
# List resources of a single stack from state
|
|
311
313
|
cdkd state resources MyStack # aligned columns: LogicalID, Type, PhysicalID
|
package/dist/cli.js
CHANGED
|
@@ -34897,6 +34897,95 @@ function createStateMigrateCommand() {
|
|
|
34897
34897
|
return cmd;
|
|
34898
34898
|
}
|
|
34899
34899
|
|
|
34900
|
+
//#endregion
|
|
34901
|
+
//#region src/cli/commands/state-list-tree.ts
|
|
34902
|
+
/**
|
|
34903
|
+
* Build a parent → child tree from the flat list of state records.
|
|
34904
|
+
*
|
|
34905
|
+
* Children are linked to their parent by `(parentStack, parentRegion)`
|
|
34906
|
+
* matching another entry's `(stackName, region)`. Children whose parent
|
|
34907
|
+
* isn't present in the input (orphans — parent state was hand-deleted,
|
|
34908
|
+
* or destroyed out-of-band) are reported at the root level so they stay
|
|
34909
|
+
* visible to `cdkd state list` rather than vanishing silently.
|
|
34910
|
+
*
|
|
34911
|
+
* A self-link (parent equals self) is treated as a missing parent — the
|
|
34912
|
+
* node lands at the root rather than building an infinite tree.
|
|
34913
|
+
*
|
|
34914
|
+
* The roots and every child list are sorted alphabetically by `stackName`,
|
|
34915
|
+
* then by `region` (legacy `undefined` last), so output is stable across
|
|
34916
|
+
* runs.
|
|
34917
|
+
*/
|
|
34918
|
+
function buildStackTree(entries) {
|
|
34919
|
+
const refKey = (stackName, region) => `${stackName}\0${region ?? ""}`;
|
|
34920
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
34921
|
+
for (const entry of entries) byKey.set(refKey(entry.stackName, entry.region), {
|
|
34922
|
+
...entry,
|
|
34923
|
+
children: []
|
|
34924
|
+
});
|
|
34925
|
+
const roots = [];
|
|
34926
|
+
for (const node of byKey.values()) {
|
|
34927
|
+
if (node.parentStack !== void 0) {
|
|
34928
|
+
const parent = byKey.get(refKey(node.parentStack, node.parentRegion));
|
|
34929
|
+
if (parent && parent !== node) {
|
|
34930
|
+
parent.children.push(node);
|
|
34931
|
+
continue;
|
|
34932
|
+
}
|
|
34933
|
+
}
|
|
34934
|
+
roots.push(node);
|
|
34935
|
+
}
|
|
34936
|
+
const cmp = (a, b) => {
|
|
34937
|
+
if (a.stackName < b.stackName) return -1;
|
|
34938
|
+
if (a.stackName > b.stackName) return 1;
|
|
34939
|
+
const ar = a.region ?? "";
|
|
34940
|
+
const br = b.region ?? "";
|
|
34941
|
+
if (ar < br) return -1;
|
|
34942
|
+
if (ar > br) return 1;
|
|
34943
|
+
return 0;
|
|
34944
|
+
};
|
|
34945
|
+
const sortRecursive = (list) => {
|
|
34946
|
+
list.sort(cmp);
|
|
34947
|
+
for (const node of list) sortRecursive(node.children);
|
|
34948
|
+
};
|
|
34949
|
+
sortRecursive(roots);
|
|
34950
|
+
return roots;
|
|
34951
|
+
}
|
|
34952
|
+
/**
|
|
34953
|
+
* Render the tree using `tree(1)`-style box-drawing prefixes.
|
|
34954
|
+
*
|
|
34955
|
+
* Each line is built by `formatLine(node)`. The caller picks the
|
|
34956
|
+
* human-readable shape (e.g. `Stack (region)`); this helper only owns the
|
|
34957
|
+
* indentation.
|
|
34958
|
+
*/
|
|
34959
|
+
function renderStackTreeAscii(roots, formatLine) {
|
|
34960
|
+
const lines = [];
|
|
34961
|
+
for (const root of roots) {
|
|
34962
|
+
lines.push(formatLine(root));
|
|
34963
|
+
renderChildren(root.children, "", lines, formatLine);
|
|
34964
|
+
}
|
|
34965
|
+
return lines.join("\n");
|
|
34966
|
+
}
|
|
34967
|
+
function renderChildren(children, prefix, out, formatLine) {
|
|
34968
|
+
const lastIdx = children.length - 1;
|
|
34969
|
+
for (let i = 0; i < children.length; i++) {
|
|
34970
|
+
const child = children[i];
|
|
34971
|
+
const isLast = i === lastIdx;
|
|
34972
|
+
const branch = isLast ? "└── " : "├── ";
|
|
34973
|
+
const childPrefix = isLast ? " " : "│ ";
|
|
34974
|
+
out.push(`${prefix}${branch}${formatLine(child)}`);
|
|
34975
|
+
renderChildren(child.children, prefix + childPrefix, out, formatLine);
|
|
34976
|
+
}
|
|
34977
|
+
}
|
|
34978
|
+
function stackTreeToJson(roots) {
|
|
34979
|
+
return roots.map((node) => ({
|
|
34980
|
+
stackName: node.stackName,
|
|
34981
|
+
region: node.region ?? null,
|
|
34982
|
+
parentStack: node.parentStack ?? null,
|
|
34983
|
+
parentLogicalId: node.parentLogicalId ?? null,
|
|
34984
|
+
parentRegion: node.parentRegion ?? null,
|
|
34985
|
+
children: stackTreeToJson(node.children)
|
|
34986
|
+
}));
|
|
34987
|
+
}
|
|
34988
|
+
|
|
34900
34989
|
//#endregion
|
|
34901
34990
|
//#region src/cli/commands/state.ts
|
|
34902
34991
|
/**
|
|
@@ -35001,6 +35090,10 @@ function sortRefs(refs) {
|
|
|
35001
35090
|
* `version: 1` records (no region) appear as plain `Stack` rows.
|
|
35002
35091
|
* - `--long`/`-l`: include resource count, last-modified time, and lock status.
|
|
35003
35092
|
* - `--json`: emit a JSON array (alongside or instead of the long form).
|
|
35093
|
+
* - `--tree`: render parent → child stack tree (issue #555 A3). Loads each
|
|
35094
|
+
* state record to read the v6 `parentStack` / `parentRegion` fields, then
|
|
35095
|
+
* reconstructs the hierarchy. Flat default is preserved so tooling that
|
|
35096
|
+
* greps the existing one-per-line shape keeps working.
|
|
35004
35097
|
*/
|
|
35005
35098
|
async function stateListCommand(options) {
|
|
35006
35099
|
const logger = getLogger();
|
|
@@ -35008,6 +35101,10 @@ async function stateListCommand(options) {
|
|
|
35008
35101
|
const setup = await setupStateBackend(options);
|
|
35009
35102
|
try {
|
|
35010
35103
|
const refs = sortRefs(await setup.stateBackend.listStacks());
|
|
35104
|
+
if (options.tree) {
|
|
35105
|
+
await renderTreeMode(refs, setup.stateBackend, options.json);
|
|
35106
|
+
return;
|
|
35107
|
+
}
|
|
35011
35108
|
if (!options.long && !options.json) {
|
|
35012
35109
|
for (const ref of refs) process.stdout.write(`${formatStackRef(ref)}\n`);
|
|
35013
35110
|
return;
|
|
@@ -35057,10 +35154,56 @@ async function stateListCommand(options) {
|
|
|
35057
35154
|
}
|
|
35058
35155
|
}
|
|
35059
35156
|
/**
|
|
35157
|
+
* Render the parent → child stack tree for `cdkd state list --tree`.
|
|
35158
|
+
*
|
|
35159
|
+
* Loads each state record in parallel to read the v6 `parentStack` /
|
|
35160
|
+
* `parentLogicalId` / `parentRegion` fields, then hands the enriched flat
|
|
35161
|
+
* list to {@link buildStackTree}. A missing state record (NoSuchKey returns
|
|
35162
|
+
* `null` from getState) OR an unreadable one (transient S3 503 / throttle /
|
|
35163
|
+
* per-stack IAM hiccup throws) degrades to a top-level entry (no parent
|
|
35164
|
+
* link) — the row still appears in the tree at the root level rather than
|
|
35165
|
+
* vanishing, and one bad record never kills the whole view.
|
|
35166
|
+
*
|
|
35167
|
+
* `tree --json` emits the nested {@link import('./state-list-tree.js').StackTreeJson}
|
|
35168
|
+
* shape; plain `tree` renders `tree(1)`-style box-drawing.
|
|
35169
|
+
*/
|
|
35170
|
+
async function renderTreeMode(refs, stateBackend, asJson) {
|
|
35171
|
+
const roots = buildStackTree(await Promise.all(refs.map(async (ref) => {
|
|
35172
|
+
if (!ref.region) return { stackName: ref.stackName };
|
|
35173
|
+
let state;
|
|
35174
|
+
try {
|
|
35175
|
+
state = (await stateBackend.getState(ref.stackName, ref.region))?.state;
|
|
35176
|
+
} catch {
|
|
35177
|
+
return {
|
|
35178
|
+
stackName: ref.stackName,
|
|
35179
|
+
region: ref.region
|
|
35180
|
+
};
|
|
35181
|
+
}
|
|
35182
|
+
return {
|
|
35183
|
+
stackName: ref.stackName,
|
|
35184
|
+
region: ref.region,
|
|
35185
|
+
...state?.parentStack !== void 0 && { parentStack: state.parentStack },
|
|
35186
|
+
...state?.parentLogicalId !== void 0 && { parentLogicalId: state.parentLogicalId },
|
|
35187
|
+
...state?.parentRegion !== void 0 && { parentRegion: state.parentRegion }
|
|
35188
|
+
};
|
|
35189
|
+
})));
|
|
35190
|
+
if (asJson) {
|
|
35191
|
+
process.stdout.write(`${JSON.stringify(stackTreeToJson(roots), null, 2)}\n`);
|
|
35192
|
+
return;
|
|
35193
|
+
}
|
|
35194
|
+
if (roots.length === 0) return;
|
|
35195
|
+
const rendered = renderStackTreeAscii(roots, (node) => formatStackRef({
|
|
35196
|
+
stackName: node.stackName,
|
|
35197
|
+
...node.region ? { region: node.region } : {}
|
|
35198
|
+
}));
|
|
35199
|
+
process.stdout.write(`${rendered}\n`);
|
|
35200
|
+
}
|
|
35201
|
+
/**
|
|
35060
35202
|
* Create the `state list` subcommand.
|
|
35061
35203
|
*/
|
|
35062
35204
|
function createStateListCommand() {
|
|
35063
|
-
const
|
|
35205
|
+
const treeOption = new Option("--tree", "Render parent → child stack tree (loads each state record to read the v6 parent link)").default(false).conflicts("long");
|
|
35206
|
+
const cmd = new Command("list").alias("ls").description("List stacks registered in the cdkd state bucket").option("-l, --long", "Show resource count, last-modified time, and lock status", false).option("--json", "Output as JSON", false).addOption(treeOption).action(withErrorHandling(stateListCommand));
|
|
35064
35207
|
[...commonOptions, ...stateOptions].forEach((opt) => cmd.addOption(opt));
|
|
35065
35208
|
cmd.addOption(deprecatedRegionOption);
|
|
35066
35209
|
return cmd;
|
|
@@ -56684,7 +56827,7 @@ function reorderArgs(argv) {
|
|
|
56684
56827
|
*/
|
|
56685
56828
|
async function main() {
|
|
56686
56829
|
const program = new Command();
|
|
56687
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
56830
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.148.0");
|
|
56688
56831
|
program.addCommand(createBootstrapCommand());
|
|
56689
56832
|
program.addCommand(createSynthCommand());
|
|
56690
56833
|
program.addCommand(createListCommand());
|