@sanity/cli 8.21.0 → 8.22.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 +106 -47
- package/codemods/dashboard.js +111 -0
- package/dist/actions/build/buildApp.js +1 -1
- package/dist/actions/build/buildApp.js.map +1 -1
- package/dist/actions/build/buildStudio.js +1 -1
- package/dist/actions/build/buildStudio.js.map +1 -1
- package/dist/actions/codemods/dashboard.js +113 -0
- package/dist/actions/codemods/dashboard.js.map +1 -0
- package/dist/actions/codemods/index.js +2 -0
- package/dist/actions/codemods/index.js.map +1 -1
- package/dist/actions/codemods/types.js.map +1 -1
- package/dist/actions/deploy/deployApp.js +13 -6
- package/dist/actions/deploy/deployApp.js.map +1 -1
- package/dist/actions/deploy/deployChecks.js +12 -7
- package/dist/actions/deploy/deployChecks.js.map +1 -1
- package/dist/actions/deploy/deployRunner.js +14 -8
- package/dist/actions/deploy/deployRunner.js.map +1 -1
- package/dist/actions/deploy/deployStudio.js +39 -4
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/deploy/resolveDeployTarget.js +7 -6
- package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
- package/dist/actions/init/project/promptForAppTemplateSetup.js +22 -0
- package/dist/actions/init/project/promptForAppTemplateSetup.js.map +1 -1
- package/dist/actions/schema/listSchemas.js +2 -3
- package/dist/actions/schema/listSchemas.js.map +1 -1
- package/dist/actions/typegen/generateResourceTypes.js +11 -8
- package/dist/actions/typegen/generateResourceTypes.js.map +1 -1
- package/dist/actions/typegen/watchResourceTypes.js +208 -0
- package/dist/actions/typegen/watchResourceTypes.js.map +1 -0
- package/dist/actions/undeploy/runUndeploy.js +14 -8
- package/dist/actions/undeploy/runUndeploy.js.map +1 -1
- package/dist/commands/codemod.js +15 -4
- package/dist/commands/codemod.js.map +1 -1
- package/dist/commands/context/get.js +3 -8
- package/dist/commands/context/get.js.map +1 -1
- package/dist/commands/context/imports/download.js +3 -8
- package/dist/commands/context/imports/download.js.map +1 -1
- package/dist/commands/context/imports/get.js +3 -8
- package/dist/commands/context/imports/get.js.map +1 -1
- package/dist/commands/context/imports/list.js +3 -8
- package/dist/commands/context/imports/list.js.map +1 -1
- package/dist/commands/context/jobs/get.js +8 -8
- package/dist/commands/context/jobs/get.js.map +1 -1
- package/dist/commands/context/list.js +2 -6
- package/dist/commands/context/list.js.map +1 -1
- package/dist/commands/deploy.js +1 -0
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.js +2 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/openapi/list.js +2 -4
- package/dist/commands/openapi/list.js.map +1 -1
- package/dist/commands/projects/create.js +3 -6
- package/dist/commands/projects/create.js.map +1 -1
- package/dist/commands/schemas/list.js +1 -3
- package/dist/commands/schemas/list.js.map +1 -1
- package/dist/commands/tokens/create.js +2 -5
- package/dist/commands/tokens/create.js.map +1 -1
- package/dist/commands/tokens/list.js +2 -6
- package/dist/commands/tokens/list.js.map +1 -1
- package/dist/commands/tokens/rotate.js +2 -5
- package/dist/commands/tokens/rotate.js.map +1 -1
- package/dist/commands/typegen/generate.js +83 -45
- package/dist/commands/typegen/generate.js.map +1 -1
- package/dist/commands/undeploy.js +1 -0
- package/dist/commands/undeploy.js.map +1 -1
- package/dist/commands/whoami.js +5 -11
- package/dist/commands/whoami.js.map +1 -1
- package/dist/exports/invokeSanityCli/index.js +26 -6
- package/dist/exports/invokeSanityCli/index.js.map +1 -1
- package/dist/generated/apiRoutes.js +11 -26
- package/dist/generated/apiRoutes.js.map +1 -1
- package/dist/telemetry/init.telemetry.js.map +1 -1
- package/oclif.manifest.json +1323 -1294
- package/package.json +6 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/codemods/dashboard.ts"],"sourcesContent":["import {\n findPathForFiles,\n getCliConfig,\n getLocalPackageVersion,\n getStudioConfig,\n isWorkbenchApp,\n tryFindStudioConfigPath,\n} from '@sanity/cli-core'\nimport {input, select} from '@sanity/cli-core/ux'\nimport {toAppSlug} from '@sanity/workbench-cli/init'\nimport {lt} from 'semver'\n\nimport {getOrganizationGrants, listOrganizations} from '../../services/organizations.js'\nimport {getProjectById} from '../../services/projects.js'\nimport {getManageUrl} from '../projects/getManageUrl.js'\nimport {type CodeMod} from './types.js'\n\n// The first `sanity` release whose `sanity/cli` exports `defineApplication`\nconst MIN_SANITY_VERSION = '6.12.0'\n\nconst purpose = 'Move an existing Studio or SDK app onto the Dashboard'\nconst description = `\nRewrites sanity.cli.ts (or .js) so the next \\`sanity dev\\` and \\`sanity deploy\\` run the project\nas a new Dashboard application. Asks for the application's title and slug, and looks up the\norganization from the project.\n\nfrom: app: {organizationId: 'oAbc', entry: './src/App.tsx'}\n to: app: defineApplication({title: 'Acme', slug: 'acme', organizationId: 'oAbc', entry: './src/App.tsx'})\n\nThe existing deployment is left alone. Remove \\`deployment.appId\\` before deploying, or the\nDashboard build replaces the existing application.\n`.trim()\n\nexport const dashboard: CodeMod = {\n description,\n filename: 'dashboard.js',\n prepare: async ({output, workDir}) => {\n const config = await getCliConfig(workDir)\n if (isWorkbenchApp(config.app)) {\n throw new Error('This project is already a Dashboard application.')\n }\n\n const projectId = config.api?.projectId\n let organizationId = config.app?.organizationId\n // Deploy creates the application with both IDs, and the API rejects a project outside the\n // organization, so a project's organization is the only valid choice\n if (!organizationId && projectId) {\n organizationId = (await getProjectById(projectId)).organizationId ?? undefined\n if (!organizationId) {\n throw new Error(\n `Project ${projectId} isn't in an organization, and a Dashboard application needs one. Move the project into an organization at ${getManageUrl(projectId)}, then run this again.`,\n )\n }\n }\n if (!organizationId) {\n const choices = await Promise.all(\n (await listOrganizations()).map(async ({id, name}) => {\n // Grants can 401 for implicit memberships; treat any failure as no access\n const grants = await getOrganizationGrants(id).catch(() => null)\n const canDeploy = (grants?.['sanity.sdk.applications'] ?? []).some((resource) =>\n resource.grants.some((grant) => grant.name === 'deploy'),\n )\n return {\n disabled: canDeploy ? false : 'Insufficient permissions',\n name: `${name} [${id}]`,\n value: id,\n }\n }),\n )\n if (!choices.some((choice) => choice.disabled === false)) {\n throw new Error(\n \"You can't deploy applications in any of your organizations. Ask an organization administrator for access, then run this again.\",\n )\n }\n organizationId = await select({choices, message: 'Organization that owns the application:'})\n }\n\n let suggestedTitle = config.app?.title\n if (!suggestedTitle && (await tryFindStudioConfigPath(workDir))) {\n const studioConfig = await getStudioConfig(workDir, {resolvePlugins: false})\n suggestedTitle = Array.isArray(studioConfig) ? undefined : studioConfig.title\n }\n\n const title = await input({\n default: suggestedTitle,\n message: 'Application title:',\n validate: (value) => (value.trim() ? true : 'Enter a title for the application.'),\n })\n\n // A studio titled after its host would otherwise suggest the one slug that's rejected\n const suggestedSlug = toAppSlug(title) ?? undefined\n const slug = await input({\n default: suggestedSlug === config.studioHost ? undefined : suggestedSlug,\n message: 'Application slug (the hostname it deploys to):',\n validate: (value) => {\n if (toAppSlug(value) !== value) {\n return 'Use lowercase letters, numbers and hyphens, starting with a letter.'\n }\n if (value === config.studioHost) {\n return `\"${value}\" is your Studio's hostname (studioHost), so the deploy would fail. Choose a different slug.`\n }\n return true\n },\n })\n\n // `app.id` is the deprecated spelling and deploy still honours it\n const appIdKey = config.deployment?.appId ? 'deployment.appId' : config.app?.id && 'app.id'\n if (appIdKey) {\n output.warn(\n `Remove \\`${appIdKey}\\` from your CLI config before you deploy. It points at your existing application, and deploying with it in place replaces that application with the Dashboard build.`,\n )\n }\n\n const sanityVersion = await getLocalPackageVersion('sanity', workDir)\n if (sanityVersion && lt(sanityVersion, MIN_SANITY_VERSION)) {\n output.warn(\n `This project uses sanity ${sanityVersion}, and \\`defineApplication\\` needs ${MIN_SANITY_VERSION} or later. Upgrade sanity before you run \\`sanity dev\\` or \\`sanity deploy\\`.`,\n )\n }\n\n // getCliConfig has already checked there is exactly one\n const cliConfigPaths = await findPathForFiles(workDir, ['sanity.cli.ts', 'sanity.cli.js'])\n const paths = cliConfigPaths.filter((path) => path.exists).map((path) => path.path)\n\n return {options: {organizationId, slug, title: title.trim()}, paths}\n },\n purpose,\n}\n"],"names":["findPathForFiles","getCliConfig","getLocalPackageVersion","getStudioConfig","isWorkbenchApp","tryFindStudioConfigPath","input","select","toAppSlug","lt","getOrganizationGrants","listOrganizations","getProjectById","getManageUrl","MIN_SANITY_VERSION","purpose","description","trim","dashboard","filename","prepare","output","workDir","config","app","Error","projectId","api","organizationId","undefined","choices","Promise","all","map","id","name","grants","catch","canDeploy","some","resource","grant","disabled","value","choice","message","suggestedTitle","title","studioConfig","resolvePlugins","Array","isArray","default","validate","suggestedSlug","slug","studioHost","appIdKey","deployment","appId","warn","sanityVersion","cliConfigPaths","paths","filter","path","exists","options"],"mappings":"AAAA,SACEA,gBAAgB,EAChBC,YAAY,EACZC,sBAAsB,EACtBC,eAAe,EACfC,cAAc,EACdC,uBAAuB,QAClB,mBAAkB;AACzB,SAAQC,KAAK,EAAEC,MAAM,QAAO,sBAAqB;AACjD,SAAQC,SAAS,QAAO,6BAA4B;AACpD,SAAQC,EAAE,QAAO,SAAQ;AAEzB,SAAQC,qBAAqB,EAAEC,iBAAiB,QAAO,kCAAiC;AACxF,SAAQC,cAAc,QAAO,6BAA4B;AACzD,SAAQC,YAAY,QAAO,8BAA6B;AAGxD,4EAA4E;AAC5E,MAAMC,qBAAqB;AAE3B,MAAMC,UAAU;AAChB,MAAMC,cAAc,CAAC;;;;;;;;;;AAUrB,CAAC,CAACC,IAAI;AAEN,OAAO,MAAMC,YAAqB;IAChCF;IACAG,UAAU;IACVC,SAAS,OAAO,EAACC,MAAM,EAAEC,OAAO,EAAC;QAC/B,MAAMC,SAAS,MAAMtB,aAAaqB;QAClC,IAAIlB,eAAemB,OAAOC,GAAG,GAAG;YAC9B,MAAM,IAAIC,MAAM;QAClB;QAEA,MAAMC,YAAYH,OAAOI,GAAG,EAAED;QAC9B,IAAIE,iBAAiBL,OAAOC,GAAG,EAAEI;QACjC,0FAA0F;QAC1F,qEAAqE;QACrE,IAAI,CAACA,kBAAkBF,WAAW;YAChCE,iBAAiB,AAAC,CAAA,MAAMhB,eAAec,UAAS,EAAGE,cAAc,IAAIC;YACrE,IAAI,CAACD,gBAAgB;gBACnB,MAAM,IAAIH,MACR,CAAC,QAAQ,EAAEC,UAAU,2GAA2G,EAAEb,aAAaa,WAAW,sBAAsB,CAAC;YAErL;QACF;QACA,IAAI,CAACE,gBAAgB;YACnB,MAAME,UAAU,MAAMC,QAAQC,GAAG,CAC/B,AAAC,CAAA,MAAMrB,mBAAkB,EAAGsB,GAAG,CAAC,OAAO,EAACC,EAAE,EAAEC,IAAI,EAAC;gBAC/C,0EAA0E;gBAC1E,MAAMC,SAAS,MAAM1B,sBAAsBwB,IAAIG,KAAK,CAAC,IAAM;gBAC3D,MAAMC,YAAY,AAACF,CAAAA,QAAQ,CAAC,0BAA0B,IAAI,EAAE,AAAD,EAAGG,IAAI,CAAC,CAACC,WAClEA,SAASJ,MAAM,CAACG,IAAI,CAAC,CAACE,QAAUA,MAAMN,IAAI,KAAK;gBAEjD,OAAO;oBACLO,UAAUJ,YAAY,QAAQ;oBAC9BH,MAAM,GAAGA,KAAK,EAAE,EAAED,GAAG,CAAC,CAAC;oBACvBS,OAAOT;gBACT;YACF;YAEF,IAAI,CAACJ,QAAQS,IAAI,CAAC,CAACK,SAAWA,OAAOF,QAAQ,KAAK,QAAQ;gBACxD,MAAM,IAAIjB,MACR;YAEJ;YACAG,iBAAiB,MAAMrB,OAAO;gBAACuB;gBAASe,SAAS;YAAyC;QAC5F;QAEA,IAAIC,iBAAiBvB,OAAOC,GAAG,EAAEuB;QACjC,IAAI,CAACD,kBAAmB,MAAMzC,wBAAwBiB,UAAW;YAC/D,MAAM0B,eAAe,MAAM7C,gBAAgBmB,SAAS;gBAAC2B,gBAAgB;YAAK;YAC1EH,iBAAiBI,MAAMC,OAAO,CAACH,gBAAgBnB,YAAYmB,aAAaD,KAAK;QAC/E;QAEA,MAAMA,QAAQ,MAAMzC,MAAM;YACxB8C,SAASN;YACTD,SAAS;YACTQ,UAAU,CAACV,QAAWA,MAAM1B,IAAI,KAAK,OAAO;QAC9C;QAEA,sFAAsF;QACtF,MAAMqC,gBAAgB9C,UAAUuC,UAAUlB;QAC1C,MAAM0B,OAAO,MAAMjD,MAAM;YACvB8C,SAASE,kBAAkB/B,OAAOiC,UAAU,GAAG3B,YAAYyB;YAC3DT,SAAS;YACTQ,UAAU,CAACV;gBACT,IAAInC,UAAUmC,WAAWA,OAAO;oBAC9B,OAAO;gBACT;gBACA,IAAIA,UAAUpB,OAAOiC,UAAU,EAAE;oBAC/B,OAAO,CAAC,CAAC,EAAEb,MAAM,4FAA4F,CAAC;gBAChH;gBACA,OAAO;YACT;QACF;QAEA,kEAAkE;QAClE,MAAMc,WAAWlC,OAAOmC,UAAU,EAAEC,QAAQ,qBAAqBpC,OAAOC,GAAG,EAAEU,MAAM;QACnF,IAAIuB,UAAU;YACZpC,OAAOuC,IAAI,CACT,CAAC,SAAS,EAAEH,SAAS,qKAAqK,CAAC;QAE/L;QAEA,MAAMI,gBAAgB,MAAM3D,uBAAuB,UAAUoB;QAC7D,IAAIuC,iBAAiBpD,GAAGoD,eAAe/C,qBAAqB;YAC1DO,OAAOuC,IAAI,CACT,CAAC,yBAAyB,EAAEC,cAAc,kCAAkC,EAAE/C,mBAAmB,6EAA6E,CAAC;QAEnL;QAEA,wDAAwD;QACxD,MAAMgD,iBAAiB,MAAM9D,iBAAiBsB,SAAS;YAAC;YAAiB;SAAgB;QACzF,MAAMyC,QAAQD,eAAeE,MAAM,CAAC,CAACC,OAASA,KAAKC,MAAM,EAAEjC,GAAG,CAAC,CAACgC,OAASA,KAAKA,IAAI;QAElF,OAAO;YAACE,SAAS;gBAACvC;gBAAgB2B;gBAAMR,OAAOA,MAAM9B,IAAI;YAAE;YAAG8C;QAAK;IACrE;IACAhD;AACF,EAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { dashboard } from './dashboard.js';
|
|
1
2
|
import { deskRename } from './deskRename.js';
|
|
2
3
|
import { partsTypeDirective } from './partsTypeDirective.js';
|
|
3
4
|
import { reactIconsV3 } from './reactIconsV3.js';
|
|
4
5
|
export const codemods = {
|
|
6
|
+
dashboard,
|
|
5
7
|
deskRename,
|
|
6
8
|
partsTypeDirective,
|
|
7
9
|
reactIconsV3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/codemods/index.ts"],"sourcesContent":["import {deskRename} from './deskRename.js'\nimport {partsTypeDirective} from './partsTypeDirective.js'\nimport {reactIconsV3} from './reactIconsV3.js'\n\nexport const codemods = {\n deskRename,\n partsTypeDirective,\n reactIconsV3,\n}\n"],"names":["deskRename","partsTypeDirective","reactIconsV3","codemods"],"mappings":"AAAA,SAAQA,UAAU,QAAO,kBAAiB;AAC1C,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,YAAY,QAAO,oBAAmB;AAE9C,OAAO,MAAMC,WAAW;
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/codemods/index.ts"],"sourcesContent":["import {dashboard} from './dashboard.js'\nimport {deskRename} from './deskRename.js'\nimport {partsTypeDirective} from './partsTypeDirective.js'\nimport {reactIconsV3} from './reactIconsV3.js'\n\nexport const codemods = {\n dashboard,\n deskRename,\n partsTypeDirective,\n reactIconsV3,\n}\n"],"names":["dashboard","deskRename","partsTypeDirective","reactIconsV3","codemods"],"mappings":"AAAA,SAAQA,SAAS,QAAO,iBAAgB;AACxC,SAAQC,UAAU,QAAO,kBAAiB;AAC1C,SAAQC,kBAAkB,QAAO,0BAAyB;AAC1D,SAAQC,YAAY,QAAO,oBAAmB;AAE9C,OAAO,MAAMC,WAAW;IACtBJ;IACAC;IACAC;IACAC;AACF,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/codemods/types.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/codemods/types.ts"],"sourcesContent":["import {type Output} from '@sanity/cli-core'\n\nexport interface CodeMod {\n description: string\n // Must match filename in `cli/codemods/`\n filename: string\n purpose: string\n\n /**\n * Runs in the CLI process before the transform (prompts, API lookups). `options` reach the\n * transform's `options` argument; `paths` replace the default target of the whole directory.\n */\n prepare?: (context: {output: Output; workDir: string}) => Promise<{\n options: Record<string, string>\n paths: string[]\n }>\n verify?: (context: {workDir: string}) => Promise<void>\n}\n"],"names":[],"mappings":"AAEA,WAeC"}
|
|
@@ -6,7 +6,8 @@ import { exitCodes } from '@sanity/cli-core';
|
|
|
6
6
|
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
7
7
|
import { getCoreAppUrl } from '@sanity/cli-core/util';
|
|
8
8
|
import { spinner } from '@sanity/cli-core/ux';
|
|
9
|
-
import {
|
|
9
|
+
import { resolveAppEntry } from '@sanity/workbench-cli/build';
|
|
10
|
+
import { createCoreApp, deployConfig, deployWorkbenchApp, getApplicationUrl, getWorkbench, getWorkbenchUrl, resolveInstallationId, resolveWorkbenchConfig, summarizeConfig, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
|
|
10
11
|
import { c as createTar } from 'tar';
|
|
11
12
|
import { createDeployment, updateUserApplication } from '../../services/userApplications.js';
|
|
12
13
|
import { getAppId } from '../../util/appId.js';
|
|
@@ -38,6 +39,7 @@ export function deployApp(options) {
|
|
|
38
39
|
const dryRun = !!flags['dry-run'];
|
|
39
40
|
const deployConfigOnly = !!config;
|
|
40
41
|
const deployApplication = !config && (!workbench || workbench.hasInterfaces);
|
|
42
|
+
const hasAppView = resolveAppEntry(cliConfig.app) !== undefined;
|
|
41
43
|
const appTitle = workbench ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug : '';
|
|
42
44
|
// A federated app with no entry, view or service would ship a remote with
|
|
43
45
|
// nothing to load — reported first so it fails before any prompt or API call.
|
|
@@ -104,6 +106,7 @@ export function deployApp(options) {
|
|
|
104
106
|
} else if (deployApplication && workbench) {
|
|
105
107
|
workbenchApp = (await checkAppTarget(reporter, {
|
|
106
108
|
appId,
|
|
109
|
+
hasAppView,
|
|
107
110
|
isWorkbenchApp: true,
|
|
108
111
|
organizationId,
|
|
109
112
|
slug: workbench.slug,
|
|
@@ -150,7 +153,7 @@ export function deployApp(options) {
|
|
|
150
153
|
// A record created above is stranded at its slug (and blocks retries) if any
|
|
151
154
|
// step before it fully deploys fails, so undo the creation on failure.
|
|
152
155
|
try {
|
|
153
|
-
await checkBuild(reporter, {
|
|
156
|
+
const built = await checkBuild(reporter, {
|
|
154
157
|
build: ()=>buildApp({
|
|
155
158
|
applicationId: workbench ? applicationId : undefined,
|
|
156
159
|
autoUpdatesEnabled: isAutoUpdating,
|
|
@@ -164,7 +167,8 @@ export function deployApp(options) {
|
|
|
164
167
|
skipReason: flags.build ? undefined : 'Build skipped (--no-build) — validating existing output directory',
|
|
165
168
|
successMessage: 'App built'
|
|
166
169
|
});
|
|
167
|
-
|
|
170
|
+
// A federated build has already read its manifest; anything else verifies the directory.
|
|
171
|
+
const mfManifest = built?.mfManifest ?? await verifyOutputDir({
|
|
168
172
|
isWorkbenchApp: workbench !== null || config !== null,
|
|
169
173
|
reporter,
|
|
170
174
|
sourceDir
|
|
@@ -261,12 +265,14 @@ export function deployApp(options) {
|
|
|
261
265
|
// The app was created (or resolved from `deployment.appId`) before the build,
|
|
262
266
|
// so this only ships the deployment; plain coreApps use user-applications below.
|
|
263
267
|
if (workbench && organizationId && applicationId) {
|
|
268
|
+
if (!mfManifest) throw new Error('The federated build produced no manifest.');
|
|
264
269
|
await deployWorkbenchApp({
|
|
265
270
|
app: cliConfig.app,
|
|
266
271
|
applicationId,
|
|
267
272
|
icon: appIcon,
|
|
268
273
|
isApp: true,
|
|
269
274
|
isAutoUpdating,
|
|
275
|
+
mfManifest,
|
|
270
276
|
// Once the deployment is live, a metadata-sync or later config failure
|
|
271
277
|
// must not delete the app.
|
|
272
278
|
onDeployed: ()=>{
|
|
@@ -279,11 +285,12 @@ export function deployApp(options) {
|
|
|
279
285
|
visibility: workbench.visibility
|
|
280
286
|
});
|
|
281
287
|
await deployApplicationConfig();
|
|
282
|
-
const url = getApplicationUrl({
|
|
288
|
+
const url = hasAppView ? getApplicationUrl({
|
|
283
289
|
id: applicationId,
|
|
284
290
|
organizationId,
|
|
291
|
+
slug: workbench.slug,
|
|
285
292
|
type: 'coreApp'
|
|
286
|
-
});
|
|
293
|
+
}) : getWorkbenchUrl(organizationId);
|
|
287
294
|
logAppDeployed({
|
|
288
295
|
applicationId,
|
|
289
296
|
cliConfig,
|
|
@@ -417,7 +424,7 @@ export function deployApp(options) {
|
|
|
417
424
|
deployDebug('Error updating application metadata', {
|
|
418
425
|
message
|
|
419
426
|
});
|
|
420
|
-
output.
|
|
427
|
+
output.logDiagnostic(`Warning: Error updating application metadata: ${message}`);
|
|
421
428
|
return application;
|
|
422
429
|
}
|
|
423
430
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {\n type CoreAppManifest,\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '@sanity/cli-build/_internal/manifest'\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n resolveInstallationId,\n resolveWorkbenchConfig,\n summarizeConfig,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {c as createTar} from 'tar'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\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 organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n // A config (the Media Library) is not an app — it resolves through its own\n // brand and persists to the org's installation instead of hosting an application.\n const config = resolveWorkbenchConfig(cliConfig)\n const dryRun = !!flags['dry-run']\n\n const deployConfigOnly = !!config\n const deployApplication = !config && (!workbench || workbench.hasInterfaces)\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n // A config with no fields would overwrite the org's live config with an empty\n // snapshot, so block it here — same \"nothing to deploy\" gate an app gets.\n if (config && config.fields.length === 0) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Nothing to deploy: the media library config declares no fields.',\n solution: 'Add at least one field to the media library config',\n status: 'fail',\n })\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deployConfigOnly) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\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\n checkAppId(reporter, {cliConfig})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n let workbenchApp: object | undefined\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n workbenchApp = (\n await checkAppTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n const created = await createCoreApp({\n isSingleton: workbench.isSingleton,\n name: workbench.name,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n })\n workbenchApp = created.application\n applicationId = created.application.id\n rollbackApp = created.rollback\n applicationCreated = true\n }\n\n // A record created above is stranded at its slug (and blocks retries) if any\n // step before it fully deploys fails, so undo the creation on failure.\n try {\n await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n await verifyOutputDir({\n isWorkbenchApp: workbench !== null || config !== null,\n reporter,\n sourceDir,\n })\n\n // Workbench apps and configs ship a federation remote and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench && !config) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let configSummary: string | undefined\n const configAppType = config?.appType\n if (deployConfigOnly && organizationId && config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n configSummary = summarizeConfig(config)\n reporter.report(\n installationId\n ? {message: configSummary, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n const interfaces = deployApplication && workbench ? reportInterfaces(reporter, workbench) : null\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n type: 'coreApp',\n version,\n ...toWorkbenchPayload(workbench, {config: configSummary, interfaces, title: appTitle}),\n ...(configSummary ? {config: configSummary} : {}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (installationId && version) {\n return {application: null, installationId, payload}\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n await deployWorkbenchApp({\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: true,\n isAutoUpdating,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n slug: workbench.slug,\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'coreApp'})\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n createRequested: flags.create,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n action: appCreated ? 'create' : 'update',\n application,\n payload,\n url: getCoreAppUrl(application.organizationId, application.id),\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {\n appId: getAppId(cliConfig),\n create: flags.create,\n organizationId,\n title,\n })\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n create: flags.create,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.warn(`Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n createRequested = false,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n createRequested?: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n createRequested\n ? '\\nSave `deployment.appId` and omit --create on later deploys to update this application.'\n : '\\nSave `deployment.appId` to update this application on later deploys.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","exitCodes","getErrorMessage","getCoreAppUrl","spinner","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","resolveInstallationId","resolveWorkbenchConfig","summarizeConfig","toWorkbenchPayload","c","createTar","createDeployment","updateUserApplication","getAppId","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","buildApp","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","config","dryRun","deployConfigOnly","deployApplication","hasInterfaces","appTitle","title","trim","slug","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","fields","length","isAutoUpdating","version","moduleName","application","appCreated","workbenchApp","external","isWorkbenchApp","created","resolveAppApplication","build","appIcon","icon","undefined","applicationId","applicationCreated","rollbackApp","isSingleton","name","visibility","id","rollback","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","manifest","installationId","configSummary","configAppType","appType","interfaces","deployApplicationConfig","payload","isApp","onDeployed","url","logAppDeployed","action","syncApplicationMetadata","shipAppDeployment","createRequested","create","unattended","yes","titleUpdate","visibilityChanged","dashboardStatus","log","from","to","spin","start","updated","body","succeed","fail","warn","tarball","cwd","pipe","error","clear","named"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {\n type CoreAppManifest,\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '@sanity/cli-build/_internal/manifest'\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {resolveAppEntry} from '@sanity/workbench-cli/build'\nimport {\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n getWorkbenchUrl,\n resolveInstallationId,\n resolveWorkbenchConfig,\n summarizeConfig,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {c as createTar} from 'tar'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\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 organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n // A config (the Media Library) is not an app — it resolves through its own\n // brand and persists to the org's installation instead of hosting an application.\n const config = resolveWorkbenchConfig(cliConfig)\n const dryRun = !!flags['dry-run']\n\n const deployConfigOnly = !!config\n const deployApplication = !config && (!workbench || workbench.hasInterfaces)\n const hasAppView = resolveAppEntry(cliConfig.app) !== undefined\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n // A config with no fields would overwrite the org's live config with an empty\n // snapshot, so block it here — same \"nothing to deploy\" gate an app gets.\n if (config && config.fields.length === 0) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Nothing to deploy: the media library config declares no fields.',\n solution: 'Add at least one field to the media library config',\n status: 'fail',\n })\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deployConfigOnly) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\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\n checkAppId(reporter, {cliConfig})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n let workbenchApp: object | undefined\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n workbenchApp = (\n await checkAppTarget(reporter, {\n appId,\n hasAppView,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n const created = await createCoreApp({\n isSingleton: workbench.isSingleton,\n name: workbench.name,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n })\n workbenchApp = created.application\n applicationId = created.application.id\n rollbackApp = created.rollback\n applicationCreated = true\n }\n\n // A record created above is stranded at its slug (and blocks retries) if any\n // step before it fully deploys fails, so undo the creation on failure.\n try {\n const built = await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n // A federated build has already read its manifest; anything else verifies the directory.\n const mfManifest =\n built?.mfManifest ??\n (await verifyOutputDir({\n isWorkbenchApp: workbench !== null || config !== null,\n reporter,\n sourceDir,\n }))\n\n // Workbench apps and configs ship a federation remote and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench && !config) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let configSummary: string | undefined\n const configAppType = config?.appType\n if (deployConfigOnly && organizationId && config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n configSummary = summarizeConfig(config)\n reporter.report(\n installationId\n ? {message: configSummary, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n const interfaces = deployApplication && workbench ? reportInterfaces(reporter, workbench) : null\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n type: 'coreApp',\n version,\n ...toWorkbenchPayload(workbench, {config: configSummary, interfaces, title: appTitle}),\n ...(configSummary ? {config: configSummary} : {}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (installationId && version) {\n return {application: null, installationId, payload}\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n if (!mfManifest) throw new Error('The federated build produced no manifest.')\n await deployWorkbenchApp({\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: true,\n isAutoUpdating,\n mfManifest,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n slug: workbench.slug,\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = hasAppView\n ? getApplicationUrl({\n id: applicationId,\n organizationId,\n slug: workbench.slug,\n type: 'coreApp',\n })\n : getWorkbenchUrl(organizationId)\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n createRequested: flags.create,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n action: appCreated ? 'create' : 'update',\n application,\n payload,\n url: getCoreAppUrl(application.organizationId, application.id),\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {\n appId: getAppId(cliConfig),\n create: flags.create,\n organizationId,\n title,\n })\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n create: flags.create,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.logDiagnostic(`Warning: Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n createRequested = false,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n createRequested?: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n createRequested\n ? '\\nSave `deployment.appId` and omit --create on later deploys to update this application.'\n : '\\nSave `deployment.appId` to update this application on later deploys.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","exitCodes","getErrorMessage","getCoreAppUrl","spinner","resolveAppEntry","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","getWorkbenchUrl","resolveInstallationId","resolveWorkbenchConfig","summarizeConfig","toWorkbenchPayload","c","createTar","createDeployment","updateUserApplication","getAppId","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","buildApp","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","config","dryRun","deployConfigOnly","deployApplication","hasInterfaces","hasAppView","undefined","appTitle","title","trim","slug","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","fields","length","isAutoUpdating","version","moduleName","application","appCreated","workbenchApp","external","isWorkbenchApp","created","resolveAppApplication","build","appIcon","icon","applicationId","applicationCreated","rollbackApp","isSingleton","name","visibility","id","rollback","built","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","mfManifest","manifest","installationId","configSummary","configAppType","appType","interfaces","deployApplicationConfig","payload","Error","isApp","onDeployed","url","logAppDeployed","action","syncApplicationMetadata","shipAppDeployment","createRequested","create","unattended","yes","titleUpdate","visibilityChanged","dashboardStatus","log","from","to","spin","start","updated","body","succeed","fail","logDiagnostic","tarball","cwd","pipe","error","clear","named"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { exitCodes, getLocalPackageVersion } from '@sanity/cli-core';
|
|
|
2
2
|
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
3
3
|
import { getCoreAppUrl } from '@sanity/cli-core/util';
|
|
4
4
|
import { spinner } from '@sanity/cli-core/ux';
|
|
5
|
-
import {
|
|
5
|
+
import { readBuiltManifest } from '@sanity/workbench-cli/build';
|
|
6
6
|
import { resolveAppIdIssue } from '../../util/appId.js';
|
|
7
7
|
import { runStep } from '../../util/checks.js';
|
|
8
8
|
import { APP_ID_NOT_FOUND_IN_ORGANIZATION } from '../../util/errorMessages.js';
|
|
@@ -113,30 +113,33 @@ export async function checkBuild(reporter, { build, skipReason, successMessage }
|
|
|
113
113
|
message: skipReason,
|
|
114
114
|
status: 'skip'
|
|
115
115
|
});
|
|
116
|
-
return;
|
|
116
|
+
return undefined;
|
|
117
117
|
}
|
|
118
|
-
await runStep(reporter, {
|
|
118
|
+
const result = await runStep(reporter, {
|
|
119
119
|
debug: deployDebug,
|
|
120
120
|
formatError: (err)=>`Build failed: ${getErrorMessage(err)}`,
|
|
121
121
|
name: 'build',
|
|
122
122
|
solution: 'Fix the build error above, then retry',
|
|
123
123
|
work: async ()=>{
|
|
124
|
-
await build();
|
|
124
|
+
const result = await build();
|
|
125
125
|
reporter.report({
|
|
126
126
|
message: successMessage,
|
|
127
127
|
status: 'pass'
|
|
128
128
|
});
|
|
129
|
+
return result;
|
|
129
130
|
}
|
|
130
131
|
});
|
|
132
|
+
return result ?? undefined;
|
|
131
133
|
}
|
|
132
134
|
/**
|
|
133
135
|
* The deploy directory must exist and hold the right build output: a federation
|
|
134
136
|
* remote for a workbench app, an `index.html` SPA otherwise.
|
|
135
137
|
*/ export async function verifyOutputDir({ isWorkbenchApp, reporter, sourceDir }) {
|
|
136
138
|
const spin = spinner('Verifying local content...').start();
|
|
137
|
-
|
|
139
|
+
let mfManifest;
|
|
138
140
|
try {
|
|
139
|
-
await
|
|
141
|
+
if (isWorkbenchApp) mfManifest = await readBuiltManifest(sourceDir);
|
|
142
|
+
else await checkDir(sourceDir);
|
|
140
143
|
spin.succeed();
|
|
141
144
|
} catch (err) {
|
|
142
145
|
spin.fail();
|
|
@@ -147,6 +150,7 @@ export async function checkBuild(reporter, { build, skipReason, successMessage }
|
|
|
147
150
|
status: 'fail'
|
|
148
151
|
});
|
|
149
152
|
}
|
|
153
|
+
return mfManifest;
|
|
150
154
|
}
|
|
151
155
|
/**
|
|
152
156
|
* The single diagnosis for each app deploy-target verdict, shared by the
|
|
@@ -255,13 +259,14 @@ export function describeAppTargetError(err, organizationId) {
|
|
|
255
259
|
*/ export async function checkAppTarget(reporter, options) {
|
|
256
260
|
const { title } = options;
|
|
257
261
|
if (options.isWorkbenchApp) {
|
|
258
|
-
const { appId, organizationId, slug } = options;
|
|
262
|
+
const { appId, hasAppView, organizationId, slug } = options;
|
|
259
263
|
return runStep(reporter, {
|
|
260
264
|
debug: deployDebug,
|
|
261
265
|
name: 'target',
|
|
262
266
|
work: async ()=>{
|
|
263
267
|
const resolution = await resolveWorkbenchApp({
|
|
264
268
|
appId,
|
|
269
|
+
hasAppView,
|
|
265
270
|
organizationId,
|
|
266
271
|
slug
|
|
267
272
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/deploy/deployChecks.ts"],"sourcesContent":["import {type CliConfig, exitCodes, getLocalPackageVersion} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {checkBuiltOutput} from '@sanity/workbench-cli/deploy'\n\nimport {resolveAppIdIssue} from '../../util/appId.js'\nimport {type Check, type CheckReporter, runStep} from '../../util/checks.js'\nimport {APP_ID_NOT_FOUND_IN_ORGANIZATION} from '../../util/errorMessages.js'\nimport {\n getAutoUpdateIssueMessage,\n getAutoUpdateMigrationHint,\n resolveAutoUpdates,\n} from '../build/shouldAutoUpdate.js'\nimport {checkDir} from './checkDir.js'\nimport {deployDebug} from './deployDebug.js'\nimport {\n type AppDeployTargetResolution,\n type DeployTargetApp,\n resolveAppDeployTarget,\n resolveStudioDeployTarget,\n resolveWorkbenchApp,\n resolveWorkbenchStudio,\n type StudioDeployTargetResolution,\n} from './resolveDeployTarget.js'\nimport {type DeployFlags} from './types.js'\nimport {normalizeUrl, validateUrl} from './urlUtils.js'\n\n/**\n * Where a deploy resolves to, computed once from the deploy-target verdict. The\n * dry-run report and its JSON both read this, so the human and machine outputs\n * can't drift.\n */\nexport interface DeployTarget {\n /** Whether the deploy creates a new application/studio or updates an existing one. */\n action: 'create' | 'update'\n /** `null` until the deploy creates the application. */\n id: string | null\n title: string | null\n type: 'coreApp' | 'studio'\n url: string | null\n\n /** Absent on a plain app, whose backend reports `appHost` instead. */\n slug?: string\n}\n\nexport interface DeployCheck extends Check {\n /** The backend's record, verbatim; `--json` reports it once the deploy succeeds. */\n application?: object\n /** Set on the deploy-target check with the resolved target both reporters read. */\n target?: DeployTarget\n}\n\nexport type DeployCheckReporter = CheckReporter<DeployCheck>\n\nexport async function checkPackageVersion(\n reporter: DeployCheckReporter,\n {moduleName, workDir}: {moduleName: string; workDir: string},\n): Promise<string | null> {\n const version = await getLocalPackageVersion(moduleName, workDir)\n reporter.report(\n version\n ? {message: `Using ${moduleName} ${version}`, status: 'pass'}\n : {\n message: `Failed to find installed ${moduleName} version`,\n solution: `Install ${moduleName} in this project`,\n status: 'fail',\n },\n )\n return version\n}\n\nexport function checkAutoUpdates(\n reporter: DeployCheckReporter,\n {cliConfig, flags}: {cliConfig: CliConfig; flags: DeployFlags},\n): boolean {\n const {enabled, issue} = resolveAutoUpdates({cliConfig, flags})\n\n if (issue) {\n reporter.report({\n message: getAutoUpdateIssueMessage(issue),\n // A config conflict makes a real deploy refuse to run; deprecations only warn\n status: issue.type === 'conflicting-config' ? 'fail' : 'warn',\n })\n\n // The deprecated top-level config also gets the styled migration edit, the\n // same second warning the build/dev path prints through shouldAutoUpdate.\n if (issue.type === 'deprecated-config') {\n reporter.report({\n message: getAutoUpdateMigrationHint(cliConfig.autoUpdates),\n status: 'warn',\n })\n }\n }\n\n return enabled\n}\n\n/**\n * The dry-run form of the `app.id` config check a real deploy runs in\n * `findUserApplication`: a conflict fails (both `app.id` and `deployment.appId`\n * set), the deprecated config alone warns.\n */\nexport function checkAppId(\n reporter: DeployCheckReporter,\n {cliConfig}: {cliConfig: CliConfig},\n): void {\n const issue = resolveAppIdIssue(cliConfig)\n if (issue === 'conflicting-config') {\n reporter.report({\n message: 'Both `app.id` (deprecated) and `deployment.appId` are set',\n solution: 'Remove `app.id` from sanity.cli.ts',\n status: 'fail',\n })\n } else if (issue === 'deprecated-config') {\n reporter.report({\n message: 'The `app.id` config is deprecated',\n solution: 'Move it to `deployment.appId` in sanity.cli.ts',\n status: 'warn',\n })\n }\n}\n\n/**\n * The origin a federated studio deployed with --external is registered\n * at. Only a first deploy registers one; a redeploy keeps the URL it has.\n */\nexport function checkExternalUrl(\n reporter: DeployCheckReporter,\n {appId, url}: {appId: string | undefined; url: string | undefined},\n): string | undefined {\n if (appId) return undefined\n\n if (!url) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first external deploy needs the URL your host serves the build from',\n solution: 'Pass it with --url, for example --url https://studio.example.com',\n status: 'fail',\n })\n return undefined\n }\n\n const normalized = normalizeUrl(url)\n const validation = validateUrl(normalized)\n if (validation !== true) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: validation,\n solution:\n 'Pass --url with an http or https URL, for example --url https://studio.example.com',\n status: 'fail',\n })\n return undefined\n }\n\n // The Dashboard loads the remote from the origin root, so a path would never be fetched.\n const {hash, origin, pathname, search} = new URL(normalized)\n if (pathname !== '/' || search || hash) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: '--url must be an origin with no path, query or hash',\n solution:\n 'Pass the origin your host serves the build from, for example --url https://studio.example.com',\n status: 'fail',\n })\n return undefined\n }\n\n reporter.report({message: `Registers at ${origin}`, status: 'pass'})\n return origin\n}\n\nexport async function checkBuild(\n reporter: DeployCheckReporter,\n {\n build,\n skipReason,\n successMessage,\n }: {build: () => Promise<void>; skipReason: string | undefined; successMessage: string},\n): Promise<void> {\n if (skipReason) {\n reporter.report({message: skipReason, status: 'skip'})\n return\n }\n\n await runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Build failed: ${getErrorMessage(err)}`,\n name: 'build',\n solution: 'Fix the build error above, then retry',\n work: async () => {\n await build()\n reporter.report({message: successMessage, status: 'pass'})\n },\n })\n}\n\n/**\n * The deploy directory must exist and hold the right build output: a federation\n * remote for a workbench app, an `index.html` SPA otherwise.\n */\nexport async function verifyOutputDir({\n isWorkbenchApp,\n reporter,\n sourceDir,\n}: {\n isWorkbenchApp: boolean\n reporter: DeployCheckReporter\n sourceDir: string\n}): Promise<void> {\n const spin = spinner('Verifying local content...').start()\n const verifyBuild = isWorkbenchApp ? checkBuiltOutput : checkDir\n try {\n await verifyBuild(sourceDir)\n spin.succeed()\n } catch (err) {\n spin.fail()\n deployDebug('Error checking directory', err)\n reporter.report({\n message: getErrorMessage(err),\n solution: 'Run the build first, or check the output directory',\n status: 'fail',\n })\n }\n}\n\n/**\n * The single diagnosis for each app deploy-target verdict, shared by the\n * dry-run report and the real deploy's unattended error paths so message,\n * fix, and exit code can't drift between the two.\n */\nexport function describeAppTarget(\n resolution: AppDeployTargetResolution,\n {title}: {title?: string} = {},\n): DeployCheck {\n switch (resolution.type) {\n case 'blocked': {\n return {message: `Deploy target not resolved — ${resolution.message}`, status: 'skip'}\n }\n case 'found': {\n const {application} = resolution\n const title = application.title ?? application.appHost\n const url = application.url ?? getCoreAppUrl(application.organizationId, application.id)\n return {\n application,\n message: `Deploys to existing application \"${title}\" at ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n id: application.id,\n title: application.title,\n type: 'coreApp',\n url,\n },\n }\n }\n case 'invalid': {\n return {\n message: APP_ID_NOT_FOUND_IN_ORGANIZATION,\n solution: 'Check `deployment.appId` matches an app in your organization',\n status: 'fail',\n }\n }\n case 'needs-input': {\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No \\`deployment.appId\\` configured (${resolution.existing.length} existing ${resolution.existing.length === 1 ? 'application' : 'applications'} to choose from)`,\n solution:\n 'Set `deployment.appId` in sanity.cli.ts to deploy to an existing app, or run `sanity deploy --create --title \"<name>\" --yes` to create a new one',\n status: 'fail',\n }\n }\n case 'slug-taken': {\n return describeSlugTaken(resolution)\n }\n // Without --title, creating an app needs a prompt no unattended run can answer\n case 'would-create': {\n const {appHost} = resolution\n if (title) {\n return {\n message: `Would create a new application \"${title}\"${appHost ? ` with slug \"${appHost}\"` : ''}`,\n status: 'pass',\n target: {\n action: 'create',\n id: null,\n ...(appHost ? {slug: appHost} : {}),\n title,\n type: 'coreApp',\n url: null,\n },\n }\n }\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: 'No application to deploy to — creating one needs a title',\n solution:\n 'Pass `--title \"<name>\"` or set `app.title` in sanity.cli.ts to create one, or set `deployment.appId` to deploy to an existing app',\n status: 'fail',\n }\n }\n }\n}\n\n/** One diagnosis for both the app and studio verdicts: they share a slug namespace. */\nfunction describeSlugTaken({\n appHost,\n existing,\n}: {\n appHost: string\n existing: DeployTargetApp\n}): DeployCheck {\n return {\n application: existing,\n exitCode: exitCodes.USAGE_ERROR,\n message: `An application already exists at slug \"${appHost}\" in this organization (app ID ${existing.id})`,\n solution: `Add \\`deployment: {appId: '${existing.id}'}\\` to sanity.cli.ts to redeploy it`,\n status: 'fail',\n target: {\n action: 'update',\n id: existing.id,\n title: existing.title,\n type: existing.type,\n url: existing.url ?? null,\n },\n }\n}\n\nexport function describeAppTargetError(err: unknown, organizationId: string | undefined): string {\n return (err as {statusCode?: number})?.statusCode === 403\n ? `You don’t have permission to view applications for the configured organization ID (\"${organizationId}\"). Verify the organization ID, or ask your organization’s admin for access.`\n : `Failed to resolve deploy target: ${getErrorMessage(err)}`\n}\n\n/**\n * Reports the app deploy target as a check and returns the resolved target;\n * `isWorkbenchApp` selects the backend. Both modes run it — a real deploy uses\n * it to reject a bad `appId` before building.\n */\nexport async function checkAppTarget(\n reporter: DeployCheckReporter,\n options:\n | {\n appId: string | undefined\n create?: boolean\n isWorkbenchApp?: false\n organizationId: string | undefined\n title?: string\n }\n | {\n appId: string | undefined\n isWorkbenchApp: true\n organizationId?: string\n slug?: string\n title?: string\n },\n): Promise<DeployCheck | null> {\n const {title} = options\n if (options.isWorkbenchApp) {\n const {appId, organizationId, slug} = options\n return runStep(reporter, {\n debug: deployDebug,\n name: 'target',\n work: async () => {\n const resolution = await resolveWorkbenchApp({appId, organizationId, slug})\n const check = describeAppTarget(resolution, {title})\n reporter.report(check)\n return check\n },\n })\n }\n\n const {appId, create, organizationId} = options\n return runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => describeAppTargetError(err, organizationId),\n name: 'target',\n work: async () => {\n const check = describeAppTarget(\n await resolveAppDeployTarget({appId, create, organizationId}),\n {\n title,\n },\n )\n reporter.report(check)\n return check\n },\n })\n}\n\n/** Same contract as {@link describeAppTarget}, for the studio verdicts. */\nexport function describeStudioTarget(\n resolution: StudioDeployTargetResolution,\n {isExternal, isWorkbench, title}: {isExternal: boolean; isWorkbench?: boolean; title?: string},\n): DeployCheck {\n const studioUrl = (host: string) => (isExternal ? host : `https://${host}.sanity.studio`)\n\n switch (resolution.type) {\n case 'blocked': {\n return {message: `Deploy target not resolved — ${resolution.message}`, status: 'skip'}\n }\n case 'found': {\n const {appHost} = resolution.application\n const url = resolution.application.url ?? (appHost ? studioUrl(appHost) : null)\n return {\n application: resolution.application,\n message: `Deploys to existing studio ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n id: resolution.application.id,\n title: resolution.application.title,\n type: 'studio',\n url,\n },\n }\n }\n case 'invalid': {\n return {\n // A bad host is a usage error; other invalid targets exit 1\n exitCode: resolution.reason === 'invalid-host' ? exitCodes.USAGE_ERROR : 1,\n message: resolution.message,\n solution: 'Check `studioHost` and `deployment.appId` in sanity.cli.ts',\n status: 'fail',\n }\n }\n case 'needs-input': {\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: isExternal ? 'No external studio URL configured' : 'No studio hostname configured',\n solution: isExternal\n ? 'Set `studioHost` in sanity.cli.ts, or pass the full URL with --url'\n : 'Set `studioHost` in sanity.cli.ts, or pass a hostname with --url',\n status: 'fail',\n }\n }\n case 'slug-taken': {\n return describeSlugTaken(resolution)\n }\n case 'would-create': {\n const appHost = resolution.appHost\n const url = isWorkbench ? null : studioUrl(appHost)\n const result = {\n status: 'pass',\n target: {action: 'create', id: null, title: title || null, type: 'studio', url},\n } as const\n const titled = title ? ` titled \"${title}\"` : ''\n\n if (isExternal) {\n return {\n message: `Would register external studio at ${appHost}${titled}`,\n ...result,\n }\n }\n\n if (isWorkbench) {\n return {\n message: `Would create a new studio${title ? ` \"${title}\"` : ''} with slug \"${appHost}\" (name availability is checked on deploy)`,\n ...result,\n target: {...result.target, slug: appHost},\n }\n }\n\n return {\n message: `Would create studio hostname ${url}${titled} (name availability is checked on deploy)`,\n ...result,\n }\n }\n }\n}\n\n/**\n * Reports the studio deploy target as a check and returns the resolved target;\n * `isWorkbenchApp` selects the backend. Both modes run it — a real deploy uses\n * it to reject a bad `appId` before building.\n */\nexport async function checkStudioTarget(\n reporter: DeployCheckReporter,\n options:\n | {\n appId: string | undefined\n isExternal: boolean\n isWorkbenchApp?: false\n projectId: string | undefined\n studioHost: string | undefined\n title: string | undefined\n urlFlag: string | undefined\n }\n | {\n appId: string | undefined\n isWorkbenchApp: true\n organizationId?: string\n slug: string\n title?: string\n },\n): Promise<DeployCheck | null> {\n const {title} = options\n const resolve = options.isWorkbenchApp\n ? resolveWorkbenchStudio(options)\n : resolveStudioDeployTarget(options)\n // A workbench studio's target is its slug, even when its build is hosted externally.\n const isExternal = options.isWorkbenchApp ? false : options.isExternal\n\n return runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Failed to resolve deploy target: ${getErrorMessage(err)}`,\n name: 'target',\n work: async () => {\n const check = describeStudioTarget(await resolve, {\n isExternal,\n isWorkbench: !!options.isWorkbenchApp,\n title,\n })\n reporter.report(check)\n return check\n },\n })\n}\n"],"names":["exitCodes","getLocalPackageVersion","getErrorMessage","getCoreAppUrl","spinner","checkBuiltOutput","resolveAppIdIssue","runStep","APP_ID_NOT_FOUND_IN_ORGANIZATION","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","resolveAutoUpdates","checkDir","deployDebug","resolveAppDeployTarget","resolveStudioDeployTarget","resolveWorkbenchApp","resolveWorkbenchStudio","normalizeUrl","validateUrl","checkPackageVersion","reporter","moduleName","workDir","version","report","message","status","solution","checkAutoUpdates","cliConfig","flags","enabled","issue","type","autoUpdates","checkAppId","checkExternalUrl","appId","url","undefined","exitCode","USAGE_ERROR","normalized","validation","hash","origin","pathname","search","URL","checkBuild","build","skipReason","successMessage","debug","formatError","err","name","work","verifyOutputDir","isWorkbenchApp","sourceDir","spin","start","verifyBuild","succeed","fail","describeAppTarget","resolution","title","application","appHost","organizationId","id","target","action","existing","length","describeSlugTaken","slug","describeAppTargetError","statusCode","checkAppTarget","options","check","create","describeStudioTarget","isExternal","isWorkbench","studioUrl","host","reason","result","titled","checkStudioTarget","resolve"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/deployChecks.ts"],"sourcesContent":["import {type CliConfig, exitCodes, getLocalPackageVersion} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {readBuiltManifest} from '@sanity/workbench-cli/build'\n\nimport {resolveAppIdIssue} from '../../util/appId.js'\nimport {type Check, type CheckReporter, runStep} from '../../util/checks.js'\nimport {APP_ID_NOT_FOUND_IN_ORGANIZATION} from '../../util/errorMessages.js'\nimport {\n getAutoUpdateIssueMessage,\n getAutoUpdateMigrationHint,\n resolveAutoUpdates,\n} from '../build/shouldAutoUpdate.js'\nimport {checkDir} from './checkDir.js'\nimport {deployDebug} from './deployDebug.js'\nimport {\n type AppDeployTargetResolution,\n type DeployTargetApp,\n resolveAppDeployTarget,\n resolveStudioDeployTarget,\n resolveWorkbenchApp,\n resolveWorkbenchStudio,\n type StudioDeployTargetResolution,\n} from './resolveDeployTarget.js'\nimport {type DeployFlags} from './types.js'\nimport {normalizeUrl, validateUrl} from './urlUtils.js'\n\n/**\n * Where a deploy resolves to, computed once from the deploy-target verdict. The\n * dry-run report and its JSON both read this, so the human and machine outputs\n * can't drift.\n */\nexport interface DeployTarget {\n /** Whether the deploy creates a new application/studio or updates an existing one. */\n action: 'create' | 'update'\n /** `null` until the deploy creates the application. */\n id: string | null\n title: string | null\n type: 'coreApp' | 'studio'\n url: string | null\n\n /** Absent on a plain app, whose backend reports `appHost` instead. */\n slug?: string\n}\n\nexport interface DeployCheck extends Check {\n /** The backend's record, verbatim; `--json` reports it once the deploy succeeds. */\n application?: object\n /** Set on the deploy-target check with the resolved target both reporters read. */\n target?: DeployTarget\n}\n\nexport type DeployCheckReporter = CheckReporter<DeployCheck>\n\nexport async function checkPackageVersion(\n reporter: DeployCheckReporter,\n {moduleName, workDir}: {moduleName: string; workDir: string},\n): Promise<string | null> {\n const version = await getLocalPackageVersion(moduleName, workDir)\n reporter.report(\n version\n ? {message: `Using ${moduleName} ${version}`, status: 'pass'}\n : {\n message: `Failed to find installed ${moduleName} version`,\n solution: `Install ${moduleName} in this project`,\n status: 'fail',\n },\n )\n return version\n}\n\nexport function checkAutoUpdates(\n reporter: DeployCheckReporter,\n {cliConfig, flags}: {cliConfig: CliConfig; flags: DeployFlags},\n): boolean {\n const {enabled, issue} = resolveAutoUpdates({cliConfig, flags})\n\n if (issue) {\n reporter.report({\n message: getAutoUpdateIssueMessage(issue),\n // A config conflict makes a real deploy refuse to run; deprecations only warn\n status: issue.type === 'conflicting-config' ? 'fail' : 'warn',\n })\n\n // The deprecated top-level config also gets the styled migration edit, the\n // same second warning the build/dev path prints through shouldAutoUpdate.\n if (issue.type === 'deprecated-config') {\n reporter.report({\n message: getAutoUpdateMigrationHint(cliConfig.autoUpdates),\n status: 'warn',\n })\n }\n }\n\n return enabled\n}\n\n/**\n * The dry-run form of the `app.id` config check a real deploy runs in\n * `findUserApplication`: a conflict fails (both `app.id` and `deployment.appId`\n * set), the deprecated config alone warns.\n */\nexport function checkAppId(\n reporter: DeployCheckReporter,\n {cliConfig}: {cliConfig: CliConfig},\n): void {\n const issue = resolveAppIdIssue(cliConfig)\n if (issue === 'conflicting-config') {\n reporter.report({\n message: 'Both `app.id` (deprecated) and `deployment.appId` are set',\n solution: 'Remove `app.id` from sanity.cli.ts',\n status: 'fail',\n })\n } else if (issue === 'deprecated-config') {\n reporter.report({\n message: 'The `app.id` config is deprecated',\n solution: 'Move it to `deployment.appId` in sanity.cli.ts',\n status: 'warn',\n })\n }\n}\n\n/**\n * The origin a federated studio deployed with --external is registered\n * at. Only a first deploy registers one; a redeploy keeps the URL it has.\n */\nexport function checkExternalUrl(\n reporter: DeployCheckReporter,\n {appId, url}: {appId: string | undefined; url: string | undefined},\n): string | undefined {\n if (appId) return undefined\n\n if (!url) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first external deploy needs the URL your host serves the build from',\n solution: 'Pass it with --url, for example --url https://studio.example.com',\n status: 'fail',\n })\n return undefined\n }\n\n const normalized = normalizeUrl(url)\n const validation = validateUrl(normalized)\n if (validation !== true) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: validation,\n solution:\n 'Pass --url with an http or https URL, for example --url https://studio.example.com',\n status: 'fail',\n })\n return undefined\n }\n\n // The Dashboard loads the remote from the origin root, so a path would never be fetched.\n const {hash, origin, pathname, search} = new URL(normalized)\n if (pathname !== '/' || search || hash) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: '--url must be an origin with no path, query or hash',\n solution:\n 'Pass the origin your host serves the build from, for example --url https://studio.example.com',\n status: 'fail',\n })\n return undefined\n }\n\n reporter.report({message: `Registers at ${origin}`, status: 'pass'})\n return origin\n}\n\nexport async function checkBuild<T>(\n reporter: DeployCheckReporter,\n {\n build,\n skipReason,\n successMessage,\n }: {build: () => Promise<T>; skipReason: string | undefined; successMessage: string},\n): Promise<T | undefined> {\n if (skipReason) {\n reporter.report({message: skipReason, status: 'skip'})\n return undefined\n }\n\n const result = await runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Build failed: ${getErrorMessage(err)}`,\n name: 'build',\n solution: 'Fix the build error above, then retry',\n work: async () => {\n const result = await build()\n reporter.report({message: successMessage, status: 'pass'})\n return result\n },\n })\n return result ?? undefined\n}\n\n/**\n * The deploy directory must exist and hold the right build output: a federation\n * remote for a workbench app, an `index.html` SPA otherwise.\n */\nexport async function verifyOutputDir({\n isWorkbenchApp,\n reporter,\n sourceDir,\n}: {\n isWorkbenchApp: boolean\n reporter: DeployCheckReporter\n sourceDir: string\n}): Promise<Record<string, unknown> | undefined> {\n const spin = spinner('Verifying local content...').start()\n let mfManifest: Record<string, unknown> | undefined\n try {\n if (isWorkbenchApp) mfManifest = await readBuiltManifest(sourceDir)\n else await checkDir(sourceDir)\n spin.succeed()\n } catch (err) {\n spin.fail()\n deployDebug('Error checking directory', err)\n reporter.report({\n message: getErrorMessage(err),\n solution: 'Run the build first, or check the output directory',\n status: 'fail',\n })\n }\n return mfManifest\n}\n\n/**\n * The single diagnosis for each app deploy-target verdict, shared by the\n * dry-run report and the real deploy's unattended error paths so message,\n * fix, and exit code can't drift between the two.\n */\nexport function describeAppTarget(\n resolution: AppDeployTargetResolution,\n {title}: {title?: string} = {},\n): DeployCheck {\n switch (resolution.type) {\n case 'blocked': {\n return {message: `Deploy target not resolved — ${resolution.message}`, status: 'skip'}\n }\n case 'found': {\n const {application} = resolution\n const title = application.title ?? application.appHost\n const url = application.url ?? getCoreAppUrl(application.organizationId, application.id)\n return {\n application,\n message: `Deploys to existing application \"${title}\" at ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n id: application.id,\n title: application.title,\n type: 'coreApp',\n url,\n },\n }\n }\n case 'invalid': {\n return {\n message: APP_ID_NOT_FOUND_IN_ORGANIZATION,\n solution: 'Check `deployment.appId` matches an app in your organization',\n status: 'fail',\n }\n }\n case 'needs-input': {\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No \\`deployment.appId\\` configured (${resolution.existing.length} existing ${resolution.existing.length === 1 ? 'application' : 'applications'} to choose from)`,\n solution:\n 'Set `deployment.appId` in sanity.cli.ts to deploy to an existing app, or run `sanity deploy --create --title \"<name>\" --yes` to create a new one',\n status: 'fail',\n }\n }\n case 'slug-taken': {\n return describeSlugTaken(resolution)\n }\n // Without --title, creating an app needs a prompt no unattended run can answer\n case 'would-create': {\n const {appHost} = resolution\n if (title) {\n return {\n message: `Would create a new application \"${title}\"${appHost ? ` with slug \"${appHost}\"` : ''}`,\n status: 'pass',\n target: {\n action: 'create',\n id: null,\n ...(appHost ? {slug: appHost} : {}),\n title,\n type: 'coreApp',\n url: null,\n },\n }\n }\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: 'No application to deploy to — creating one needs a title',\n solution:\n 'Pass `--title \"<name>\"` or set `app.title` in sanity.cli.ts to create one, or set `deployment.appId` to deploy to an existing app',\n status: 'fail',\n }\n }\n }\n}\n\n/** One diagnosis for both the app and studio verdicts: they share a slug namespace. */\nfunction describeSlugTaken({\n appHost,\n existing,\n}: {\n appHost: string\n existing: DeployTargetApp\n}): DeployCheck {\n return {\n application: existing,\n exitCode: exitCodes.USAGE_ERROR,\n message: `An application already exists at slug \"${appHost}\" in this organization (app ID ${existing.id})`,\n solution: `Add \\`deployment: {appId: '${existing.id}'}\\` to sanity.cli.ts to redeploy it`,\n status: 'fail',\n target: {\n action: 'update',\n id: existing.id,\n title: existing.title,\n type: existing.type,\n url: existing.url ?? null,\n },\n }\n}\n\nexport function describeAppTargetError(err: unknown, organizationId: string | undefined): string {\n return (err as {statusCode?: number})?.statusCode === 403\n ? `You don’t have permission to view applications for the configured organization ID (\"${organizationId}\"). Verify the organization ID, or ask your organization’s admin for access.`\n : `Failed to resolve deploy target: ${getErrorMessage(err)}`\n}\n\n/**\n * Reports the app deploy target as a check and returns the resolved target;\n * `isWorkbenchApp` selects the backend. Both modes run it — a real deploy uses\n * it to reject a bad `appId` before building.\n */\nexport async function checkAppTarget(\n reporter: DeployCheckReporter,\n options:\n | {\n appId: string | undefined\n create?: boolean\n isWorkbenchApp?: false\n organizationId: string | undefined\n title?: string\n }\n | {\n appId: string | undefined\n hasAppView: boolean\n isWorkbenchApp: true\n organizationId?: string\n slug?: string\n title?: string\n },\n): Promise<DeployCheck | null> {\n const {title} = options\n if (options.isWorkbenchApp) {\n const {appId, hasAppView, organizationId, slug} = options\n return runStep(reporter, {\n debug: deployDebug,\n name: 'target',\n work: async () => {\n const resolution = await resolveWorkbenchApp({appId, hasAppView, organizationId, slug})\n const check = describeAppTarget(resolution, {title})\n reporter.report(check)\n return check\n },\n })\n }\n\n const {appId, create, organizationId} = options\n return runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => describeAppTargetError(err, organizationId),\n name: 'target',\n work: async () => {\n const check = describeAppTarget(\n await resolveAppDeployTarget({appId, create, organizationId}),\n {\n title,\n },\n )\n reporter.report(check)\n return check\n },\n })\n}\n\n/** Same contract as {@link describeAppTarget}, for the studio verdicts. */\nexport function describeStudioTarget(\n resolution: StudioDeployTargetResolution,\n {isExternal, isWorkbench, title}: {isExternal: boolean; isWorkbench?: boolean; title?: string},\n): DeployCheck {\n const studioUrl = (host: string) => (isExternal ? host : `https://${host}.sanity.studio`)\n\n switch (resolution.type) {\n case 'blocked': {\n return {message: `Deploy target not resolved — ${resolution.message}`, status: 'skip'}\n }\n case 'found': {\n const {appHost} = resolution.application\n const url = resolution.application.url ?? (appHost ? studioUrl(appHost) : null)\n return {\n application: resolution.application,\n message: `Deploys to existing studio ${url}`,\n status: 'pass',\n target: {\n action: 'update',\n id: resolution.application.id,\n title: resolution.application.title,\n type: 'studio',\n url,\n },\n }\n }\n case 'invalid': {\n return {\n // A bad host is a usage error; other invalid targets exit 1\n exitCode: resolution.reason === 'invalid-host' ? exitCodes.USAGE_ERROR : 1,\n message: resolution.message,\n solution: 'Check `studioHost` and `deployment.appId` in sanity.cli.ts',\n status: 'fail',\n }\n }\n case 'needs-input': {\n return {\n exitCode: exitCodes.USAGE_ERROR,\n message: isExternal ? 'No external studio URL configured' : 'No studio hostname configured',\n solution: isExternal\n ? 'Set `studioHost` in sanity.cli.ts, or pass the full URL with --url'\n : 'Set `studioHost` in sanity.cli.ts, or pass a hostname with --url',\n status: 'fail',\n }\n }\n case 'slug-taken': {\n return describeSlugTaken(resolution)\n }\n case 'would-create': {\n const appHost = resolution.appHost\n const url = isWorkbench ? null : studioUrl(appHost)\n const result = {\n status: 'pass',\n target: {action: 'create', id: null, title: title || null, type: 'studio', url},\n } as const\n const titled = title ? ` titled \"${title}\"` : ''\n\n if (isExternal) {\n return {\n message: `Would register external studio at ${appHost}${titled}`,\n ...result,\n }\n }\n\n if (isWorkbench) {\n return {\n message: `Would create a new studio${title ? ` \"${title}\"` : ''} with slug \"${appHost}\" (name availability is checked on deploy)`,\n ...result,\n target: {...result.target, slug: appHost},\n }\n }\n\n return {\n message: `Would create studio hostname ${url}${titled} (name availability is checked on deploy)`,\n ...result,\n }\n }\n }\n}\n\n/**\n * Reports the studio deploy target as a check and returns the resolved target;\n * `isWorkbenchApp` selects the backend. Both modes run it — a real deploy uses\n * it to reject a bad `appId` before building.\n */\nexport async function checkStudioTarget(\n reporter: DeployCheckReporter,\n options:\n | {\n appId: string | undefined\n isExternal: boolean\n isWorkbenchApp?: false\n projectId: string | undefined\n studioHost: string | undefined\n title: string | undefined\n urlFlag: string | undefined\n }\n | {\n appId: string | undefined\n isWorkbenchApp: true\n organizationId?: string\n slug: string\n title?: string\n },\n): Promise<DeployCheck | null> {\n const {title} = options\n const resolve = options.isWorkbenchApp\n ? resolveWorkbenchStudio(options)\n : resolveStudioDeployTarget(options)\n // A workbench studio's target is its slug, even when its build is hosted externally.\n const isExternal = options.isWorkbenchApp ? false : options.isExternal\n\n return runStep(reporter, {\n debug: deployDebug,\n formatError: (err) => `Failed to resolve deploy target: ${getErrorMessage(err)}`,\n name: 'target',\n work: async () => {\n const check = describeStudioTarget(await resolve, {\n isExternal,\n isWorkbench: !!options.isWorkbenchApp,\n title,\n })\n reporter.report(check)\n return check\n },\n })\n}\n"],"names":["exitCodes","getLocalPackageVersion","getErrorMessage","getCoreAppUrl","spinner","readBuiltManifest","resolveAppIdIssue","runStep","APP_ID_NOT_FOUND_IN_ORGANIZATION","getAutoUpdateIssueMessage","getAutoUpdateMigrationHint","resolveAutoUpdates","checkDir","deployDebug","resolveAppDeployTarget","resolveStudioDeployTarget","resolveWorkbenchApp","resolveWorkbenchStudio","normalizeUrl","validateUrl","checkPackageVersion","reporter","moduleName","workDir","version","report","message","status","solution","checkAutoUpdates","cliConfig","flags","enabled","issue","type","autoUpdates","checkAppId","checkExternalUrl","appId","url","undefined","exitCode","USAGE_ERROR","normalized","validation","hash","origin","pathname","search","URL","checkBuild","build","skipReason","successMessage","result","debug","formatError","err","name","work","verifyOutputDir","isWorkbenchApp","sourceDir","spin","start","mfManifest","succeed","fail","describeAppTarget","resolution","title","application","appHost","organizationId","id","target","action","existing","length","describeSlugTaken","slug","describeAppTargetError","statusCode","checkAppTarget","options","hasAppView","check","create","describeStudioTarget","isExternal","isWorkbench","studioUrl","host","reason","titled","checkStudioTarget","resolve"],"mappings":"AAAA,SAAwBA,SAAS,EAAEC,sBAAsB,QAAO,mBAAkB;AAClF,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,aAAa,QAAO,wBAAuB;AACnD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,iBAAiB,QAAO,8BAA6B;AAE7D,SAAQC,iBAAiB,QAAO,sBAAqB;AACrD,SAAwCC,OAAO,QAAO,uBAAsB;AAC5E,SAAQC,gCAAgC,QAAO,8BAA6B;AAC5E,SACEC,yBAAyB,EACzBC,0BAA0B,EAC1BC,kBAAkB,QACb,+BAA8B;AACrC,SAAQC,QAAQ,QAAO,gBAAe;AACtC,SAAQC,WAAW,QAAO,mBAAkB;AAC5C,SAGEC,sBAAsB,EACtBC,yBAAyB,EACzBC,mBAAmB,EACnBC,sBAAsB,QAEjB,2BAA0B;AAEjC,SAAQC,YAAY,EAAEC,WAAW,QAAO,gBAAe;AA6BvD,OAAO,eAAeC,oBACpBC,QAA6B,EAC7B,EAACC,UAAU,EAAEC,OAAO,EAAwC;IAE5D,MAAMC,UAAU,MAAMvB,uBAAuBqB,YAAYC;IACzDF,SAASI,MAAM,CACbD,UACI;QAACE,SAAS,CAAC,MAAM,EAAEJ,WAAW,CAAC,EAAEE,SAAS;QAAEG,QAAQ;IAAM,IAC1D;QACED,SAAS,CAAC,yBAAyB,EAAEJ,WAAW,QAAQ,CAAC;QACzDM,UAAU,CAAC,QAAQ,EAAEN,WAAW,gBAAgB,CAAC;QACjDK,QAAQ;IACV;IAEN,OAAOH;AACT;AAEA,OAAO,SAASK,iBACdR,QAA6B,EAC7B,EAACS,SAAS,EAAEC,KAAK,EAA6C;IAE9D,MAAM,EAACC,OAAO,EAAEC,KAAK,EAAC,GAAGtB,mBAAmB;QAACmB;QAAWC;IAAK;IAE7D,IAAIE,OAAO;QACTZ,SAASI,MAAM,CAAC;YACdC,SAASjB,0BAA0BwB;YACnC,8EAA8E;YAC9EN,QAAQM,MAAMC,IAAI,KAAK,uBAAuB,SAAS;QACzD;QAEA,2EAA2E;QAC3E,0EAA0E;QAC1E,IAAID,MAAMC,IAAI,KAAK,qBAAqB;YACtCb,SAASI,MAAM,CAAC;gBACdC,SAAShB,2BAA2BoB,UAAUK,WAAW;gBACzDR,QAAQ;YACV;QACF;IACF;IAEA,OAAOK;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASI,WACdf,QAA6B,EAC7B,EAACS,SAAS,EAAyB;IAEnC,MAAMG,QAAQ3B,kBAAkBwB;IAChC,IAAIG,UAAU,sBAAsB;QAClCZ,SAASI,MAAM,CAAC;YACdC,SAAS;YACTE,UAAU;YACVD,QAAQ;QACV;IACF,OAAO,IAAIM,UAAU,qBAAqB;QACxCZ,SAASI,MAAM,CAAC;YACdC,SAAS;YACTE,UAAU;YACVD,QAAQ;QACV;IACF;AACF;AAEA;;;CAGC,GACD,OAAO,SAASU,iBACdhB,QAA6B,EAC7B,EAACiB,KAAK,EAAEC,GAAG,EAAuD;IAElE,IAAID,OAAO,OAAOE;IAElB,IAAI,CAACD,KAAK;QACRlB,SAASI,MAAM,CAAC;YACdgB,UAAUzC,UAAU0C,WAAW;YAC/BhB,SAAS;YACTE,UAAU;YACVD,QAAQ;QACV;QACA,OAAOa;IACT;IAEA,MAAMG,aAAazB,aAAaqB;IAChC,MAAMK,aAAazB,YAAYwB;IAC/B,IAAIC,eAAe,MAAM;QACvBvB,SAASI,MAAM,CAAC;YACdgB,UAAUzC,UAAU0C,WAAW;YAC/BhB,SAASkB;YACThB,UACE;YACFD,QAAQ;QACV;QACA,OAAOa;IACT;IAEA,yFAAyF;IACzF,MAAM,EAACK,IAAI,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,MAAM,EAAC,GAAG,IAAIC,IAAIN;IACjD,IAAII,aAAa,OAAOC,UAAUH,MAAM;QACtCxB,SAASI,MAAM,CAAC;YACdgB,UAAUzC,UAAU0C,WAAW;YAC/BhB,SAAS;YACTE,UACE;YACFD,QAAQ;QACV;QACA,OAAOa;IACT;IAEAnB,SAASI,MAAM,CAAC;QAACC,SAAS,CAAC,aAAa,EAAEoB,QAAQ;QAAEnB,QAAQ;IAAM;IAClE,OAAOmB;AACT;AAEA,OAAO,eAAeI,WACpB7B,QAA6B,EAC7B,EACE8B,KAAK,EACLC,UAAU,EACVC,cAAc,EACoE;IAEpF,IAAID,YAAY;QACd/B,SAASI,MAAM,CAAC;YAACC,SAAS0B;YAAYzB,QAAQ;QAAM;QACpD,OAAOa;IACT;IAEA,MAAMc,SAAS,MAAM/C,QAAQc,UAAU;QACrCkC,OAAO1C;QACP2C,aAAa,CAACC,MAAQ,CAAC,cAAc,EAAEvD,gBAAgBuD,MAAM;QAC7DC,MAAM;QACN9B,UAAU;QACV+B,MAAM;YACJ,MAAML,SAAS,MAAMH;YACrB9B,SAASI,MAAM,CAAC;gBAACC,SAAS2B;gBAAgB1B,QAAQ;YAAM;YACxD,OAAO2B;QACT;IACF;IACA,OAAOA,UAAUd;AACnB;AAEA;;;CAGC,GACD,OAAO,eAAeoB,gBAAgB,EACpCC,cAAc,EACdxC,QAAQ,EACRyC,SAAS,EAKV;IACC,MAAMC,OAAO3D,QAAQ,8BAA8B4D,KAAK;IACxD,IAAIC;IACJ,IAAI;QACF,IAAIJ,gBAAgBI,aAAa,MAAM5D,kBAAkByD;aACpD,MAAMlD,SAASkD;QACpBC,KAAKG,OAAO;IACd,EAAE,OAAOT,KAAK;QACZM,KAAKI,IAAI;QACTtD,YAAY,4BAA4B4C;QACxCpC,SAASI,MAAM,CAAC;YACdC,SAASxB,gBAAgBuD;YACzB7B,UAAU;YACVD,QAAQ;QACV;IACF;IACA,OAAOsC;AACT;AAEA;;;;CAIC,GACD,OAAO,SAASG,kBACdC,UAAqC,EACrC,EAACC,KAAK,EAAmB,GAAG,CAAC,CAAC;IAE9B,OAAQD,WAAWnC,IAAI;QACrB,KAAK;YAAW;gBACd,OAAO;oBAACR,SAAS,CAAC,6BAA6B,EAAE2C,WAAW3C,OAAO,EAAE;oBAAEC,QAAQ;gBAAM;YACvF;QACA,KAAK;YAAS;gBACZ,MAAM,EAAC4C,WAAW,EAAC,GAAGF;gBACtB,MAAMC,QAAQC,YAAYD,KAAK,IAAIC,YAAYC,OAAO;gBACtD,MAAMjC,MAAMgC,YAAYhC,GAAG,IAAIpC,cAAcoE,YAAYE,cAAc,EAAEF,YAAYG,EAAE;gBACvF,OAAO;oBACLH;oBACA7C,SAAS,CAAC,iCAAiC,EAAE4C,MAAM,KAAK,EAAE/B,KAAK;oBAC/DZ,QAAQ;oBACRgD,QAAQ;wBACNC,QAAQ;wBACRF,IAAIH,YAAYG,EAAE;wBAClBJ,OAAOC,YAAYD,KAAK;wBACxBpC,MAAM;wBACNK;oBACF;gBACF;YACF;QACA,KAAK;YAAW;gBACd,OAAO;oBACLb,SAASlB;oBACToB,UAAU;oBACVD,QAAQ;gBACV;YACF;QACA,KAAK;YAAe;gBAClB,OAAO;oBACLc,UAAUzC,UAAU0C,WAAW;oBAC/BhB,SAAS,CAAC,oCAAoC,EAAE2C,WAAWQ,QAAQ,CAACC,MAAM,CAAC,UAAU,EAAET,WAAWQ,QAAQ,CAACC,MAAM,KAAK,IAAI,gBAAgB,eAAe,gBAAgB,CAAC;oBAC1KlD,UACE;oBACFD,QAAQ;gBACV;YACF;QACA,KAAK;YAAc;gBACjB,OAAOoD,kBAAkBV;YAC3B;QACA,+EAA+E;QAC/E,KAAK;YAAgB;gBACnB,MAAM,EAACG,OAAO,EAAC,GAAGH;gBAClB,IAAIC,OAAO;oBACT,OAAO;wBACL5C,SAAS,CAAC,gCAAgC,EAAE4C,MAAM,CAAC,EAAEE,UAAU,CAAC,YAAY,EAAEA,QAAQ,CAAC,CAAC,GAAG,IAAI;wBAC/F7C,QAAQ;wBACRgD,QAAQ;4BACNC,QAAQ;4BACRF,IAAI;4BACJ,GAAIF,UAAU;gCAACQ,MAAMR;4BAAO,IAAI,CAAC,CAAC;4BAClCF;4BACApC,MAAM;4BACNK,KAAK;wBACP;oBACF;gBACF;gBACA,OAAO;oBACLE,UAAUzC,UAAU0C,WAAW;oBAC/BhB,SAAS;oBACTE,UACE;oBACFD,QAAQ;gBACV;YACF;IACF;AACF;AAEA,qFAAqF,GACrF,SAASoD,kBAAkB,EACzBP,OAAO,EACPK,QAAQ,EAIT;IACC,OAAO;QACLN,aAAaM;QACbpC,UAAUzC,UAAU0C,WAAW;QAC/BhB,SAAS,CAAC,uCAAuC,EAAE8C,QAAQ,+BAA+B,EAAEK,SAASH,EAAE,CAAC,CAAC,CAAC;QAC1G9C,UAAU,CAAC,2BAA2B,EAAEiD,SAASH,EAAE,CAAC,oCAAoC,CAAC;QACzF/C,QAAQ;QACRgD,QAAQ;YACNC,QAAQ;YACRF,IAAIG,SAASH,EAAE;YACfJ,OAAOO,SAASP,KAAK;YACrBpC,MAAM2C,SAAS3C,IAAI;YACnBK,KAAKsC,SAAStC,GAAG,IAAI;QACvB;IACF;AACF;AAEA,OAAO,SAAS0C,uBAAuBxB,GAAY,EAAEgB,cAAkC;IACrF,OAAO,AAAChB,KAA+ByB,eAAe,MAClD,CAAC,oFAAoF,EAAET,eAAe,4EAA4E,CAAC,GACnL,CAAC,iCAAiC,EAAEvE,gBAAgBuD,MAAM;AAChE;AAEA;;;;CAIC,GACD,OAAO,eAAe0B,eACpB9D,QAA6B,EAC7B+D,OAeK;IAEL,MAAM,EAACd,KAAK,EAAC,GAAGc;IAChB,IAAIA,QAAQvB,cAAc,EAAE;QAC1B,MAAM,EAACvB,KAAK,EAAE+C,UAAU,EAAEZ,cAAc,EAAEO,IAAI,EAAC,GAAGI;QAClD,OAAO7E,QAAQc,UAAU;YACvBkC,OAAO1C;YACP6C,MAAM;YACNC,MAAM;gBACJ,MAAMU,aAAa,MAAMrD,oBAAoB;oBAACsB;oBAAO+C;oBAAYZ;oBAAgBO;gBAAI;gBACrF,MAAMM,QAAQlB,kBAAkBC,YAAY;oBAACC;gBAAK;gBAClDjD,SAASI,MAAM,CAAC6D;gBAChB,OAAOA;YACT;QACF;IACF;IAEA,MAAM,EAAChD,KAAK,EAAEiD,MAAM,EAAEd,cAAc,EAAC,GAAGW;IACxC,OAAO7E,QAAQc,UAAU;QACvBkC,OAAO1C;QACP2C,aAAa,CAACC,MAAQwB,uBAAuBxB,KAAKgB;QAClDf,MAAM;QACNC,MAAM;YACJ,MAAM2B,QAAQlB,kBACZ,MAAMtD,uBAAuB;gBAACwB;gBAAOiD;gBAAQd;YAAc,IAC3D;gBACEH;YACF;YAEFjD,SAASI,MAAM,CAAC6D;YAChB,OAAOA;QACT;IACF;AACF;AAEA,yEAAyE,GACzE,OAAO,SAASE,qBACdnB,UAAwC,EACxC,EAACoB,UAAU,EAAEC,WAAW,EAAEpB,KAAK,EAA+D;IAE9F,MAAMqB,YAAY,CAACC,OAAkBH,aAAaG,OAAO,CAAC,QAAQ,EAAEA,KAAK,cAAc,CAAC;IAExF,OAAQvB,WAAWnC,IAAI;QACrB,KAAK;YAAW;gBACd,OAAO;oBAACR,SAAS,CAAC,6BAA6B,EAAE2C,WAAW3C,OAAO,EAAE;oBAAEC,QAAQ;gBAAM;YACvF;QACA,KAAK;YAAS;gBACZ,MAAM,EAAC6C,OAAO,EAAC,GAAGH,WAAWE,WAAW;gBACxC,MAAMhC,MAAM8B,WAAWE,WAAW,CAAChC,GAAG,IAAKiC,CAAAA,UAAUmB,UAAUnB,WAAW,IAAG;gBAC7E,OAAO;oBACLD,aAAaF,WAAWE,WAAW;oBACnC7C,SAAS,CAAC,2BAA2B,EAAEa,KAAK;oBAC5CZ,QAAQ;oBACRgD,QAAQ;wBACNC,QAAQ;wBACRF,IAAIL,WAAWE,WAAW,CAACG,EAAE;wBAC7BJ,OAAOD,WAAWE,WAAW,CAACD,KAAK;wBACnCpC,MAAM;wBACNK;oBACF;gBACF;YACF;QACA,KAAK;YAAW;gBACd,OAAO;oBACL,4DAA4D;oBAC5DE,UAAU4B,WAAWwB,MAAM,KAAK,iBAAiB7F,UAAU0C,WAAW,GAAG;oBACzEhB,SAAS2C,WAAW3C,OAAO;oBAC3BE,UAAU;oBACVD,QAAQ;gBACV;YACF;QACA,KAAK;YAAe;gBAClB,OAAO;oBACLc,UAAUzC,UAAU0C,WAAW;oBAC/BhB,SAAS+D,aAAa,sCAAsC;oBAC5D7D,UAAU6D,aACN,uEACA;oBACJ9D,QAAQ;gBACV;YACF;QACA,KAAK;YAAc;gBACjB,OAAOoD,kBAAkBV;YAC3B;QACA,KAAK;YAAgB;gBACnB,MAAMG,UAAUH,WAAWG,OAAO;gBAClC,MAAMjC,MAAMmD,cAAc,OAAOC,UAAUnB;gBAC3C,MAAMlB,SAAS;oBACb3B,QAAQ;oBACRgD,QAAQ;wBAACC,QAAQ;wBAAUF,IAAI;wBAAMJ,OAAOA,SAAS;wBAAMpC,MAAM;wBAAUK;oBAAG;gBAChF;gBACA,MAAMuD,SAASxB,QAAQ,CAAC,SAAS,EAAEA,MAAM,CAAC,CAAC,GAAG;gBAE9C,IAAImB,YAAY;oBACd,OAAO;wBACL/D,SAAS,CAAC,kCAAkC,EAAE8C,UAAUsB,QAAQ;wBAChE,GAAGxC,MAAM;oBACX;gBACF;gBAEA,IAAIoC,aAAa;oBACf,OAAO;wBACLhE,SAAS,CAAC,yBAAyB,EAAE4C,QAAQ,CAAC,EAAE,EAAEA,MAAM,CAAC,CAAC,GAAG,GAAG,YAAY,EAAEE,QAAQ,0CAA0C,CAAC;wBACjI,GAAGlB,MAAM;wBACTqB,QAAQ;4BAAC,GAAGrB,OAAOqB,MAAM;4BAAEK,MAAMR;wBAAO;oBAC1C;gBACF;gBAEA,OAAO;oBACL9C,SAAS,CAAC,6BAA6B,EAAEa,MAAMuD,OAAO,yCAAyC,CAAC;oBAChG,GAAGxC,MAAM;gBACX;YACF;IACF;AACF;AAEA;;;;CAIC,GACD,OAAO,eAAeyC,kBACpB1E,QAA6B,EAC7B+D,OAgBK;IAEL,MAAM,EAACd,KAAK,EAAC,GAAGc;IAChB,MAAMY,UAAUZ,QAAQvB,cAAc,GAClC5C,uBAAuBmE,WACvBrE,0BAA0BqE;IAC9B,qFAAqF;IACrF,MAAMK,aAAaL,QAAQvB,cAAc,GAAG,QAAQuB,QAAQK,UAAU;IAEtE,OAAOlF,QAAQc,UAAU;QACvBkC,OAAO1C;QACP2C,aAAa,CAACC,MAAQ,CAAC,iCAAiC,EAAEvD,gBAAgBuD,MAAM;QAChFC,MAAM;QACNC,MAAM;YACJ,MAAM2B,QAAQE,qBAAqB,MAAMQ,SAAS;gBAChDP;gBACAC,aAAa,CAAC,CAACN,QAAQvB,cAAc;gBACrCS;YACF;YACAjD,SAASI,MAAM,CAAC6D;YAChB,OAAOA;QACT;IACF;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CLIError } from '@oclif/core/errors';
|
|
2
2
|
import { exitCodes } from '@sanity/cli-core';
|
|
3
|
-
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
3
|
+
import { getErrorMessage, JsonOutputError } from '@sanity/cli-core/errors';
|
|
4
4
|
import { createCollectingReporter, createFailFastReporter } from '../../util/checks.js';
|
|
5
5
|
import { toStderrOutput } from '../../util/toStderrOutput.js';
|
|
6
6
|
import { deployDebug } from './deployDebug.js';
|
|
@@ -12,7 +12,8 @@ import { deploymentPlanToJson, isDeployable, renderDeploymentPlan } from './depl
|
|
|
12
12
|
*/ export async function runDeploy(options, spec) {
|
|
13
13
|
const { output } = options;
|
|
14
14
|
const json = !!options.flags.json;
|
|
15
|
-
const emitJson = (payload)=>output.
|
|
15
|
+
const emitJson = (payload)=>output.logJson(payload);
|
|
16
|
+
let failurePayload;
|
|
16
17
|
// The JSON payload owns stdout, so the run's progress logs go to stderr; only
|
|
17
18
|
// the final JSON.stringify writes to stdout.
|
|
18
19
|
const runOptions = json ? {
|
|
@@ -22,8 +23,11 @@ import { deploymentPlanToJson, isDeployable, renderDeploymentPlan } from './depl
|
|
|
22
23
|
try {
|
|
23
24
|
if (options.flags['dry-run']) {
|
|
24
25
|
const plan = await collectPlan(runOptions, spec);
|
|
25
|
-
if (json)
|
|
26
|
-
|
|
26
|
+
if (json) {
|
|
27
|
+
const payload = deploymentPlanToJson(plan);
|
|
28
|
+
if (isDeployable(plan)) emitJson(payload);
|
|
29
|
+
else failurePayload = payload;
|
|
30
|
+
} else renderDeploymentPlan(plan, output);
|
|
27
31
|
exitIfBlocked(plan, output);
|
|
28
32
|
return;
|
|
29
33
|
}
|
|
@@ -35,10 +39,9 @@ import { deploymentPlanToJson, isDeployable, renderDeploymentPlan } from './depl
|
|
|
35
39
|
});
|
|
36
40
|
} catch (error) {
|
|
37
41
|
const failure = normalizeFailure(error, spec.type);
|
|
38
|
-
//
|
|
39
|
-
// printed its plan, so only a real deploy adds the {deployed: false} envelope.
|
|
42
|
+
// Preserve the blocked plan or the existing deployment failure envelope.
|
|
40
43
|
if (json && !options.flags['dry-run']) {
|
|
41
|
-
|
|
44
|
+
failurePayload = {
|
|
42
45
|
application: null,
|
|
43
46
|
deployed: false,
|
|
44
47
|
error: {
|
|
@@ -46,7 +49,10 @@ import { deploymentPlanToJson, isDeployable, renderDeploymentPlan } from './depl
|
|
|
46
49
|
},
|
|
47
50
|
payload: null,
|
|
48
51
|
reason: failure.message
|
|
49
|
-
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (json && failurePayload !== undefined) {
|
|
55
|
+
throw new JsonOutputError(failure.message, failurePayload, failure.exit);
|
|
50
56
|
}
|
|
51
57
|
output.error(failure.message, {
|
|
52
58
|
exit: failure.exit
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/deploy/deployRunner.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {exitCodes, type Output} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {type WorkbenchDeployPayload} from '@sanity/workbench-cli/deploy'\n\nimport {createCollectingReporter, createFailFastReporter} from '../../util/checks.js'\nimport {toStderrOutput} from '../../util/toStderrOutput.js'\nimport {type DeployCheck, type DeployCheckReporter, type DeployTarget} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {\n type DeploymentFile,\n type DeploymentPlan,\n deploymentPlanToJson,\n isDeployable,\n renderDeploymentPlan,\n} from './deploymentPlan.js'\nimport {type DeployAppOptions} from './types.js'\n\nexport interface DeployResult {\n application: object | null\n payload: DeployPayload\n\n action?: DeployTarget['action']\n /** Resolved server-side, so it stays out of the local payload. */\n installationId?: string\n url?: string | null\n}\n\n/** Collected locally, so a dry run reports it too. */\nexport interface DeployPayload extends Partial<WorkbenchDeployPayload> {\n /** The configured `deployment.appId`; `null` when the deploy would mint one. */\n appId: string | null\n isAutoUpdating: boolean\n type: 'coreApp' | 'studio'\n version: string | null\n\n organizationId?: string\n projectId?: string\n}\n\n/**\n * The parts of a deploy that differ between core apps and studios. The shared\n * sequence — mode selection, error handling, the dry-run plan, `--json` — lives\n * in `runDeploy`.\n */\nexport interface DeploySpec {\n /** Files a real deploy would upload, listed only for the dry-run plan. */\n listFiles: (options: DeployAppOptions) => Promise<DeploymentFile[]>\n /** The step sequence; every step reports through `reporter`. */\n run: (options: DeployAppOptions, reporter: DeployCheckReporter) => Promise<DeployResult | void>\n type: 'coreApp' | 'studio'\n}\n\n/**\n * Runs a deploy in the mode the flags select: a real deploy fails fast and\n * mutates, `--dry-run` drives the same `run` sequence read-only and renders a\n * plan, and `--json` emits the same information as machine-readable JSON.\n */\nexport async function runDeploy(options: DeployAppOptions, spec: DeploySpec): Promise<void> {\n const {output} = options\n const json = !!options.flags.json\n const emitJson = (payload: unknown) => output.
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/deployRunner.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {exitCodes, type Output} from '@sanity/cli-core'\nimport {getErrorMessage, JsonOutputError} from '@sanity/cli-core/errors'\nimport {type WorkbenchDeployPayload} from '@sanity/workbench-cli/deploy'\n\nimport {createCollectingReporter, createFailFastReporter} from '../../util/checks.js'\nimport {toStderrOutput} from '../../util/toStderrOutput.js'\nimport {type DeployCheck, type DeployCheckReporter, type DeployTarget} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {\n type DeploymentFile,\n type DeploymentPlan,\n deploymentPlanToJson,\n isDeployable,\n renderDeploymentPlan,\n} from './deploymentPlan.js'\nimport {type DeployAppOptions} from './types.js'\n\nexport interface DeployResult {\n application: object | null\n payload: DeployPayload\n\n action?: DeployTarget['action']\n /** Resolved server-side, so it stays out of the local payload. */\n installationId?: string\n url?: string | null\n}\n\n/** Collected locally, so a dry run reports it too. */\nexport interface DeployPayload extends Partial<WorkbenchDeployPayload> {\n /** The configured `deployment.appId`; `null` when the deploy would mint one. */\n appId: string | null\n isAutoUpdating: boolean\n type: 'coreApp' | 'studio'\n version: string | null\n\n organizationId?: string\n projectId?: string\n}\n\n/**\n * The parts of a deploy that differ between core apps and studios. The shared\n * sequence — mode selection, error handling, the dry-run plan, `--json` — lives\n * in `runDeploy`.\n */\nexport interface DeploySpec {\n /** Files a real deploy would upload, listed only for the dry-run plan. */\n listFiles: (options: DeployAppOptions) => Promise<DeploymentFile[]>\n /** The step sequence; every step reports through `reporter`. */\n run: (options: DeployAppOptions, reporter: DeployCheckReporter) => Promise<DeployResult | void>\n type: 'coreApp' | 'studio'\n}\n\n/**\n * Runs a deploy in the mode the flags select: a real deploy fails fast and\n * mutates, `--dry-run` drives the same `run` sequence read-only and renders a\n * plan, and `--json` emits the same information as machine-readable JSON.\n */\nexport async function runDeploy(options: DeployAppOptions, spec: DeploySpec): Promise<void> {\n const {output} = options\n const json = !!options.flags.json\n const emitJson = (payload: unknown) => output.logJson(payload)\n let failurePayload: unknown\n\n // The JSON payload owns stdout, so the run's progress logs go to stderr; only\n // the final JSON.stringify writes to stdout.\n const runOptions = json ? {...options, output: toStderrOutput(output)} : options\n\n try {\n if (options.flags['dry-run']) {\n const plan = await collectPlan(runOptions, spec)\n if (json) {\n const payload = deploymentPlanToJson(plan)\n if (isDeployable(plan)) emitJson(payload)\n else failurePayload = payload\n } else renderDeploymentPlan(plan, output)\n exitIfBlocked(plan, output)\n return\n }\n\n const result = await spec.run(runOptions, createFailFastReporter(runOptions.output))\n if (json && result) emitJson({deployed: true, reason: null, ...result})\n } catch (error) {\n const failure = normalizeFailure(error, spec.type)\n // Preserve the blocked plan or the existing deployment failure envelope.\n if (json && !options.flags['dry-run']) {\n failurePayload = {\n application: null,\n deployed: false,\n error: {message: failure.message},\n payload: null,\n reason: failure.message,\n }\n }\n if (json && failurePayload !== undefined) {\n throw new JsonOutputError(failure.message, failurePayload, failure.exit)\n }\n output.error(failure.message, {exit: failure.exit})\n }\n}\n\n/** Runs the step sequence read-only and gathers the plan a dry run reports. */\nasync function collectPlan(options: DeployAppOptions, spec: DeploySpec): Promise<DeploymentPlan> {\n const reporter = createCollectingReporter<DeployCheck>()\n const result = await spec.run(options, reporter)\n const plan: DeploymentPlan = {\n checks: reporter.results,\n files: [],\n payload: result?.payload ?? null,\n target:\n reporter.results.find((check) => check.target && check.status !== 'fail')?.target ?? null,\n type: spec.type,\n }\n // A blocked deploy uploads nothing, so only enumerate files for a deployable plan.\n if (isDeployable(plan)) plan.files = await spec.listFiles(options)\n return plan\n}\n\n/** Exits like a real (fail-fast) deploy would, on the first failing check's exit code. */\nfunction exitIfBlocked(plan: DeploymentPlan, output: Output): void {\n if (isDeployable(plan)) return\n const failed = plan.checks.find((check) => check.status === 'fail')\n output.error('Deploy blocked by failing checks.', {exit: failed?.exitCode ?? 1})\n}\n\n/** The one failure diagnosis both the stderr message and the `--json` envelope read. */\nfunction normalizeFailure(\n error: unknown,\n type: 'coreApp' | 'studio',\n): {exit: number; message: string} {\n // Ctrl+C on an interactive prompt isn't a real failure\n if (error instanceof Error && error.name === 'ExitPromptError') {\n return {exit: exitCodes.RUNTIME_ERROR, message: 'Deployment cancelled by user'}\n }\n // A failed check already carries its own message and exit code\n if (error instanceof CLIError) {\n return {exit: error.oclif?.exit ?? 1, message: error.message}\n }\n deployDebug(`Error deploying ${type === 'coreApp' ? 'application' : 'studio'}`, error)\n return {\n exit: exitCodes.RUNTIME_ERROR,\n message: `Error deploying ${type === 'coreApp' ? 'application' : 'studio'}: ${getErrorMessage(error)}`,\n }\n}\n"],"names":["CLIError","exitCodes","getErrorMessage","JsonOutputError","createCollectingReporter","createFailFastReporter","toStderrOutput","deployDebug","deploymentPlanToJson","isDeployable","renderDeploymentPlan","runDeploy","options","spec","output","json","flags","emitJson","payload","logJson","failurePayload","runOptions","plan","collectPlan","exitIfBlocked","result","run","deployed","reason","error","failure","normalizeFailure","type","application","message","undefined","exit","reporter","checks","results","files","target","find","check","status","listFiles","failed","exitCode","Error","name","RUNTIME_ERROR","oclif"],"mappings":"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"}
|