@sanity/cli 7.7.1 → 7.9.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 +17 -2
- package/dist/actions/auth/ensureAuthenticated.js +1 -1
- package/dist/actions/auth/ensureAuthenticated.js.map +1 -1
- package/dist/actions/auth/login/validateToken.js +1 -1
- package/dist/actions/auth/login/validateToken.js.map +1 -1
- package/dist/actions/build/buildApp.js +2 -3
- package/dist/actions/build/buildApp.js.map +1 -1
- package/dist/actions/build/buildStudio.js +1 -2
- package/dist/actions/build/buildStudio.js.map +1 -1
- package/dist/actions/deploy/createUserApplication.js +8 -8
- package/dist/actions/deploy/createUserApplication.js.map +1 -1
- package/dist/actions/deploy/deployApp.js +128 -26
- package/dist/actions/deploy/deployApp.js.map +1 -1
- package/dist/actions/deploy/deployChecks.js +97 -72
- package/dist/actions/deploy/deployChecks.js.map +1 -1
- package/dist/actions/deploy/deployRunner.js +8 -8
- package/dist/actions/deploy/deployRunner.js.map +1 -1
- package/dist/actions/deploy/deployStudio.js +129 -23
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/deploy/deploymentPlan.js +29 -30
- package/dist/actions/deploy/deploymentPlan.js.map +1 -1
- package/dist/actions/deploy/findUserApplication.js +39 -14
- package/dist/actions/deploy/findUserApplication.js.map +1 -1
- package/dist/actions/deploy/resolveDeployTarget.js +44 -0
- package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
- package/dist/actions/deploy/urlUtils.js +0 -4
- package/dist/actions/deploy/urlUtils.js.map +1 -1
- package/dist/actions/dev/servers/getDevServerConfig.js +1 -1
- package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
- package/dist/actions/dev/servers/startStudioDevServer.js +1 -2
- package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
- package/dist/actions/documents/types.js.map +1 -1
- package/dist/actions/documents/validate.js +2 -1
- package/dist/actions/documents/validate.js.map +1 -1
- package/dist/actions/graphql/SchemaError.js.map +1 -1
- package/dist/actions/graphql/extractGraphQLAPIs.js +3 -1
- package/dist/actions/graphql/extractGraphQLAPIs.js.map +1 -1
- package/dist/actions/manifest/extractCoreAppManifest.js +1 -1
- package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
- package/dist/actions/organizations/getOrganization.js +1 -1
- package/dist/actions/organizations/getOrganization.js.map +1 -1
- package/dist/actions/schema/validateAction.js +1 -1
- package/dist/actions/schema/validateAction.js.map +1 -1
- package/dist/actions/skills/setupSkills.js +1 -1
- package/dist/actions/skills/setupSkills.js.map +1 -1
- package/dist/actions/undeploy/adapters.js +101 -0
- package/dist/actions/undeploy/adapters.js.map +1 -0
- package/dist/actions/undeploy/runUndeploy.js +179 -0
- package/dist/actions/undeploy/runUndeploy.js.map +1 -0
- package/dist/actions/undeploy/undeployPlan.js +123 -0
- package/dist/actions/undeploy/undeployPlan.js.map +1 -0
- package/dist/commands/datasets/copy.js +2 -1
- package/dist/commands/datasets/copy.js.map +1 -1
- package/dist/commands/documents/validate.js +18 -17
- package/dist/commands/documents/validate.js.map +1 -1
- package/dist/commands/mcp/configure.js +1 -1
- package/dist/commands/mcp/configure.js.map +1 -1
- package/dist/commands/projects/create.js +18 -13
- package/dist/commands/projects/create.js.map +1 -1
- package/dist/commands/projects/list.js +2 -1
- package/dist/commands/projects/list.js.map +1 -1
- package/dist/commands/schemas/validate.js +3 -2
- package/dist/commands/schemas/validate.js.map +1 -1
- package/dist/commands/skills/install.js +1 -1
- package/dist/commands/skills/install.js.map +1 -1
- package/dist/commands/tokens/list.js +1 -1
- package/dist/commands/tokens/list.js.map +1 -1
- package/dist/commands/undeploy.js +47 -73
- package/dist/commands/undeploy.js.map +1 -1
- package/dist/server/devServer.js.map +1 -1
- package/dist/util/checks.js +83 -0
- package/dist/util/checks.js.map +1 -0
- package/dist/util/toStderrOutput.js +13 -0
- package/dist/util/toStderrOutput.js.map +1 -0
- package/oclif.manifest.json +28 -1
- package/package.json +7 -8
- package/dist/actions/undeploy/getStudioOrAppUserApplication.js +0 -36
- package/dist/actions/undeploy/getStudioOrAppUserApplication.js.map +0 -1
- package/dist/util/compareDependencyVersions.js +0 -110
- package/dist/util/compareDependencyVersions.js.map +0 -1
- package/dist/util/getErrorMessage.js +0 -28
- package/dist/util/getErrorMessage.js.map +0 -1
|
@@ -4,16 +4,16 @@ import { createGzip } from 'node:zlib';
|
|
|
4
4
|
import { formatSchemaValidation, SchemaExtractionError } from '@sanity/cli-build/_internal/extract';
|
|
5
5
|
import { exitCodes } from '@sanity/cli-core';
|
|
6
6
|
import { spinner } from '@sanity/cli-core/ux';
|
|
7
|
-
import { getWorkbench } from '@sanity/workbench-cli/deploy';
|
|
7
|
+
import { buildExposes, deployStudio as deployWorkbenchStudio, getApplicationUrl, getWorkbench } from '@sanity/workbench-cli/deploy';
|
|
8
8
|
import { pack } from 'tar-fs';
|
|
9
9
|
import { createDeployment } from '../../services/userApplications.js';
|
|
10
10
|
import { getAppId } from '../../util/appId.js';
|
|
11
|
-
import { NO_PROJECT_ID } from '../../util/errorMessages.js';
|
|
11
|
+
import { NO_ORGANIZATION_ID, NO_PROJECT_ID } from '../../util/errorMessages.js';
|
|
12
12
|
import { buildStudio } from '../build/buildStudio.js';
|
|
13
13
|
import { createStudioUserApplication } from './createUserApplication.js';
|
|
14
14
|
import { checkAutoUpdates, checkBuild, checkPackageVersion, checkStudioTarget, verifyOutputDir } from './deployChecks.js';
|
|
15
15
|
import { deployDebug } from './deployDebug.js';
|
|
16
|
-
import { listDeploymentFiles } from './deploymentPlan.js';
|
|
16
|
+
import { listDeploymentFiles, reportExposes } from './deploymentPlan.js';
|
|
17
17
|
import { runDeploy } from './deployRunner.js';
|
|
18
18
|
import { deployStudioSchemasAndManifests } from './deployStudioSchemasAndManifests.js';
|
|
19
19
|
import { findUserApplicationForStudio } from './findUserApplication.js';
|
|
@@ -29,16 +29,15 @@ export function deployStudio(options) {
|
|
|
29
29
|
const { cliConfig, flags, output, sourceDir } = options;
|
|
30
30
|
const workDir = options.projectRoot.directory;
|
|
31
31
|
const isExternal = !!flags.external;
|
|
32
|
-
const
|
|
32
|
+
const workbench = getWorkbench(cliConfig);
|
|
33
|
+
const isWorkbenchApp = workbench !== null;
|
|
33
34
|
const projectId = cliConfig.api?.projectId;
|
|
35
|
+
const organizationId = cliConfig.app?.organizationId;
|
|
36
|
+
const appId = getAppId(cliConfig);
|
|
34
37
|
const dryRun = !!flags['dry-run'];
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
flags
|
|
38
|
-
});
|
|
38
|
+
// A federated app deploys through Sanity's build/hosting pipeline, which
|
|
39
|
+
// --external skips — fail before doing any other work.
|
|
39
40
|
if (isExternal && isWorkbenchApp) {
|
|
40
|
-
// A federated app deploys through Sanity's build/hosting pipeline, which
|
|
41
|
-
// --external skips.
|
|
42
41
|
reporter.report({
|
|
43
42
|
exitCode: exitCodes.USAGE_ERROR,
|
|
44
43
|
message: 'Deploying a federated application to an external host is not yet supported',
|
|
@@ -46,6 +45,11 @@ export function deployStudio(options) {
|
|
|
46
45
|
status: 'fail'
|
|
47
46
|
});
|
|
48
47
|
}
|
|
48
|
+
const appTitle = workbench ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.name : '';
|
|
49
|
+
const isAutoUpdating = checkAutoUpdates(reporter, {
|
|
50
|
+
cliConfig,
|
|
51
|
+
flags
|
|
52
|
+
});
|
|
49
53
|
const version = await checkPackageVersion(reporter, {
|
|
50
54
|
moduleName: STUDIO_PACKAGE,
|
|
51
55
|
workDir
|
|
@@ -58,10 +62,32 @@ export function deployStudio(options) {
|
|
|
58
62
|
solution: 'Add `api.projectId` to sanity.cli.ts',
|
|
59
63
|
status: 'fail'
|
|
60
64
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
// Workbench studios deploy to Brett (which needs the org); plain studios
|
|
66
|
+
// resolve/create on user-applications, unchanged.
|
|
67
|
+
let application = null;
|
|
68
|
+
let studioCreated = false;
|
|
69
|
+
if (workbench && !isExternal) {
|
|
70
|
+
reporter.report(organizationId ? {
|
|
71
|
+
message: `Organization: ${organizationId}`,
|
|
72
|
+
status: 'pass'
|
|
73
|
+
} : {
|
|
74
|
+
message: NO_ORGANIZATION_ID,
|
|
75
|
+
solution: 'Add `app.organizationId` to sanity.cli.ts',
|
|
76
|
+
status: 'fail'
|
|
77
|
+
});
|
|
78
|
+
await checkStudioTarget(reporter, {
|
|
79
|
+
appId,
|
|
80
|
+
isWorkbenchApp: true,
|
|
81
|
+
studioHost: cliConfig.studioHost,
|
|
82
|
+
title: appTitle
|
|
83
|
+
});
|
|
84
|
+
} else {
|
|
85
|
+
;
|
|
86
|
+
({ application, created: studioCreated } = await resolveStudioApplication(options, {
|
|
87
|
+
dryRun,
|
|
88
|
+
reporter
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
65
91
|
await checkBuild(reporter, {
|
|
66
92
|
build: ()=>buildStudio({
|
|
67
93
|
autoUpdatesEnabled: isAutoUpdating,
|
|
@@ -85,14 +111,63 @@ export function deployStudio(options) {
|
|
|
85
111
|
sourceDir
|
|
86
112
|
});
|
|
87
113
|
}
|
|
114
|
+
// Report the exposes deploying with the studio, both modes. External studios
|
|
115
|
+
// host their own bundle, so nothing registers.
|
|
116
|
+
const exposes = workbench && !isExternal ? reportExposes(reporter, workbench) : [];
|
|
88
117
|
// Dry run stops here — everything below mutates.
|
|
89
118
|
if (dryRun) return;
|
|
90
119
|
// A real deploy has already exited if anything failed; landing here without a
|
|
91
|
-
// resolved
|
|
92
|
-
if (!
|
|
120
|
+
// resolved version means the deploy target was never resolved.
|
|
121
|
+
if (!version) return;
|
|
93
122
|
const studioManifest = await uploadStudioSchema(options, {
|
|
94
123
|
isExternal
|
|
95
124
|
});
|
|
125
|
+
// Workbench studios deploy to Brett; plain studios use user-applications.
|
|
126
|
+
if (workbench && !isExternal && organizationId) {
|
|
127
|
+
const { applicationId } = await deployWorkbenchStudio({
|
|
128
|
+
appId,
|
|
129
|
+
interfaces: buildExposes(workbench, {
|
|
130
|
+
appName: workbench.name,
|
|
131
|
+
appTitle,
|
|
132
|
+
exposesAppView: true,
|
|
133
|
+
version
|
|
134
|
+
}),
|
|
135
|
+
isAutoUpdating,
|
|
136
|
+
organizationId,
|
|
137
|
+
output,
|
|
138
|
+
projectId,
|
|
139
|
+
sourceDir,
|
|
140
|
+
studioHost: cliConfig.studioHost,
|
|
141
|
+
title: appTitle,
|
|
142
|
+
version,
|
|
143
|
+
workspaces: toWorkspaces(studioManifest)
|
|
144
|
+
});
|
|
145
|
+
const url = getApplicationUrl({
|
|
146
|
+
id: applicationId,
|
|
147
|
+
organizationId,
|
|
148
|
+
type: 'studio'
|
|
149
|
+
});
|
|
150
|
+
logWorkbenchStudioDeployed({
|
|
151
|
+
applicationId,
|
|
152
|
+
cliConfig,
|
|
153
|
+
output,
|
|
154
|
+
url
|
|
155
|
+
});
|
|
156
|
+
return {
|
|
157
|
+
applicationType: 'studio',
|
|
158
|
+
applicationVersion: version,
|
|
159
|
+
...exposes.length > 0 ? {
|
|
160
|
+
exposes
|
|
161
|
+
} : {},
|
|
162
|
+
target: {
|
|
163
|
+
action: appId ? 'update' : 'create',
|
|
164
|
+
applicationId,
|
|
165
|
+
title: appTitle,
|
|
166
|
+
url
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (!application) return;
|
|
96
171
|
const location = await shipStudioDeployment({
|
|
97
172
|
application,
|
|
98
173
|
isAutoUpdating,
|
|
@@ -105,6 +180,7 @@ export function deployStudio(options) {
|
|
|
105
180
|
applicationType: 'studio',
|
|
106
181
|
applicationVersion: version,
|
|
107
182
|
target: {
|
|
183
|
+
action: studioCreated ? 'create' : 'update',
|
|
108
184
|
applicationId: application.id,
|
|
109
185
|
title: application.title ?? null,
|
|
110
186
|
url: location
|
|
@@ -117,22 +193,27 @@ export function deployStudio(options) {
|
|
|
117
193
|
*/ async function resolveStudioApplication(options, { dryRun, reporter }) {
|
|
118
194
|
const { cliConfig, flags, output } = options;
|
|
119
195
|
const isExternal = !!flags.external;
|
|
196
|
+
const appId = getAppId(cliConfig);
|
|
120
197
|
// Sets the title on a newly registered studio; blank falls back to undefined
|
|
121
198
|
const title = flags.title?.trim() || undefined;
|
|
122
199
|
if (dryRun) {
|
|
123
200
|
await checkStudioTarget(reporter, {
|
|
124
|
-
appId
|
|
201
|
+
appId,
|
|
125
202
|
isExternal,
|
|
126
203
|
projectId: cliConfig.api?.projectId,
|
|
127
204
|
studioHost: cliConfig.studioHost,
|
|
128
205
|
title,
|
|
129
206
|
urlFlag: flags.url
|
|
130
207
|
});
|
|
131
|
-
return
|
|
208
|
+
return {
|
|
209
|
+
application: null,
|
|
210
|
+
created: false
|
|
211
|
+
};
|
|
132
212
|
}
|
|
133
213
|
const projectId = cliConfig.api?.projectId ?? '';
|
|
134
|
-
|
|
135
|
-
|
|
214
|
+
// `created` is true when a configured-but-unregistered host was just registered.
|
|
215
|
+
const { application, created } = await findUserApplicationForStudio({
|
|
216
|
+
appId,
|
|
136
217
|
isExternal,
|
|
137
218
|
output,
|
|
138
219
|
projectId,
|
|
@@ -150,15 +231,22 @@ export function deployStudio(options) {
|
|
|
150
231
|
output.log('To deploy your Sanity Studio to our hosted sanity.studio service,');
|
|
151
232
|
output.log('you will need one. Please enter the subdomain you want to use.');
|
|
152
233
|
}
|
|
153
|
-
|
|
234
|
+
const registered = await createStudioUserApplication({
|
|
154
235
|
projectId,
|
|
155
236
|
title,
|
|
156
237
|
urlType: isExternal ? 'external' : 'internal'
|
|
157
238
|
});
|
|
158
|
-
deployDebug('Created user application',
|
|
239
|
+
deployDebug('Created user application', registered);
|
|
240
|
+
return {
|
|
241
|
+
application: registered,
|
|
242
|
+
created: true
|
|
243
|
+
};
|
|
159
244
|
}
|
|
160
245
|
deployDebug('Found user application', application);
|
|
161
|
-
return
|
|
246
|
+
return {
|
|
247
|
+
application,
|
|
248
|
+
created
|
|
249
|
+
};
|
|
162
250
|
}
|
|
163
251
|
/** Extracts the studio schema and manifest and uploads them to the schema store. */ async function uploadStudioSchema(options, { isExternal }) {
|
|
164
252
|
const { cliConfig, flags, output, projectRoot, sourceDir } = options;
|
|
@@ -236,6 +324,24 @@ export default defineCliConfig({
|
|
|
236
324
|
output.log(`\n${example}`);
|
|
237
325
|
return location;
|
|
238
326
|
}
|
|
327
|
+
function toWorkspaces(manifest) {
|
|
328
|
+
return (manifest?.workspaces ?? []).map((workspace)=>({
|
|
329
|
+
basePath: workspace.basePath,
|
|
330
|
+
dataset: workspace.dataset,
|
|
331
|
+
icon: workspace.icon,
|
|
332
|
+
name: workspace.name,
|
|
333
|
+
projectId: workspace.projectId,
|
|
334
|
+
subtitle: workspace.subtitle,
|
|
335
|
+
title: workspace.title
|
|
336
|
+
}));
|
|
337
|
+
}
|
|
338
|
+
/** Renders the workbench studio's deploy result; the appId hint shows only when none is configured. */ function logWorkbenchStudioDeployed({ applicationId, cliConfig, output, url }) {
|
|
339
|
+
output.log(`\nSuccess! Studio deployed to ${styleText('cyan', url)}`);
|
|
340
|
+
if (getAppId(cliConfig)) return;
|
|
341
|
+
output.log(`\nAdd ${styleText('cyan', `appId: '${applicationId}'`)}`);
|
|
342
|
+
output.log(`to the \`deployment\` section in sanity.cli.js or sanity.cli.ts`);
|
|
343
|
+
output.log(`to avoid prompting for application id on next deploy.`);
|
|
344
|
+
}
|
|
239
345
|
function studioBuildSkipReason({ build, isExternal }) {
|
|
240
346
|
if (isExternal) return 'Build skipped for externally hosted studios';
|
|
241
347
|
if (!build) return 'Build skipped (--no-build) — validating existing output directory';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/deploy/deployStudio.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip, type Gzip} from 'node:zlib'\n\nimport {formatSchemaValidation, SchemaExtractionError} from '@sanity/cli-build/_internal/extract'\nimport {exitCodes} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {getWorkbench} from '@sanity/workbench-cli/deploy'\nimport {type StudioManifest} from 'sanity'\nimport {pack} from 'tar-fs'\n\nimport {createDeployment, type UserApplication} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {NO_PROJECT_ID} from '../../util/errorMessages.js'\nimport {buildStudio} from '../build/buildStudio.js'\nimport {createStudioUserApplication} from './createUserApplication.js'\nimport {\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type CheckReporter,\n checkStudioTarget,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles} from './deploymentPlan.js'\nimport {type DeployResult, runDeploy} from './deployRunner.js'\nimport {deployStudioSchemasAndManifests} from './deployStudioSchemasAndManifests.js'\nimport {findUserApplicationForStudio} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst STUDIO_PACKAGE = 'sanity'\n\nexport function deployStudio(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({flags, projectRoot, sourceDir}) =>\n flags.external ? Promise.resolve([]) : listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runStudioDeployment,\n type: 'studio',\n })\n}\n\n/** Validates the deploy, extracts and uploads the schema, and ships the build. */\nasync function runStudioDeployment(\n options: DeployAppOptions,\n reporter: CheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const isExternal = !!flags.external\n const isWorkbenchApp = getWorkbench(cliConfig) !== null\n const projectId = cliConfig.api?.projectId\n const dryRun = !!flags['dry-run']\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n if (isExternal && isWorkbenchApp) {\n // A federated app deploys through Sanity's build/hosting pipeline, which\n // --external skips.\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Deploying a federated application to an external host is not yet supported',\n solution: 'Remove the --external flag to deploy to Sanity hosting',\n status: 'fail',\n })\n }\n\n const version = await checkPackageVersion(reporter, {\n moduleName: STUDIO_PACKAGE,\n workDir,\n })\n\n reporter.report(\n projectId\n ? {message: `Project: ${projectId}`, status: 'pass'}\n : {\n message: NO_PROJECT_ID,\n solution: 'Add `api.projectId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n const application = await resolveStudioApplication(options, {dryRun, reporter})\n\n await checkBuild(reporter, {\n build: () =>\n buildStudio({\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: studioBuildSkipReason({build: flags.build, isExternal}),\n successMessage: 'Studio built',\n })\n\n if (!isExternal) {\n await verifyOutputDir({isWorkbenchApp, reporter, sourceDir})\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application or version means the deploy target was never resolved.\n if (!application || !version) return\n\n const studioManifest = await uploadStudioSchema(options, {isExternal})\n const location = await shipStudioDeployment({\n application,\n isAutoUpdating,\n isExternal,\n options,\n studioManifest,\n version,\n })\n\n return {\n applicationType: 'studio',\n applicationVersion: version,\n target: {applicationId: application.id, title: application.title ?? null, url: location},\n }\n}\n\n/**\n * Finds the application a real deploy targets, registering a studio host when\n * none is configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveStudioApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: CheckReporter},\n): Promise<UserApplication | null> {\n const {cliConfig, flags, output} = options\n const isExternal = !!flags.external\n // Sets the title on a newly registered studio; blank falls back to undefined\n const title = flags.title?.trim() || undefined\n\n if (dryRun) {\n await checkStudioTarget(reporter, {\n appId: getAppId(cliConfig),\n isExternal,\n projectId: cliConfig.api?.projectId,\n studioHost: cliConfig.studioHost,\n title,\n urlFlag: flags.url,\n })\n return null\n }\n\n const projectId = cliConfig.api?.projectId ?? ''\n let application = await findUserApplicationForStudio({\n appId: getAppId(cliConfig),\n isExternal,\n output,\n projectId,\n studioHost: cliConfig.studioHost,\n title,\n unattended: !!flags.yes,\n urlFlag: flags.url,\n })\n\n if (!application) {\n if (isExternal) {\n output.log('Your project has not been registered with an external studio URL.')\n output.log('Please enter the full URL where your studio is hosted.')\n } else {\n output.log('Your project has not been assigned a studio hostname.')\n output.log('To deploy your Sanity Studio to our hosted sanity.studio service,')\n output.log('you will need one. Please enter the subdomain you want to use.')\n }\n\n application = await createStudioUserApplication({\n projectId,\n title,\n urlType: isExternal ? 'external' : 'internal',\n })\n deployDebug('Created user application', application)\n }\n\n deployDebug('Found user application', application)\n return application\n}\n\n/** Extracts the studio schema and manifest and uploads them to the schema store. */\nasync function uploadStudioSchema(\n options: DeployAppOptions,\n {isExternal}: {isExternal: boolean},\n): Promise<StudioManifest | null> {\n const {cliConfig, flags, output, projectRoot, sourceDir} = options\n\n let studioManifest: StudioManifest | null = null\n try {\n studioManifest = await deployStudioSchemasAndManifests(\n {\n configPath: projectRoot.path,\n isExternal,\n outPath: `${sourceDir}/static`,\n projectId: cliConfig.api?.projectId ?? '',\n schemaRequired: flags['schema-required'],\n verbose: flags.verbose,\n workDir: projectRoot.directory,\n },\n output,\n )\n } catch (error) {\n deployDebug('Error deploying studio schemas and manifests', error)\n if (error instanceof SchemaExtractionError) {\n output.error(formatSchemaValidation(error.validation || []), {exit: 1})\n }\n output.error(`Error deploying studio schemas and manifests: ${error}`, {exit: 1})\n }\n\n if (!studioManifest) {\n output.error('Failed to generate studio manifest. Please check your schemas and manifests.', {\n exit: 1,\n })\n }\n\n return studioManifest\n}\n\nasync function shipStudioDeployment({\n application,\n isAutoUpdating,\n isExternal,\n options,\n studioManifest,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n isExternal: boolean\n options: DeployAppOptions\n studioManifest: StudioManifest | null\n version: string\n}): Promise<string> {\n const {cliConfig, output, sourceDir} = options\n\n let tarball: Gzip | undefined\n if (!isExternal) {\n tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n }\n\n const spin = spinner(isExternal ? 'Registering studio' : 'Deploying to sanity.studio').start()\n let location: string\n try {\n ;({location} = await createDeployment({\n applicationId: application.id,\n isApp: false,\n isAutoUpdating,\n manifest: studioManifest,\n projectId: cliConfig.api?.projectId,\n tarball,\n version,\n }))\n } catch (error) {\n spin.fail()\n throw error\n }\n spin.succeed()\n\n const named = application.title ? ` — \"${application.title}\"` : ''\n output.log(\n isExternal\n ? `\\nSuccess! Studio registered${named}`\n : `\\nSuccess! Studio deployed to ${styleText('cyan', location)}${named}`,\n )\n\n if (getAppId(cliConfig)) return location\n\n const example = `Example:\nexport default defineCliConfig({\n //…\n deployment: {\n ${styleText('cyan', `appId: '${application.id}'`)},\n },\n //…\n})`\n output.log(`\\nAdd ${styleText('cyan', `appId: '${application.id}'`)}`)\n output.log(`to the \\`deployment\\` section in sanity.cli.js or sanity.cli.ts`)\n output.log(`to avoid prompting for application id on next deploy.`)\n output.log(`\\n${example}`)\n\n return location\n}\n\nfunction studioBuildSkipReason({build, isExternal}: {build: boolean; isExternal: boolean}) {\n if (isExternal) return 'Build skipped for externally hosted studios'\n if (!build) return 'Build skipped (--no-build) — validating existing output directory'\n return\n}\n"],"names":["basename","dirname","styleText","createGzip","formatSchemaValidation","SchemaExtractionError","exitCodes","spinner","getWorkbench","pack","createDeployment","getAppId","NO_PROJECT_ID","buildStudio","createStudioUserApplication","checkAutoUpdates","checkBuild","checkPackageVersion","checkStudioTarget","verifyOutputDir","deployDebug","listDeploymentFiles","runDeploy","deployStudioSchemasAndManifests","findUserApplicationForStudio","STUDIO_PACKAGE","deployStudio","options","listFiles","flags","projectRoot","sourceDir","external","Promise","resolve","directory","run","runStudioDeployment","type","reporter","cliConfig","output","workDir","isExternal","isWorkbenchApp","projectId","api","dryRun","isAutoUpdating","report","exitCode","USAGE_ERROR","message","solution","status","version","moduleName","application","resolveStudioApplication","build","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","studioBuildSkipReason","successMessage","studioManifest","uploadStudioSchema","location","shipStudioDeployment","applicationType","applicationVersion","target","applicationId","id","title","url","trim","undefined","appId","studioHost","urlFlag","unattended","yes","log","urlType","configPath","path","outPath","schemaRequired","verbose","error","validation","exit","tarball","entries","pipe","spin","start","isApp","manifest","fail","succeed","named","example"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/deployStudio.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip, type Gzip} from 'node:zlib'\n\nimport {formatSchemaValidation, SchemaExtractionError} from '@sanity/cli-build/_internal/extract'\nimport {exitCodes} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n type BrettWorkspace,\n buildExposes,\n deployStudio as deployWorkbenchStudio,\n getApplicationUrl,\n getWorkbench,\n} from '@sanity/workbench-cli/deploy'\nimport {type StudioManifest} from 'sanity'\nimport {pack} from 'tar-fs'\n\nimport {createDeployment, type UserApplication} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {NO_ORGANIZATION_ID, NO_PROJECT_ID} from '../../util/errorMessages.js'\nimport {buildStudio} from '../build/buildStudio.js'\nimport {createStudioUserApplication} from './createUserApplication.js'\nimport {\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n checkStudioTarget,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportExposes} from './deploymentPlan.js'\nimport {type DeployResult, runDeploy} from './deployRunner.js'\nimport {deployStudioSchemasAndManifests} from './deployStudioSchemasAndManifests.js'\nimport {findUserApplicationForStudio} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst STUDIO_PACKAGE = 'sanity'\n\nexport function deployStudio(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({flags, projectRoot, sourceDir}) =>\n flags.external ? Promise.resolve([]) : listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runStudioDeployment,\n type: 'studio',\n })\n}\n\n/** Validates the deploy, extracts and uploads the schema, and ships the build. */\nasync function runStudioDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const isExternal = !!flags.external\n const workbench = getWorkbench(cliConfig)\n const isWorkbenchApp = workbench !== null\n const projectId = cliConfig.api?.projectId\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const dryRun = !!flags['dry-run']\n\n // A federated app deploys through Sanity's build/hosting pipeline, which\n // --external skips — fail before doing any other work.\n if (isExternal && isWorkbenchApp) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Deploying a federated application to an external host is not yet supported',\n solution: 'Remove the --external flag to deploy to Sanity hosting',\n status: 'fail',\n })\n }\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.name\n : ''\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n const version = await checkPackageVersion(reporter, {\n moduleName: STUDIO_PACKAGE,\n workDir,\n })\n\n reporter.report(\n projectId\n ? {message: `Project: ${projectId}`, status: 'pass'}\n : {\n message: NO_PROJECT_ID,\n solution: 'Add `api.projectId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n // Workbench studios deploy to Brett (which needs the org); plain studios\n // resolve/create on user-applications, unchanged.\n let application: UserApplication | null = null\n let studioCreated = false\n if (workbench && !isExternal) {\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n await checkStudioTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n studioHost: cliConfig.studioHost,\n title: appTitle,\n })\n } else {\n ;({application, created: studioCreated} = await resolveStudioApplication(options, {\n dryRun,\n reporter,\n }))\n }\n\n await checkBuild(reporter, {\n build: () =>\n buildStudio({\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: studioBuildSkipReason({build: flags.build, isExternal}),\n successMessage: 'Studio built',\n })\n\n if (!isExternal) {\n await verifyOutputDir({isWorkbenchApp, reporter, sourceDir})\n }\n\n // Report the exposes deploying with the studio, both modes. External studios\n // host their own bundle, so nothing registers.\n const exposes = workbench && !isExternal ? reportExposes(reporter, workbench) : []\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved version means the deploy target was never resolved.\n if (!version) return\n\n const studioManifest = await uploadStudioSchema(options, {isExternal})\n // Workbench studios deploy to Brett; plain studios use user-applications.\n if (workbench && !isExternal && organizationId) {\n const {applicationId} = await deployWorkbenchStudio({\n appId,\n interfaces: buildExposes(workbench, {\n appName: workbench.name,\n appTitle,\n exposesAppView: true,\n version,\n }),\n isAutoUpdating,\n organizationId,\n output,\n projectId,\n sourceDir,\n studioHost: cliConfig.studioHost,\n title: appTitle,\n version,\n workspaces: toWorkspaces(studioManifest),\n })\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'studio'})\n logWorkbenchStudioDeployed({applicationId, cliConfig, output, url})\n return {\n applicationType: 'studio',\n applicationVersion: version,\n ...(exposes.length > 0 ? {exposes} : {}),\n target: {\n action: appId ? 'update' : 'create',\n applicationId,\n title: appTitle,\n url,\n },\n }\n }\n\n if (!application) return\n const location = await shipStudioDeployment({\n application,\n isAutoUpdating,\n isExternal,\n options,\n studioManifest,\n version,\n })\n\n return {\n applicationType: 'studio',\n applicationVersion: version,\n target: {\n action: studioCreated ? 'create' : 'update',\n applicationId: application.id,\n title: application.title ?? null,\n url: location,\n },\n }\n}\n\n/**\n * Finds the application a real deploy targets, registering a studio host when\n * none is configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveStudioApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplication | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const isExternal = !!flags.external\n const appId = getAppId(cliConfig)\n // Sets the title on a newly registered studio; blank falls back to undefined\n const title = flags.title?.trim() || undefined\n\n if (dryRun) {\n await checkStudioTarget(reporter, {\n appId,\n isExternal,\n projectId: cliConfig.api?.projectId,\n studioHost: cliConfig.studioHost,\n title,\n urlFlag: flags.url,\n })\n return {application: null, created: false}\n }\n\n const projectId = cliConfig.api?.projectId ?? ''\n // `created` is true when a configured-but-unregistered host was just registered.\n const {application, created} = await findUserApplicationForStudio({\n appId,\n isExternal,\n output,\n projectId,\n studioHost: cliConfig.studioHost,\n title,\n unattended: !!flags.yes,\n urlFlag: flags.url,\n })\n\n if (!application) {\n if (isExternal) {\n output.log('Your project has not been registered with an external studio URL.')\n output.log('Please enter the full URL where your studio is hosted.')\n } else {\n output.log('Your project has not been assigned a studio hostname.')\n output.log('To deploy your Sanity Studio to our hosted sanity.studio service,')\n output.log('you will need one. Please enter the subdomain you want to use.')\n }\n\n const registered = await createStudioUserApplication({\n projectId,\n title,\n urlType: isExternal ? 'external' : 'internal',\n })\n deployDebug('Created user application', registered)\n return {application: registered, created: true}\n }\n\n deployDebug('Found user application', application)\n return {application, created}\n}\n\n/** Extracts the studio schema and manifest and uploads them to the schema store. */\nasync function uploadStudioSchema(\n options: DeployAppOptions,\n {isExternal}: {isExternal: boolean},\n): Promise<StudioManifest | null> {\n const {cliConfig, flags, output, projectRoot, sourceDir} = options\n\n let studioManifest: StudioManifest | null = null\n try {\n studioManifest = await deployStudioSchemasAndManifests(\n {\n configPath: projectRoot.path,\n isExternal,\n outPath: `${sourceDir}/static`,\n projectId: cliConfig.api?.projectId ?? '',\n schemaRequired: flags['schema-required'],\n verbose: flags.verbose,\n workDir: projectRoot.directory,\n },\n output,\n )\n } catch (error) {\n deployDebug('Error deploying studio schemas and manifests', error)\n if (error instanceof SchemaExtractionError) {\n output.error(formatSchemaValidation(error.validation || []), {exit: 1})\n }\n output.error(`Error deploying studio schemas and manifests: ${error}`, {exit: 1})\n }\n\n if (!studioManifest) {\n output.error('Failed to generate studio manifest. Please check your schemas and manifests.', {\n exit: 1,\n })\n }\n\n return studioManifest\n}\n\nasync function shipStudioDeployment({\n application,\n isAutoUpdating,\n isExternal,\n options,\n studioManifest,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n isExternal: boolean\n options: DeployAppOptions\n studioManifest: StudioManifest | null\n version: string\n}): Promise<string> {\n const {cliConfig, output, sourceDir} = options\n\n let tarball: Gzip | undefined\n if (!isExternal) {\n tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n }\n\n const spin = spinner(isExternal ? 'Registering studio' : 'Deploying to sanity.studio').start()\n let location: string\n try {\n ;({location} = await createDeployment({\n applicationId: application.id,\n isApp: false,\n isAutoUpdating,\n manifest: studioManifest,\n projectId: cliConfig.api?.projectId,\n tarball,\n version,\n }))\n } catch (error) {\n spin.fail()\n throw error\n }\n spin.succeed()\n\n const named = application.title ? ` — \"${application.title}\"` : ''\n output.log(\n isExternal\n ? `\\nSuccess! Studio registered${named}`\n : `\\nSuccess! Studio deployed to ${styleText('cyan', location)}${named}`,\n )\n\n if (getAppId(cliConfig)) return location\n\n const example = `Example:\nexport default defineCliConfig({\n //…\n deployment: {\n ${styleText('cyan', `appId: '${application.id}'`)},\n },\n //…\n})`\n output.log(`\\nAdd ${styleText('cyan', `appId: '${application.id}'`)}`)\n output.log(`to the \\`deployment\\` section in sanity.cli.js or sanity.cli.ts`)\n output.log(`to avoid prompting for application id on next deploy.`)\n output.log(`\\n${example}`)\n\n return location\n}\n\nfunction toWorkspaces(manifest: StudioManifest | null): BrettWorkspace[] {\n return (manifest?.workspaces ?? []).map((workspace) => ({\n basePath: workspace.basePath,\n dataset: workspace.dataset,\n icon: workspace.icon,\n name: workspace.name,\n projectId: workspace.projectId,\n subtitle: workspace.subtitle,\n title: workspace.title,\n }))\n}\n\n/** Renders the workbench studio's deploy result; the appId hint shows only when none is configured. */\nfunction logWorkbenchStudioDeployed({\n applicationId,\n cliConfig,\n output,\n url,\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n output: DeployAppOptions['output']\n url: string\n}): void {\n output.log(`\\nSuccess! Studio deployed to ${styleText('cyan', url)}`)\n if (getAppId(cliConfig)) return\n\n output.log(`\\nAdd ${styleText('cyan', `appId: '${applicationId}'`)}`)\n output.log(`to the \\`deployment\\` section in sanity.cli.js or sanity.cli.ts`)\n output.log(`to avoid prompting for application id on next deploy.`)\n}\n\nfunction studioBuildSkipReason({build, isExternal}: {build: boolean; isExternal: boolean}) {\n if (isExternal) return 'Build skipped for externally hosted studios'\n if (!build) return 'Build skipped (--no-build) — validating existing output directory'\n return\n}\n"],"names":["basename","dirname","styleText","createGzip","formatSchemaValidation","SchemaExtractionError","exitCodes","spinner","buildExposes","deployStudio","deployWorkbenchStudio","getApplicationUrl","getWorkbench","pack","createDeployment","getAppId","NO_ORGANIZATION_ID","NO_PROJECT_ID","buildStudio","createStudioUserApplication","checkAutoUpdates","checkBuild","checkPackageVersion","checkStudioTarget","verifyOutputDir","deployDebug","listDeploymentFiles","reportExposes","runDeploy","deployStudioSchemasAndManifests","findUserApplicationForStudio","STUDIO_PACKAGE","options","listFiles","flags","projectRoot","sourceDir","external","Promise","resolve","directory","run","runStudioDeployment","type","reporter","cliConfig","output","workDir","isExternal","workbench","isWorkbenchApp","projectId","api","organizationId","app","appId","dryRun","report","exitCode","USAGE_ERROR","message","solution","status","appTitle","title","trim","name","isAutoUpdating","version","moduleName","application","studioCreated","studioHost","created","resolveStudioApplication","build","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","studioBuildSkipReason","successMessage","exposes","studioManifest","uploadStudioSchema","applicationId","interfaces","appName","exposesAppView","workspaces","toWorkspaces","url","id","logWorkbenchStudioDeployed","applicationType","applicationVersion","length","target","action","location","shipStudioDeployment","undefined","urlFlag","unattended","yes","log","registered","urlType","configPath","path","outPath","schemaRequired","verbose","error","validation","exit","tarball","entries","pipe","spin","start","isApp","manifest","fail","succeed","named","example","map","workspace","basePath","dataset","icon","subtitle"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { readdir, stat } from 'node:fs/promises';
|
|
2
2
|
import { join, relative, sep } from 'node:path';
|
|
3
3
|
import { styleText } from 'node:util';
|
|
4
|
-
import {
|
|
4
|
+
import { summarizeExposes } from '@sanity/workbench-cli/deploy';
|
|
5
|
+
import { checkStatusIcon, nestLines, renderIssues } from '../../util/checks.js';
|
|
5
6
|
import { pluralize } from '../../util/pluralize.js';
|
|
6
7
|
/**
|
|
7
8
|
* Lists the files a deploy would pack from `sourceDir`, as paths relative to
|
|
@@ -49,17 +50,43 @@ function totalBytes(files) {
|
|
|
49
50
|
if (check.status === 'fail') errors[check.message] = check.solution ?? null;
|
|
50
51
|
else if (check.status === 'warn') warnings.push(check.message);
|
|
51
52
|
}
|
|
53
|
+
// `exposes`, `config` and `isSingleton` are workbench-only; plain
|
|
54
|
+
// apps (and apps that don't set the flag) omit them.
|
|
52
55
|
return {
|
|
53
56
|
applicationType: plan.type,
|
|
54
57
|
applicationVersion: plan.version,
|
|
55
58
|
errors,
|
|
59
|
+
...plan.exposes.length > 0 ? {
|
|
60
|
+
exposes: plan.exposes
|
|
61
|
+
} : {},
|
|
56
62
|
files: plan.files,
|
|
63
|
+
...plan.config ? {
|
|
64
|
+
config: plan.config
|
|
65
|
+
} : {},
|
|
57
66
|
isDeployable: isDeployable(plan),
|
|
67
|
+
...plan.isSingleton === undefined ? {} : {
|
|
68
|
+
isSingleton: plan.isSingleton
|
|
69
|
+
},
|
|
58
70
|
target: plan.target,
|
|
59
71
|
totalBytes: totalBytes(plan.files),
|
|
60
72
|
warnings
|
|
61
73
|
};
|
|
62
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Reports an app's exposes as pass checks and returns them structured for the
|
|
77
|
+
* `--json` payload. The structured list rides on the first check so a dry run's
|
|
78
|
+
* collector can read it back.
|
|
79
|
+
*/ export function reportExposes(reporter, app) {
|
|
80
|
+
const { exposes, lines } = summarizeExposes(app);
|
|
81
|
+
for (const [index, message] of lines.entries()){
|
|
82
|
+
reporter.report({
|
|
83
|
+
exposes: index === 0 ? exposes : undefined,
|
|
84
|
+
message,
|
|
85
|
+
status: 'pass'
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
return exposes;
|
|
89
|
+
}
|
|
63
90
|
export function renderDeploymentPlan(plan, output) {
|
|
64
91
|
const label = plan.type === 'coreApp' ? 'application' : 'studio';
|
|
65
92
|
const problems = plan.checks.filter((check)=>check.status === 'fail');
|
|
@@ -68,7 +95,7 @@ export function renderDeploymentPlan(plan, output) {
|
|
|
68
95
|
// Only pass/skip here; problems and warnings render below with their fixes.
|
|
69
96
|
for (const check of plan.checks){
|
|
70
97
|
if (check.status === 'pass' || check.status === 'skip') {
|
|
71
|
-
output.log(` ${
|
|
98
|
+
output.log(nestLines(` ${checkStatusIcon(check.status)} ${check.message}`));
|
|
72
99
|
}
|
|
73
100
|
}
|
|
74
101
|
output.log(isDeployable(plan) ? styleText('green', `\nThis ${label} can be deployed.`) : styleText('red', `\nThis ${label} can't be deployed.`));
|
|
@@ -82,36 +109,8 @@ export function renderDeploymentPlan(plan, output) {
|
|
|
82
109
|
}
|
|
83
110
|
}
|
|
84
111
|
}
|
|
85
|
-
function renderIssues(output, title, checks) {
|
|
86
|
-
if (checks.length === 0) return;
|
|
87
|
-
output.log(`\n${title}`);
|
|
88
|
-
for (const check of checks){
|
|
89
|
-
const fix = check.solution ? `: ${check.solution}` : '';
|
|
90
|
-
output.log(` ${statusIcon(check.status)} ${check.message}${fix}`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
112
|
function formatMB(bytes) {
|
|
94
113
|
return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
|
|
95
114
|
}
|
|
96
|
-
function statusIcon(status) {
|
|
97
|
-
switch(status){
|
|
98
|
-
case 'fail':
|
|
99
|
-
{
|
|
100
|
-
return logSymbols.error;
|
|
101
|
-
}
|
|
102
|
-
case 'skip':
|
|
103
|
-
{
|
|
104
|
-
return logSymbols.info;
|
|
105
|
-
}
|
|
106
|
-
case 'warn':
|
|
107
|
-
{
|
|
108
|
-
return logSymbols.warning;
|
|
109
|
-
}
|
|
110
|
-
default:
|
|
111
|
-
{
|
|
112
|
-
return logSymbols.success;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
115
|
|
|
117
116
|
//# sourceMappingURL=deploymentPlan.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/deploy/deploymentPlan.ts"],"sourcesContent":["import {readdir, stat} from 'node:fs/promises'\nimport {join, relative, sep} from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {type Output} from '@sanity/cli-core'\nimport {logSymbols} from '@sanity/cli-core/ux'\n\nimport {pluralize} from '../../util/pluralize.js'\nimport {type DeployCheck, type DeployTarget} from './deployChecks.js'\n\nexport interface DeploymentFile {\n /** Path relative to the project root, POSIX-style. */\n path: string\n size: number\n}\n\n/** What a `--dry-run` deploy would do: the real deploy sequence with every mutation gated off. */\nexport interface DeploymentPlan {\n checks: DeployCheck[]\n files: DeploymentFile[]\n /** The resolved deploy target; `null` when the checks can't determine one. */\n target: DeployTarget | null\n type: 'coreApp' | 'studio'\n /** Installed framework version the deploy would use; `null` when not found. */\n version: string | null\n}\n\n/**\n * Lists the files a deploy would pack from `sourceDir`, as paths relative to\n * `fromDir`. A missing directory yields an empty list rather than throwing.\n */\nexport async function listDeploymentFiles(\n sourceDir: string,\n fromDir: string,\n): Promise<DeploymentFile[]> {\n const walk = async (dir: string): Promise<string[]> => {\n let entries\n try {\n entries = await readdir(dir, {withFileTypes: true})\n } catch {\n return []\n }\n const nested = await Promise.all(\n entries.map((entry) => {\n const full = join(dir, entry.name)\n return entry.isDirectory() ? walk(full) : Promise.resolve([full])\n }),\n )\n return nested.flat()\n }\n\n const absolute = await walk(sourceDir)\n const files = await Promise.all(\n absolute.map(async (file) => ({\n // Deploy paths are POSIX-style regardless of the host OS (Windows gives `\\`).\n path: relative(fromDir, file).split(sep).join('/'),\n size: (await stat(file)).size,\n })),\n )\n return files.toSorted((a, b) => a.path.localeCompare(b.path))\n}\n\nexport function isDeployable(plan: DeploymentPlan): boolean {\n return plan.checks.every((check) => check.status !== 'fail')\n}\n\nfunction totalBytes(files: DeploymentFile[]): number {\n return files.reduce((sum, file) => sum + file.size, 0)\n}\n\n/**\n * A problem-focused, machine-readable projection of the plan: blocking problems\n * mapped to their fix, warnings as messages. Derived from the same checks the\n * human report renders (its pass/skip lines are informational and omitted here).\n */\nexport function deploymentPlanToJson(plan: DeploymentPlan): {\n applicationType: DeploymentPlan['type']\n applicationVersion: string | null\n errors: Record<string, string | null>\n files: DeploymentFile[]\n isDeployable: boolean\n target: DeployTarget | null\n totalBytes: number\n warnings: string[]\n} {\n const errors: Record<string, string | null> = {}\n const warnings: string[] = []\n for (const check of plan.checks) {\n if (check.status === 'fail') errors[check.message] = check.solution ?? null\n else if (check.status === 'warn') warnings.push(check.message)\n }\n\n return {\n applicationType: plan.type,\n applicationVersion: plan.version,\n errors,\n files: plan.files,\n isDeployable: isDeployable(plan),\n target: plan.target,\n totalBytes: totalBytes(plan.files),\n warnings,\n }\n}\n\nexport function renderDeploymentPlan(plan: DeploymentPlan, output: Output): void {\n const label = plan.type === 'coreApp' ? 'application' : 'studio'\n const problems = plan.checks.filter((check) => check.status === 'fail')\n const warnings = plan.checks.filter((check) => check.status === 'warn')\n\n output.log('\\nDry run — no changes made.\\n')\n\n // Only pass/skip here; problems and warnings render below with their fixes.\n for (const check of plan.checks) {\n if (check.status === 'pass' || check.status === 'skip') {\n output.log(` ${statusIcon(check.status)} ${check.message}`)\n }\n }\n\n output.log(\n isDeployable(plan)\n ? styleText('green', `\\nThis ${label} can be deployed.`)\n : styleText('red', `\\nThis ${label} can't be deployed.`),\n )\n\n renderIssues(output, 'Problems to fix:', problems)\n renderIssues(output, 'Warnings:', warnings)\n\n // A blocked deploy uploads nothing, so only list files for a deployable plan.\n if (isDeployable(plan) && plan.files.length > 0) {\n output.log(\n `\\nFiles to deploy (${plan.files.length} ${pluralize('file', plan.files.length)}, ${formatMB(totalBytes(plan.files))}):`,\n )\n for (const file of plan.files) {\n output.log(` ${file.path} (${formatMB(file.size)})`)\n }\n }\n}\n\nfunction renderIssues(output: Output, title: string, checks: DeployCheck[]): void {\n if (checks.length === 0) return\n\n output.log(`\\n${title}`)\n for (const check of checks) {\n const fix = check.solution ? `: ${check.solution}` : ''\n output.log(` ${statusIcon(check.status)} ${check.message}${fix}`)\n }\n}\n\nfunction formatMB(bytes: number): string {\n return `${(bytes / 1024 / 1024).toFixed(2)} MB`\n}\n\nfunction statusIcon(status: DeployCheck['status']): string {\n switch (status) {\n case 'fail': {\n return logSymbols.error\n }\n case 'skip': {\n return logSymbols.info\n }\n case 'warn': {\n return logSymbols.warning\n }\n default: {\n return logSymbols.success\n }\n }\n}\n"],"names":["readdir","stat","join","relative","sep","styleText","logSymbols","pluralize","listDeploymentFiles","sourceDir","fromDir","walk","dir","entries","withFileTypes","nested","Promise","all","map","entry","full","name","isDirectory","resolve","flat","absolute","files","file","path","split","size","toSorted","a","b","localeCompare","isDeployable","plan","checks","every","check","status","totalBytes","reduce","sum","deploymentPlanToJson","errors","warnings","message","solution","push","applicationType","type","applicationVersion","version","target","renderDeploymentPlan","output","label","problems","filter","log","statusIcon","renderIssues","length","formatMB","title","fix","bytes","toFixed","error","info","warning","success"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/deploymentPlan.ts"],"sourcesContent":["import {readdir, stat} from 'node:fs/promises'\nimport {join, relative, sep} from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {type Output} from '@sanity/cli-core'\nimport {type DeployedExpose, summarizeExposes} from '@sanity/workbench-cli/deploy'\n\nimport {checkStatusIcon, nestLines, renderIssues} from '../../util/checks.js'\nimport {pluralize} from '../../util/pluralize.js'\nimport {type DeployCheck, type DeployCheckReporter, type DeployTarget} from './deployChecks.js'\n\nexport interface DeploymentFile {\n /** Path relative to the project root, POSIX-style. */\n path: string\n size: number\n}\n\n/** What a `--dry-run` deploy would do: the real deploy sequence with every mutation gated off. */\nexport interface DeploymentPlan {\n checks: DeployCheck[]\n /** Media-library config summary; `null` unless a config deploys. */\n config: string | null\n /** Workbench views and services registered with the deploy. */\n exposes: DeployedExpose[]\n files: DeploymentFile[]\n /** The resolved deploy target; `null` when the checks can't determine one. */\n target: DeployTarget | null\n type: 'coreApp' | 'studio'\n /** Installed framework version the deploy would use; `null` when not found. */\n version: string | null\n\n /** The app's explicit `isSingleton` flag; `undefined` when the app doesn't set it. */\n isSingleton?: boolean\n}\n\n/**\n * Lists the files a deploy would pack from `sourceDir`, as paths relative to\n * `fromDir`. A missing directory yields an empty list rather than throwing.\n */\nexport async function listDeploymentFiles(\n sourceDir: string,\n fromDir: string,\n): Promise<DeploymentFile[]> {\n const walk = async (dir: string): Promise<string[]> => {\n let entries\n try {\n entries = await readdir(dir, {withFileTypes: true})\n } catch {\n return []\n }\n const nested = await Promise.all(\n entries.map((entry) => {\n const full = join(dir, entry.name)\n return entry.isDirectory() ? walk(full) : Promise.resolve([full])\n }),\n )\n return nested.flat()\n }\n\n const absolute = await walk(sourceDir)\n const files = await Promise.all(\n absolute.map(async (file) => ({\n // Deploy paths are POSIX-style regardless of the host OS (Windows gives `\\`).\n path: relative(fromDir, file).split(sep).join('/'),\n size: (await stat(file)).size,\n })),\n )\n return files.toSorted((a, b) => a.path.localeCompare(b.path))\n}\n\nexport function isDeployable(plan: DeploymentPlan): boolean {\n return plan.checks.every((check) => check.status !== 'fail')\n}\n\nfunction totalBytes(files: DeploymentFile[]): number {\n return files.reduce((sum, file) => sum + file.size, 0)\n}\n\n/**\n * A problem-focused, machine-readable projection of the plan: blocking problems\n * mapped to their fix, warnings as messages. Derived from the same checks the\n * human report renders (its pass/skip lines are informational and omitted here).\n */\nexport function deploymentPlanToJson(plan: DeploymentPlan): {\n applicationType: DeploymentPlan['type']\n applicationVersion: string | null\n config?: string\n errors: Record<string, string | null>\n exposes?: DeployedExpose[]\n files: DeploymentFile[]\n isDeployable: boolean\n isSingleton?: boolean\n target: DeployTarget | null\n totalBytes: number\n warnings: string[]\n} {\n const errors: Record<string, string | null> = {}\n const warnings: string[] = []\n for (const check of plan.checks) {\n if (check.status === 'fail') errors[check.message] = check.solution ?? null\n else if (check.status === 'warn') warnings.push(check.message)\n }\n\n // `exposes`, `config` and `isSingleton` are workbench-only; plain\n // apps (and apps that don't set the flag) omit them.\n return {\n applicationType: plan.type,\n applicationVersion: plan.version,\n errors,\n ...(plan.exposes.length > 0 ? {exposes: plan.exposes} : {}),\n files: plan.files,\n ...(plan.config ? {config: plan.config} : {}),\n isDeployable: isDeployable(plan),\n ...(plan.isSingleton === undefined ? {} : {isSingleton: plan.isSingleton}),\n target: plan.target,\n totalBytes: totalBytes(plan.files),\n warnings,\n }\n}\n\n/**\n * Reports an app's exposes as pass checks and returns them structured for the\n * `--json` payload. The structured list rides on the first check so a dry run's\n * collector can read it back.\n */\nexport function reportExposes(\n reporter: DeployCheckReporter,\n app: Parameters<typeof summarizeExposes>[0],\n): DeployedExpose[] {\n const {exposes, lines} = summarizeExposes(app)\n for (const [index, message] of lines.entries()) {\n reporter.report({exposes: index === 0 ? exposes : undefined, message, status: 'pass'})\n }\n return exposes\n}\n\nexport function renderDeploymentPlan(plan: DeploymentPlan, output: Output): void {\n const label = plan.type === 'coreApp' ? 'application' : 'studio'\n const problems = plan.checks.filter((check) => check.status === 'fail')\n const warnings = plan.checks.filter((check) => check.status === 'warn')\n\n output.log('\\nDry run — no changes made.\\n')\n\n // Only pass/skip here; problems and warnings render below with their fixes.\n for (const check of plan.checks) {\n if (check.status === 'pass' || check.status === 'skip') {\n output.log(nestLines(` ${checkStatusIcon(check.status)} ${check.message}`))\n }\n }\n\n output.log(\n isDeployable(plan)\n ? styleText('green', `\\nThis ${label} can be deployed.`)\n : styleText('red', `\\nThis ${label} can't be deployed.`),\n )\n\n renderIssues(output, 'Problems to fix:', problems)\n renderIssues(output, 'Warnings:', warnings)\n\n // A blocked deploy uploads nothing, so only list files for a deployable plan.\n if (isDeployable(plan) && plan.files.length > 0) {\n output.log(\n `\\nFiles to deploy (${plan.files.length} ${pluralize('file', plan.files.length)}, ${formatMB(totalBytes(plan.files))}):`,\n )\n for (const file of plan.files) {\n output.log(` ${file.path} (${formatMB(file.size)})`)\n }\n }\n}\n\nfunction formatMB(bytes: number): string {\n return `${(bytes / 1024 / 1024).toFixed(2)} MB`\n}\n"],"names":["readdir","stat","join","relative","sep","styleText","summarizeExposes","checkStatusIcon","nestLines","renderIssues","pluralize","listDeploymentFiles","sourceDir","fromDir","walk","dir","entries","withFileTypes","nested","Promise","all","map","entry","full","name","isDirectory","resolve","flat","absolute","files","file","path","split","size","toSorted","a","b","localeCompare","isDeployable","plan","checks","every","check","status","totalBytes","reduce","sum","deploymentPlanToJson","errors","warnings","message","solution","push","applicationType","type","applicationVersion","version","exposes","length","config","isSingleton","undefined","target","reportExposes","reporter","app","lines","index","report","renderDeploymentPlan","output","label","problems","filter","log","formatMB","bytes","toFixed"],"mappings":"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"}
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* Finds (or creates) the user application a deploy targets — the interactive
|
|
3
3
|
* adapter that turns the resolveDeployTarget verdicts into prompts, creation,
|
|
4
4
|
* and exits. Dry runs consume the same verdicts read-only (see deployChecks).
|
|
5
|
-
*/ import {
|
|
5
|
+
*/ import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
6
|
+
import { select, Separator, spinner } from '@sanity/cli-core/ux';
|
|
6
7
|
import { createUserApplication } from '../../services/userApplications.js';
|
|
7
8
|
import { getAppId } from '../../util/appId.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
9
|
+
import { createFailFastReporter } from '../../util/checks.js';
|
|
10
|
+
import { describeAppTarget, describeAppTargetError, describeStudioTarget } from './deployChecks.js';
|
|
10
11
|
import { deployDebug } from './deployDebug.js';
|
|
11
12
|
import { resolveAppDeployTarget, resolveStudioDeployTarget } from './resolveDeployTarget.js';
|
|
12
13
|
export async function findUserApplication(options) {
|
|
@@ -73,31 +74,49 @@ export async function findUserApplicationForStudio(options) {
|
|
|
73
74
|
output.error(`Failed to resolve deploy target: ${getErrorMessage(error)}`, {
|
|
74
75
|
exit: 1
|
|
75
76
|
});
|
|
76
|
-
return
|
|
77
|
+
return {
|
|
78
|
+
application: null,
|
|
79
|
+
created: false
|
|
80
|
+
};
|
|
77
81
|
}
|
|
78
82
|
if (resolution.type === 'found') {
|
|
79
83
|
spin.succeed();
|
|
80
|
-
return
|
|
84
|
+
return {
|
|
85
|
+
application: resolution.application,
|
|
86
|
+
created: false
|
|
87
|
+
};
|
|
81
88
|
}
|
|
82
|
-
// The configured host isn't registered yet — a deploy registers it without
|
|
89
|
+
// The configured host isn't registered yet — a deploy registers it without
|
|
90
|
+
// prompting, so this returns a newly created studio.
|
|
83
91
|
if (resolution.type === 'would-create') {
|
|
84
92
|
spin.succeed();
|
|
85
|
-
|
|
93
|
+
const application = await createFromConfiguredHost({
|
|
86
94
|
appHost: resolution.appHost,
|
|
87
95
|
output,
|
|
88
96
|
projectId,
|
|
89
97
|
title,
|
|
90
98
|
urlType
|
|
91
99
|
});
|
|
100
|
+
return {
|
|
101
|
+
application,
|
|
102
|
+
created: application !== null
|
|
103
|
+
};
|
|
92
104
|
}
|
|
93
105
|
if (resolution.type === 'needs-input' && !unattended) {
|
|
94
106
|
spin.succeed();
|
|
95
107
|
// Nothing to select from — the caller prompts for a brand new host
|
|
96
|
-
if (resolution.existing.length === 0) return
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
108
|
+
if (resolution.existing.length === 0) return {
|
|
109
|
+
application: null,
|
|
110
|
+
created: false
|
|
111
|
+
};
|
|
112
|
+
// A selected existing studio is an update; "new" returns null and the caller registers it.
|
|
113
|
+
return {
|
|
114
|
+
application: await promptForExistingStudio({
|
|
115
|
+
existing: resolution.existing,
|
|
116
|
+
urlType
|
|
117
|
+
}),
|
|
118
|
+
created: false
|
|
119
|
+
};
|
|
101
120
|
}
|
|
102
121
|
spin.fail();
|
|
103
122
|
// 'blocked' diagnoses as a skip (its root cause fails an earlier check), so it
|
|
@@ -106,12 +125,18 @@ export async function findUserApplicationForStudio(options) {
|
|
|
106
125
|
output.error(resolution.message, {
|
|
107
126
|
exit: 1
|
|
108
127
|
});
|
|
109
|
-
return
|
|
128
|
+
return {
|
|
129
|
+
application: null,
|
|
130
|
+
created: false
|
|
131
|
+
};
|
|
110
132
|
}
|
|
111
133
|
createFailFastReporter(output).report(describeStudioTarget(resolution, {
|
|
112
134
|
isExternal
|
|
113
135
|
}));
|
|
114
|
-
return
|
|
136
|
+
return {
|
|
137
|
+
application: null,
|
|
138
|
+
created: false
|
|
139
|
+
};
|
|
115
140
|
}
|
|
116
141
|
/**
|
|
117
142
|
* The host is configured (studioHost or --url) but not registered yet:
|