@sanity/runtime-cli 3.2.0 → 4.1.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 +29 -21
- package/dist/actions/blueprints/blueprint.d.ts +32 -16
- package/dist/actions/blueprints/blueprint.js +157 -106
- package/dist/actions/blueprints/stacks.js +1 -1
- package/dist/actions/functions/env/index.d.ts +2 -2
- package/dist/actions/functions/env/index.js +2 -2
- package/dist/commands/blueprints/add.js +3 -4
- package/dist/commands/blueprints/config.js +29 -17
- package/dist/commands/blueprints/deploy.d.ts +3 -0
- package/dist/commands/blueprints/deploy.js +49 -46
- package/dist/commands/blueprints/info.js +12 -6
- package/dist/commands/blueprints/init.js +54 -11
- package/dist/commands/blueprints/logs.js +6 -6
- package/dist/commands/blueprints/stacks.d.ts +3 -0
- package/dist/commands/blueprints/stacks.js +34 -10
- package/dist/commands/functions/test.js +5 -3
- package/dist/server/static/components/payload-panel.js +5 -3
- package/dist/utils/child-process-wrapper.js +1 -26
- package/dist/utils/display/blueprints-formatting.js +9 -6
- package/dist/utils/display/colors.d.ts +1 -0
- package/dist/utils/display/colors.js +3 -0
- package/dist/utils/invoke-local.d.ts +1 -0
- package/dist/utils/invoke-local.js +9 -3
- package/dist/utils/types.d.ts +37 -3
- package/oclif.manifest.json +23 -6
- package/package.json +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import highlight from 'color-json';
|
|
3
3
|
import inquirer from 'inquirer';
|
|
4
|
-
import {
|
|
4
|
+
import { readBlueprintOnDisk, writeConfigFile } from '../../actions/blueprints/blueprint.js';
|
|
5
5
|
import { listProjects } from '../../actions/blueprints/projects.js';
|
|
6
6
|
import { listStacks } from '../../actions/blueprints/stacks.js';
|
|
7
7
|
import config from '../../config.js';
|
|
8
|
+
import { bold, dim, niceId } from '../../utils/display/colors.js';
|
|
8
9
|
const { token } = config;
|
|
9
10
|
export default class Config extends Command {
|
|
10
11
|
static description = 'View or edit Blueprint configuration';
|
|
@@ -20,12 +21,15 @@ export default class Config extends Command {
|
|
|
20
21
|
};
|
|
21
22
|
async run() {
|
|
22
23
|
const { flags } = await this.parse(Config);
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const blueprint = await readBlueprintOnDisk();
|
|
25
|
+
const { stackId: configStackId, projectId: configProjectId, configPath, fileInfo } = blueprint;
|
|
26
|
+
const { extension: blueprintExtension, blueprintFilePath } = fileInfo;
|
|
27
|
+
if (!configStackId && !configProjectId) {
|
|
28
|
+
this.log('Project and Stack configuration is missing.');
|
|
26
29
|
}
|
|
27
|
-
this.log('
|
|
28
|
-
this.log(
|
|
30
|
+
this.log(bold('Current configuration:'));
|
|
31
|
+
this.log(`Sanity Project: ${niceId(configProjectId)}`);
|
|
32
|
+
this.log(`Blueprint Stack: ${niceId(configStackId)}`);
|
|
29
33
|
if (!flags.edit)
|
|
30
34
|
return;
|
|
31
35
|
const { ok, projects, error } = await listProjects({ token });
|
|
@@ -34,9 +38,9 @@ export default class Config extends Command {
|
|
|
34
38
|
if (projects.length === 0) {
|
|
35
39
|
this.error('No projects found. Please create a project in Sanity.io first.');
|
|
36
40
|
}
|
|
37
|
-
const projectChoices = projects.map(({ displayName, id }) => ({
|
|
38
|
-
name:
|
|
39
|
-
value:
|
|
41
|
+
const projectChoices = projects.map(({ displayName, id: projectId }) => ({
|
|
42
|
+
name: `"${displayName}" ${niceId(projectId)}`,
|
|
43
|
+
value: projectId,
|
|
40
44
|
}));
|
|
41
45
|
const { projectId } = await inquirer.prompt([
|
|
42
46
|
{
|
|
@@ -44,7 +48,7 @@ export default class Config extends Command {
|
|
|
44
48
|
name: 'projectId',
|
|
45
49
|
message: 'Select your Sanity project:',
|
|
46
50
|
choices: projectChoices,
|
|
47
|
-
default:
|
|
51
|
+
default: configProjectId,
|
|
48
52
|
},
|
|
49
53
|
]);
|
|
50
54
|
const auth = { token, projectId };
|
|
@@ -54,22 +58,30 @@ export default class Config extends Command {
|
|
|
54
58
|
this.error(stacksError ?? 'Unknown error listing stacks');
|
|
55
59
|
let stackId;
|
|
56
60
|
if (stacks.length > 0) {
|
|
57
|
-
const stackChoices = stacks.map((
|
|
58
|
-
name:
|
|
59
|
-
value: id,
|
|
61
|
+
const stackChoices = stacks.map((s) => ({
|
|
62
|
+
name: `"${s.name}" ${niceId(s.id)} ${dim(`(${s.resources.length} res)`)}`,
|
|
63
|
+
value: s.id,
|
|
60
64
|
}));
|
|
65
|
+
stackChoices.push({ name: 'Unset Stack association', value: 'unset' });
|
|
61
66
|
const { stackId: selectedStackId } = await inquirer.prompt([
|
|
62
67
|
{
|
|
63
68
|
type: 'list',
|
|
64
69
|
name: 'stackId',
|
|
65
70
|
message: 'Select a stack:',
|
|
66
71
|
choices: stackChoices,
|
|
67
|
-
default:
|
|
72
|
+
default: configStackId,
|
|
68
73
|
},
|
|
69
74
|
]);
|
|
70
|
-
stackId = selectedStackId;
|
|
75
|
+
stackId = selectedStackId === 'unset' ? undefined : selectedStackId;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
// update or create .blueprint/config.json
|
|
79
|
+
writeConfigFile({ projectId, stackId });
|
|
80
|
+
this.log('Configuration updated successfully.');
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
this.log('Unable to dynamically update config. Use these values in your blueprint:');
|
|
84
|
+
this.log(highlight(JSON.stringify({ metadata: { projectId, stackId } }, null, 2)));
|
|
71
85
|
}
|
|
72
|
-
writeConfigFile({ projectId, stackId });
|
|
73
|
-
this.log('\nConfiguration updated successfully.');
|
|
74
86
|
}
|
|
75
87
|
}
|
|
@@ -1,55 +1,37 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { setTimeout } from 'node:timers/promises';
|
|
2
|
+
import { Command, Flags } from '@oclif/core';
|
|
3
3
|
import Spinner from 'yocto-spinner';
|
|
4
4
|
import { stashAsset } from '../../actions/blueprints/assets.js';
|
|
5
|
-
import { readBlueprintOnDisk
|
|
6
|
-
import {
|
|
5
|
+
import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
6
|
+
import { getStack, updateStack } from '../../actions/blueprints/stacks.js';
|
|
7
7
|
import config from '../../config.js';
|
|
8
|
-
import { bold,
|
|
8
|
+
import { bold, niceId, red } from '../../utils/display/colors.js';
|
|
9
9
|
import { isLocalFunctionResource } from '../../utils/types.js';
|
|
10
10
|
const { token } = config;
|
|
11
11
|
export default class Deploy extends Command {
|
|
12
12
|
static description = 'Deploy a Blueprint';
|
|
13
13
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
14
|
+
static flags = {
|
|
15
|
+
'no-wait': Flags.boolean({
|
|
16
|
+
description: 'Do not wait for deployment to complete',
|
|
17
|
+
default: false,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
14
20
|
async run() {
|
|
15
|
-
const {
|
|
21
|
+
const { flags } = await this.parse(Deploy);
|
|
22
|
+
const { errors, projectId, stackId, parsedBlueprint: { resources }, deployedStack, } = await readBlueprintOnDisk({ getStack: true, token });
|
|
16
23
|
if (errors.length > 0) {
|
|
17
24
|
// printErrors(errors) // TODO: error printer in formatting
|
|
18
25
|
this.log('Blueprint parse errors:');
|
|
19
26
|
console.dir(errors, { depth: null });
|
|
20
27
|
return;
|
|
21
28
|
}
|
|
22
|
-
if (stackId
|
|
23
|
-
this.error('
|
|
24
|
-
let projectId = configuredProjectId;
|
|
25
|
-
if (!projectId) {
|
|
26
|
-
this.log('No Sanity Project context found in Blueprint configuration.');
|
|
27
|
-
const { maybeProjectId } = await inquirer.prompt([
|
|
28
|
-
{
|
|
29
|
-
type: 'input',
|
|
30
|
-
name: 'maybeProjectId',
|
|
31
|
-
message: 'Enter Sanity Project ID:',
|
|
32
|
-
},
|
|
33
|
-
]);
|
|
34
|
-
projectId = maybeProjectId;
|
|
29
|
+
if (!deployedStack || !stackId || !projectId) {
|
|
30
|
+
this.error('Before deploying, run `sanity blueprints init`');
|
|
35
31
|
}
|
|
36
|
-
if (
|
|
37
|
-
this.error('
|
|
32
|
+
if (stackId !== deployedStack.id)
|
|
33
|
+
this.error('Stack ID mismatch');
|
|
38
34
|
const auth = { token, projectId };
|
|
39
|
-
let name = deployedStack?.name;
|
|
40
|
-
if (!name) {
|
|
41
|
-
const { stackName } = await inquirer.prompt([
|
|
42
|
-
{
|
|
43
|
-
type: 'input',
|
|
44
|
-
name: 'stackName',
|
|
45
|
-
message: 'Enter stack name:',
|
|
46
|
-
validate: (input) => input.length > 0 || 'Stack name is required',
|
|
47
|
-
},
|
|
48
|
-
]);
|
|
49
|
-
name = stackName;
|
|
50
|
-
}
|
|
51
|
-
if (!name)
|
|
52
|
-
this.error('Stack name is required');
|
|
53
35
|
const validResources = resources?.filter((r) => r.type);
|
|
54
36
|
const functionResources = validResources?.filter(isLocalFunctionResource);
|
|
55
37
|
// First stash all function assets
|
|
@@ -60,7 +42,7 @@ export default class Deploy extends Command {
|
|
|
60
42
|
if (result.success && result.assetId) {
|
|
61
43
|
const src = resource.src;
|
|
62
44
|
resource.src = result.assetId; // TODO: properly reference asset - for now, the API expects the assetId
|
|
63
|
-
fnSpinner.success(`${resource.name}
|
|
45
|
+
fnSpinner.success(`${resource.name} ${niceId(result.assetId)}`);
|
|
64
46
|
this.log(` Source: ${src}`);
|
|
65
47
|
}
|
|
66
48
|
else {
|
|
@@ -71,23 +53,44 @@ export default class Deploy extends Command {
|
|
|
71
53
|
}
|
|
72
54
|
}
|
|
73
55
|
const stackPayload = {
|
|
74
|
-
name,
|
|
75
56
|
projectId,
|
|
57
|
+
name: deployedStack.name,
|
|
76
58
|
document: { resources: validResources },
|
|
77
59
|
};
|
|
78
60
|
this.debug('BLUEPRINT DOCUMENT:', stackPayload);
|
|
79
61
|
const spinner = Spinner({ text: 'Deploying stack...' }).start();
|
|
80
|
-
const { ok: deployOk, stack, error: deployError, } = deployedStack
|
|
81
|
-
? await updateStack({ stackId: deployedStack.id, stackPayload, auth })
|
|
82
|
-
: await createStack({ stackPayload, auth });
|
|
62
|
+
const { ok: deployOk, stack, error: deployError, } = await updateStack({ stackId: deployedStack.id, stackPayload, auth });
|
|
83
63
|
this.debug('STACK RESPONSE:', stack);
|
|
84
64
|
if (deployOk) {
|
|
85
|
-
spinner.success(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
65
|
+
spinner.success(`Stack "${bold(stack.name)}" ${niceId(stack.id)} deployment started!`);
|
|
66
|
+
if (!flags['no-wait']) {
|
|
67
|
+
const waitSpinner = Spinner({ text: 'Waiting for deployment to complete...' }).start();
|
|
68
|
+
while (true) {
|
|
69
|
+
// TODO: watch logs and print those while polling
|
|
70
|
+
const { ok, stack: currentStack } = await getStack({ stackId: stack.id, auth });
|
|
71
|
+
if (!ok) {
|
|
72
|
+
waitSpinner.error('Failed to check deployment status');
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
const operation = currentStack.recentOperation;
|
|
76
|
+
if (!operation) {
|
|
77
|
+
waitSpinner.error('No operation found');
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
if (operation.status === 'COMPLETED') {
|
|
81
|
+
waitSpinner.success('Deployment completed successfully');
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
if (operation.status === 'FAILED') {
|
|
85
|
+
waitSpinner.error('Deployment failed');
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
await setTimeout(1000);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
this.log('Use `sanity blueprints info` to check deployment status');
|
|
93
|
+
}
|
|
91
94
|
}
|
|
92
95
|
else {
|
|
93
96
|
this.debug('STACK ERROR RESPONSE:', stack);
|
|
@@ -3,12 +3,13 @@ import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
|
3
3
|
import { getStack } from '../../actions/blueprints/stacks.js';
|
|
4
4
|
import config from '../../config.js';
|
|
5
5
|
import { formatResourceTree, formatStackInfo } from '../../utils/display/blueprints-formatting.js';
|
|
6
|
+
import { niceId } from '../../utils/display/colors.js';
|
|
6
7
|
const { token } = config;
|
|
7
8
|
export default class Info extends Command {
|
|
8
|
-
static description = 'Show information about a Blueprint';
|
|
9
|
+
static description = 'Show information about a deployed Blueprint Stack';
|
|
9
10
|
static examples = [
|
|
10
11
|
'<%= config.bin %> <%= command.id %>',
|
|
11
|
-
'<%= config.bin %> <%= command.id %> --id
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --id ST-a1b2c3',
|
|
12
13
|
];
|
|
13
14
|
static flags = {
|
|
14
15
|
id: Flags.string({
|
|
@@ -18,25 +19,30 @@ export default class Info extends Command {
|
|
|
18
19
|
};
|
|
19
20
|
async run() {
|
|
20
21
|
const { flags } = await this.parse(Info);
|
|
21
|
-
const { errors, deployedStack, projectId } = await readBlueprintOnDisk({
|
|
22
|
+
const { errors, deployedStack, projectId, stackId } = await readBlueprintOnDisk({
|
|
23
|
+
getStack: true,
|
|
24
|
+
token,
|
|
25
|
+
});
|
|
22
26
|
if (errors.length > 0) {
|
|
23
27
|
// printErrors(errors)
|
|
24
28
|
this.warn('Blueprint parse errors:');
|
|
25
29
|
console.dir(errors, { depth: null });
|
|
26
30
|
return;
|
|
27
31
|
}
|
|
32
|
+
if (!stackId && !flags.id)
|
|
33
|
+
this.error('No Stack ID provided');
|
|
28
34
|
if (!projectId)
|
|
29
|
-
this.error('Project
|
|
35
|
+
this.error('Missing Project ID for Blueprint');
|
|
30
36
|
const auth = { token, projectId };
|
|
31
37
|
let stack = deployedStack;
|
|
32
38
|
if (flags.id) {
|
|
33
39
|
const { ok, stack: foundStack, error } = await getStack({ stackId: flags.id, auth });
|
|
34
40
|
if (!ok)
|
|
35
|
-
this.error(
|
|
41
|
+
this.error(`Failed to get Stack ${niceId(flags.id)}: ${error}`);
|
|
36
42
|
stack = foundStack;
|
|
37
43
|
}
|
|
38
44
|
else if (!stack) {
|
|
39
|
-
this.error(
|
|
45
|
+
this.error(`Stack ${niceId(stackId)} not found`);
|
|
40
46
|
}
|
|
41
47
|
if (!stack)
|
|
42
48
|
this.error('Stack not found. Is it deployed?');
|
|
@@ -4,13 +4,15 @@ import { Command } from '@oclif/core';
|
|
|
4
4
|
import inquirer from 'inquirer';
|
|
5
5
|
import { findBlueprintFile, writeBlueprintToDisk, writeConfigFile, } from '../../actions/blueprints/blueprint.js';
|
|
6
6
|
import { listProjects } from '../../actions/blueprints/projects.js';
|
|
7
|
+
import { createStack, listStacks } from '../../actions/blueprints/stacks.js';
|
|
7
8
|
import config from '../../config.js';
|
|
9
|
+
import { bold, dim, niceId, underline } from '../../utils/display/colors.js';
|
|
8
10
|
const { token } = config;
|
|
9
11
|
export default class Init extends Command {
|
|
10
12
|
static description = 'Initialize a new Blueprint';
|
|
11
13
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
12
14
|
async run() {
|
|
13
|
-
const existingBlueprint = findBlueprintFile(
|
|
15
|
+
const existingBlueprint = findBlueprintFile();
|
|
14
16
|
if (existingBlueprint) {
|
|
15
17
|
this.error(`A blueprint file already exists: ${existingBlueprint.fileName}`);
|
|
16
18
|
}
|
|
@@ -21,21 +23,21 @@ export default class Init extends Command {
|
|
|
21
23
|
message: 'Choose a blueprint type:',
|
|
22
24
|
choices: [
|
|
23
25
|
{ name: 'JSON (Recommended)', value: 'json' },
|
|
24
|
-
{ name: 'JavaScript
|
|
25
|
-
{ name: 'TypeScript
|
|
26
|
+
{ name: 'JavaScript', value: 'js', disabled: true },
|
|
27
|
+
{ name: 'TypeScript', value: 'ts', disabled: true },
|
|
26
28
|
],
|
|
27
29
|
default: 'json',
|
|
28
30
|
},
|
|
29
31
|
]);
|
|
30
|
-
const { ok
|
|
31
|
-
if (!
|
|
32
|
-
this.error(
|
|
32
|
+
const { ok: projectsOk, error: projectsErr, projects } = await listProjects({ token });
|
|
33
|
+
if (!projectsOk)
|
|
34
|
+
this.error(projectsErr ?? 'Unknown error listing projects');
|
|
33
35
|
if (projects.length === 0) {
|
|
34
36
|
this.error('No projects found. Please create a project in Sanity.io first.');
|
|
35
37
|
}
|
|
36
|
-
const projectChoices = projects.map(({ displayName, id }) => ({
|
|
37
|
-
name:
|
|
38
|
-
value:
|
|
38
|
+
const projectChoices = projects.map(({ displayName, id: projectId }) => ({
|
|
39
|
+
name: `"${displayName}" ${niceId(projectId)}`,
|
|
40
|
+
value: projectId,
|
|
39
41
|
}));
|
|
40
42
|
const { projectId } = await inquirer.prompt([
|
|
41
43
|
{
|
|
@@ -45,11 +47,52 @@ export default class Init extends Command {
|
|
|
45
47
|
choices: projectChoices,
|
|
46
48
|
},
|
|
47
49
|
]);
|
|
50
|
+
const { ok: stacksOk, error: stacksErr, stacks } = await listStacks({ token, projectId });
|
|
51
|
+
if (!stacksOk)
|
|
52
|
+
this.error(stacksErr || 'Failed to list Stacks');
|
|
53
|
+
const stackChoices = [{ name: bold('✨ Create a new Stack'), value: 'new' }];
|
|
54
|
+
if (stacks.length > 0) {
|
|
55
|
+
stackChoices.push(new inquirer.Separator(underline('Use an existing Stack:')));
|
|
56
|
+
stackChoices.push(...stacks.map((s) => ({
|
|
57
|
+
name: `"${s.name}" ${niceId(s.id)} ${dim(`(${s.resources.length} res)`)}`,
|
|
58
|
+
value: s.id,
|
|
59
|
+
})));
|
|
60
|
+
}
|
|
61
|
+
let stackId;
|
|
62
|
+
const { stackId: stackIdChoice } = await inquirer.prompt([
|
|
63
|
+
{
|
|
64
|
+
type: 'list',
|
|
65
|
+
name: 'stackId',
|
|
66
|
+
message: 'Select your Blueprint Stack:',
|
|
67
|
+
choices: stackChoices,
|
|
68
|
+
},
|
|
69
|
+
]);
|
|
70
|
+
if (stackIdChoice === 'new') {
|
|
71
|
+
const { stackName } = await inquirer.prompt([
|
|
72
|
+
{
|
|
73
|
+
type: 'input',
|
|
74
|
+
name: 'stackName',
|
|
75
|
+
message: 'Enter a name for your Stack:',
|
|
76
|
+
validate: (input) => input.length > 0 || 'Stack name is required',
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
const { ok: stackOk, error: stackErr, stack, } = await createStack({
|
|
80
|
+
stackPayload: { name: stackName, projectId, document: { resources: [] } },
|
|
81
|
+
auth: { token, projectId },
|
|
82
|
+
});
|
|
83
|
+
if (!stackOk)
|
|
84
|
+
this.error(stackErr || 'Failed to create Stack');
|
|
85
|
+
stackId = stack.id;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
stackId = stackIdChoice;
|
|
89
|
+
}
|
|
48
90
|
const fileName = `blueprint.${blueprintExtension}`;
|
|
49
91
|
const filePath = join(cwd(), fileName);
|
|
50
|
-
writeBlueprintToDisk({
|
|
51
|
-
writeConfigFile({ projectId });
|
|
92
|
+
writeBlueprintToDisk({ blueprintFilePath: filePath });
|
|
52
93
|
this.log(`Created new blueprint: ./${fileName}`);
|
|
94
|
+
writeConfigFile({ blueprintFilePath: filePath, projectId, stackId });
|
|
95
|
+
this.log(`Created new config file: ./${fileName}.config.json`);
|
|
53
96
|
if (blueprintExtension === 'ts') {
|
|
54
97
|
this.log('\nNote: TypeScript support requires "tsx" to be installed. Run: npm install -D tsx');
|
|
55
98
|
}
|
|
@@ -4,7 +4,7 @@ import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
|
4
4
|
import { findNewestLogTimestamp, getLogs, getRecentLogs, isNewerLog, streamLogs, } from '../../actions/blueprints/logs.js';
|
|
5
5
|
import config from '../../config.js';
|
|
6
6
|
import { formatTitle } from '../../utils/display/blueprints-formatting.js';
|
|
7
|
-
import { bold,
|
|
7
|
+
import { bold, niceId, red } from '../../utils/display/colors.js';
|
|
8
8
|
import { formatLogEntry, formatLogsByDay, organizeLogsByDay, } from '../../utils/display/logs-formatting.js';
|
|
9
9
|
const { token } = config;
|
|
10
10
|
export default class Logs extends Command {
|
|
@@ -35,7 +35,7 @@ export default class Logs extends Command {
|
|
|
35
35
|
this.error('Stack not found'); // returns
|
|
36
36
|
const { id: stackId, projectId, name } = deployedStack;
|
|
37
37
|
const auth = { token, projectId };
|
|
38
|
-
const spinner = Spinner({ text: `Fetching logs for stack ${
|
|
38
|
+
const spinner = Spinner({ text: `Fetching logs for stack ${niceId(stackId)}` }).start();
|
|
39
39
|
if (watchMode) {
|
|
40
40
|
const { ok, logs, error } = await getLogs(stackId, auth);
|
|
41
41
|
if (!ok) {
|
|
@@ -44,7 +44,7 @@ export default class Logs extends Command {
|
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
spinner.stop().clear(); // stop and remove the spinner
|
|
47
|
-
this.log(`${formatTitle('Blueprint', name)}
|
|
47
|
+
this.log(`${formatTitle('Blueprint', name)} ${niceId(stackId)} logs`);
|
|
48
48
|
if (logs.length > 0) {
|
|
49
49
|
this.log('\nMost recent logs:');
|
|
50
50
|
const recentLogs = getRecentLogs(logs);
|
|
@@ -53,7 +53,7 @@ export default class Logs extends Command {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
else {
|
|
56
|
-
this.log(`No recent logs found for stack
|
|
56
|
+
this.log(`No recent logs found for stack ${niceId(stackId)}`);
|
|
57
57
|
}
|
|
58
58
|
const onOpen = () => {
|
|
59
59
|
this.log(`Watching for new logs... ${bold('ctrl+c')} to stop`);
|
|
@@ -65,7 +65,7 @@ export default class Logs extends Command {
|
|
|
65
65
|
newestTimestamp = new Date(log.timestamp).getTime();
|
|
66
66
|
this.log(formatLogEntry(log, true));
|
|
67
67
|
};
|
|
68
|
-
this.debug(
|
|
68
|
+
this.debug(`Connecting to streaming endpoint for Stack ${niceId(stackId)}...`);
|
|
69
69
|
streamLogs(stackId, auth, renderLog, onOpen, (error) => this.log(`${red('Error:')} ${error}`));
|
|
70
70
|
return new Promise(() => {
|
|
71
71
|
// hold the line until the user terminates with Ctrl+C
|
|
@@ -82,7 +82,7 @@ export default class Logs extends Command {
|
|
|
82
82
|
return;
|
|
83
83
|
}
|
|
84
84
|
spinner.success(`${formatTitle('Blueprint', name)} Logs`);
|
|
85
|
-
this.log(`Found ${bold(logs.length.toString())} log entries for
|
|
85
|
+
this.log(`Found ${bold(logs.length.toString())} log entries for Stack ${niceId(stackId)}\n`);
|
|
86
86
|
// Organize and format logs by day
|
|
87
87
|
const logsByDay = organizeLogsByDay(logs);
|
|
88
88
|
this.log(formatLogsByDay(logsByDay));
|
|
@@ -2,5 +2,8 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
export default class Stacks extends Command {
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
projectId: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
};
|
|
5
8
|
run(): Promise<void>;
|
|
6
9
|
}
|
|
@@ -1,22 +1,46 @@
|
|
|
1
|
-
import { Command } from '@oclif/core';
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
3
3
|
import { listStacks } from '../../actions/blueprints/stacks.js';
|
|
4
4
|
import config from '../../config.js';
|
|
5
5
|
import { formatStacksListing } from '../../utils/display/blueprints-formatting.js';
|
|
6
|
-
import { bold,
|
|
6
|
+
import { bold, niceId } from '../../utils/display/colors.js';
|
|
7
7
|
const { token } = config;
|
|
8
8
|
export default class Stacks extends Command {
|
|
9
9
|
static description = 'List all Blueprint stacks';
|
|
10
|
-
static examples = [
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> <%= command.id %>',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --projectId a1b2c3',
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
projectId: Flags.string({
|
|
16
|
+
description: 'Project ID to show stacks for',
|
|
17
|
+
required: false,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
11
20
|
async run() {
|
|
12
|
-
const {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
const { flags } = await this.parse(Stacks);
|
|
22
|
+
let { projectId } = flags;
|
|
23
|
+
let stackId;
|
|
24
|
+
if (!projectId) {
|
|
25
|
+
try {
|
|
26
|
+
const { errors, projectId: projectIdFromBlueprint, stackId: stackIdFromBlueprint, } = await readBlueprintOnDisk();
|
|
27
|
+
if (errors.length > 0) {
|
|
28
|
+
this.log('Blueprint parse errors:');
|
|
29
|
+
console.dir(errors, { depth: null });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
projectId = projectIdFromBlueprint;
|
|
33
|
+
stackId = stackIdFromBlueprint;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// continue to print error
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (!projectId) {
|
|
40
|
+
this.log('Unable to determine Project ID. Provide one with --projectId');
|
|
41
|
+
this.log('Or create a Blueprint with `sanity blueprints init`');
|
|
16
42
|
return;
|
|
17
43
|
}
|
|
18
|
-
if (!projectId)
|
|
19
|
-
this.error('Project resource not found in blueprint');
|
|
20
44
|
const auth = { token, projectId };
|
|
21
45
|
const { ok, stacks, error } = await listStacks(auth);
|
|
22
46
|
if (!ok)
|
|
@@ -25,7 +49,7 @@ export default class Stacks extends Command {
|
|
|
25
49
|
this.warn('No stacks found');
|
|
26
50
|
return;
|
|
27
51
|
}
|
|
28
|
-
this.log(`${bold('Project')}
|
|
52
|
+
this.log(`${bold('Project')} ${niceId(projectId)} ${bold('Stacks')}:\n`);
|
|
29
53
|
this.log(formatStacksListing(stacks, stackId));
|
|
30
54
|
}
|
|
31
55
|
}
|
|
@@ -51,9 +51,11 @@ export default class Test extends Command {
|
|
|
51
51
|
file: flags.file,
|
|
52
52
|
timeout: flags.timeout,
|
|
53
53
|
}, {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
clientOptions: {
|
|
55
|
+
apiVersion: flags.api,
|
|
56
|
+
dataset: flags.dataset,
|
|
57
|
+
projectId: flags.project,
|
|
58
|
+
},
|
|
57
59
|
});
|
|
58
60
|
if (!error) {
|
|
59
61
|
this.log('Logs:');
|
|
@@ -21,9 +21,11 @@ class PayloadPanel extends ApiBaseElement {
|
|
|
21
21
|
const payloadText = this.api.store.payload.state.doc.text.join('') || '{}'
|
|
22
22
|
const event = JSON.parse(payloadText)
|
|
23
23
|
const context = {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
clientOptions: {
|
|
25
|
+
apiVersion: this.apiVersion.value,
|
|
26
|
+
dataset: this.api.store.selectedDataset,
|
|
27
|
+
projectId: this.api.store.selectedProject,
|
|
28
|
+
},
|
|
27
29
|
}
|
|
28
30
|
this.api.invoke({context, event})
|
|
29
31
|
}
|
|
@@ -13,30 +13,6 @@ export function getFunctionSource(src) {
|
|
|
13
13
|
return src
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
async function enhanceContext(context = {}) {
|
|
17
|
-
const {apiHost, apiVersion, dataset, projectId, token} = context
|
|
18
|
-
const enhancedContext = {...context}
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
if (apiHost && apiVersion && dataset && projectId && token) {
|
|
22
|
-
// @ts-ignore
|
|
23
|
-
const {createClient} = await import('@sanity/client')
|
|
24
|
-
const client = createClient({
|
|
25
|
-
projectId,
|
|
26
|
-
dataset,
|
|
27
|
-
useCdn: true,
|
|
28
|
-
apiHost,
|
|
29
|
-
apiVersion,
|
|
30
|
-
token,
|
|
31
|
-
})
|
|
32
|
-
enhancedContext.client = client
|
|
33
|
-
}
|
|
34
|
-
} catch {
|
|
35
|
-
// ignore as user hasn't provided the @sanity/client
|
|
36
|
-
}
|
|
37
|
-
return enhancedContext
|
|
38
|
-
}
|
|
39
|
-
|
|
40
16
|
// Start when payload data arrives from parent process
|
|
41
17
|
process.on('message', async (data) => {
|
|
42
18
|
let jsonData = null
|
|
@@ -48,7 +24,6 @@ process.on('message', async (data) => {
|
|
|
48
24
|
}
|
|
49
25
|
const {srcPath, payload} = jsonData
|
|
50
26
|
const {context, ...event} = payload
|
|
51
|
-
const enhancedContext = await enhanceContext(context)
|
|
52
27
|
let logs = ''
|
|
53
28
|
let json = null
|
|
54
29
|
|
|
@@ -67,7 +42,7 @@ process.on('message', async (data) => {
|
|
|
67
42
|
}
|
|
68
43
|
|
|
69
44
|
if (handler && typeof handler === 'function') {
|
|
70
|
-
json = await handler({context
|
|
45
|
+
json = await handler({context, event})
|
|
71
46
|
}
|
|
72
47
|
|
|
73
48
|
// revert changes to stdout
|