@sanity/runtime-cli 11.2.5 → 12.0.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/README.md +36 -38
- package/dist/actions/blueprints/blueprint.d.ts +3 -0
- package/dist/actions/blueprints/blueprint.js +26 -14
- package/dist/actions/blueprints/config.d.ts +34 -3
- package/dist/actions/blueprints/config.js +67 -14
- package/dist/actions/blueprints/stacks.d.ts +1 -2
- package/dist/actions/blueprints/stacks.js +2 -3
- package/dist/commands/blueprints/config.d.ts +0 -1
- package/dist/commands/blueprints/config.js +4 -12
- package/dist/commands/blueprints/deploy.js +1 -1
- package/dist/commands/blueprints/destroy.js +3 -3
- package/dist/commands/blueprints/info.js +2 -2
- package/dist/commands/blueprints/init.d.ts +1 -0
- package/dist/commands/blueprints/init.js +4 -0
- package/dist/commands/blueprints/logs.js +2 -2
- package/dist/commands/blueprints/plan.js +1 -0
- package/dist/config.d.ts +2 -1
- package/dist/config.js +8 -1
- package/dist/cores/blueprints/config.d.ts +1 -1
- package/dist/cores/blueprints/config.js +92 -78
- package/dist/cores/blueprints/deploy.js +8 -8
- package/dist/cores/blueprints/destroy.d.ts +1 -0
- package/dist/cores/blueprints/destroy.js +22 -26
- package/dist/cores/blueprints/doctor.js +24 -72
- package/dist/cores/blueprints/info.d.ts +1 -0
- package/dist/cores/blueprints/info.js +5 -4
- package/dist/cores/blueprints/init.d.ts +1 -1
- package/dist/cores/blueprints/init.js +50 -78
- package/dist/cores/blueprints/logs.d.ts +1 -0
- package/dist/cores/blueprints/logs.js +7 -7
- package/dist/cores/blueprints/plan.d.ts +3 -0
- package/dist/cores/blueprints/plan.js +5 -4
- package/dist/cores/blueprints/stacks.d.ts +1 -0
- package/dist/cores/blueprints/stacks.js +1 -2
- package/dist/cores/functions/add.js +58 -70
- package/dist/cores/functions/logs.js +2 -4
- package/dist/cores/index.js +3 -3
- package/dist/utils/display/blueprints-formatting.js +8 -3
- package/dist/utils/display/errors.js +2 -2
- package/dist/utils/display/presenters.d.ts +2 -0
- package/dist/utils/display/presenters.js +7 -0
- package/dist/utils/display/prompt.d.ts +14 -2
- package/dist/utils/display/prompt.js +60 -41
- package/dist/utils/types.d.ts +0 -1
- package/oclif.manifest.json +19 -26
- package/package.json +6 -8
|
@@ -2,14 +2,14 @@ import { Flags } from '@oclif/core';
|
|
|
2
2
|
import { BlueprintCommand } from '../../baseCommands.js';
|
|
3
3
|
import { blueprintDestroyCore } from '../../cores/blueprints/destroy.js';
|
|
4
4
|
export default class DestroyCommand extends BlueprintCommand {
|
|
5
|
-
static description = 'Destroy a Blueprint deployment (will not delete local files)';
|
|
5
|
+
static description = 'Destroy a Blueprint Stack deployment and its resources (will not delete local files)';
|
|
6
6
|
static examples = [
|
|
7
7
|
'<%= config.bin %> <%= command.id %>',
|
|
8
8
|
'<%= config.bin %> <%= command.id %> --stack-id <stackId> --project-id <projectId> --force --no-wait',
|
|
9
9
|
];
|
|
10
10
|
static flags = {
|
|
11
11
|
force: Flags.boolean({
|
|
12
|
-
description: 'Force
|
|
12
|
+
description: 'Force Stack destruction (skip confirmation)',
|
|
13
13
|
aliases: ['f'],
|
|
14
14
|
default: false,
|
|
15
15
|
}),
|
|
@@ -28,7 +28,7 @@ export default class DestroyCommand extends BlueprintCommand {
|
|
|
28
28
|
aliases: ['stackId', 'stack'],
|
|
29
29
|
}),
|
|
30
30
|
'no-wait': Flags.boolean({
|
|
31
|
-
description: 'Do not wait for destruction to complete',
|
|
31
|
+
description: 'Do not wait for Stack destruction to complete',
|
|
32
32
|
default: false,
|
|
33
33
|
}),
|
|
34
34
|
};
|
|
@@ -2,14 +2,14 @@ import { Flags } from '@oclif/core';
|
|
|
2
2
|
import { DeployedBlueprintCommand } from '../../baseCommands.js';
|
|
3
3
|
import { blueprintInfoCore } from '../../cores/blueprints/info.js';
|
|
4
4
|
export default class InfoCommand extends DeployedBlueprintCommand {
|
|
5
|
-
static description = 'Show information about a Blueprint deployment';
|
|
5
|
+
static description = 'Show information about a Blueprint Stack deployment';
|
|
6
6
|
static examples = [
|
|
7
7
|
'<%= config.bin %> <%= command.id %>',
|
|
8
8
|
'<%= config.bin %> <%= command.id %> --stack-id <stackId>',
|
|
9
9
|
];
|
|
10
10
|
static flags = {
|
|
11
11
|
id: Flags.string({
|
|
12
|
-
description: 'Stack ID to show info for (defaults to current
|
|
12
|
+
description: 'Stack ID to show info for (defaults to current Stack)',
|
|
13
13
|
}),
|
|
14
14
|
};
|
|
15
15
|
async run() {
|
|
@@ -13,6 +13,7 @@ export default class InitCommand extends Command {
|
|
|
13
13
|
'organization-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
14
|
'stack-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
15
|
'stack-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
17
|
};
|
|
17
18
|
run(): Promise<void>;
|
|
18
19
|
}
|
|
@@ -48,6 +48,10 @@ export default class InitCommand extends Command {
|
|
|
48
48
|
aliases: ['name'],
|
|
49
49
|
exclusive: ['stack-id'],
|
|
50
50
|
}),
|
|
51
|
+
verbose: Flags.boolean({
|
|
52
|
+
description: 'Verbose output',
|
|
53
|
+
default: false,
|
|
54
|
+
}),
|
|
51
55
|
};
|
|
52
56
|
async run() {
|
|
53
57
|
const { args, flags } = await this.parse(InitCommand);
|
|
@@ -2,7 +2,7 @@ import { Flags } from '@oclif/core';
|
|
|
2
2
|
import { DeployedBlueprintCommand } from '../../baseCommands.js';
|
|
3
3
|
import { blueprintLogsCore } from '../../cores/blueprints/logs.js';
|
|
4
4
|
export default class LogsCommand extends DeployedBlueprintCommand {
|
|
5
|
-
static description = 'Display logs for a Blueprint deployment';
|
|
5
|
+
static description = 'Display logs for a Blueprint Stack deployment';
|
|
6
6
|
static examples = [
|
|
7
7
|
'<%= config.bin %> <%= command.id %>',
|
|
8
8
|
'<%= config.bin %> <%= command.id %> --watch',
|
|
@@ -10,7 +10,7 @@ export default class LogsCommand extends DeployedBlueprintCommand {
|
|
|
10
10
|
static flags = {
|
|
11
11
|
watch: Flags.boolean({
|
|
12
12
|
char: 'w',
|
|
13
|
-
description: 'Watch for new logs (streaming mode)',
|
|
13
|
+
description: 'Watch for new Stack logs (streaming mode)',
|
|
14
14
|
aliases: ['follow'],
|
|
15
15
|
}),
|
|
16
16
|
};
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const BLUEPRINT_CONFIG_VERSION = "v2025-05-08";
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const BLUEPRINT_CONFIG_DIR = ".sanity";
|
|
3
3
|
export declare const BLUEPRINT_CONFIG_FILE = "blueprint.config.json";
|
|
4
|
+
export declare let RUNTIME_CLI_VERSION: string | undefined;
|
|
4
5
|
declare const _default: {
|
|
5
6
|
isTest: boolean;
|
|
6
7
|
apiUrl: string;
|
package/dist/config.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
1
3
|
import { env } from 'node:process';
|
|
2
4
|
import getToken from './utils/get-token.js';
|
|
3
5
|
export const BLUEPRINT_CONFIG_VERSION = 'v2025-05-08';
|
|
4
|
-
export const
|
|
6
|
+
export const BLUEPRINT_CONFIG_DIR = '.sanity';
|
|
5
7
|
export const BLUEPRINT_CONFIG_FILE = 'blueprint.config.json';
|
|
8
|
+
export let RUNTIME_CLI_VERSION;
|
|
9
|
+
try {
|
|
10
|
+
RUNTIME_CLI_VERSION = JSON.parse(readFileSync(join(dirname(import.meta.url), '..', 'package.json'), 'utf8')).version;
|
|
11
|
+
}
|
|
12
|
+
catch { }
|
|
6
13
|
const nodeEnv = env.NODE_ENV?.toLowerCase() ?? 'production';
|
|
7
14
|
const isTest = nodeEnv === 'test';
|
|
8
15
|
const sanityEnv = env.SANITY_INTERNAL_ENV?.toLowerCase() ?? 'production';
|
|
@@ -4,11 +4,11 @@ export interface BlueprintConfigOptions extends CoreConfig {
|
|
|
4
4
|
token: string;
|
|
5
5
|
blueprint: ReadBlueprintResult;
|
|
6
6
|
flags: {
|
|
7
|
-
'test-config'?: boolean;
|
|
8
7
|
edit?: boolean;
|
|
9
8
|
'project-id'?: string;
|
|
10
9
|
'organization-id'?: string;
|
|
11
10
|
'stack-id'?: string;
|
|
11
|
+
verbose?: boolean;
|
|
12
12
|
};
|
|
13
13
|
}
|
|
14
14
|
export declare function blueprintConfigCore(options: BlueprintConfigOptions): Promise<CoreResult>;
|
|
@@ -1,89 +1,103 @@
|
|
|
1
1
|
import { highlight } from 'cardinal';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import { writeConfigFile } from '../../actions/blueprints/config.js';
|
|
4
|
-
import {
|
|
5
|
-
import { capitalize, niceId, warn } from '../../utils/display/presenters.js';
|
|
6
|
-
import { promptForProject } from '../../utils/display/prompt.js';
|
|
3
|
+
import { patchConfigFile, writeConfigFile, } from '../../actions/blueprints/config.js';
|
|
4
|
+
import { BLUEPRINT_CONFIG_DIR, BLUEPRINT_CONFIG_FILE } from '../../config.js';
|
|
5
|
+
import { capitalize, filePathRelativeToCwd, niceId, warn } from '../../utils/display/presenters.js';
|
|
6
|
+
import { promptForProject, promptForStack } from '../../utils/display/prompt.js';
|
|
7
7
|
export async function blueprintConfigCore(options) {
|
|
8
|
-
const { bin = 'sanity', log, token, flags } = options;
|
|
9
|
-
const { edit: editConfig = false, '
|
|
10
|
-
const {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
8
|
+
const { bin = 'sanity', blueprint, log, token, flags } = options;
|
|
9
|
+
const { edit: editConfig = false, 'project-id': flagProjectId, 'organization-id': flagOrganizationId, 'stack-id': flagStackId, verbose: v = false, } = flags;
|
|
10
|
+
const { stackId: configStackId, scopeType: configScopeType, scopeId: configScopeId, blueprintConfig, fileInfo, } = blueprint;
|
|
11
|
+
const blueprintFilePath = fileInfo.blueprintFilePath;
|
|
12
|
+
const configPath = blueprintConfig?.configPath;
|
|
13
|
+
if (!configStackId && !configScopeType && !configScopeId) {
|
|
14
|
+
log(warn('Incomplete configuration.'));
|
|
15
|
+
if (!editConfig) {
|
|
16
|
+
// blueprint.json exists but no config JSON
|
|
17
|
+
log(`Run \`${bin} blueprints doctor\` for diagnostics.`);
|
|
18
|
+
return { success: true }; // not necessarily fatal
|
|
20
19
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
}
|
|
21
|
+
log(chalk.bold('Current Blueprint configuration:'));
|
|
22
|
+
if (configPath) {
|
|
23
|
+
if (v)
|
|
24
|
+
log(` File: ${filePathRelativeToCwd(configPath)}`);
|
|
25
|
+
}
|
|
26
|
+
log(` Deployment: ${chalk.blue('Stack')} ${niceId(configStackId || 'unknown')}`);
|
|
27
|
+
log(` Scoped to: ${chalk.blue(capitalize(configScopeType || 'unknown'))} ${niceId(configScopeId || 'unknown')}`);
|
|
28
|
+
if (blueprintConfig?.updatedAt) {
|
|
29
|
+
if (v)
|
|
30
|
+
log(` Updated: ${new Date(blueprintConfig.updatedAt).toLocaleString()}`);
|
|
31
|
+
}
|
|
32
|
+
// passing new config without --edit flag is not allowed
|
|
33
|
+
if ((flagProjectId || flagOrganizationId || flagStackId) && !editConfig) {
|
|
34
|
+
log('To update the configuration, use the --edit flag.');
|
|
35
|
+
return { success: true };
|
|
36
|
+
}
|
|
37
|
+
if (!editConfig) {
|
|
38
|
+
// no edit; return success early
|
|
39
|
+
return { success: true };
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// if a config property flag was passed, set the value and return success
|
|
43
|
+
// do not try to validate correctness of combined flags; this should not be interactive
|
|
44
|
+
const providedConfigFlag = [flagProjectId, flagStackId, flagOrganizationId].some(Boolean);
|
|
45
|
+
if (providedConfigFlag) {
|
|
46
|
+
const configUpdate = {};
|
|
47
|
+
if (flagProjectId)
|
|
48
|
+
configUpdate.projectId = flagProjectId;
|
|
49
|
+
if (flagStackId)
|
|
50
|
+
configUpdate.stackId = flagStackId;
|
|
51
|
+
if (flagOrganizationId)
|
|
52
|
+
configUpdate.organizationId = flagOrganizationId;
|
|
53
|
+
try {
|
|
54
|
+
patchConfigFile(blueprintFilePath, configUpdate);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return { success: false, error: 'Unable to update configuration.' };
|
|
58
|
+
}
|
|
59
|
+
log('\nConfiguration updated.');
|
|
27
60
|
return { success: true };
|
|
28
61
|
}
|
|
29
|
-
//
|
|
30
|
-
if (
|
|
62
|
+
// organization-based Blueprints are not yet supported for interactive editing
|
|
63
|
+
if (configScopeType === 'organization') {
|
|
64
|
+
return { success: false, error: 'Only project-based Blueprints are supported.' };
|
|
65
|
+
}
|
|
66
|
+
// otherwise, prompt for values interactively
|
|
67
|
+
let updatedProjectId = flagProjectId;
|
|
68
|
+
if (!updatedProjectId) {
|
|
69
|
+
const pickedProject = await promptForProject({
|
|
70
|
+
token,
|
|
71
|
+
knownProjectId: configScopeId,
|
|
72
|
+
});
|
|
73
|
+
updatedProjectId = pickedProject.projectId;
|
|
74
|
+
}
|
|
75
|
+
if (!updatedProjectId)
|
|
76
|
+
return { success: false, error: 'Project ID is required.' };
|
|
77
|
+
let updatedStackId = flagStackId;
|
|
78
|
+
if (!updatedStackId) {
|
|
79
|
+
const pickedStack = await promptForStack({ projectId: updatedProjectId, token });
|
|
80
|
+
updatedStackId = pickedStack.stackId;
|
|
81
|
+
}
|
|
82
|
+
if (!updatedStackId)
|
|
83
|
+
return { success: false, error: 'Stack is required.' };
|
|
84
|
+
try {
|
|
85
|
+
// update or create config JSON
|
|
86
|
+
writeConfigFile({ blueprintFilePath, projectId: updatedProjectId, stackId: updatedStackId });
|
|
87
|
+
log(`\n${chalk.bold('New configuration:')}`);
|
|
88
|
+
log(` Deployment: ${chalk.blue('Stack')} ${niceId(updatedStackId)}`);
|
|
89
|
+
log(` Scoped to: ${chalk.blue('Project')} ${niceId(updatedProjectId)}`);
|
|
90
|
+
log('');
|
|
91
|
+
log('Configuration updated.');
|
|
31
92
|
return { success: true };
|
|
32
|
-
// warn about deprecated test-config flag
|
|
33
|
-
if (testConfig) {
|
|
34
|
-
log(warn(`The "test" flag is deprecated. Use "${bin} blueprints doctor" instead.`));
|
|
35
93
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
knownProjectId: configScopeId,
|
|
44
|
-
})).projectId;
|
|
45
|
-
if (!updatedProjectId) {
|
|
46
|
-
return {
|
|
47
|
-
success: false,
|
|
48
|
-
error: 'Project ID is required.',
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
// LAUNCH LIMIT: 1 Stack per Project - configStackId is always inferred from projectId if not set in config JSON
|
|
52
|
-
let updatedStackId = flagStackId ?? // flag first
|
|
53
|
-
configStackId ?? // existing config second
|
|
54
|
-
`ST-${updatedProjectId}`; //?? LAUNCH LIMIT: 1 Stack per Project - project-based third
|
|
55
|
-
// (await promptForStackId({projectId: updatedProjectId, knownStackId: configStackId})) // prompt for stackId
|
|
56
|
-
const isProjectBasedId = updatedStackId === `ST-${updatedProjectId}`;
|
|
57
|
-
log(`\n${chalk.bold('New configuration:')}`);
|
|
58
|
-
log(` Blueprint scoped to: ${chalk.blue(capitalize(configScopeType))} ${niceId(updatedProjectId)}`);
|
|
59
|
-
log(` Deployment ID: ${niceId(updatedStackId)}`);
|
|
60
|
-
// LAUNCH LIMIT: 1 Stack per Project - do not set Stack ID if it's project-based
|
|
61
|
-
if (isProjectBasedId)
|
|
62
|
-
updatedStackId = undefined;
|
|
63
|
-
try {
|
|
64
|
-
// update or create config JSON
|
|
65
|
-
writeConfigFile({ projectId: updatedProjectId, stackId: updatedStackId });
|
|
66
|
-
log('Configuration updated successfully.');
|
|
67
|
-
return { success: true };
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
log(`Unable to update config. These values should be set in ${BLUEPRINT_DIR}/${BLUEPRINT_CONFIG_FILE}`);
|
|
71
|
-
log(highlight(JSON.stringify({ metadata: { projectId: updatedProjectId, stackId: updatedStackId } }, null, 2)));
|
|
72
|
-
return {
|
|
73
|
-
success: false,
|
|
74
|
-
error: `Be sure to update your ${BLUEPRINT_DIR}/${BLUEPRINT_CONFIG_FILE}`,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
log(warn('Only project-based Blueprints are currently supported.'));
|
|
80
|
-
return { success: false, error: 'Only project-based Blueprints are supported.' };
|
|
81
|
-
}
|
|
94
|
+
catch {
|
|
95
|
+
log(`Unable to update config. These values should be set in ${BLUEPRINT_CONFIG_DIR}/${BLUEPRINT_CONFIG_FILE}`);
|
|
96
|
+
log(highlight(JSON.stringify({ metadata: { projectId: updatedProjectId, stackId: updatedStackId } }, null, 2)));
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
error: `Be sure to update your ${BLUEPRINT_CONFIG_DIR}/${BLUEPRINT_CONFIG_FILE}`,
|
|
100
|
+
};
|
|
82
101
|
}
|
|
83
|
-
// Default return (shouldn't reach here with proper flow control)
|
|
84
|
-
return { success: true };
|
|
85
|
-
}
|
|
86
|
-
catch {
|
|
87
|
-
return { success: false, error: 'Unknown error' };
|
|
88
102
|
}
|
|
89
103
|
}
|
|
@@ -64,16 +64,16 @@ export async function blueprintDeployCore(options) {
|
|
|
64
64
|
auth,
|
|
65
65
|
});
|
|
66
66
|
if (!deployOk) {
|
|
67
|
-
spinner.fail(`${chalk.red('Failed')} to update deployment`);
|
|
68
|
-
return { success: false, error: deployError || 'Failed to update deployment' };
|
|
67
|
+
spinner.fail(`${chalk.red('Failed')} to update Stack deployment`);
|
|
68
|
+
return { success: false, error: deployError || 'Failed to update Stack deployment' };
|
|
69
69
|
}
|
|
70
70
|
spinner.stop().clear();
|
|
71
71
|
if (noWait) {
|
|
72
|
-
log(chalk.bold.green('
|
|
72
|
+
log(chalk.bold.green('Stack deployment started!'));
|
|
73
73
|
log(`Use \`${bin} blueprints info\` to check status`);
|
|
74
74
|
return { success: true, data: { resources } };
|
|
75
75
|
}
|
|
76
|
-
log(chalk.dim('
|
|
76
|
+
log(chalk.dim('Stack deployment progress:'));
|
|
77
77
|
let logStreamCleanup = null;
|
|
78
78
|
try {
|
|
79
79
|
logStreamCleanup = await setupLogStreaming({
|
|
@@ -87,23 +87,23 @@ export async function blueprintDeployCore(options) {
|
|
|
87
87
|
if (!ok) {
|
|
88
88
|
if (logStreamCleanup)
|
|
89
89
|
logStreamCleanup();
|
|
90
|
-
return { success: false, error: 'Failed to check deployment status' };
|
|
90
|
+
return { success: false, error: 'Failed to check Stack deployment status' };
|
|
91
91
|
}
|
|
92
92
|
const operation = currentStack.recentOperation;
|
|
93
93
|
if (!operation) {
|
|
94
94
|
if (logStreamCleanup)
|
|
95
95
|
logStreamCleanup();
|
|
96
|
-
return { success: false, error: 'No deployment operation found' };
|
|
96
|
+
return { success: false, error: 'No Stack deployment operation found' };
|
|
97
97
|
}
|
|
98
98
|
if (operation.status === 'FAILED') {
|
|
99
99
|
if (logStreamCleanup)
|
|
100
100
|
logStreamCleanup();
|
|
101
|
-
return { success: false, error: '
|
|
101
|
+
return { success: false, error: 'Stack deployment failed' };
|
|
102
102
|
}
|
|
103
103
|
if (operation.status === 'COMPLETED') {
|
|
104
104
|
if (logStreamCleanup)
|
|
105
105
|
logStreamCleanup();
|
|
106
|
-
log(chalk.bold.green('
|
|
106
|
+
log(chalk.bold.green('Stack deployment completed!'));
|
|
107
107
|
return { success: true, data: { resources } };
|
|
108
108
|
}
|
|
109
109
|
await setTimeout(1500);
|
|
@@ -9,6 +9,7 @@ export interface BlueprintDestroyOptions extends CoreConfig {
|
|
|
9
9
|
'organization-id'?: string;
|
|
10
10
|
'stack-id'?: string;
|
|
11
11
|
'no-wait'?: boolean;
|
|
12
|
+
verbose?: boolean;
|
|
12
13
|
};
|
|
13
14
|
}
|
|
14
15
|
export declare function blueprintDestroyCore(options: BlueprintDestroyOptions): Promise<CoreResult>;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { setTimeout } from 'node:timers/promises';
|
|
2
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
3
|
import chalk from 'chalk';
|
|
3
|
-
import inquirer from 'inquirer';
|
|
4
4
|
import ora from 'ora';
|
|
5
5
|
import { setupLogStreaming } from '../../actions/blueprints/logs-streaming.js';
|
|
6
6
|
import { destroyStack, getStack } from '../../actions/blueprints/stacks.js';
|
|
7
7
|
import { niceId } from '../../utils/display/presenters.js';
|
|
8
8
|
export async function blueprintDestroyCore(options) {
|
|
9
9
|
const { log, token, blueprint, flags } = options;
|
|
10
|
-
const { force = false, 'project-id': flagProjectId, 'organization-id': flagOrganizationId, 'stack-id': flagStackId, 'no-wait': noWait = false, } = flags;
|
|
10
|
+
const { force = false, 'project-id': flagProjectId, 'organization-id': flagOrganizationId, 'stack-id': flagStackId, 'no-wait': noWait = false, verbose: _verbose = false, } = flags;
|
|
11
11
|
// 3-flag combo: just destroy it
|
|
12
12
|
if ((flagProjectId || flagOrganizationId) && flagStackId && force) {
|
|
13
13
|
let scopeType;
|
|
@@ -28,8 +28,8 @@ export async function blueprintDestroyCore(options) {
|
|
|
28
28
|
auth: { token, scopeType, scopeId },
|
|
29
29
|
});
|
|
30
30
|
if (!ok)
|
|
31
|
-
return { success: false, error: error || 'Failed to destroy deployment' };
|
|
32
|
-
log(`
|
|
31
|
+
return { success: false, error: error || 'Failed to destroy Stack deployment' };
|
|
32
|
+
log(`Stack deployment "${stack.name}" ${niceId(stack.id)} destroyed`);
|
|
33
33
|
return { success: true };
|
|
34
34
|
}
|
|
35
35
|
const { scopeType, scopeId, stackId } = blueprint;
|
|
@@ -41,42 +41,38 @@ export async function blueprintDestroyCore(options) {
|
|
|
41
41
|
if (flagStackId) {
|
|
42
42
|
const flagStack = await getStack({ stackId: flagStackId, auth });
|
|
43
43
|
if (!flagStack.ok)
|
|
44
|
-
return { success: false, error: flagStack.error || 'Failed to get
|
|
44
|
+
return { success: false, error: flagStack.error || 'Failed to get Stack' };
|
|
45
45
|
stack = flagStack.stack;
|
|
46
46
|
}
|
|
47
47
|
else if (stackId) {
|
|
48
48
|
const blueprintStack = await getStack({ stackId, auth });
|
|
49
49
|
if (!blueprintStack.ok)
|
|
50
|
-
return { success: false, error: blueprintStack.error || 'Failed to get
|
|
50
|
+
return { success: false, error: blueprintStack.error || 'Failed to get Stack' };
|
|
51
51
|
stack = blueprintStack.stack;
|
|
52
52
|
}
|
|
53
53
|
if (!stack)
|
|
54
|
-
return { success: false, error: '
|
|
54
|
+
return { success: false, error: 'Stack deployment not found' };
|
|
55
55
|
const destroySpinner = ora({
|
|
56
|
-
text: `Destroying ${chalk.bold(stack.name)} ${niceId(stack.id)}...`,
|
|
56
|
+
text: `Destroying Stack deployment "${chalk.bold(stack.name)}" ${niceId(stack.id)}...`,
|
|
57
57
|
color: 'red',
|
|
58
58
|
});
|
|
59
59
|
if (!force) {
|
|
60
|
-
const
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
},
|
|
67
|
-
]);
|
|
68
|
-
if (!confirm) {
|
|
69
|
-
log('Deployment destruction cancelled');
|
|
60
|
+
const confirmed = await confirm({
|
|
61
|
+
message: `Are you sure you want to destroy stack "${stack.name}" ${niceId(stack.id)}?`,
|
|
62
|
+
default: false,
|
|
63
|
+
});
|
|
64
|
+
if (!confirmed) {
|
|
65
|
+
log('Stack deployment destruction cancelled');
|
|
70
66
|
return { success: true };
|
|
71
67
|
}
|
|
72
68
|
destroySpinner.start();
|
|
73
69
|
// 5 second countdown
|
|
74
70
|
let i = 5;
|
|
75
71
|
while (i >= 0) {
|
|
76
|
-
destroySpinner.text = `Destroying deployment in ${chalk.bold((i--).toString())} seconds...`;
|
|
72
|
+
destroySpinner.text = `Destroying Stack deployment in ${chalk.bold((i--).toString())} seconds...`;
|
|
77
73
|
await setTimeout(1000);
|
|
78
74
|
}
|
|
79
|
-
destroySpinner.text = 'Destroying deployment 💥';
|
|
75
|
+
destroySpinner.text = 'Destroying Stack deployment 💥';
|
|
80
76
|
await setTimeout(500);
|
|
81
77
|
}
|
|
82
78
|
else {
|
|
@@ -85,15 +81,15 @@ export async function blueprintDestroyCore(options) {
|
|
|
85
81
|
const isoNow = new Date().toISOString();
|
|
86
82
|
const { ok, error } = await destroyStack({ stackId: stack.id, auth });
|
|
87
83
|
if (!ok) {
|
|
88
|
-
destroySpinner.fail('Failed to destroy deployment');
|
|
89
|
-
return { success: false, error: error || 'Failed to destroy deployment' };
|
|
84
|
+
destroySpinner.fail('Failed to destroy Stack deployment');
|
|
85
|
+
return { success: false, error: error || 'Failed to destroy Stack deployment' };
|
|
90
86
|
}
|
|
91
87
|
destroySpinner.stop().clear();
|
|
92
88
|
if (noWait) {
|
|
93
|
-
log(chalk.bold.magenta('
|
|
89
|
+
log(chalk.bold.magenta('Stack destruction started!'));
|
|
94
90
|
return { success: true };
|
|
95
91
|
}
|
|
96
|
-
log(chalk.dim('
|
|
92
|
+
log(chalk.dim('Stack destruction progress:'));
|
|
97
93
|
let logStreamCleanup = null;
|
|
98
94
|
try {
|
|
99
95
|
logStreamCleanup = await setupLogStreaming({
|
|
@@ -110,13 +106,13 @@ export async function blueprintDestroyCore(options) {
|
|
|
110
106
|
// it's possible that the operation is "gone" or available and "COMPLETED"
|
|
111
107
|
if (logStreamCleanup)
|
|
112
108
|
logStreamCleanup();
|
|
113
|
-
log(chalk.bold.magenta('
|
|
109
|
+
log(chalk.bold.magenta('Stack destruction completed!'));
|
|
114
110
|
return { success: true };
|
|
115
111
|
}
|
|
116
112
|
if (operation.status === 'FAILED') {
|
|
117
113
|
if (logStreamCleanup)
|
|
118
114
|
logStreamCleanup();
|
|
119
|
-
return { success: false, error: '
|
|
115
|
+
return { success: false, error: 'Stack destruction failed' };
|
|
120
116
|
}
|
|
121
117
|
await setTimeout(1500);
|
|
122
118
|
}
|