@sanity/runtime-cli 5.1.0 → 5.2.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 +23 -22
- package/dist/actions/blueprints/blueprint.d.ts +9 -5
- package/dist/actions/blueprints/index.d.ts +1 -1
- package/dist/actions/blueprints/index.js +1 -1
- package/dist/baseCommands.d.ts +10 -0
- package/dist/baseCommands.js +23 -11
- package/dist/commands/blueprints/add.d.ts +0 -8
- package/dist/commands/blueprints/add.js +12 -93
- package/dist/commands/blueprints/config.d.ts +2 -24
- package/dist/commands/blueprints/config.js +12 -179
- package/dist/commands/blueprints/deploy.js +12 -69
- package/dist/commands/blueprints/destroy.d.ts +5 -4
- package/dist/commands/blueprints/destroy.js +21 -61
- package/dist/commands/blueprints/info.js +11 -19
- package/dist/commands/blueprints/init.d.ts +0 -16
- package/dist/commands/blueprints/init.js +10 -167
- package/dist/commands/blueprints/logs.js +14 -67
- package/dist/commands/blueprints/plan.js +8 -13
- package/dist/commands/blueprints/stacks.js +10 -19
- package/dist/cores/blueprints/add.d.ts +13 -0
- package/dist/cores/blueprints/add.js +107 -0
- package/dist/cores/blueprints/config.d.ts +13 -0
- package/dist/cores/blueprints/config.js +222 -0
- package/dist/cores/blueprints/deploy.d.ts +14 -0
- package/dist/cores/blueprints/deploy.js +81 -0
- package/dist/cores/blueprints/destroy.d.ts +13 -0
- package/dist/cores/blueprints/destroy.js +106 -0
- package/dist/cores/blueprints/index.d.ts +18 -0
- package/dist/cores/blueprints/index.js +9 -0
- package/dist/cores/blueprints/info.d.ts +11 -0
- package/dist/cores/blueprints/info.js +33 -0
- package/dist/cores/blueprints/init.d.ts +15 -0
- package/dist/cores/blueprints/init.js +190 -0
- package/dist/cores/blueprints/logs.d.ts +11 -0
- package/dist/cores/blueprints/logs.js +74 -0
- package/dist/cores/blueprints/plan.d.ts +6 -0
- package/dist/cores/blueprints/plan.js +11 -0
- package/dist/cores/blueprints/stacks.d.ts +10 -0
- package/dist/cores/blueprints/stacks.js +30 -0
- package/dist/cores/index.d.ts +20 -0
- package/dist/cores/index.js +1 -0
- package/dist/utils/display/blueprints-formatting.js +12 -11
- package/dist/utils/display/colors.d.ts +3 -1
- package/dist/utils/display/colors.js +8 -2
- package/oclif.manifest.json +29 -15
- package/package.json +5 -1
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import highlight from 'color-json';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import Spinner from 'yocto-spinner';
|
|
5
|
+
import { writeConfigFile } from '../../actions/blueprints/blueprint.js';
|
|
6
|
+
import { getProject, listProjects } from '../../actions/blueprints/projects.js';
|
|
7
|
+
import { createStack, getStack, listStacks } from '../../actions/blueprints/stacks.js';
|
|
8
|
+
import { niceId, warn } from '../../utils/display/colors.js';
|
|
9
|
+
export async function blueprintConfigCore(options) {
|
|
10
|
+
const { bin = 'sanity', log, token, flags } = options;
|
|
11
|
+
const { edit: editConfig = false, 'test-config': testConfig = false, 'project-id': flagProjectId, 'stack-id': flagStackId, } = flags;
|
|
12
|
+
const { blueprint } = options;
|
|
13
|
+
const { stackId: configStackId, projectId: configProjectId } = blueprint;
|
|
14
|
+
try {
|
|
15
|
+
if (!configStackId && !configProjectId) {
|
|
16
|
+
log(warn('Missing local configuration.'));
|
|
17
|
+
if (!editConfig) {
|
|
18
|
+
// blueprint.json exists but no config.json
|
|
19
|
+
log(`Use \`${bin} blueprints config --edit\` to set a configuration.`);
|
|
20
|
+
return { success: true }; // not necessarily fatal
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
log(chalk.bold('Current configuration:'));
|
|
24
|
+
log(` Sanity Project: ${niceId(configProjectId)}`);
|
|
25
|
+
log(` Deployment ID: ${niceId(configStackId)}`);
|
|
26
|
+
// passing new config without --edit flag is not allowed
|
|
27
|
+
if ((flagProjectId || flagStackId) && !editConfig) {
|
|
28
|
+
log('To update the configuration, use the --edit flag.');
|
|
29
|
+
return { success: true };
|
|
30
|
+
}
|
|
31
|
+
// no edit or test: return success
|
|
32
|
+
if (!editConfig && !testConfig)
|
|
33
|
+
return { success: true };
|
|
34
|
+
// testing without editing
|
|
35
|
+
if (testConfig && !editConfig) {
|
|
36
|
+
if (configStackId && configProjectId) {
|
|
37
|
+
const testResult = await testConfigAndReport({
|
|
38
|
+
token,
|
|
39
|
+
stackId: configStackId,
|
|
40
|
+
projectId: configProjectId,
|
|
41
|
+
});
|
|
42
|
+
if (!testResult.ok) {
|
|
43
|
+
// command should exit with error code 1
|
|
44
|
+
return { success: false, error: 'Existing Blueprint deployment not found.' };
|
|
45
|
+
}
|
|
46
|
+
return { success: testResult.ok };
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
error: 'Unable to test the configuration. Both Project and Stack IDs must be set.',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// editing...
|
|
54
|
+
if (editConfig) {
|
|
55
|
+
const updatedProjectId = flagProjectId ||
|
|
56
|
+
(await promptForProjectId({
|
|
57
|
+
token,
|
|
58
|
+
knownProjectId: configProjectId,
|
|
59
|
+
}));
|
|
60
|
+
if (!updatedProjectId) {
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
error: 'Project ID is required.',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// LAUNCH LIMIT: 1 Stack per Project - configStackId is always inferred from projectId if not set in config.json
|
|
67
|
+
let updatedStackId = flagStackId ?? configStackId; // ?? (await promptForStackId({projectId: newProjectId, knownStackId: configStackId}))
|
|
68
|
+
const isProjectBasedId = updatedStackId === `ST-${updatedProjectId}`;
|
|
69
|
+
log(`\n${chalk.bold('New configuration:')}`);
|
|
70
|
+
log(` Sanity Project: ${niceId(updatedProjectId)}`);
|
|
71
|
+
log(` Deployment ID: ${niceId(updatedStackId)}`);
|
|
72
|
+
if (testConfig) {
|
|
73
|
+
if (updatedProjectId && updatedStackId) {
|
|
74
|
+
const { ok: newConfigOk, error: configError } = await testConfigAndReport({
|
|
75
|
+
token,
|
|
76
|
+
stackId: updatedStackId,
|
|
77
|
+
projectId: updatedProjectId,
|
|
78
|
+
});
|
|
79
|
+
if (!newConfigOk) {
|
|
80
|
+
// is this a projectBasedId stack?
|
|
81
|
+
if (isProjectBasedId) {
|
|
82
|
+
log(warn('Existing Blueprint deployment not found.'));
|
|
83
|
+
const reinitResult = await startReinitializeStack({
|
|
84
|
+
token,
|
|
85
|
+
projectId: updatedProjectId,
|
|
86
|
+
stackId: updatedStackId,
|
|
87
|
+
});
|
|
88
|
+
if (!reinitResult.ok) {
|
|
89
|
+
return { success: false, error: reinitResult.error || 'Failed to reinitialize stack' };
|
|
90
|
+
}
|
|
91
|
+
log(`New Blueprint deployment created for "${reinitResult.projectDisplayName}"`);
|
|
92
|
+
// continuing to save the config
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
return {
|
|
96
|
+
success: false,
|
|
97
|
+
error: configError || 'Updated configuration has not been saved.',
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
return {
|
|
104
|
+
success: false,
|
|
105
|
+
error: 'Unable to test the configuration. Both Project and Stack IDs must be set.',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// LAUNCH LIMIT: 1 Stack per Project - do not set Stack ID if it's project-based
|
|
110
|
+
if (isProjectBasedId)
|
|
111
|
+
updatedStackId = undefined;
|
|
112
|
+
try {
|
|
113
|
+
// update or create .blueprint/config.json
|
|
114
|
+
writeConfigFile({ projectId: updatedProjectId, stackId: updatedStackId });
|
|
115
|
+
log('Configuration updated successfully.');
|
|
116
|
+
return { success: true };
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
log('Unable to update config. These values should be set in .blueprint/config.json');
|
|
120
|
+
log(highlight(JSON.stringify({ metadata: { projectId: updatedProjectId, stackId: updatedStackId } }, null, 2)));
|
|
121
|
+
return { success: false, error: 'Be sure to update your ./blueprint/config.json' };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Default return (shouldn't reach here with proper flow control)
|
|
125
|
+
return { success: true };
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
return { success: false, error: 'Unknown error' };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function promptForProjectId({ token, knownProjectId, }) {
|
|
132
|
+
const { ok, projects, error } = await listProjects({ token });
|
|
133
|
+
if (!ok) {
|
|
134
|
+
throw new Error(error ?? 'Unknown error listing projects');
|
|
135
|
+
}
|
|
136
|
+
if (projects.length === 0) {
|
|
137
|
+
throw new Error('No Sanity projects found. Use `npx sanity init` to create one.');
|
|
138
|
+
}
|
|
139
|
+
const projectChoices = projects.map(({ displayName, id: projectId }) => ({
|
|
140
|
+
name: `"${displayName}" ${niceId(projectId)}`,
|
|
141
|
+
value: projectId,
|
|
142
|
+
}));
|
|
143
|
+
const { pickedProjectId } = await inquirer.prompt([
|
|
144
|
+
{
|
|
145
|
+
type: 'list',
|
|
146
|
+
name: 'pickedProjectId',
|
|
147
|
+
message: 'Select your Sanity project:',
|
|
148
|
+
choices: projectChoices,
|
|
149
|
+
default: knownProjectId,
|
|
150
|
+
},
|
|
151
|
+
]);
|
|
152
|
+
return pickedProjectId;
|
|
153
|
+
}
|
|
154
|
+
async function promptForStackId({ token, projectId, knownStackId, }) {
|
|
155
|
+
const auth = { token, projectId };
|
|
156
|
+
// get stacks for selected project
|
|
157
|
+
const { ok: stacksOk, stacks, error: stacksError } = await listStacks(auth);
|
|
158
|
+
if (!stacksOk)
|
|
159
|
+
throw new Error(stacksError ?? 'Unknown error listing stacks');
|
|
160
|
+
if (stacks.length > 0) {
|
|
161
|
+
const stackChoices = stacks.map((s) => ({
|
|
162
|
+
name: `"${s.name}" ${niceId(s.id)} ${chalk.dim(`(${s.resources.length} res)`)}`,
|
|
163
|
+
value: s.id,
|
|
164
|
+
}));
|
|
165
|
+
stackChoices.push({ name: 'Unset Stack association', value: 'unset' });
|
|
166
|
+
const { pickedStackId } = await inquirer.prompt([
|
|
167
|
+
{
|
|
168
|
+
type: 'list',
|
|
169
|
+
name: 'pickedStackId',
|
|
170
|
+
message: 'Select a stack:',
|
|
171
|
+
choices: stackChoices,
|
|
172
|
+
default: knownStackId,
|
|
173
|
+
},
|
|
174
|
+
]);
|
|
175
|
+
return pickedStackId === 'unset' ? undefined : pickedStackId;
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
async function testConfigAndReport({ token, stackId, projectId, }) {
|
|
180
|
+
const spinner = Spinner({ text: 'Testing the configuration...' }).start();
|
|
181
|
+
const { ok, error } = await getStack({
|
|
182
|
+
stackId,
|
|
183
|
+
auth: { token, projectId },
|
|
184
|
+
});
|
|
185
|
+
if (!ok) {
|
|
186
|
+
spinner.error('Configuration test failed.');
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
spinner.success('Configuration is valid.');
|
|
190
|
+
}
|
|
191
|
+
return { ok, error };
|
|
192
|
+
}
|
|
193
|
+
async function startReinitializeStack({ token, projectId, }) {
|
|
194
|
+
const auth = { token, projectId };
|
|
195
|
+
// stack id IS ST-${projectId} – it has already been checked and doesn't exist
|
|
196
|
+
const { confirm } = await inquirer.prompt([
|
|
197
|
+
{
|
|
198
|
+
type: 'confirm',
|
|
199
|
+
name: 'confirm',
|
|
200
|
+
message: `Do you want to create a ${chalk.blue('new')}, empty Blueprint deployment with the ${chalk.blue('existing')} configuration?`,
|
|
201
|
+
},
|
|
202
|
+
]);
|
|
203
|
+
if (!confirm)
|
|
204
|
+
return { ok: false, error: 'Reinitialization cancelled.' };
|
|
205
|
+
const { ok: projectOk, project, error: projectError } = await getProject(auth);
|
|
206
|
+
if (!projectOk) {
|
|
207
|
+
return {
|
|
208
|
+
ok: false,
|
|
209
|
+
error: projectError || 'Failed to find Project while creating Stack',
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
const projectDisplayName = project.displayName;
|
|
213
|
+
const stackPayload = { name: projectDisplayName, projectId, document: { resources: [] } };
|
|
214
|
+
const response = await createStack({ stackPayload, auth });
|
|
215
|
+
if (!response.ok)
|
|
216
|
+
return { ok: false, error: response.error || 'Failed to create new Stack' };
|
|
217
|
+
return {
|
|
218
|
+
ok: true,
|
|
219
|
+
stackId: response.stack.id,
|
|
220
|
+
projectDisplayName,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReadBlueprintResult } from '../../actions/blueprints/blueprint.js';
|
|
2
|
+
import type { AuthParams, Stack } from '../../utils/types.js';
|
|
3
|
+
import type { CoreConfig, CoreResult } from '../index.js';
|
|
4
|
+
export interface BlueprintDeployOptions extends CoreConfig {
|
|
5
|
+
auth: AuthParams;
|
|
6
|
+
stackId: string;
|
|
7
|
+
projectId: string;
|
|
8
|
+
deployedStack: Stack;
|
|
9
|
+
blueprint: ReadBlueprintResult;
|
|
10
|
+
flags: {
|
|
11
|
+
'no-wait'?: boolean;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare function blueprintDeployCore(options: BlueprintDeployOptions): Promise<CoreResult>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { setTimeout } from 'node:timers/promises';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import Spinner from 'yocto-spinner';
|
|
4
|
+
import { stashAsset } from '../../actions/blueprints/assets.js';
|
|
5
|
+
import { getStack, updateStack } from '../../actions/blueprints/stacks.js';
|
|
6
|
+
import { bold, niceId } from '../../utils/display/colors.js';
|
|
7
|
+
import { isLocalFunctionResource } from '../../utils/types.js';
|
|
8
|
+
export async function blueprintDeployCore(options) {
|
|
9
|
+
const { bin = 'sanity', log, auth, stackId, projectId, deployedStack, blueprint, flags } = options;
|
|
10
|
+
const noWait = flags['no-wait'] || false;
|
|
11
|
+
try {
|
|
12
|
+
const { resources } = blueprint.parsedBlueprint;
|
|
13
|
+
const validResources = resources?.filter((r) => r.type);
|
|
14
|
+
const functionResources = validResources?.filter(isLocalFunctionResource);
|
|
15
|
+
// First stash all function assets
|
|
16
|
+
if (functionResources?.length) {
|
|
17
|
+
for (const resource of functionResources) {
|
|
18
|
+
const fnSpinner = Spinner({ text: `Processing ${resource.name}...` }).start();
|
|
19
|
+
const result = await stashAsset({ resource, auth });
|
|
20
|
+
if (result.success && result.assetId) {
|
|
21
|
+
const src = resource.src;
|
|
22
|
+
resource.src = result.assetId; // TODO: properly reference asset - for now, the API expects the assetId
|
|
23
|
+
fnSpinner.success(`${resource.name} ${niceId(result.assetId)}`);
|
|
24
|
+
log(` Source: ${src}`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
fnSpinner.error(`Failed to process ${resource.name}`);
|
|
28
|
+
log(` Error: ${result.error}`);
|
|
29
|
+
return { success: false, error: result.error || 'Failed to process function resource' };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const stackPayload = {
|
|
34
|
+
projectId,
|
|
35
|
+
name: deployedStack.name,
|
|
36
|
+
document: { resources: validResources },
|
|
37
|
+
};
|
|
38
|
+
const spinner = Spinner({ text: 'Deploying...' }).start();
|
|
39
|
+
const { ok: deployOk, stack, error: deployError, } = await updateStack({ stackId, stackPayload, auth });
|
|
40
|
+
if (deployOk) {
|
|
41
|
+
spinner.success(`Deployment "${bold(stack.name)}" ${niceId(stack.id)} started!`);
|
|
42
|
+
if (!noWait) {
|
|
43
|
+
const waitSpinner = Spinner({ text: 'Waiting for deployment to complete...' }).start();
|
|
44
|
+
while (true) {
|
|
45
|
+
// TODO: watch logs and print those while polling
|
|
46
|
+
const { ok, stack: currentStack } = await getStack({ stackId: stack.id, auth });
|
|
47
|
+
if (!ok) {
|
|
48
|
+
waitSpinner.error('Failed to check deployment status');
|
|
49
|
+
return { success: false, error: 'Failed to check deployment status' };
|
|
50
|
+
}
|
|
51
|
+
const operation = currentStack.recentOperation;
|
|
52
|
+
if (!operation) {
|
|
53
|
+
waitSpinner.error('No operation found');
|
|
54
|
+
return { success: false, error: 'No operation found' };
|
|
55
|
+
}
|
|
56
|
+
if (operation.status === 'COMPLETED') {
|
|
57
|
+
waitSpinner.success('Deployment completed successfully');
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
if (operation.status === 'FAILED') {
|
|
61
|
+
waitSpinner.error('Deployment failed');
|
|
62
|
+
return { success: false, error: 'Deployment failed' };
|
|
63
|
+
}
|
|
64
|
+
await setTimeout(1000);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
log(`Use \`${bin} blueprints info\` to check status`);
|
|
69
|
+
}
|
|
70
|
+
return { success: true };
|
|
71
|
+
}
|
|
72
|
+
spinner.error(`${chalk.red('Failed')} to update deployment`);
|
|
73
|
+
log(`Error: ${deployError || JSON.stringify(stack, null, 2) || 'Unknown error'}`);
|
|
74
|
+
return { success: false, error: deployError || 'Failed to update deployment' };
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
78
|
+
log(`Error: ${errorMessage}`);
|
|
79
|
+
return { success: false, error: errorMessage };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReadBlueprintResult } from '../../actions/blueprints/blueprint.js';
|
|
2
|
+
import type { CoreConfig, CoreResult } from '../index.js';
|
|
3
|
+
export interface BlueprintDestroyOptions extends CoreConfig {
|
|
4
|
+
token: string;
|
|
5
|
+
blueprint: ReadBlueprintResult;
|
|
6
|
+
flags: {
|
|
7
|
+
force?: boolean;
|
|
8
|
+
'project-id'?: string;
|
|
9
|
+
'stack-id'?: string;
|
|
10
|
+
'no-wait'?: boolean;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare function blueprintDestroyCore(options: BlueprintDestroyOptions): Promise<CoreResult>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { setTimeout } from 'node:timers/promises';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import Spinner from 'yocto-spinner';
|
|
5
|
+
import { destroyStack, getStack } from '../../actions/blueprints/stacks.js';
|
|
6
|
+
import { niceId } from '../../utils/display/colors.js';
|
|
7
|
+
export async function blueprintDestroyCore(options) {
|
|
8
|
+
const { bin = 'sanity', log, token, blueprint, flags } = options;
|
|
9
|
+
const { force = false, 'project-id': flagProjectId, 'stack-id': flagStackId, 'no-wait': noWait = false, } = flags;
|
|
10
|
+
// 3-flag combo: just destroy it
|
|
11
|
+
if (flagProjectId && flagStackId && force) {
|
|
12
|
+
const { ok, error, stack } = await destroyStack({
|
|
13
|
+
stackId: flagStackId,
|
|
14
|
+
auth: { token, projectId: flagProjectId },
|
|
15
|
+
});
|
|
16
|
+
if (!ok)
|
|
17
|
+
return { success: false, error: error || 'Failed to destroy deployment' };
|
|
18
|
+
log(`Deployment "${stack.name}" ${niceId(stack.id)} destroyed`);
|
|
19
|
+
return { success: true };
|
|
20
|
+
}
|
|
21
|
+
const { projectId, stackId } = blueprint;
|
|
22
|
+
if (!projectId)
|
|
23
|
+
return { success: false, error: 'Project ID is required' };
|
|
24
|
+
const auth = { token, projectId };
|
|
25
|
+
let stack;
|
|
26
|
+
try {
|
|
27
|
+
if (flagStackId) {
|
|
28
|
+
const flagStack = await getStack({ stackId: flagStackId, auth });
|
|
29
|
+
if (!flagStack.ok)
|
|
30
|
+
return { success: false, error: flagStack.error || 'Failed to get stack' };
|
|
31
|
+
stack = flagStack.stack;
|
|
32
|
+
}
|
|
33
|
+
else if (stackId) {
|
|
34
|
+
const blueprintStack = await getStack({ stackId, auth });
|
|
35
|
+
if (!blueprintStack.ok)
|
|
36
|
+
return { success: false, error: blueprintStack.error || 'Failed to get stack' };
|
|
37
|
+
stack = blueprintStack.stack;
|
|
38
|
+
}
|
|
39
|
+
if (!stack)
|
|
40
|
+
return { success: false, error: 'Deployment not found' };
|
|
41
|
+
const destroySpinner = Spinner({
|
|
42
|
+
text: `Destroying ${chalk.bold(stack.name)} ${niceId(stack.id)}...`,
|
|
43
|
+
color: 'red',
|
|
44
|
+
});
|
|
45
|
+
if (!force) {
|
|
46
|
+
const { confirm } = await inquirer.prompt([
|
|
47
|
+
{
|
|
48
|
+
type: 'confirm',
|
|
49
|
+
name: 'confirm',
|
|
50
|
+
message: `Are you sure you want to destroy stack "${stack.name}" ${niceId(stack.id)}?`,
|
|
51
|
+
default: false,
|
|
52
|
+
},
|
|
53
|
+
]);
|
|
54
|
+
if (!confirm) {
|
|
55
|
+
log('Deployment destruction cancelled');
|
|
56
|
+
return { success: true };
|
|
57
|
+
}
|
|
58
|
+
destroySpinner.start();
|
|
59
|
+
// 5 second countdown
|
|
60
|
+
let i = 5;
|
|
61
|
+
while (i >= 0) {
|
|
62
|
+
destroySpinner.text = `Destroying deployment in ${chalk.bold((i--).toString())} seconds...`;
|
|
63
|
+
await setTimeout(1000);
|
|
64
|
+
}
|
|
65
|
+
destroySpinner.text = 'Destroying deployment 💥';
|
|
66
|
+
await setTimeout(500);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
destroySpinner.start();
|
|
70
|
+
}
|
|
71
|
+
const { ok, error } = await destroyStack({ stackId: stack.id, auth });
|
|
72
|
+
if (!ok) {
|
|
73
|
+
destroySpinner.error('Failed to destroy deployment');
|
|
74
|
+
return { success: false, error: error || 'Failed to destroy deployment' };
|
|
75
|
+
}
|
|
76
|
+
if (noWait) {
|
|
77
|
+
destroySpinner.success(`Deployment "${stack.name}" ${niceId(stack.id)} destroy started!`);
|
|
78
|
+
log(`Use \`${bin} blueprints info\` to check status`);
|
|
79
|
+
return { success: true };
|
|
80
|
+
}
|
|
81
|
+
destroySpinner.stop().clear();
|
|
82
|
+
const waitSpinner = Spinner({ text: 'Waiting for destruction to complete...' }).start();
|
|
83
|
+
while (true) {
|
|
84
|
+
const { ok: pollOk, stack: currentStack } = await getStack({ stackId: stack.id, auth });
|
|
85
|
+
const operation = currentStack?.recentOperation;
|
|
86
|
+
if (!pollOk || !operation || operation?.status === 'COMPLETED') {
|
|
87
|
+
// Operation is also marked destroyed when stack is deleted
|
|
88
|
+
// It's possible that the operation is "gone" or available and "COMPLETED"
|
|
89
|
+
waitSpinner.success(`Deployment "${stack.name}" ${niceId(stack.id)} destroyed`);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
if (operation.status === 'FAILED') {
|
|
93
|
+
waitSpinner.error('Destruction failed');
|
|
94
|
+
log(`Run \`${bin} blueprints logs\` for more details`);
|
|
95
|
+
return { success: false, error: 'Destruction failed' };
|
|
96
|
+
}
|
|
97
|
+
await setTimeout(1000);
|
|
98
|
+
}
|
|
99
|
+
return { success: true };
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
103
|
+
log(`Error: ${errorMessage}`);
|
|
104
|
+
return { success: false, error: errorMessage };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { blueprintAddCore } from './add.js';
|
|
2
|
+
export type { BlueprintAddOptions } from './add.js';
|
|
3
|
+
export { blueprintConfigCore } from './config.js';
|
|
4
|
+
export type { BlueprintConfigOptions } from './config.js';
|
|
5
|
+
export { blueprintDeployCore } from './deploy.js';
|
|
6
|
+
export type { BlueprintDeployOptions } from './deploy.js';
|
|
7
|
+
export { blueprintDestroyCore } from './destroy.js';
|
|
8
|
+
export type { BlueprintDestroyOptions } from './destroy.js';
|
|
9
|
+
export { blueprintInfoCore } from './info.js';
|
|
10
|
+
export type { BlueprintInfoOptions } from './info.js';
|
|
11
|
+
export { blueprintInitCore } from './init.js';
|
|
12
|
+
export type { BlueprintInitOptions } from './init.js';
|
|
13
|
+
export { blueprintLogsCore } from './logs.js';
|
|
14
|
+
export type { BlueprintLogsOptions } from './logs.js';
|
|
15
|
+
export { blueprintPlanCore } from './plan.js';
|
|
16
|
+
export type { BlueprintPlanOptions } from './plan.js';
|
|
17
|
+
export { blueprintStacksCore } from './stacks.js';
|
|
18
|
+
export type { BlueprintStacksOptions } from './stacks.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { blueprintAddCore } from './add.js';
|
|
2
|
+
export { blueprintConfigCore } from './config.js';
|
|
3
|
+
export { blueprintDeployCore } from './deploy.js';
|
|
4
|
+
export { blueprintDestroyCore } from './destroy.js';
|
|
5
|
+
export { blueprintInfoCore } from './info.js';
|
|
6
|
+
export { blueprintInitCore } from './init.js';
|
|
7
|
+
export { blueprintLogsCore } from './logs.js';
|
|
8
|
+
export { blueprintPlanCore } from './plan.js';
|
|
9
|
+
export { blueprintStacksCore } from './stacks.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AuthParams, Stack } from '../../utils/types.js';
|
|
2
|
+
import type { CoreConfig, CoreResult } from '../index.js';
|
|
3
|
+
export interface BlueprintInfoOptions extends CoreConfig {
|
|
4
|
+
auth: AuthParams;
|
|
5
|
+
stackId: string;
|
|
6
|
+
deployedStack: Stack;
|
|
7
|
+
flags: {
|
|
8
|
+
id?: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export declare function blueprintInfoCore(options: BlueprintInfoOptions): Promise<CoreResult>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getStack } from '../../actions/blueprints/stacks.js';
|
|
2
|
+
import { formatResourceTree, formatStackInfo } from '../../utils/display/blueprints-formatting.js';
|
|
3
|
+
import { niceId } from '../../utils/display/colors.js';
|
|
4
|
+
export async function blueprintInfoCore(options) {
|
|
5
|
+
const { log, auth, stackId, flags, deployedStack } = options;
|
|
6
|
+
try {
|
|
7
|
+
const targetStackId = flags.id || stackId;
|
|
8
|
+
let stack = deployedStack;
|
|
9
|
+
if (flags.id) {
|
|
10
|
+
const existingStackResponse = await getStack({ stackId: targetStackId, auth });
|
|
11
|
+
if (!existingStackResponse.ok) {
|
|
12
|
+
log(`Could not retrieve deployment info for ${niceId(targetStackId)}`);
|
|
13
|
+
return {
|
|
14
|
+
success: false,
|
|
15
|
+
error: existingStackResponse.error || 'Failed to retrieve stack',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
stack = existingStackResponse.stack;
|
|
19
|
+
}
|
|
20
|
+
log(formatStackInfo(stack, true));
|
|
21
|
+
if (stack.resources)
|
|
22
|
+
log(formatResourceTree(stack.resources));
|
|
23
|
+
return { success: true };
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
27
|
+
log(`Error: ${errorMessage}`);
|
|
28
|
+
return {
|
|
29
|
+
success: false,
|
|
30
|
+
error: errorMessage,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CoreConfig, CoreResult } from '../index.js';
|
|
2
|
+
export interface BlueprintInitOptions extends CoreConfig {
|
|
3
|
+
token: string;
|
|
4
|
+
args: {
|
|
5
|
+
dir?: string;
|
|
6
|
+
};
|
|
7
|
+
flags: {
|
|
8
|
+
dir?: string;
|
|
9
|
+
'blueprint-type'?: string;
|
|
10
|
+
'project-id'?: string;
|
|
11
|
+
'stack-id'?: string;
|
|
12
|
+
'stack-name'?: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare function blueprintInitCore(options: BlueprintInitOptions): Promise<CoreResult>;
|