@sanity/runtime-cli 1.4.2 → 1.6.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 +10 -10
- package/dist/actions/blueprints/blueprint.d.ts +26 -0
- package/dist/actions/blueprints/blueprint.js +199 -0
- package/dist/actions/blueprints/logs.js +3 -1
- package/dist/commands/blueprints/deploy.js +23 -6
- package/dist/commands/blueprints/info.js +4 -4
- package/dist/commands/blueprints/logs.js +1 -1
- package/dist/commands/blueprints/plan.js +6 -8
- package/dist/commands/blueprints/stacks.js +6 -6
- package/dist/commands/functions/invoke.js +1 -1
- package/dist/commands/functions/logs.js +1 -1
- package/dist/server/app.js +1 -1
- package/dist/utils/display/blueprints-formatting.js +1 -1
- package/dist/utils/types.d.ts +2 -0
- package/oclif.manifest.json +1 -1
- package/package.json +5 -1
- package/dist/actions/blueprints/read-blueprint.d.ts +0 -16
- package/dist/actions/blueprints/read-blueprint.js +0 -83
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ $ npm install -g @sanity/runtime-cli
|
|
|
20
20
|
$ sanity COMMAND
|
|
21
21
|
running command...
|
|
22
22
|
$ sanity (--version)
|
|
23
|
-
@sanity/runtime-cli/1.
|
|
23
|
+
@sanity/runtime-cli/1.6.0 linux-x64 node-v22.14.0
|
|
24
24
|
$ sanity --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ sanity COMMAND
|
|
@@ -65,7 +65,7 @@ EXAMPLES
|
|
|
65
65
|
$ sanity blueprints deploy
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
68
|
+
_See code: [src/commands/blueprints/deploy.ts](https://github.com/sanity-io/runtime-cli/blob/v1.6.0/src/commands/blueprints/deploy.ts)_
|
|
69
69
|
|
|
70
70
|
## `sanity blueprints info`
|
|
71
71
|
|
|
@@ -87,7 +87,7 @@ EXAMPLES
|
|
|
87
87
|
$ sanity blueprints info --id abc123
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
90
|
+
_See code: [src/commands/blueprints/info.ts](https://github.com/sanity-io/runtime-cli/blob/v1.6.0/src/commands/blueprints/info.ts)_
|
|
91
91
|
|
|
92
92
|
## `sanity blueprints logs`
|
|
93
93
|
|
|
@@ -109,7 +109,7 @@ EXAMPLES
|
|
|
109
109
|
$ sanity blueprints logs --watch
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
112
|
+
_See code: [src/commands/blueprints/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v1.6.0/src/commands/blueprints/logs.ts)_
|
|
113
113
|
|
|
114
114
|
## `sanity blueprints plan`
|
|
115
115
|
|
|
@@ -126,7 +126,7 @@ EXAMPLES
|
|
|
126
126
|
$ sanity blueprints plan
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
129
|
+
_See code: [src/commands/blueprints/plan.ts](https://github.com/sanity-io/runtime-cli/blob/v1.6.0/src/commands/blueprints/plan.ts)_
|
|
130
130
|
|
|
131
131
|
## `sanity blueprints stacks`
|
|
132
132
|
|
|
@@ -143,7 +143,7 @@ EXAMPLES
|
|
|
143
143
|
$ sanity blueprints stacks
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
146
|
+
_See code: [src/commands/blueprints/stacks.ts](https://github.com/sanity-io/runtime-cli/blob/v1.6.0/src/commands/blueprints/stacks.ts)_
|
|
147
147
|
|
|
148
148
|
## `sanity functions dev`
|
|
149
149
|
|
|
@@ -163,7 +163,7 @@ EXAMPLES
|
|
|
163
163
|
$ sanity functions dev --port 8974
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
166
|
+
_See code: [src/commands/functions/dev.ts](https://github.com/sanity-io/runtime-cli/blob/v1.6.0/src/commands/functions/dev.ts)_
|
|
167
167
|
|
|
168
168
|
## `sanity functions invoke ID`
|
|
169
169
|
|
|
@@ -189,7 +189,7 @@ EXAMPLES
|
|
|
189
189
|
$ sanity functions invoke <ID> --file 'payload.json'
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
_See code: [src/commands/functions/invoke.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
192
|
+
_See code: [src/commands/functions/invoke.ts](https://github.com/sanity-io/runtime-cli/blob/v1.6.0/src/commands/functions/invoke.ts)_
|
|
193
193
|
|
|
194
194
|
## `sanity functions logs ID`
|
|
195
195
|
|
|
@@ -209,7 +209,7 @@ EXAMPLES
|
|
|
209
209
|
$ sanity functions logs <ID>
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
212
|
+
_See code: [src/commands/functions/logs.ts](https://github.com/sanity-io/runtime-cli/blob/v1.6.0/src/commands/functions/logs.ts)_
|
|
213
213
|
|
|
214
214
|
## `sanity functions test PATH`
|
|
215
215
|
|
|
@@ -238,7 +238,7 @@ EXAMPLES
|
|
|
238
238
|
$ sanity functions test ./test.ts --data '{ "id": 1 }' --timeout 60
|
|
239
239
|
```
|
|
240
240
|
|
|
241
|
-
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v1.
|
|
241
|
+
_See code: [src/commands/functions/test.ts](https://github.com/sanity-io/runtime-cli/blob/v1.6.0/src/commands/functions/test.ts)_
|
|
242
242
|
|
|
243
243
|
## `sanity help [COMMAND]`
|
|
244
244
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Blueprint, BlueprintError, BlueprintStack } from '../../utils/types.js';
|
|
2
|
+
export declare function readBlueprintOnDisk({ blueprintPath, getStack, }?: {
|
|
3
|
+
blueprintPath?: string;
|
|
4
|
+
getStack?: boolean;
|
|
5
|
+
}): Promise<{
|
|
6
|
+
fileInfo: {
|
|
7
|
+
path: string;
|
|
8
|
+
fileName: string;
|
|
9
|
+
extension: string;
|
|
10
|
+
};
|
|
11
|
+
parsedBlueprint: Blueprint;
|
|
12
|
+
errors: BlueprintError[];
|
|
13
|
+
projectId?: string;
|
|
14
|
+
stackId?: string;
|
|
15
|
+
deployedStack?: BlueprintStack;
|
|
16
|
+
}>;
|
|
17
|
+
/** @experimental */ export declare function updateBlueprintMetadata({ blueprintPath, projectId, stackId, }: {
|
|
18
|
+
blueprintPath?: string;
|
|
19
|
+
projectId: string;
|
|
20
|
+
stackId: string;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
export declare function writeBlueprintConfig({ blueprintPath, projectId, stackId, }: {
|
|
23
|
+
blueprintPath?: string;
|
|
24
|
+
projectId: string;
|
|
25
|
+
stackId: string;
|
|
26
|
+
}): void;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { dirname, extname, join } from 'node:path';
|
|
4
|
+
import { cwd } from 'node:process';
|
|
5
|
+
import { BlueprintErrorType } from '../../utils/types.js';
|
|
6
|
+
// @ts-ignore - this is currently untyped
|
|
7
|
+
import blueprintParserValidator from '../../utils/vendor/parser-validator.js';
|
|
8
|
+
import { getStack as getStackById } from './stacks.js';
|
|
9
|
+
const SUPPORTED_FILE_NAMES_IN_PRIORITY_ORDER = [
|
|
10
|
+
'blueprint.json',
|
|
11
|
+
'blueprint.js',
|
|
12
|
+
'blueprint.mjs',
|
|
13
|
+
'blueprint.cjs',
|
|
14
|
+
'blueprint.ts',
|
|
15
|
+
];
|
|
16
|
+
function findBlueprintFile(blueprintPath) {
|
|
17
|
+
if (blueprintPath) {
|
|
18
|
+
if (existsSync(blueprintPath)) {
|
|
19
|
+
return { path: blueprintPath, fileName: blueprintPath, extension: extname(blueprintPath) };
|
|
20
|
+
}
|
|
21
|
+
throw Error(`Blueprint file not found: ${blueprintPath}`);
|
|
22
|
+
}
|
|
23
|
+
for (const fileName of SUPPORTED_FILE_NAMES_IN_PRIORITY_ORDER) {
|
|
24
|
+
const filePath = join(cwd(), fileName);
|
|
25
|
+
if (existsSync(filePath)) {
|
|
26
|
+
return { path: filePath, fileName, extension: extname(filePath) };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function readConfigFile(blueprintPath) {
|
|
32
|
+
if (blueprintPath) {
|
|
33
|
+
const blueprintDir = dirname(blueprintPath);
|
|
34
|
+
const configPath = join(blueprintDir, '.blueprint', 'config.json');
|
|
35
|
+
if (existsSync(configPath)) {
|
|
36
|
+
try {
|
|
37
|
+
const config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
38
|
+
return config || null;
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const configFilePath = join(cwd(), '.blueprint', 'config.json');
|
|
46
|
+
if (!existsSync(configFilePath))
|
|
47
|
+
return null;
|
|
48
|
+
try {
|
|
49
|
+
const config = JSON.parse(readFileSync(configFilePath, 'utf8'));
|
|
50
|
+
return config || null;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export async function readBlueprintOnDisk({ blueprintPath, getStack, } = {}) {
|
|
57
|
+
try {
|
|
58
|
+
const blueprintFile = findBlueprintFile(blueprintPath);
|
|
59
|
+
if (!blueprintFile)
|
|
60
|
+
throw Error('Could not find Blueprint file! Use the init command.');
|
|
61
|
+
const { path, fileName, extension } = blueprintFile;
|
|
62
|
+
let blueprintString;
|
|
63
|
+
let blueprintJson;
|
|
64
|
+
let blueprintModule;
|
|
65
|
+
switch (extension) {
|
|
66
|
+
case '.json': {
|
|
67
|
+
blueprintString = readFileSync(path, 'utf8').toString();
|
|
68
|
+
blueprintJson = JSON.parse(blueprintString);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case '.js':
|
|
72
|
+
case '.mjs': {
|
|
73
|
+
const module = await import(path);
|
|
74
|
+
blueprintModule = module.default;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case '.cjs': {
|
|
78
|
+
const require = createRequire(import.meta.url);
|
|
79
|
+
blueprintModule = require(path);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
case '.ts': {
|
|
83
|
+
console.warn('\x1b[2mSupport for Typescript blueprints is experimental.\x1b[0m');
|
|
84
|
+
try {
|
|
85
|
+
const { tsImport } = await import('tsx/esm/api');
|
|
86
|
+
const module = await tsImport(path, dirname(path));
|
|
87
|
+
blueprintModule = module.default;
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
if (err instanceof Error && err.message.includes('Cannot find module')) {
|
|
91
|
+
throw Error(`TypeScript support requires 'tsx' to be installed. Run: npm install -D tsx`);
|
|
92
|
+
}
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
default:
|
|
98
|
+
throw Error(`Unsupported blueprint file extension: ${extension}`);
|
|
99
|
+
}
|
|
100
|
+
if (blueprintModule) {
|
|
101
|
+
if (typeof blueprintModule !== 'function')
|
|
102
|
+
throw Error(`Blueprint ${fileName} must export a default function`);
|
|
103
|
+
blueprintJson = blueprintModule();
|
|
104
|
+
}
|
|
105
|
+
const parserResult = blueprintParserValidator(blueprintJson);
|
|
106
|
+
const { blueprint: parsedBlueprint } = parserResult;
|
|
107
|
+
const errors = parserResult.errors || [];
|
|
108
|
+
// find project and stack IDs from .blueprint/config.json first,
|
|
109
|
+
// then fallback to metadata in blueprint file,
|
|
110
|
+
// finally fallback to resources array...
|
|
111
|
+
let projectId;
|
|
112
|
+
let stackId;
|
|
113
|
+
const configIds = readConfigFile(blueprintPath);
|
|
114
|
+
const blueprintMetadata = parsedBlueprint.metadata;
|
|
115
|
+
// find/create project resource
|
|
116
|
+
if (configIds?.projectId) {
|
|
117
|
+
projectId = configIds.projectId;
|
|
118
|
+
}
|
|
119
|
+
else if (blueprintMetadata?.projectId) {
|
|
120
|
+
projectId = blueprintMetadata.projectId;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const projectResource = parsedBlueprint.resources.find((r) => r.type === 'sanity.project');
|
|
124
|
+
if (projectResource)
|
|
125
|
+
projectId = projectResource.id;
|
|
126
|
+
}
|
|
127
|
+
// find/create stack resource
|
|
128
|
+
if (configIds?.stackId) {
|
|
129
|
+
stackId = configIds.stackId;
|
|
130
|
+
}
|
|
131
|
+
else if (blueprintMetadata?.stackId) {
|
|
132
|
+
stackId = blueprintMetadata.stackId;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const stackResource = parsedBlueprint.resources.find((r) => r.type === 'sanity.blueprints.stack');
|
|
136
|
+
if (stackResource)
|
|
137
|
+
stackId = stackResource.id;
|
|
138
|
+
}
|
|
139
|
+
let deployedStack;
|
|
140
|
+
if (getStack && projectId && stackId) {
|
|
141
|
+
const { stack } = await getStackById({ stackId, projectId });
|
|
142
|
+
if (!stack) {
|
|
143
|
+
errors.push({
|
|
144
|
+
message: 'Stack not found',
|
|
145
|
+
type: BlueprintErrorType.InvalidStack,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
deployedStack = stack;
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
fileInfo: { path, fileName, extension },
|
|
152
|
+
errors,
|
|
153
|
+
projectId,
|
|
154
|
+
stackId,
|
|
155
|
+
deployedStack,
|
|
156
|
+
parsedBlueprint,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
throw Error(`Unable to parse Blueprint file: ${err}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** @experimental */ // no, that's not a real JSDoc pragma
|
|
164
|
+
export async function updateBlueprintMetadata({ blueprintPath, projectId, stackId, }) {
|
|
165
|
+
const blueprintFile = findBlueprintFile(blueprintPath);
|
|
166
|
+
if (!blueprintFile)
|
|
167
|
+
throw Error('Could not find Blueprint file');
|
|
168
|
+
const { path } = blueprintFile;
|
|
169
|
+
const blueprintString = readFileSync(path, 'utf8').toString();
|
|
170
|
+
const blueprint = JSON.parse(blueprintString);
|
|
171
|
+
blueprint.metadata = blueprint.metadata || {};
|
|
172
|
+
blueprint.metadata.projectId = projectId;
|
|
173
|
+
blueprint.metadata.stackId = stackId;
|
|
174
|
+
writeFileSync(path, JSON.stringify(blueprint, null, 2));
|
|
175
|
+
}
|
|
176
|
+
export function writeBlueprintConfig({ blueprintPath, projectId, stackId, }) {
|
|
177
|
+
const blueprintFile = findBlueprintFile(blueprintPath);
|
|
178
|
+
if (!blueprintFile)
|
|
179
|
+
throw Error('Could not find Blueprint file');
|
|
180
|
+
const { path } = blueprintFile;
|
|
181
|
+
const blueprintDir = dirname(path);
|
|
182
|
+
const configDir = join(blueprintDir, '.blueprint');
|
|
183
|
+
const configPath = join(configDir, 'config.json');
|
|
184
|
+
if (!existsSync(configDir)) {
|
|
185
|
+
mkdirSync(configDir, { recursive: true });
|
|
186
|
+
}
|
|
187
|
+
let config = {};
|
|
188
|
+
if (existsSync(configPath)) {
|
|
189
|
+
try {
|
|
190
|
+
config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
// config broken, start fresh
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
config.projectId = projectId;
|
|
197
|
+
config.stackId = stackId;
|
|
198
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
199
|
+
}
|
|
@@ -3,7 +3,9 @@ import config from '../../config.js';
|
|
|
3
3
|
const { blueprints } = config.server;
|
|
4
4
|
export const logsUrl = `${blueprints}vX/blueprints/logs`;
|
|
5
5
|
export async function getLogs(stackId, projectId, token) {
|
|
6
|
-
const
|
|
6
|
+
const url = new URL(logsUrl);
|
|
7
|
+
url.searchParams.append('stackId', stackId);
|
|
8
|
+
const response = await fetch(url.toString(), {
|
|
7
9
|
headers: {
|
|
8
10
|
Accept: 'application/json',
|
|
9
11
|
'Content-Type': 'application/json',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
-
import readBlueprintOnDisk from '../../actions/blueprints/
|
|
3
|
+
import { readBlueprintOnDisk, writeBlueprintConfig } from '../../actions/blueprints/blueprint.js';
|
|
4
4
|
import { createStack, updateStack } from '../../actions/blueprints/stacks.js';
|
|
5
5
|
import { stashAsset } from '../../actions/blueprints/stash-asset.js';
|
|
6
6
|
import { bold, green, red, yellow } from '../../utils/display/colors.js';
|
|
@@ -9,17 +9,30 @@ export default class Deploy extends Command {
|
|
|
9
9
|
static description = 'Deploy a Blueprint';
|
|
10
10
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
11
11
|
async run() {
|
|
12
|
-
const { errors,
|
|
12
|
+
const { errors, projectId: configuredProjectId, stackId, parsedBlueprint: { resources }, deployedStack, } = await readBlueprintOnDisk({ getStack: true });
|
|
13
13
|
if (errors.length > 0) {
|
|
14
14
|
// printErrors(errors) // TODO: error printer in formatting
|
|
15
15
|
this.log('Blueprint parse errors:');
|
|
16
16
|
console.dir(errors, { depth: null });
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
if (!
|
|
20
|
-
this.error('
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
if (stackId && !deployedStack)
|
|
20
|
+
this.error('Stack ID defined but deployed stack not found');
|
|
21
|
+
let projectId = configuredProjectId;
|
|
22
|
+
if (!projectId) {
|
|
23
|
+
this.log('No Sanity Project context found in Blueprint configuration.');
|
|
24
|
+
const { maybeProjectId } = await inquirer.prompt([
|
|
25
|
+
{
|
|
26
|
+
type: 'input',
|
|
27
|
+
name: 'maybeProjectId',
|
|
28
|
+
message: 'Enter Sanity Project ID:',
|
|
29
|
+
},
|
|
30
|
+
]);
|
|
31
|
+
projectId = maybeProjectId;
|
|
32
|
+
}
|
|
33
|
+
if (!projectId)
|
|
34
|
+
this.error('Sanity Project context is required');
|
|
35
|
+
let name = deployedStack?.name;
|
|
23
36
|
if (!name) {
|
|
24
37
|
const { stackName } = await inquirer.prompt([
|
|
25
38
|
{
|
|
@@ -67,6 +80,10 @@ export default class Deploy extends Command {
|
|
|
67
80
|
this.debug('STACK RESPONSE:', stack);
|
|
68
81
|
if (deployOk) {
|
|
69
82
|
s.stop(`${green('Success!')} Stack "${bold(stack.name)}" ${deployedStack ? 'updated' : 'created'} <${yellow(stack.id)}>`);
|
|
83
|
+
writeBlueprintConfig({
|
|
84
|
+
projectId,
|
|
85
|
+
stackId: stack.id,
|
|
86
|
+
});
|
|
70
87
|
this.log('\nUse `sanity blueprints info` to check deployment status');
|
|
71
88
|
}
|
|
72
89
|
else {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import readBlueprintOnDisk from '../../actions/blueprints/
|
|
2
|
+
import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
3
3
|
import { getStack } from '../../actions/blueprints/stacks.js';
|
|
4
4
|
import { formatResourceTree } from '../../utils/display/blueprints-formatting.js';
|
|
5
5
|
import { bold, green, red, yellow } from '../../utils/display/colors.js';
|
|
@@ -18,18 +18,18 @@ export default class Info extends Command {
|
|
|
18
18
|
};
|
|
19
19
|
async run() {
|
|
20
20
|
const { flags } = await this.parse(Info);
|
|
21
|
-
const { errors, deployedStack,
|
|
21
|
+
const { errors, deployedStack, projectId } = await readBlueprintOnDisk({ getStack: true });
|
|
22
22
|
if (errors.length > 0) {
|
|
23
23
|
// printErrors(errors)
|
|
24
24
|
this.log('Blueprint parse errors:');
|
|
25
25
|
console.dir(errors, { depth: null });
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
-
if (!
|
|
28
|
+
if (!projectId)
|
|
29
29
|
this.error('Project resource not found in blueprint');
|
|
30
30
|
let stack = deployedStack;
|
|
31
31
|
if (flags.id) {
|
|
32
|
-
const { ok, stack: foundStack, error
|
|
32
|
+
const { ok, stack: foundStack, error } = await getStack({ stackId: flags.id, projectId });
|
|
33
33
|
if (!ok)
|
|
34
34
|
this.error(error || 'Failed to get stack');
|
|
35
35
|
stack = foundStack;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
2
3
|
import { getLogs, streamLogs } from '../../actions/blueprints/logs.js';
|
|
3
|
-
import readBlueprintOnDisk from '../../actions/blueprints/read-blueprint.js';
|
|
4
4
|
import config from '../../config.js';
|
|
5
5
|
import { formatTitle } from '../../utils/display/blueprints-formatting.js';
|
|
6
6
|
import { blue, bold, green, red, yellow } from '../../utils/display/colors.js';
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import readBlueprintOnDisk from '../../actions/blueprints/
|
|
2
|
+
import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
3
3
|
import { formatResourceTree, formatTitle } from '../../utils/display/blueprints-formatting.js';
|
|
4
4
|
export default class Plan extends Command {
|
|
5
5
|
static description = 'Enumerate resources to be deployed - will not modify any resources';
|
|
6
6
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
7
7
|
async run() {
|
|
8
|
-
const { errors,
|
|
8
|
+
const { errors, projectId, stackId, parsedBlueprint: { resources }, fileInfo, } = await readBlueprintOnDisk();
|
|
9
9
|
if (errors.length > 0) {
|
|
10
10
|
// printErrors(errors)
|
|
11
11
|
this.log('Blueprint parse errors:');
|
|
12
12
|
console.dir(errors, { depth: null });
|
|
13
|
-
return
|
|
13
|
+
// return // don't return, show the plan
|
|
14
14
|
}
|
|
15
|
-
if (!
|
|
15
|
+
if (!projectId)
|
|
16
16
|
this.log('Blueprint must contain a project resource');
|
|
17
|
-
|
|
18
|
-
this.log('Blueprint must contain a stack resource');
|
|
19
|
-
const name = stackResource?.name || 'Unknown';
|
|
17
|
+
const name = stackId || 'Unknown'; // TODO: what is a name, really?
|
|
20
18
|
this.log(`${formatTitle('Blueprint', name)} Plan\n`);
|
|
21
|
-
this.log(`Blueprint document:
|
|
19
|
+
this.log(`Blueprint document: (${fileInfo.fileName})`);
|
|
22
20
|
this.log('');
|
|
23
21
|
formatResourceTree(resources, this.log.bind(this));
|
|
24
22
|
if (resources.length > 0) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from '@oclif/core';
|
|
2
|
-
import readBlueprintOnDisk from '../../actions/blueprints/
|
|
2
|
+
import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
3
3
|
import { listStacks } from '../../actions/blueprints/stacks.js';
|
|
4
4
|
import { bold, boldnblue, yellow } from '../../utils/display/colors.js';
|
|
5
5
|
import { formatDate } from '../../utils/display/dates.js';
|
|
@@ -7,24 +7,24 @@ export default class Stacks extends Command {
|
|
|
7
7
|
static description = 'List all Blueprint stacks';
|
|
8
8
|
static examples = ['<%= config.bin %> <%= command.id %>'];
|
|
9
9
|
async run() {
|
|
10
|
-
const { errors,
|
|
10
|
+
const { errors, projectId, stackId } = await readBlueprintOnDisk();
|
|
11
11
|
if (errors.length > 0) {
|
|
12
12
|
this.log('Blueprint parse errors:');
|
|
13
13
|
console.dir(errors, { depth: null });
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
|
-
if (!
|
|
16
|
+
if (!projectId)
|
|
17
17
|
this.error('Project resource not found in blueprint');
|
|
18
|
-
const { ok, stacks, error } = await listStacks({ projectId
|
|
18
|
+
const { ok, stacks, error } = await listStacks({ projectId });
|
|
19
19
|
if (!ok)
|
|
20
20
|
this.error(error || 'Failed to list stacks');
|
|
21
21
|
if (!stacks || stacks.length === 0) {
|
|
22
22
|
this.log('No stacks found');
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
this.log(`${bold('Project')} <${yellow(
|
|
25
|
+
this.log(`${bold('Project')} <${yellow(projectId)}> ${bold('Stacks')} :\n`);
|
|
26
26
|
for (const stack of stacks) {
|
|
27
|
-
const isCurrentStack =
|
|
27
|
+
const isCurrentStack = stackId === stack.id;
|
|
28
28
|
const stackName = isCurrentStack ? boldnblue(stack.name) : bold(stack.name);
|
|
29
29
|
this.log(`${stackName} <${yellow(stack.id)}>${isCurrentStack ? ' (current)' : ''}`);
|
|
30
30
|
if (stack.createdAt) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
-
import readBlueprintOnDisk from '../../actions/blueprints/
|
|
2
|
+
import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
3
3
|
import { invoke } from '../../actions/functions/invoke.js';
|
|
4
4
|
import config from '../../config.js';
|
|
5
5
|
import { red } from '../../utils/display/colors.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Args, Command } from '@oclif/core';
|
|
2
|
-
import readBlueprintOnDisk from '../../actions/blueprints/
|
|
2
|
+
import { readBlueprintOnDisk } from '../../actions/blueprints/blueprint.js';
|
|
3
3
|
import { logs } from '../../actions/functions/logs.js';
|
|
4
4
|
import config from '../../config.js';
|
|
5
5
|
import { bold, red, yellow } from '../../utils/display/colors.js';
|
package/dist/server/app.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { default as mime } from 'mime-types';
|
|
3
|
-
import readBlueprintOnDisk from '../actions/blueprints/
|
|
3
|
+
import { readBlueprintOnDisk } from '../actions/blueprints/blueprint.js';
|
|
4
4
|
import invoke from '../utils/invoke-local.js';
|
|
5
5
|
import * as http from 'node:http';
|
|
6
6
|
const host = 'localhost';
|
|
@@ -36,7 +36,7 @@ export function formatResourceTree(resources, logger) {
|
|
|
36
36
|
logger(` └─ ${bold('Other Resources')} [${otherResources.length}]`);
|
|
37
37
|
for (const [i, other] of otherResources.entries()) {
|
|
38
38
|
const isLast = i === otherResources.length - 1;
|
|
39
|
-
logger(`
|
|
39
|
+
logger(` ${isLast ? '└─' : '├─'} "${yellow(other.displayName || other.name || other.src)}"`);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
}
|
package/dist/utils/types.d.ts
CHANGED
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/runtime-cli",
|
|
3
3
|
"description": "A new CLI generated with oclif",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.6.0",
|
|
5
5
|
"author": "Sanity Runtime Team",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"engines": {
|
|
14
14
|
"node": ">=20.11.0"
|
|
15
15
|
},
|
|
16
|
+
"optionalPeerDependencies": {
|
|
17
|
+
"tsx": "^4.19.3"
|
|
18
|
+
},
|
|
16
19
|
"files": [
|
|
17
20
|
"./bin",
|
|
18
21
|
"./dist",
|
|
@@ -64,6 +67,7 @@
|
|
|
64
67
|
"rollup": "^4.36.0",
|
|
65
68
|
"shx": "^0.4.0",
|
|
66
69
|
"ts-node": "^10",
|
|
70
|
+
"tsx": "^4.19.3",
|
|
67
71
|
"typescript": "^5",
|
|
68
72
|
"vitest": "3.0.8"
|
|
69
73
|
},
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { Blueprint, BlueprintError, BlueprintResource, BlueprintStack } from '../../utils/types.js';
|
|
2
|
-
export default function readBlueprintOnDisk({ blueprintPath, getStack, }?: {
|
|
3
|
-
blueprintPath?: string;
|
|
4
|
-
getStack?: boolean;
|
|
5
|
-
}): Promise<{
|
|
6
|
-
fileInfo: {
|
|
7
|
-
path: string;
|
|
8
|
-
fileName: string;
|
|
9
|
-
extension: string;
|
|
10
|
-
};
|
|
11
|
-
parsedBlueprint: Blueprint;
|
|
12
|
-
errors: BlueprintError[];
|
|
13
|
-
projectResource?: BlueprintResource;
|
|
14
|
-
stackResource?: BlueprintResource;
|
|
15
|
-
deployedStack?: BlueprintStack;
|
|
16
|
-
}>;
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { extname, join } from 'node:path';
|
|
3
|
-
import { cwd } from 'node:process';
|
|
4
|
-
import { getStackByName } from '../../actions/blueprints/stacks.js';
|
|
5
|
-
import { BlueprintErrorType } from '../../utils/types.js';
|
|
6
|
-
// @ts-ignore - this is currently untyped
|
|
7
|
-
import blueprintParserValidator from '../../utils/vendor/parser-validator.js';
|
|
8
|
-
const SUPPORTED_FILE_NAMES_IN_PRIORITY_ORDER = [
|
|
9
|
-
'blueprint.json',
|
|
10
|
-
// 'blueprint.js',
|
|
11
|
-
// 'blueprint.mjs',
|
|
12
|
-
// 'blueprint.cjs',
|
|
13
|
-
// 'blueprint.ts',
|
|
14
|
-
];
|
|
15
|
-
function findBlueprintFile(blueprintPath) {
|
|
16
|
-
if (blueprintPath) {
|
|
17
|
-
if (existsSync(blueprintPath)) {
|
|
18
|
-
return { path: blueprintPath, fileName: blueprintPath, extension: extname(blueprintPath) };
|
|
19
|
-
}
|
|
20
|
-
throw Error(`Blueprint file not found: ${blueprintPath}`);
|
|
21
|
-
}
|
|
22
|
-
for (const fileName of SUPPORTED_FILE_NAMES_IN_PRIORITY_ORDER) {
|
|
23
|
-
const filePath = join(cwd(), fileName);
|
|
24
|
-
if (existsSync(filePath)) {
|
|
25
|
-
return { path: filePath, fileName, extension: extname(filePath) };
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
export default async function readBlueprintOnDisk({ blueprintPath, getStack, } = {}) {
|
|
31
|
-
try {
|
|
32
|
-
const blueprintFile = findBlueprintFile(blueprintPath);
|
|
33
|
-
if (!blueprintFile)
|
|
34
|
-
throw Error('Could not find Blueprint file');
|
|
35
|
-
const { path, fileName, extension } = blueprintFile;
|
|
36
|
-
let blueprintString;
|
|
37
|
-
if (extension === '.json') {
|
|
38
|
-
blueprintString = readFileSync(path, 'utf8').toString();
|
|
39
|
-
// } else if (extension === '.js' || extension === '.mjs') {
|
|
40
|
-
// const blueprintModule = require(path)
|
|
41
|
-
// blueprintJson = blueprintModule.default
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
throw Error(`Unsupported blueprint file extension: ${extension}`);
|
|
45
|
-
}
|
|
46
|
-
const parsed = blueprintParserValidator(JSON.parse(blueprintString));
|
|
47
|
-
const { blueprint: parsedBlueprint } = parsed;
|
|
48
|
-
const errors = parsed.errors || [];
|
|
49
|
-
const projectResource = parsedBlueprint.resources.find((r) => r.type === 'sanity.project');
|
|
50
|
-
const stackResource = parsedBlueprint.resources.find((r) => r.type === 'sanity.blueprints.stack');
|
|
51
|
-
if (!projectResource) {
|
|
52
|
-
errors.push({
|
|
53
|
-
message: 'Blueprint is missing a project resource',
|
|
54
|
-
type: BlueprintErrorType.MissingProject,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
let deployedStack;
|
|
58
|
-
if (getStack && projectResource && stackResource) {
|
|
59
|
-
const { stack } = await getStackByName({
|
|
60
|
-
name: stackResource.name,
|
|
61
|
-
projectId: projectResource.id,
|
|
62
|
-
});
|
|
63
|
-
if (!stack) {
|
|
64
|
-
errors.push({
|
|
65
|
-
message: 'Stack not found',
|
|
66
|
-
type: BlueprintErrorType.InvalidStack,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
deployedStack = stack;
|
|
70
|
-
}
|
|
71
|
-
return {
|
|
72
|
-
fileInfo: { path, fileName, extension },
|
|
73
|
-
errors,
|
|
74
|
-
projectResource,
|
|
75
|
-
stackResource,
|
|
76
|
-
deployedStack,
|
|
77
|
-
parsedBlueprint,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
catch (err) {
|
|
81
|
-
throw Error(`Unable to parse Blueprint file: ${err}`);
|
|
82
|
-
}
|
|
83
|
-
}
|