@sanity/cli 7.12.0 → 7.13.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 +88 -0
- package/dist/actions/api/constants.js +13 -0
- package/dist/actions/api/constants.js.map +1 -0
- package/dist/actions/api/distillApiRoutes.js +106 -0
- package/dist/actions/api/distillApiRoutes.js.map +1 -0
- package/dist/actions/api/errors.js +18 -0
- package/dist/actions/api/errors.js.map +1 -0
- package/dist/actions/api/parseFields.js +183 -0
- package/dist/actions/api/parseFields.js.map +1 -0
- package/dist/actions/api/resolveEndpoint.js +159 -0
- package/dist/actions/api/resolveEndpoint.js.map +1 -0
- package/dist/actions/api/types.js +10 -0
- package/dist/actions/api/types.js.map +1 -0
- package/dist/actions/build/buildApp.js +4 -2
- package/dist/actions/build/buildApp.js.map +1 -1
- package/dist/actions/build/buildStudio.js +105 -14
- package/dist/actions/build/buildStudio.js.map +1 -1
- package/dist/actions/build/eventListenerFactory.js +70 -0
- package/dist/actions/build/eventListenerFactory.js.map +1 -0
- package/dist/actions/dev/servers/startStudioDevServer.js +5 -1
- package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
- package/dist/commands/api.js +294 -0
- package/dist/commands/api.js.map +1 -0
- package/dist/commands/backups/disable.js +4 -4
- package/dist/commands/backups/disable.js.map +1 -1
- package/dist/commands/backups/download.js +7 -7
- package/dist/commands/backups/download.js.map +1 -1
- package/dist/commands/backups/enable.js +4 -4
- package/dist/commands/backups/enable.js.map +1 -1
- package/dist/commands/backups/list.js +7 -7
- package/dist/commands/backups/list.js.map +1 -1
- package/dist/commands/codemod.js +5 -5
- package/dist/commands/codemod.js.map +1 -1
- package/dist/commands/cors/add.js +1 -1
- package/dist/commands/cors/add.js.map +1 -1
- package/dist/commands/cors/delete.js +4 -4
- package/dist/commands/cors/delete.js.map +1 -1
- package/dist/commands/cors/list.js +2 -2
- package/dist/commands/cors/list.js.map +1 -1
- package/dist/commands/datasets/alias/create.js +5 -5
- package/dist/commands/datasets/alias/create.js.map +1 -1
- package/dist/commands/datasets/alias/delete.js +2 -2
- package/dist/commands/datasets/alias/delete.js.map +1 -1
- package/dist/commands/datasets/alias/link.js +5 -5
- package/dist/commands/datasets/alias/link.js.map +1 -1
- package/dist/commands/datasets/alias/unlink.js +3 -3
- package/dist/commands/datasets/alias/unlink.js.map +1 -1
- package/dist/commands/datasets/copy.js +7 -7
- package/dist/commands/datasets/copy.js.map +1 -1
- package/dist/commands/datasets/create.js +3 -3
- package/dist/commands/datasets/create.js.map +1 -1
- package/dist/commands/datasets/delete.js +2 -2
- package/dist/commands/datasets/delete.js.map +1 -1
- package/dist/commands/datasets/embeddings/disable.js +3 -3
- package/dist/commands/datasets/embeddings/disable.js.map +1 -1
- package/dist/commands/datasets/embeddings/enable.js +5 -5
- package/dist/commands/datasets/embeddings/enable.js.map +1 -1
- package/dist/commands/datasets/embeddings/status.js +3 -3
- package/dist/commands/datasets/embeddings/status.js.map +1 -1
- package/dist/commands/datasets/export.js +6 -6
- package/dist/commands/datasets/export.js.map +1 -1
- package/dist/commands/datasets/import.js +3 -3
- package/dist/commands/datasets/import.js.map +1 -1
- package/dist/commands/datasets/list.js +2 -2
- package/dist/commands/datasets/list.js.map +1 -1
- package/dist/commands/datasets/visibility/get.js +2 -2
- package/dist/commands/datasets/visibility/get.js.map +1 -1
- package/dist/commands/datasets/visibility/set.js +3 -3
- package/dist/commands/datasets/visibility/set.js.map +1 -1
- package/dist/commands/deploy.js +2 -2
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.js +2 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/docs/read.js +1 -1
- package/dist/commands/docs/read.js.map +1 -1
- package/dist/commands/docs/search.js +3 -3
- package/dist/commands/docs/search.js.map +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/documents/create.js +3 -3
- package/dist/commands/documents/create.js.map +1 -1
- package/dist/commands/documents/delete.js +3 -3
- package/dist/commands/documents/delete.js.map +1 -1
- package/dist/commands/documents/get.js +2 -2
- package/dist/commands/documents/get.js.map +1 -1
- package/dist/commands/documents/query.js +2 -2
- package/dist/commands/documents/query.js.map +1 -1
- package/dist/commands/documents/validate.js +3 -3
- package/dist/commands/documents/validate.js.map +1 -1
- package/dist/commands/graphql/deploy.js +13 -13
- package/dist/commands/graphql/deploy.js.map +1 -1
- package/dist/commands/graphql/list.js +2 -2
- package/dist/commands/graphql/list.js.map +1 -1
- package/dist/commands/graphql/undeploy.js +2 -2
- package/dist/commands/graphql/undeploy.js.map +1 -1
- package/dist/commands/hooks/attempt.js +2 -2
- package/dist/commands/hooks/attempt.js.map +1 -1
- package/dist/commands/hooks/create.js +3 -3
- package/dist/commands/hooks/create.js.map +1 -1
- package/dist/commands/hooks/delete.js +4 -4
- package/dist/commands/hooks/delete.js.map +1 -1
- package/dist/commands/hooks/list.js +2 -2
- package/dist/commands/hooks/list.js.map +1 -1
- package/dist/commands/hooks/logs.js +5 -5
- package/dist/commands/hooks/logs.js.map +1 -1
- package/dist/commands/login.js +2 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +2 -2
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/manifest/extract.js +3 -3
- package/dist/commands/manifest/extract.js.map +1 -1
- package/dist/commands/mcp/configure.js +4 -4
- package/dist/commands/mcp/configure.js.map +1 -1
- package/dist/commands/media/create-aspect.js +3 -3
- package/dist/commands/media/create-aspect.js.map +1 -1
- package/dist/commands/media/delete-aspect.js +1 -1
- package/dist/commands/media/delete-aspect.js.map +1 -1
- package/dist/commands/media/deploy-aspect.js +4 -4
- package/dist/commands/media/deploy-aspect.js.map +1 -1
- package/dist/commands/media/export.js +7 -7
- package/dist/commands/media/export.js.map +1 -1
- package/dist/commands/media/import.js +6 -6
- package/dist/commands/media/import.js.map +1 -1
- package/dist/commands/migrations/create.js +4 -4
- package/dist/commands/migrations/create.js.map +1 -1
- package/dist/commands/migrations/list.js +2 -2
- package/dist/commands/migrations/list.js.map +1 -1
- package/dist/commands/migrations/run.js +14 -14
- package/dist/commands/migrations/run.js.map +1 -1
- package/dist/commands/openapi/get.js +3 -3
- package/dist/commands/openapi/get.js.map +1 -1
- package/dist/commands/openapi/list.js +2 -2
- package/dist/commands/openapi/list.js.map +1 -1
- package/dist/commands/organizations/create.js +5 -5
- package/dist/commands/organizations/create.js.map +1 -1
- package/dist/commands/organizations/delete.js +6 -6
- package/dist/commands/organizations/delete.js.map +1 -1
- package/dist/commands/organizations/get.js +3 -3
- package/dist/commands/organizations/get.js.map +1 -1
- package/dist/commands/organizations/list.js +2 -2
- package/dist/commands/organizations/list.js.map +1 -1
- package/dist/commands/organizations/update.js +6 -6
- package/dist/commands/organizations/update.js.map +1 -1
- package/dist/commands/preview.js +2 -2
- package/dist/commands/preview.js.map +1 -1
- package/dist/commands/projects/create.js +2 -2
- package/dist/commands/projects/create.js.map +1 -1
- package/dist/commands/projects/list.js +2 -2
- package/dist/commands/projects/list.js.map +1 -1
- package/dist/commands/schemas/delete.js +2 -2
- package/dist/commands/schemas/delete.js.map +1 -1
- package/dist/commands/schemas/deploy.js +2 -2
- package/dist/commands/schemas/deploy.js.map +1 -1
- package/dist/commands/schemas/list.js +1 -1
- package/dist/commands/schemas/list.js.map +1 -1
- package/dist/commands/schemas/validate.js +2 -1
- package/dist/commands/schemas/validate.js.map +1 -1
- package/dist/commands/skills/install.js +2 -2
- package/dist/commands/skills/install.js.map +1 -1
- package/dist/commands/telemetry/disable.js +2 -2
- package/dist/commands/telemetry/disable.js.map +1 -1
- package/dist/commands/telemetry/enable.js +2 -2
- package/dist/commands/telemetry/enable.js.map +1 -1
- package/dist/commands/tokens/create.js +2 -2
- package/dist/commands/tokens/create.js.map +1 -1
- package/dist/commands/tokens/delete.js +2 -2
- package/dist/commands/tokens/delete.js.map +1 -1
- package/dist/commands/tokens/list.js +2 -2
- package/dist/commands/tokens/list.js.map +1 -1
- package/dist/commands/users/invite.js +3 -3
- package/dist/commands/users/invite.js.map +1 -1
- package/dist/generated/apiRoutes.js +401 -0
- package/dist/generated/apiRoutes.js.map +1 -0
- package/dist/services/api.js +116 -0
- package/dist/services/api.js.map +1 -0
- package/oclif.manifest.json +433 -252
- package/package.json +5 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/media/deploy-aspect.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {\n type CliConfig,\n exitCodes,\n ProjectRootNotFoundError,\n SanityCommand,\n subdebug,\n} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {isAssetAspect, type SchemaValidationProblem} from '@sanity/types'\n\nimport {getMediaLibraryConfig} from '../../actions/media/getMediaLibraryConfig.js'\nimport {importAspects} from '../../actions/media/importAspects.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {selectMediaLibrary} from '../../prompts/selectMediaLibrary.js'\nimport {deployAspects} from '../../services/mediaLibraries.js'\nimport {NO_MEDIA_LIBRARY_ASPECTS_PATH} from '../../util/errorMessages.js'\nimport {pluralize} from '../../util/pluralize.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst deployAspectDebug = subdebug('media:deploy-aspect')\n\nexport class MediaDeployAspectCommand extends SanityCommand<typeof MediaDeployAspectCommand> {\n static override args = {\n aspectName: Args.string({\n description: 'Name of the aspect to deploy',\n required: false,\n }),\n }\n\n static override description = 'Deploy an aspect'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> someAspect',\n description: 'Deploy the aspect named \"someAspect\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --all',\n description: 'Deploy all aspects',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to deploy media aspect to',\n semantics: 'override',\n }),\n all: Flags.boolean({\n description: 'Deploy all aspects',\n required: false,\n }),\n 'media-library-id': Flags.string({\n description: 'The id of the target media library',\n required: false,\n }),\n }\n\n public async run(): Promise<void> {\n const {aspectName} = this.args\n const {all, 'media-library-id': mediaLibraryIdFlag} = this.flags\n\n // Validation: must provide either aspect name or --all flag\n if (!all && !aspectName) {\n this.error(\n 'Aspect name is required. Pass it as the `<aspectName>` argument, or pass `--all`.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n // Validation: cannot provide both aspect name and --all flag\n if (all && aspectName) {\n this.error('Specify either the `<aspectName>` argument or `--all`, but not both.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n let cliConfig: CliConfig\n try {\n cliConfig = await this.getCliConfig()\n } catch (err) {\n if (err instanceof ProjectRootNotFoundError) {\n this.error(\n 'This command must be run from within a Sanity project directory (requires media library configuration)',\n {exit: 1},\n )\n }\n throw err\n }\n const mediaLibrary = getMediaLibraryConfig(cliConfig)\n\n if (!mediaLibrary?.aspectsPath) {\n this.error(NO_MEDIA_LIBRARY_ASPECTS_PATH, {exit: 1})\n }\n\n const projectId = await this.getProjectId({fallback: () => promptForProject({})})\n\n if (!mediaLibraryIdFlag && this.isUnattended()) {\n this.error('Media library ID is required. Pass it with `--media-library-id <id>`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n try {\n // Determine target media library\n let mediaLibraryId = mediaLibraryIdFlag\n if (!mediaLibraryId) {\n mediaLibraryId = await selectMediaLibrary(projectId)\n }\n\n // Import and validate aspects\n const spin = spinner('Loading aspect definitions').start()\n const result = await importAspects({\n aspectsPath: mediaLibrary.aspectsPath,\n filterAspects: (aspect) => {\n if (all) {\n return true\n }\n\n if (typeof aspect === 'object' && aspect !== null && '_id' in aspect) {\n return aspect._id === aspectName\n }\n\n return false\n },\n })\n spin.stop()\n\n // Handle invalid aspects\n if (result.invalid.length > 0) {\n this.logToStderr('')\n this.warn(\n styleText(\n 'bold',\n `Skipped ${result.invalid.length} invalid ${pluralize('aspect', result.invalid.length)}`,\n ),\n )\n this.logToStderr(this.formatAspectList(result.invalid))\n }\n\n // Check if we found the requested aspect (when not using --all)\n if (!all && result.valid.length === 0 && result.invalid.length === 0) {\n this.log()\n this.error(`Could not find aspect: ${styleText('bold', aspectName ?? '')}`, {exit: 1})\n }\n\n // Deploy valid aspects\n if (result.valid.length === 0) {\n this.logToStderr('')\n this.warn('No valid aspects to deploy')\n return\n }\n\n const deploySpin = spinner(\n `Deploying ${result.valid.length} ${pluralize('aspect', result.valid.length)}`,\n ).start()\n\n const deployResponse = await deployAspects({\n aspects: result.valid.map((a) => a.aspect),\n mediaLibraryId,\n })\n\n deploySpin.succeed()\n\n // Display success message\n this.log()\n this.log(\n `${styleText('green', '✓')} ${styleText('bold', `Deployed ${result.valid.length} ${pluralize('aspect', result.valid.length)}`)}`,\n )\n this.log(this.formatAspectList(result.valid))\n\n deployAspectDebug('Deployed aspects', {\n count: result.valid.length,\n results: deployResponse.results,\n })\n } catch (error) {\n const err = error as Error\n deployAspectDebug('Failed to deploy aspects', {\n all,\n aspectName,\n error: err,\n mediaLibraryId: mediaLibraryIdFlag,\n })\n this.error(\n styleText('bold', 'Failed to deploy aspects') + `\\n\\n${styleText('red', err.message)}`,\n {\n exit: 1,\n },\n )\n }\n }\n\n /**\n * Format a list of aspects for display\n */\n private formatAspectList(\n aspects: Array<{\n aspect: unknown\n filename: string\n validationErrors?: SchemaValidationProblem[][]\n }>,\n ): string {\n return aspects\n .map(({aspect, filename, validationErrors = []}) => {\n const label = isAssetAspect(aspect) ? aspect._id : 'Unnamed aspect'\n\n // Flatten the nested validation errors and extract messages\n const simplifiedErrors = validationErrors.flatMap((group) =>\n group.map(({message}) => message),\n )\n\n const errorLabel =\n simplifiedErrors.length > 0 ? ` ${styleText('bgRed', simplifiedErrors[0])}` : ''\n\n const remainingErrorsCount = simplifiedErrors.length - 1\n const remainingErrorsLabel =\n remainingErrorsCount > 0\n ? styleText(\n 'italic',\n ` and ${remainingErrorsCount} other ${pluralize('error', remainingErrorsCount)}`,\n )\n : ''\n\n return ` - ${label} ${styleText('dim', filename)}${errorLabel}${remainingErrorsLabel}`\n })\n .join('\\n')\n }\n}\n"],"names":["styleText","Args","Flags","exitCodes","ProjectRootNotFoundError","SanityCommand","subdebug","spinner","isAssetAspect","getMediaLibraryConfig","importAspects","promptForProject","selectMediaLibrary","deployAspects","NO_MEDIA_LIBRARY_ASPECTS_PATH","pluralize","getProjectIdFlag","deployAspectDebug","MediaDeployAspectCommand","args","aspectName","string","description","required","examples","command","flags","semantics","all","boolean","run","mediaLibraryIdFlag","error","exit","USAGE_ERROR","cliConfig","getCliConfig","err","mediaLibrary","aspectsPath","projectId","getProjectId","fallback","isUnattended","mediaLibraryId","spin","start","result","filterAspects","aspect","_id","stop","invalid","length","logToStderr","warn","formatAspectList","valid","log","deploySpin","deployResponse","aspects","map","a","succeed","count","results","message","filename","validationErrors","label","simplifiedErrors","flatMap","group","errorLabel","remainingErrorsCount","remainingErrorsLabel","join"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/media/deploy-aspect.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {\n type CliConfig,\n exitCodes,\n ProjectRootNotFoundError,\n SanityCommand,\n subdebug,\n} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {isAssetAspect, type SchemaValidationProblem} from '@sanity/types'\n\nimport {getMediaLibraryConfig} from '../../actions/media/getMediaLibraryConfig.js'\nimport {importAspects} from '../../actions/media/importAspects.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {selectMediaLibrary} from '../../prompts/selectMediaLibrary.js'\nimport {deployAspects} from '../../services/mediaLibraries.js'\nimport {NO_MEDIA_LIBRARY_ASPECTS_PATH} from '../../util/errorMessages.js'\nimport {pluralize} from '../../util/pluralize.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst deployAspectDebug = subdebug('media:deploy-aspect')\n\nexport class MediaDeployAspectCommand extends SanityCommand<typeof MediaDeployAspectCommand> {\n static override args = {\n aspectName: Args.string({\n description: 'Name of the aspect to deploy',\n required: false,\n }),\n }\n\n static override description = 'Deploy an aspect'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> someAspect',\n description: 'Deploy the aspect named \"someAspect\"',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --all',\n description: 'Deploy all aspects',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to deploy media aspect to',\n semantics: 'override',\n }),\n all: Flags.boolean({\n description: 'Deploy all aspects',\n required: false,\n }),\n 'media-library-id': Flags.string({\n description: 'The id of the target media library',\n required: false,\n }),\n }\n\n public async run(): Promise<void> {\n const {aspectName} = this.args\n const {all, 'media-library-id': mediaLibraryIdFlag} = this.flags\n\n // Validation: must provide either aspect name or --all flag\n if (!all && !aspectName) {\n this.error(\n 'Aspect name is required. Pass it as the `<aspectName>` argument, or pass `--all`.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n // Validation: cannot provide both aspect name and --all flag\n if (all && aspectName) {\n this.error('Specify either the `<aspectName>` argument or `--all`, but not both.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n let cliConfig: CliConfig\n try {\n cliConfig = await this.getCliConfig()\n } catch (err) {\n if (err instanceof ProjectRootNotFoundError) {\n this.error(\n 'This command must be run from within a Sanity project directory (requires media library configuration)',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n throw err\n }\n const mediaLibrary = getMediaLibraryConfig(cliConfig)\n\n if (!mediaLibrary?.aspectsPath) {\n this.error(NO_MEDIA_LIBRARY_ASPECTS_PATH, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n const projectId = await this.getProjectId({fallback: () => promptForProject({})})\n\n if (!mediaLibraryIdFlag && this.isUnattended()) {\n this.error('Media library ID is required. Pass it with `--media-library-id <id>`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n try {\n // Determine target media library\n let mediaLibraryId = mediaLibraryIdFlag\n if (!mediaLibraryId) {\n mediaLibraryId = await selectMediaLibrary(projectId)\n }\n\n // Import and validate aspects\n const spin = spinner('Loading aspect definitions').start()\n const result = await importAspects({\n aspectsPath: mediaLibrary.aspectsPath,\n filterAspects: (aspect) => {\n if (all) {\n return true\n }\n\n if (typeof aspect === 'object' && aspect !== null && '_id' in aspect) {\n return aspect._id === aspectName\n }\n\n return false\n },\n })\n spin.stop()\n\n // Handle invalid aspects\n if (result.invalid.length > 0) {\n this.logToStderr('')\n this.warn(\n styleText(\n 'bold',\n `Skipped ${result.invalid.length} invalid ${pluralize('aspect', result.invalid.length)}`,\n ),\n )\n this.logToStderr(this.formatAspectList(result.invalid))\n }\n\n // Check if we found the requested aspect (when not using --all)\n if (!all && result.valid.length === 0 && result.invalid.length === 0) {\n this.log()\n this.error(`Could not find aspect: ${styleText('bold', aspectName ?? '')}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // Deploy valid aspects\n if (result.valid.length === 0) {\n this.logToStderr('')\n this.warn('No valid aspects to deploy')\n return\n }\n\n const deploySpin = spinner(\n `Deploying ${result.valid.length} ${pluralize('aspect', result.valid.length)}`,\n ).start()\n\n const deployResponse = await deployAspects({\n aspects: result.valid.map((a) => a.aspect),\n mediaLibraryId,\n })\n\n deploySpin.succeed()\n\n // Display success message\n this.log()\n this.log(\n `${styleText('green', '✓')} ${styleText('bold', `Deployed ${result.valid.length} ${pluralize('aspect', result.valid.length)}`)}`,\n )\n this.log(this.formatAspectList(result.valid))\n\n deployAspectDebug('Deployed aspects', {\n count: result.valid.length,\n results: deployResponse.results,\n })\n } catch (error) {\n const err = error as Error\n deployAspectDebug('Failed to deploy aspects', {\n all,\n aspectName,\n error: err,\n mediaLibraryId: mediaLibraryIdFlag,\n })\n this.error(\n styleText('bold', 'Failed to deploy aspects') + `\\n\\n${styleText('red', err.message)}`,\n {\n exit: exitCodes.RUNTIME_ERROR,\n },\n )\n }\n }\n\n /**\n * Format a list of aspects for display\n */\n private formatAspectList(\n aspects: Array<{\n aspect: unknown\n filename: string\n validationErrors?: SchemaValidationProblem[][]\n }>,\n ): string {\n return aspects\n .map(({aspect, filename, validationErrors = []}) => {\n const label = isAssetAspect(aspect) ? aspect._id : 'Unnamed aspect'\n\n // Flatten the nested validation errors and extract messages\n const simplifiedErrors = validationErrors.flatMap((group) =>\n group.map(({message}) => message),\n )\n\n const errorLabel =\n simplifiedErrors.length > 0 ? ` ${styleText('bgRed', simplifiedErrors[0])}` : ''\n\n const remainingErrorsCount = simplifiedErrors.length - 1\n const remainingErrorsLabel =\n remainingErrorsCount > 0\n ? styleText(\n 'italic',\n ` and ${remainingErrorsCount} other ${pluralize('error', remainingErrorsCount)}`,\n )\n : ''\n\n return ` - ${label} ${styleText('dim', filename)}${errorLabel}${remainingErrorsLabel}`\n })\n .join('\\n')\n }\n}\n"],"names":["styleText","Args","Flags","exitCodes","ProjectRootNotFoundError","SanityCommand","subdebug","spinner","isAssetAspect","getMediaLibraryConfig","importAspects","promptForProject","selectMediaLibrary","deployAspects","NO_MEDIA_LIBRARY_ASPECTS_PATH","pluralize","getProjectIdFlag","deployAspectDebug","MediaDeployAspectCommand","args","aspectName","string","description","required","examples","command","flags","semantics","all","boolean","run","mediaLibraryIdFlag","error","exit","USAGE_ERROR","cliConfig","getCliConfig","err","RUNTIME_ERROR","mediaLibrary","aspectsPath","projectId","getProjectId","fallback","isUnattended","mediaLibraryId","spin","start","result","filterAspects","aspect","_id","stop","invalid","length","logToStderr","warn","formatAspectList","valid","log","deploySpin","deployResponse","aspects","map","a","succeed","count","results","message","filename","validationErrors","label","simplifiedErrors","flatMap","group","errorLabel","remainingErrorsCount","remainingErrorsLabel","join"],"mappings":"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"}
|
|
@@ -71,12 +71,12 @@ export class MediaExportCommand extends SanityCommand {
|
|
|
71
71
|
} catch (error) {
|
|
72
72
|
exportDebug('Error listing media libraries', error);
|
|
73
73
|
this.error(`Failed to list media libraries:\n${error instanceof Error ? error.message : error}`, {
|
|
74
|
-
exit:
|
|
74
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
if (mediaLibraries.length === 0) {
|
|
78
78
|
this.error('No active media libraries found in this project', {
|
|
79
|
-
exit:
|
|
79
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
let mediaLibraryId = flags['media-library-id'];
|
|
@@ -93,13 +93,13 @@ export class MediaExportCommand extends SanityCommand {
|
|
|
93
93
|
} catch (error) {
|
|
94
94
|
exportDebug('Error selecting media library', error);
|
|
95
95
|
this.error(`Failed to select media library:\n${error instanceof Error ? error.message : error}`, {
|
|
96
|
-
exit:
|
|
96
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
if (!mediaLibraries.some((library)=>library.id === mediaLibraryId)) {
|
|
101
101
|
this.error(`Media library with id "${mediaLibraryId}" not found`, {
|
|
102
|
-
exit:
|
|
102
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
105
|
this.log(boxen(`Exporting from:
|
|
@@ -117,7 +117,7 @@ mediaLibraryId: ${mediaLibraryId.padEnd(37)}`, {
|
|
|
117
117
|
const outputPath = await this.getOutputPath(destinationPath, mediaLibraryId, flags);
|
|
118
118
|
if (!outputPath) {
|
|
119
119
|
this.error('Cancelled', {
|
|
120
|
-
exit:
|
|
120
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
123
|
const { fail, onProgress, succeed } = this.createProgressHandler();
|
|
@@ -139,7 +139,7 @@ mediaLibraryId: ${mediaLibraryId.padEnd(37)}`, {
|
|
|
139
139
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
140
140
|
exportDebug('Export failed', err);
|
|
141
141
|
this.error(`Export failed: ${err.message}`, {
|
|
142
|
-
exit:
|
|
142
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
145
|
}
|
|
@@ -183,7 +183,7 @@ mediaLibraryId: ${mediaLibraryId.padEnd(37)}`, {
|
|
|
183
183
|
} catch (error) {
|
|
184
184
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
185
185
|
this.error(`Failed to create directory "${createPath}": ${err.message}`, {
|
|
186
|
-
exit:
|
|
186
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
187
187
|
});
|
|
188
188
|
}
|
|
189
189
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/media/export.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport {type Writable} from 'node:stream'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, getProjectCliClient, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {boxen, input, spinner} from '@sanity/cli-core/ux'\nimport {exportDataset, type ExportOptions, type ExportProgress} from '@sanity/export'\nimport prettyMs from 'pretty-ms'\n\nimport {promptForMediaLibrary} from '../../prompts/promptForMediaLibrary.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getMediaLibraries} from '../../services/mediaLibraries.js'\nimport {absolutify} from '../../util/absolutify.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst noop = () => null\nconst exportDebug = subdebug('media:export')\n\nexport class MediaExportCommand extends SanityCommand<typeof MediaExportCommand> {\n static override args = {\n destination: Args.string({\n description: 'Output destination file path',\n }),\n }\n\n static override description = 'Export file and image assets from a media library (excludes video)'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Export media library interactively',\n },\n {\n command: '<%= config.bin %> <%= command.id %> output.tar.gz',\n description: 'Export media library to output.tar.gz',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --media-library-id my-library-id',\n description: 'Export specific media library',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to export media from',\n semantics: 'override',\n }),\n 'asset-concurrency': Flags.integer({\n default: 8,\n description: 'Concurrent number of asset downloads',\n }),\n 'media-library-id': Flags.string({\n description: 'The id of the target media library',\n }),\n 'no-compress': Flags.boolean({\n default: false,\n description: 'Skips compressing tarball entries (still generates a gzip file)',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Overwrite any file with the same name',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(MediaExportCommand)\n const {destination: targetDestination} = args\n\n const projectId = await this.getProjectId({fallback: () => promptForProject({})})\n\n const projectClient = await getProjectCliClient({\n apiVersion: 'v2025-02-19',\n projectId,\n requireUser: true,\n })\n\n let mediaLibraries\n try {\n mediaLibraries = await getMediaLibraries(projectId)\n } catch (error) {\n exportDebug('Error listing media libraries', error)\n this.error(\n `Failed to list media libraries:\\n${error instanceof Error ? error.message : error}`,\n {\n exit: 1,\n },\n )\n }\n\n if (mediaLibraries.length === 0) {\n this.error('No active media libraries found in this project', {exit: 1})\n }\n\n let mediaLibraryId = flags['media-library-id']\n if (!mediaLibraryId) {\n if (this.isUnattended()) {\n this.error('Media library ID is required. Pass it with `--media-library-id <id>`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n try {\n mediaLibraryId = await promptForMediaLibrary({mediaLibraries})\n } catch (error) {\n exportDebug('Error selecting media library', error)\n this.error(\n `Failed to select media library:\\n${error instanceof Error ? error.message : error}`,\n {\n exit: 1,\n },\n )\n }\n }\n\n if (!mediaLibraries.some((library) => library.id === mediaLibraryId)) {\n this.error(`Media library with id \"${mediaLibraryId}\" not found`, {exit: 1})\n }\n\n this.log(\n boxen(\n `Exporting from:\nprojectId: ${projectId.padEnd(44)}\nmediaLibraryId: ${mediaLibraryId.padEnd(37)}`,\n {\n borderColor: 'yellow',\n borderStyle: 'round',\n },\n ),\n )\n\n let destinationPath = targetDestination\n if (!destinationPath) {\n destinationPath = this.isUnattended()\n ? path.join(process.cwd(), `${mediaLibraryId}-export.tar.gz`)\n : await this.promptForDestination({mediaLibraryId})\n }\n\n const outputPath = await this.getOutputPath(destinationPath, mediaLibraryId, flags)\n if (!outputPath) {\n this.error('Cancelled', {exit: 1})\n }\n\n const {fail, onProgress, succeed} = this.createProgressHandler()\n const exportOptions: ExportOptions = {\n assetConcurrency: flags['asset-concurrency'],\n client: projectClient,\n compress: !flags['no-compress'],\n mediaLibraryId,\n onProgress,\n outputPath,\n }\n\n const start = Date.now()\n try {\n await exportDataset(exportOptions)\n succeed()\n this.log(`Export finished (${prettyMs(Date.now() - start)})`)\n } catch (error) {\n fail()\n const err = error instanceof Error ? error : new Error(String(error))\n exportDebug('Export failed', err)\n this.error(`Export failed: ${err.message}`, {exit: 1})\n }\n }\n\n private createProgressHandler() {\n let currentSpinner: ReturnType<typeof spinner> | null = null\n let currentStep = ''\n\n const onProgress = (progress: ExportProgress) => {\n if (progress.step !== currentStep) {\n succeed()\n\n currentStep = progress.step\n currentSpinner = spinner(progress.step).start()\n } else if (progress.step === currentStep && progress.update && currentSpinner) {\n currentSpinner.text = `${progress.step} (${progress.current}/${progress.total})`\n }\n }\n\n const succeed = () => {\n currentSpinner?.succeed()\n }\n\n const fail = () => {\n currentSpinner?.fail()\n }\n\n return {fail, onProgress, succeed}\n }\n\n private async getOutputPath(\n destination: string,\n mediaLibraryId: string,\n flags: {overwrite?: boolean},\n ): Promise<string | Writable> {\n if (destination === '-') {\n return process.stdout\n }\n\n const dstPath = path.isAbsolute(destination)\n ? destination\n : path.resolve(process.cwd(), destination)\n\n const dstStats = await fs.stat(dstPath).catch(noop)\n const looksLikeFile = dstStats ? dstStats.isFile() : path.basename(dstPath).includes('.')\n\n if (!dstStats) {\n const createPath = looksLikeFile ? path.dirname(dstPath) : dstPath\n try {\n await fs.mkdir(createPath, {recursive: true})\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n this.error(`Failed to create directory \"${createPath}\": ${err.message}`, {\n exit: 1,\n })\n }\n }\n\n const finalPath = looksLikeFile\n ? dstPath\n : path.join(dstPath, `${mediaLibraryId}-export.tar.gz`)\n const finalPathStats = await fs.stat(finalPath).catch(noop)\n\n if (!flags.overwrite && finalPathStats && finalPathStats.isFile()) {\n this.error(`File \"${finalPath}\" already exists. Pass \\`--overwrite\\` to replace it.`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n return finalPath\n }\n\n private promptForDestination(options: {\n mediaLibraryId: string\n workDir?: string\n }): Promise<string> {\n const {mediaLibraryId, workDir = process.cwd()} = options\n\n const defaultPath = path.join(workDir, `${mediaLibraryId}-export.tar.gz`)\n\n return input({\n default: defaultPath,\n message: 'Output path:',\n transformer: (value: string) => absolutify(value.trim()),\n validate: (value: string) => {\n const trimmed = value.trim()\n if (!trimmed) {\n return 'Please provide a valid output path'\n }\n return true\n },\n })\n }\n}\n"],"names":["fs","path","Args","Flags","exitCodes","getProjectCliClient","SanityCommand","subdebug","boxen","input","spinner","exportDataset","prettyMs","promptForMediaLibrary","promptForProject","getMediaLibraries","absolutify","getProjectIdFlag","noop","exportDebug","MediaExportCommand","args","destination","string","description","examples","command","flags","semantics","integer","default","boolean","overwrite","run","parse","targetDestination","projectId","getProjectId","fallback","projectClient","apiVersion","requireUser","mediaLibraries","error","Error","message","exit","length","mediaLibraryId","isUnattended","USAGE_ERROR","some","library","id","log","padEnd","borderColor","borderStyle","destinationPath","join","process","cwd","promptForDestination","outputPath","getOutputPath","fail","onProgress","succeed","createProgressHandler","exportOptions","assetConcurrency","client","compress","start","Date","now","err","String","currentSpinner","currentStep","progress","step","update","text","current","total","stdout","dstPath","isAbsolute","resolve","dstStats","stat","catch","looksLikeFile","isFile","basename","includes","createPath","dirname","mkdir","recursive","finalPath","finalPathStats","options","workDir","defaultPath","transformer","value","trim","validate","trimmed"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/media/export.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport {type Writable} from 'node:stream'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, getProjectCliClient, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {boxen, input, spinner} from '@sanity/cli-core/ux'\nimport {exportDataset, type ExportOptions, type ExportProgress} from '@sanity/export'\nimport prettyMs from 'pretty-ms'\n\nimport {promptForMediaLibrary} from '../../prompts/promptForMediaLibrary.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getMediaLibraries} from '../../services/mediaLibraries.js'\nimport {absolutify} from '../../util/absolutify.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst noop = () => null\nconst exportDebug = subdebug('media:export')\n\nexport class MediaExportCommand extends SanityCommand<typeof MediaExportCommand> {\n static override args = {\n destination: Args.string({\n description: 'Output destination file path',\n }),\n }\n\n static override description = 'Export file and image assets from a media library (excludes video)'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Export media library interactively',\n },\n {\n command: '<%= config.bin %> <%= command.id %> output.tar.gz',\n description: 'Export media library to output.tar.gz',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --media-library-id my-library-id',\n description: 'Export specific media library',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to export media from',\n semantics: 'override',\n }),\n 'asset-concurrency': Flags.integer({\n default: 8,\n description: 'Concurrent number of asset downloads',\n }),\n 'media-library-id': Flags.string({\n description: 'The id of the target media library',\n }),\n 'no-compress': Flags.boolean({\n default: false,\n description: 'Skips compressing tarball entries (still generates a gzip file)',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Overwrite any file with the same name',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(MediaExportCommand)\n const {destination: targetDestination} = args\n\n const projectId = await this.getProjectId({fallback: () => promptForProject({})})\n\n const projectClient = await getProjectCliClient({\n apiVersion: 'v2025-02-19',\n projectId,\n requireUser: true,\n })\n\n let mediaLibraries\n try {\n mediaLibraries = await getMediaLibraries(projectId)\n } catch (error) {\n exportDebug('Error listing media libraries', error)\n this.error(\n `Failed to list media libraries:\\n${error instanceof Error ? error.message : error}`,\n {\n exit: exitCodes.RUNTIME_ERROR,\n },\n )\n }\n\n if (mediaLibraries.length === 0) {\n this.error('No active media libraries found in this project', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n let mediaLibraryId = flags['media-library-id']\n if (!mediaLibraryId) {\n if (this.isUnattended()) {\n this.error('Media library ID is required. Pass it with `--media-library-id <id>`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n try {\n mediaLibraryId = await promptForMediaLibrary({mediaLibraries})\n } catch (error) {\n exportDebug('Error selecting media library', error)\n this.error(\n `Failed to select media library:\\n${error instanceof Error ? error.message : error}`,\n {\n exit: exitCodes.RUNTIME_ERROR,\n },\n )\n }\n }\n\n if (!mediaLibraries.some((library) => library.id === mediaLibraryId)) {\n this.error(`Media library with id \"${mediaLibraryId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n this.log(\n boxen(\n `Exporting from:\nprojectId: ${projectId.padEnd(44)}\nmediaLibraryId: ${mediaLibraryId.padEnd(37)}`,\n {\n borderColor: 'yellow',\n borderStyle: 'round',\n },\n ),\n )\n\n let destinationPath = targetDestination\n if (!destinationPath) {\n destinationPath = this.isUnattended()\n ? path.join(process.cwd(), `${mediaLibraryId}-export.tar.gz`)\n : await this.promptForDestination({mediaLibraryId})\n }\n\n const outputPath = await this.getOutputPath(destinationPath, mediaLibraryId, flags)\n if (!outputPath) {\n this.error('Cancelled', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n const {fail, onProgress, succeed} = this.createProgressHandler()\n const exportOptions: ExportOptions = {\n assetConcurrency: flags['asset-concurrency'],\n client: projectClient,\n compress: !flags['no-compress'],\n mediaLibraryId,\n onProgress,\n outputPath,\n }\n\n const start = Date.now()\n try {\n await exportDataset(exportOptions)\n succeed()\n this.log(`Export finished (${prettyMs(Date.now() - start)})`)\n } catch (error) {\n fail()\n const err = error instanceof Error ? error : new Error(String(error))\n exportDebug('Export failed', err)\n this.error(`Export failed: ${err.message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n\n private createProgressHandler() {\n let currentSpinner: ReturnType<typeof spinner> | null = null\n let currentStep = ''\n\n const onProgress = (progress: ExportProgress) => {\n if (progress.step !== currentStep) {\n succeed()\n\n currentStep = progress.step\n currentSpinner = spinner(progress.step).start()\n } else if (progress.step === currentStep && progress.update && currentSpinner) {\n currentSpinner.text = `${progress.step} (${progress.current}/${progress.total})`\n }\n }\n\n const succeed = () => {\n currentSpinner?.succeed()\n }\n\n const fail = () => {\n currentSpinner?.fail()\n }\n\n return {fail, onProgress, succeed}\n }\n\n private async getOutputPath(\n destination: string,\n mediaLibraryId: string,\n flags: {overwrite?: boolean},\n ): Promise<string | Writable> {\n if (destination === '-') {\n return process.stdout\n }\n\n const dstPath = path.isAbsolute(destination)\n ? destination\n : path.resolve(process.cwd(), destination)\n\n const dstStats = await fs.stat(dstPath).catch(noop)\n const looksLikeFile = dstStats ? dstStats.isFile() : path.basename(dstPath).includes('.')\n\n if (!dstStats) {\n const createPath = looksLikeFile ? path.dirname(dstPath) : dstPath\n try {\n await fs.mkdir(createPath, {recursive: true})\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error))\n this.error(`Failed to create directory \"${createPath}\": ${err.message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n const finalPath = looksLikeFile\n ? dstPath\n : path.join(dstPath, `${mediaLibraryId}-export.tar.gz`)\n const finalPathStats = await fs.stat(finalPath).catch(noop)\n\n if (!flags.overwrite && finalPathStats && finalPathStats.isFile()) {\n this.error(`File \"${finalPath}\" already exists. Pass \\`--overwrite\\` to replace it.`, {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n return finalPath\n }\n\n private promptForDestination(options: {\n mediaLibraryId: string\n workDir?: string\n }): Promise<string> {\n const {mediaLibraryId, workDir = process.cwd()} = options\n\n const defaultPath = path.join(workDir, `${mediaLibraryId}-export.tar.gz`)\n\n return input({\n default: defaultPath,\n message: 'Output path:',\n transformer: (value: string) => absolutify(value.trim()),\n validate: (value: string) => {\n const trimmed = value.trim()\n if (!trimmed) {\n return 'Please provide a valid output path'\n }\n return true\n },\n })\n }\n}\n"],"names":["fs","path","Args","Flags","exitCodes","getProjectCliClient","SanityCommand","subdebug","boxen","input","spinner","exportDataset","prettyMs","promptForMediaLibrary","promptForProject","getMediaLibraries","absolutify","getProjectIdFlag","noop","exportDebug","MediaExportCommand","args","destination","string","description","examples","command","flags","semantics","integer","default","boolean","overwrite","run","parse","targetDestination","projectId","getProjectId","fallback","projectClient","apiVersion","requireUser","mediaLibraries","error","Error","message","exit","RUNTIME_ERROR","length","mediaLibraryId","isUnattended","USAGE_ERROR","some","library","id","log","padEnd","borderColor","borderStyle","destinationPath","join","process","cwd","promptForDestination","outputPath","getOutputPath","fail","onProgress","succeed","createProgressHandler","exportOptions","assetConcurrency","client","compress","start","Date","now","err","String","currentSpinner","currentStep","progress","step","update","text","current","total","stdout","dstPath","isAbsolute","resolve","dstStats","stat","catch","looksLikeFile","isFile","basename","includes","createPath","dirname","mkdir","recursive","finalPath","finalPathStats","options","workDir","defaultPath","transformer","value","trim","validate","trimmed"],"mappings":"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"}
|
|
@@ -58,12 +58,12 @@ export class MediaImportCommand extends SanityCommand {
|
|
|
58
58
|
} catch (error) {
|
|
59
59
|
importMediaDebug('Error listing media libraries', error);
|
|
60
60
|
this.error(`Failed to list media libraries:\n${error instanceof Error ? error.message : error}`, {
|
|
61
|
-
exit:
|
|
61
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
if (mediaLibraries.length === 0) {
|
|
65
65
|
this.error('No active media libraries found in this project', {
|
|
66
|
-
exit:
|
|
66
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
69
|
let mediaLibraryId = flags['media-library-id'];
|
|
@@ -80,13 +80,13 @@ export class MediaImportCommand extends SanityCommand {
|
|
|
80
80
|
} catch (error) {
|
|
81
81
|
importMediaDebug('Error selecting media library', error);
|
|
82
82
|
this.error(`Failed to select media library:\n${error instanceof Error ? error.message : error}`, {
|
|
83
|
-
exit:
|
|
83
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
if (!mediaLibraries.some((library)=>library.id === mediaLibraryId)) {
|
|
88
88
|
this.error(`Media library with id "${mediaLibraryId}" not found`, {
|
|
89
|
-
exit:
|
|
89
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
const projectClient = await getProjectCliClient({
|
|
@@ -138,11 +138,11 @@ export class MediaImportCommand extends SanityCommand {
|
|
|
138
138
|
process.once('SIGINT', ()=>{
|
|
139
139
|
subscription.unsubscribe();
|
|
140
140
|
spin.fail('Import interrupted.');
|
|
141
|
-
process.exit(
|
|
141
|
+
process.exit(exitCodes.SIGINT);
|
|
142
142
|
});
|
|
143
143
|
}).catch((error)=>{
|
|
144
144
|
this.error(styleText('red', error.message), {
|
|
145
|
-
exit:
|
|
145
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
146
146
|
});
|
|
147
147
|
});
|
|
148
148
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/media/import.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, getProjectCliClient, SanityCommand} from '@sanity/cli-core'\nimport {boxen, spinner} from '@sanity/cli-core/ux'\nimport {SanityClient} from '@sanity/client'\nimport {type OperatorFunction, pipe, scan, tap} from 'rxjs'\n\nimport {importer, type State} from '../../actions/media/importMedia.js'\nimport {importMediaDebug} from '../../actions/media/importMediaDebug.js'\nimport {promptForMediaLibrary} from '../../prompts/promptForMediaLibrary.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getMediaLibraries} from '../../services/mediaLibraries.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nexport class MediaImportCommand extends SanityCommand<typeof MediaImportCommand> {\n static override args = {\n source: Args.string({\n description: 'Image file or folder to import from',\n required: true,\n }),\n }\n\n static override description = 'Import a set of assets to the target media library.'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> products',\n description: 'Import all assets from the \"products\" directory',\n },\n {\n command: '<%= config.bin %> <%= command.id %> gallery.tar.gz',\n description: 'Import all assets from \"gallery\" archive',\n },\n {\n command: '<%= config.bin %> <%= command.id %> products --replace-aspects',\n description: 'Import all assets from the \"products\" directory and replace aspects',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to import media to',\n semantics: 'override',\n }),\n 'media-library-id': Flags.string({\n description: 'The id of the target media library',\n }),\n 'replace-aspects': Flags.boolean({\n description:\n 'Replace existing aspect data. All versions will be replaced (e.g. published and draft aspect data)',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(MediaImportCommand)\n const {source} = args\n const replaceAspects = flags['replace-aspects']\n\n const projectId = await this.getProjectId({fallback: () => promptForProject({})})\n\n const cliConfig = await this.tryGetCliConfig()\n const dataset = cliConfig.api?.dataset\n\n let mediaLibraries\n try {\n mediaLibraries = await getMediaLibraries(projectId)\n } catch (error) {\n importMediaDebug('Error listing media libraries', error)\n this.error(\n `Failed to list media libraries:\\n${error instanceof Error ? error.message : error}`,\n {\n exit: 1,\n },\n )\n }\n\n if (mediaLibraries.length === 0) {\n this.error('No active media libraries found in this project', {exit: 1})\n }\n\n let mediaLibraryId = flags['media-library-id']\n if (!mediaLibraryId) {\n if (this.isUnattended()) {\n this.error('Media library ID is required. Pass it with `--media-library-id <id>`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n try {\n mediaLibraryId = await promptForMediaLibrary({mediaLibraries})\n } catch (error) {\n importMediaDebug('Error selecting media library', error)\n this.error(\n `Failed to select media library:\\n${error instanceof Error ? error.message : error}`,\n {\n exit: 1,\n },\n )\n }\n }\n\n if (!mediaLibraries.some((library) => library.id === mediaLibraryId)) {\n this.error(`Media library with id \"${mediaLibraryId}\" not found`, {exit: 1})\n }\n\n const projectClient = await getProjectCliClient({\n apiVersion: 'v2025-02-19',\n dataset,\n perspective: 'drafts',\n projectId,\n requestTagPrefix: 'sanity.mediaLibraryCli.import',\n requireUser: true,\n '~experimental_resource': {\n id: mediaLibraryId,\n type: 'media-library',\n },\n })\n\n this.log(\n boxen(\n `\n Importing to media library: ${mediaLibraryId.padEnd(37)}\n Importing from path: ${source}\n `,\n {\n borderColor: 'yellow',\n borderStyle: 'round',\n },\n ),\n )\n\n const spin = spinner('Beginning import…').start()\n\n await this.importAssets({projectClient, replaceAspects, source, spin})\n }\n\n private async importAssets(options: {\n projectClient: SanityClient\n replaceAspects: boolean\n source: string\n spin: ReturnType<typeof spinner>\n }): Promise<void> {\n const {projectClient, replaceAspects, source, spin} = options\n\n return new Promise<void>((resolve, reject) => {\n const subscription = importer({\n client: projectClient,\n replaceAspects,\n sourcePath: source,\n spinner: spin,\n })\n .pipe(this.reportResult(spin))\n .subscribe({\n complete: () => {\n resolve()\n },\n error: (error: unknown) => {\n const message = error instanceof Error ? error.message : String(error)\n spin.stop()\n reject(new Error(message))\n },\n })\n\n // Cleanup on Ctrl+C\n process.once('SIGINT', () => {\n subscription.unsubscribe()\n spin.fail('Import interrupted.')\n process.exit(130)\n })\n }).catch((error) => {\n this.error(styleText('red', error.message), {exit: 1})\n })\n }\n\n private reportResult(\n spin: ReturnType<typeof spinner>,\n ): OperatorFunction<State, [number, State | undefined]> {\n let previousState: State | undefined\n\n return pipe(\n scan<State, [number, State | undefined]>(\n (processedAssetsCount, state) => [processedAssetsCount[0] + 1, state],\n [0, undefined],\n ),\n tap({\n complete: () => spin.succeed(`Imported ${previousState?.fileCount} assets`),\n next: ([processedAssetsCount, state]) => {\n previousState = state\n spin.text = `${processedAssetsCount} of ${state?.fileCount} assets imported ${styleText('dim', state?.asset.originalFilename ?? '')}`\n },\n }),\n )\n }\n}\n"],"names":["styleText","Args","Flags","exitCodes","getProjectCliClient","SanityCommand","boxen","spinner","pipe","scan","tap","importer","importMediaDebug","promptForMediaLibrary","promptForProject","getMediaLibraries","getProjectIdFlag","MediaImportCommand","args","source","string","description","required","examples","command","flags","semantics","boolean","run","parse","replaceAspects","projectId","getProjectId","fallback","cliConfig","tryGetCliConfig","dataset","api","mediaLibraries","error","Error","message","exit","length","mediaLibraryId","isUnattended","USAGE_ERROR","some","library","id","projectClient","apiVersion","perspective","requestTagPrefix","requireUser","type","log","padEnd","borderColor","borderStyle","spin","start","importAssets","options","Promise","resolve","reject","subscription","client","sourcePath","reportResult","subscribe","complete","String","stop","process","once","unsubscribe","fail","catch","previousState","processedAssetsCount","state","undefined","succeed","fileCount","next","text","asset","originalFilename"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAQC,SAAS,EAAEC,mBAAmB,EAAEC,aAAa,QAAO,mBAAkB;AAC9E,SAAQC,KAAK,EAAEC,OAAO,QAAO,sBAAqB;AAElD,SAA+BC,IAAI,EAAEC,IAAI,EAAEC,GAAG,QAAO,OAAM;AAE3D,SAAQC,QAAQ,QAAmB,qCAAoC;AACvE,SAAQC,gBAAgB,QAAO,0CAAyC;AACxE,SAAQC,qBAAqB,QAAO,yCAAwC;AAC5E,SAAQC,gBAAgB,QAAO,oCAAmC;AAClE,SAAQC,iBAAiB,QAAO,mCAAkC;AAClE,SAAQC,gBAAgB,QAAO,4BAA2B;AAE1D,OAAO,MAAMC,2BAA2BZ;IACtC,OAAgBa,OAAO;QACrBC,QAAQlB,KAAKmB,MAAM,CAAC;YAClBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,sDAAqD;IAEnF,OAAgBE,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtB,GAAGT,iBAAiB;YAClBK,aAAa;YACbK,WAAW;QACb,EAAE;QACF,oBAAoBxB,MAAMkB,MAAM,CAAC;YAC/BC,aAAa;QACf;QACA,mBAAmBnB,MAAMyB,OAAO,CAAC;YAC/BN,aACE;QACJ;IACF,EAAC;IAED,MAAaO,MAAqB;QAChC,MAAM,EAACV,IAAI,EAAEO,KAAK,EAAC,GAAG,MAAM,IAAI,CAACI,KAAK,CAACZ;QACvC,MAAM,EAACE,MAAM,EAAC,GAAGD;QACjB,MAAMY,iBAAiBL,KAAK,CAAC,kBAAkB;QAE/C,MAAMM,YAAY,MAAM,IAAI,CAACC,YAAY,CAAC;YAACC,UAAU,IAAMnB,iBAAiB,CAAC;QAAE;QAE/E,MAAMoB,YAAY,MAAM,IAAI,CAACC,eAAe;QAC5C,MAAMC,UAAUF,UAAUG,GAAG,EAAED;QAE/B,IAAIE;QACJ,IAAI;YACFA,iBAAiB,MAAMvB,kBAAkBgB;QAC3C,EAAE,OAAOQ,OAAO;YACd3B,iBAAiB,iCAAiC2B;YAClD,IAAI,CAACA,KAAK,CACR,CAAC,iCAAiC,EAAEA,iBAAiBC,QAAQD,MAAME,OAAO,GAAGF,OAAO,EACpF;gBACEG,MAAM;YACR;QAEJ;QAEA,IAAIJ,eAAeK,MAAM,KAAK,GAAG;YAC/B,IAAI,CAACJ,KAAK,CAAC,mDAAmD;gBAACG,MAAM;YAAC;QACxE;QAEA,IAAIE,iBAAiBnB,KAAK,CAAC,mBAAmB;QAC9C,IAAI,CAACmB,gBAAgB;YACnB,IAAI,IAAI,CAACC,YAAY,IAAI;gBACvB,IAAI,CAACN,KAAK,CAAC,yEAAyE;oBAClFG,MAAMvC,UAAU2C,WAAW;gBAC7B;YACF;YACA,IAAI;gBACFF,iBAAiB,MAAM/B,sBAAsB;oBAACyB;gBAAc;YAC9D,EAAE,OAAOC,OAAO;gBACd3B,iBAAiB,iCAAiC2B;gBAClD,IAAI,CAACA,KAAK,CACR,CAAC,iCAAiC,EAAEA,iBAAiBC,QAAQD,MAAME,OAAO,GAAGF,OAAO,EACpF;oBACEG,MAAM;gBACR;YAEJ;QACF;QAEA,IAAI,CAACJ,eAAeS,IAAI,CAAC,CAACC,UAAYA,QAAQC,EAAE,KAAKL,iBAAiB;YACpE,IAAI,CAACL,KAAK,CAAC,CAAC,uBAAuB,EAAEK,eAAe,WAAW,CAAC,EAAE;gBAACF,MAAM;YAAC;QAC5E;QAEA,MAAMQ,gBAAgB,MAAM9C,oBAAoB;YAC9C+C,YAAY;YACZf;YACAgB,aAAa;YACbrB;YACAsB,kBAAkB;YAClBC,aAAa;YACb,0BAA0B;gBACxBL,IAAIL;gBACJW,MAAM;YACR;QACF;QAEA,IAAI,CAACC,GAAG,CACNlD,MACE,CAAC;sCAC6B,EAAEsC,eAAea,MAAM,CAAC,IAAI;+BACnC,EAAEtC,OAAO;QAChC,CAAC,EACD;YACEuC,aAAa;YACbC,aAAa;QACf;QAIJ,MAAMC,OAAOrD,QAAQ,qBAAqBsD,KAAK;QAE/C,MAAM,IAAI,CAACC,YAAY,CAAC;YAACZ;YAAepB;YAAgBX;YAAQyC;QAAI;IACtE;IAEA,MAAcE,aAAaC,OAK1B,EAAiB;QAChB,MAAM,EAACb,aAAa,EAAEpB,cAAc,EAAEX,MAAM,EAAEyC,IAAI,EAAC,GAAGG;QAEtD,OAAO,IAAIC,QAAc,CAACC,SAASC;YACjC,MAAMC,eAAexD,SAAS;gBAC5ByD,QAAQlB;gBACRpB;gBACAuC,YAAYlD;gBACZZ,SAASqD;YACX,GACGpD,IAAI,CAAC,IAAI,CAAC8D,YAAY,CAACV,OACvBW,SAAS,CAAC;gBACTC,UAAU;oBACRP;gBACF;gBACA1B,OAAO,CAACA;oBACN,MAAME,UAAUF,iBAAiBC,QAAQD,MAAME,OAAO,GAAGgC,OAAOlC;oBAChEqB,KAAKc,IAAI;oBACTR,OAAO,IAAI1B,MAAMC;gBACnB;YACF;YAEF,oBAAoB;YACpBkC,QAAQC,IAAI,CAAC,UAAU;gBACrBT,aAAaU,WAAW;gBACxBjB,KAAKkB,IAAI,CAAC;gBACVH,QAAQjC,IAAI,CAAC;YACf;QACF,GAAGqC,KAAK,CAAC,CAACxC;YACR,IAAI,CAACA,KAAK,CAACvC,UAAU,OAAOuC,MAAME,OAAO,GAAG;gBAACC,MAAM;YAAC;QACtD;IACF;IAEQ4B,aACNV,IAAgC,EACsB;QACtD,IAAIoB;QAEJ,OAAOxE,KACLC,KACE,CAACwE,sBAAsBC,QAAU;gBAACD,oBAAoB,CAAC,EAAE,GAAG;gBAAGC;aAAM,EACrE;YAAC;YAAGC;SAAU,GAEhBzE,IAAI;YACF8D,UAAU,IAAMZ,KAAKwB,OAAO,CAAC,CAAC,SAAS,EAAEJ,eAAeK,UAAU,OAAO,CAAC;YAC1EC,MAAM,CAAC,CAACL,sBAAsBC,MAAM;gBAClCF,gBAAgBE;gBAChBtB,KAAK2B,IAAI,GAAG,GAAGN,qBAAqB,IAAI,EAAEC,OAAOG,UAAU,iBAAiB,EAAErF,UAAU,OAAOkF,OAAOM,MAAMC,oBAAoB,KAAK;YACvI;QACF;IAEJ;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/media/import.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, getProjectCliClient, SanityCommand} from '@sanity/cli-core'\nimport {boxen, spinner} from '@sanity/cli-core/ux'\nimport {SanityClient} from '@sanity/client'\nimport {type OperatorFunction, pipe, scan, tap} from 'rxjs'\n\nimport {importer, type State} from '../../actions/media/importMedia.js'\nimport {importMediaDebug} from '../../actions/media/importMediaDebug.js'\nimport {promptForMediaLibrary} from '../../prompts/promptForMediaLibrary.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {getMediaLibraries} from '../../services/mediaLibraries.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nexport class MediaImportCommand extends SanityCommand<typeof MediaImportCommand> {\n static override args = {\n source: Args.string({\n description: 'Image file or folder to import from',\n required: true,\n }),\n }\n\n static override description = 'Import a set of assets to the target media library.'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> products',\n description: 'Import all assets from the \"products\" directory',\n },\n {\n command: '<%= config.bin %> <%= command.id %> gallery.tar.gz',\n description: 'Import all assets from \"gallery\" archive',\n },\n {\n command: '<%= config.bin %> <%= command.id %> products --replace-aspects',\n description: 'Import all assets from the \"products\" directory and replace aspects',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to import media to',\n semantics: 'override',\n }),\n 'media-library-id': Flags.string({\n description: 'The id of the target media library',\n }),\n 'replace-aspects': Flags.boolean({\n description:\n 'Replace existing aspect data. All versions will be replaced (e.g. published and draft aspect data)',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(MediaImportCommand)\n const {source} = args\n const replaceAspects = flags['replace-aspects']\n\n const projectId = await this.getProjectId({fallback: () => promptForProject({})})\n\n const cliConfig = await this.tryGetCliConfig()\n const dataset = cliConfig.api?.dataset\n\n let mediaLibraries\n try {\n mediaLibraries = await getMediaLibraries(projectId)\n } catch (error) {\n importMediaDebug('Error listing media libraries', error)\n this.error(\n `Failed to list media libraries:\\n${error instanceof Error ? error.message : error}`,\n {\n exit: exitCodes.RUNTIME_ERROR,\n },\n )\n }\n\n if (mediaLibraries.length === 0) {\n this.error('No active media libraries found in this project', {exit: exitCodes.RUNTIME_ERROR})\n }\n\n let mediaLibraryId = flags['media-library-id']\n if (!mediaLibraryId) {\n if (this.isUnattended()) {\n this.error('Media library ID is required. Pass it with `--media-library-id <id>`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n try {\n mediaLibraryId = await promptForMediaLibrary({mediaLibraries})\n } catch (error) {\n importMediaDebug('Error selecting media library', error)\n this.error(\n `Failed to select media library:\\n${error instanceof Error ? error.message : error}`,\n {\n exit: exitCodes.RUNTIME_ERROR,\n },\n )\n }\n }\n\n if (!mediaLibraries.some((library) => library.id === mediaLibraryId)) {\n this.error(`Media library with id \"${mediaLibraryId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const projectClient = await getProjectCliClient({\n apiVersion: 'v2025-02-19',\n dataset,\n perspective: 'drafts',\n projectId,\n requestTagPrefix: 'sanity.mediaLibraryCli.import',\n requireUser: true,\n '~experimental_resource': {\n id: mediaLibraryId,\n type: 'media-library',\n },\n })\n\n this.log(\n boxen(\n `\n Importing to media library: ${mediaLibraryId.padEnd(37)}\n Importing from path: ${source}\n `,\n {\n borderColor: 'yellow',\n borderStyle: 'round',\n },\n ),\n )\n\n const spin = spinner('Beginning import…').start()\n\n await this.importAssets({projectClient, replaceAspects, source, spin})\n }\n\n private async importAssets(options: {\n projectClient: SanityClient\n replaceAspects: boolean\n source: string\n spin: ReturnType<typeof spinner>\n }): Promise<void> {\n const {projectClient, replaceAspects, source, spin} = options\n\n return new Promise<void>((resolve, reject) => {\n const subscription = importer({\n client: projectClient,\n replaceAspects,\n sourcePath: source,\n spinner: spin,\n })\n .pipe(this.reportResult(spin))\n .subscribe({\n complete: () => {\n resolve()\n },\n error: (error: unknown) => {\n const message = error instanceof Error ? error.message : String(error)\n spin.stop()\n reject(new Error(message))\n },\n })\n\n // Cleanup on Ctrl+C\n process.once('SIGINT', () => {\n subscription.unsubscribe()\n spin.fail('Import interrupted.')\n process.exit(exitCodes.SIGINT)\n })\n }).catch((error) => {\n this.error(styleText('red', error.message), {exit: exitCodes.RUNTIME_ERROR})\n })\n }\n\n private reportResult(\n spin: ReturnType<typeof spinner>,\n ): OperatorFunction<State, [number, State | undefined]> {\n let previousState: State | undefined\n\n return pipe(\n scan<State, [number, State | undefined]>(\n (processedAssetsCount, state) => [processedAssetsCount[0] + 1, state],\n [0, undefined],\n ),\n tap({\n complete: () => spin.succeed(`Imported ${previousState?.fileCount} assets`),\n next: ([processedAssetsCount, state]) => {\n previousState = state\n spin.text = `${processedAssetsCount} of ${state?.fileCount} assets imported ${styleText('dim', state?.asset.originalFilename ?? '')}`\n },\n }),\n )\n }\n}\n"],"names":["styleText","Args","Flags","exitCodes","getProjectCliClient","SanityCommand","boxen","spinner","pipe","scan","tap","importer","importMediaDebug","promptForMediaLibrary","promptForProject","getMediaLibraries","getProjectIdFlag","MediaImportCommand","args","source","string","description","required","examples","command","flags","semantics","boolean","run","parse","replaceAspects","projectId","getProjectId","fallback","cliConfig","tryGetCliConfig","dataset","api","mediaLibraries","error","Error","message","exit","RUNTIME_ERROR","length","mediaLibraryId","isUnattended","USAGE_ERROR","some","library","id","projectClient","apiVersion","perspective","requestTagPrefix","requireUser","type","log","padEnd","borderColor","borderStyle","spin","start","importAssets","options","Promise","resolve","reject","subscription","client","sourcePath","reportResult","subscribe","complete","String","stop","process","once","unsubscribe","fail","SIGINT","catch","previousState","processedAssetsCount","state","undefined","succeed","fileCount","next","text","asset","originalFilename"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { access, mkdir, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { styleText } from 'node:util';
|
|
4
4
|
import { Args } from '@oclif/core';
|
|
5
|
-
import { SanityCommand } from '@sanity/cli-core';
|
|
5
|
+
import { exitCodes, SanityCommand } from '@sanity/cli-core';
|
|
6
6
|
import { confirm, input, select } from '@sanity/cli-core/ux';
|
|
7
7
|
import { MIGRATIONS_DIRECTORY } from '../../actions/migration/constants.js';
|
|
8
8
|
import { minimalAdvanced, minimalSimple, renameField, renameType, stringToPTE } from '../../actions/migration/templates/index.js';
|
|
@@ -62,7 +62,7 @@ export class CreateMigrationCommand extends SanityCommand {
|
|
|
62
62
|
const sluggedName = title.toLowerCase().normalize('NFD').replaceAll(/\p{Mn}/gu, '').replaceAll(/\s+/g, '-').replaceAll(/[^a-z0-9-]/g, '');
|
|
63
63
|
if (!sluggedName) {
|
|
64
64
|
this.error(`Could not derive a valid migration name from title ${JSON.stringify(title)}. Use a title that contains at least one letter or number.`, {
|
|
65
|
-
exit:
|
|
65
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
const destDir = path.join(workDir, MIGRATIONS_DIRECTORY, sluggedName);
|
|
@@ -93,7 +93,7 @@ export class CreateMigrationCommand extends SanityCommand {
|
|
|
93
93
|
} catch (error) {
|
|
94
94
|
const message = error instanceof Error ? error.message : String(error);
|
|
95
95
|
this.error(`Failed to create migration directory: ${message}`, {
|
|
96
|
-
exit:
|
|
96
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
97
97
|
});
|
|
98
98
|
}
|
|
99
99
|
try {
|
|
@@ -101,7 +101,7 @@ export class CreateMigrationCommand extends SanityCommand {
|
|
|
101
101
|
} catch (error) {
|
|
102
102
|
const message = error instanceof Error ? error.message : String(error);
|
|
103
103
|
this.error(`Failed to create migration file: ${message}`, {
|
|
104
|
-
exit:
|
|
104
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/migrations/create.ts"],"sourcesContent":["import {access, mkdir, writeFile} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {confirm, input, select} from '@sanity/cli-core/ux'\n\nimport {MIGRATIONS_DIRECTORY} from '../../actions/migration/constants.js'\nimport {\n minimalAdvanced,\n minimalSimple,\n renameField,\n renameType,\n stringToPTE,\n} from '../../actions/migration/templates/index.js'\n\nconst TEMPLATES = [\n {name: 'Minimalistic migration to get you started', template: minimalSimple},\n {name: 'Rename an object type', template: renameType},\n {name: 'Rename a field', template: renameField},\n {name: 'Convert string field to Portable Text', template: stringToPTE},\n {\n name: 'Advanced template using async iterators providing more fine grained control',\n template: minimalAdvanced,\n },\n]\n\nexport class CreateMigrationCommand extends SanityCommand<typeof CreateMigrationCommand> {\n static override args = {\n title: Args.string({\n description: 'Title of migration',\n required: false,\n }),\n }\n\n static override description = 'Create a new migration within your project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Create a new migration, prompting for title and options',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"Rename field from location to address\"',\n description: 'Create a new migration with the provided title, prompting for options',\n },\n ]\n\n static override hiddenAliases = ['migration:create']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(CreateMigrationCommand)\n const {directory: workDir} = await this.getProjectRoot()\n\n const title = await this.promptForTitle(args.title)\n const types = await this.promptForDocumentTypes()\n const {template} = await this.promptForTemplate()\n\n const renderedTemplate = (template || minimalSimple)({\n documentTypes: types\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean),\n migrationName: title,\n })\n\n const sluggedName = title\n .toLowerCase()\n .normalize('NFD')\n .replaceAll(/\\p{Mn}/gu, '')\n .replaceAll(/\\s+/g, '-')\n .replaceAll(/[^a-z0-9-]/g, '')\n\n if (!sluggedName) {\n this.error(\n `Could not derive a valid migration name from title ${JSON.stringify(\n title,\n )}. Use a title that contains at least one letter or number.`,\n {exit: 1},\n )\n }\n\n const destDir = path.join(workDir, MIGRATIONS_DIRECTORY, sluggedName)\n const definitionFile = path.join(destDir, 'index.ts')\n\n const dirCreated = await this.createMigrationFile(destDir, definitionFile, renderedTemplate)\n\n if (dirCreated) {\n this.log()\n this.log(`${styleText('green', '✓')} Migration created!`)\n this.log()\n this.log('Next steps:')\n this.log(\n `Open ${styleText(\n 'bold',\n definitionFile,\n )} in your code editor and write the code for your migration.`,\n )\n this.log(\n `Dry run the migration with:\\n\\`${styleText(\n 'bold',\n `sanity migration run ${sluggedName} --project=<projectId> --dataset <dataset> `,\n )}\\``,\n )\n this.log(\n `Run the migration against a dataset with:\\n \\`${styleText(\n 'bold',\n `sanity migration run ${sluggedName} --project=<projectId> --dataset <dataset> --no-dry-run`,\n )}\\``,\n )\n this.log()\n this.log(\n `👉 Learn more about schema and content migrations at ${styleText(\n 'bold',\n 'https://www.sanity.io/docs/schema-and-content-migrations',\n )}`,\n )\n }\n }\n\n private async createMigrationFile(\n destDir: string,\n definitionFile: string,\n renderedTemplate: string,\n ): Promise<boolean> {\n const dirExists = await access(destDir)\n .then(() => true)\n .catch(() => false)\n\n if (dirExists) {\n const shouldOverwrite = await this.promptForOverwrite(destDir)\n if (!shouldOverwrite) return false\n }\n\n try {\n await mkdir(destDir, {recursive: true})\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n this.error(`Failed to create migration directory: ${message}`, {exit: 1})\n }\n\n try {\n await writeFile(definitionFile, renderedTemplate)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n this.error(`Failed to create migration file: ${message}`, {exit: 1})\n }\n\n return true\n }\n\n private async promptForDocumentTypes(): Promise<string> {\n return input({\n message:\n 'Type of documents to migrate. You can add multiple types separated by comma (optional)',\n })\n }\n\n private async promptForOverwrite(destDir: string): Promise<boolean> {\n return confirm({\n default: false,\n message: `Migration directory ${styleText('cyan', destDir)} already exists. Overwrite?`,\n })\n }\n\n private async promptForTemplate(): Promise<{\n name: string\n template: (params: {documentTypes: string[]; migrationName: string}) => string\n }> {\n const templatesByName = Object.fromEntries(TEMPLATES.map((t) => [t.name, t]))\n const templateName = await select({\n choices: TEMPLATES.map((definedTemplate) => ({\n name: definedTemplate.name,\n value: definedTemplate.name,\n })),\n message: 'Select a template',\n })\n\n return templatesByName[templateName]!\n }\n\n private async promptForTitle(providedTitle?: string): Promise<string> {\n if (providedTitle?.trim()) {\n return providedTitle\n }\n\n return input({\n message: 'Title of migration (e.g. \"Rename field from location to address\")',\n validate: (value) => {\n if (!value.trim()) {\n return 'Title cannot be empty'\n }\n\n return true\n },\n })\n }\n}\n"],"names":["access","mkdir","writeFile","path","styleText","Args","SanityCommand","confirm","input","select","MIGRATIONS_DIRECTORY","minimalAdvanced","minimalSimple","renameField","renameType","stringToPTE","TEMPLATES","name","template","CreateMigrationCommand","args","title","string","description","required","examples","command","hiddenAliases","run","parse","directory","workDir","getProjectRoot","promptForTitle","types","promptForDocumentTypes","promptForTemplate","renderedTemplate","documentTypes","split","map","t","trim","filter","Boolean","migrationName","sluggedName","toLowerCase","normalize","replaceAll","error","JSON","stringify","exit","destDir","join","definitionFile","dirCreated","createMigrationFile","log","dirExists","then","catch","shouldOverwrite","promptForOverwrite","recursive","message","Error","String","default","templatesByName","Object","fromEntries","templateName","choices","definedTemplate","value","providedTitle","validate"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/migrations/create.ts"],"sourcesContent":["import {access, mkdir, writeFile} from 'node:fs/promises'\nimport path from 'node:path'\nimport {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {confirm, input, select} from '@sanity/cli-core/ux'\n\nimport {MIGRATIONS_DIRECTORY} from '../../actions/migration/constants.js'\nimport {\n minimalAdvanced,\n minimalSimple,\n renameField,\n renameType,\n stringToPTE,\n} from '../../actions/migration/templates/index.js'\n\nconst TEMPLATES = [\n {name: 'Minimalistic migration to get you started', template: minimalSimple},\n {name: 'Rename an object type', template: renameType},\n {name: 'Rename a field', template: renameField},\n {name: 'Convert string field to Portable Text', template: stringToPTE},\n {\n name: 'Advanced template using async iterators providing more fine grained control',\n template: minimalAdvanced,\n },\n]\n\nexport class CreateMigrationCommand extends SanityCommand<typeof CreateMigrationCommand> {\n static override args = {\n title: Args.string({\n description: 'Title of migration',\n required: false,\n }),\n }\n\n static override description = 'Create a new migration within your project'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Create a new migration, prompting for title and options',\n },\n {\n command: '<%= config.bin %> <%= command.id %> \"Rename field from location to address\"',\n description: 'Create a new migration with the provided title, prompting for options',\n },\n ]\n\n static override hiddenAliases = ['migration:create']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(CreateMigrationCommand)\n const {directory: workDir} = await this.getProjectRoot()\n\n const title = await this.promptForTitle(args.title)\n const types = await this.promptForDocumentTypes()\n const {template} = await this.promptForTemplate()\n\n const renderedTemplate = (template || minimalSimple)({\n documentTypes: types\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean),\n migrationName: title,\n })\n\n const sluggedName = title\n .toLowerCase()\n .normalize('NFD')\n .replaceAll(/\\p{Mn}/gu, '')\n .replaceAll(/\\s+/g, '-')\n .replaceAll(/[^a-z0-9-]/g, '')\n\n if (!sluggedName) {\n this.error(\n `Could not derive a valid migration name from title ${JSON.stringify(\n title,\n )}. Use a title that contains at least one letter or number.`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n const destDir = path.join(workDir, MIGRATIONS_DIRECTORY, sluggedName)\n const definitionFile = path.join(destDir, 'index.ts')\n\n const dirCreated = await this.createMigrationFile(destDir, definitionFile, renderedTemplate)\n\n if (dirCreated) {\n this.log()\n this.log(`${styleText('green', '✓')} Migration created!`)\n this.log()\n this.log('Next steps:')\n this.log(\n `Open ${styleText(\n 'bold',\n definitionFile,\n )} in your code editor and write the code for your migration.`,\n )\n this.log(\n `Dry run the migration with:\\n\\`${styleText(\n 'bold',\n `sanity migration run ${sluggedName} --project=<projectId> --dataset <dataset> `,\n )}\\``,\n )\n this.log(\n `Run the migration against a dataset with:\\n \\`${styleText(\n 'bold',\n `sanity migration run ${sluggedName} --project=<projectId> --dataset <dataset> --no-dry-run`,\n )}\\``,\n )\n this.log()\n this.log(\n `👉 Learn more about schema and content migrations at ${styleText(\n 'bold',\n 'https://www.sanity.io/docs/schema-and-content-migrations',\n )}`,\n )\n }\n }\n\n private async createMigrationFile(\n destDir: string,\n definitionFile: string,\n renderedTemplate: string,\n ): Promise<boolean> {\n const dirExists = await access(destDir)\n .then(() => true)\n .catch(() => false)\n\n if (dirExists) {\n const shouldOverwrite = await this.promptForOverwrite(destDir)\n if (!shouldOverwrite) return false\n }\n\n try {\n await mkdir(destDir, {recursive: true})\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n this.error(`Failed to create migration directory: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n try {\n await writeFile(definitionFile, renderedTemplate)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n this.error(`Failed to create migration file: ${message}`, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n return true\n }\n\n private async promptForDocumentTypes(): Promise<string> {\n return input({\n message:\n 'Type of documents to migrate. You can add multiple types separated by comma (optional)',\n })\n }\n\n private async promptForOverwrite(destDir: string): Promise<boolean> {\n return confirm({\n default: false,\n message: `Migration directory ${styleText('cyan', destDir)} already exists. Overwrite?`,\n })\n }\n\n private async promptForTemplate(): Promise<{\n name: string\n template: (params: {documentTypes: string[]; migrationName: string}) => string\n }> {\n const templatesByName = Object.fromEntries(TEMPLATES.map((t) => [t.name, t]))\n const templateName = await select({\n choices: TEMPLATES.map((definedTemplate) => ({\n name: definedTemplate.name,\n value: definedTemplate.name,\n })),\n message: 'Select a template',\n })\n\n return templatesByName[templateName]!\n }\n\n private async promptForTitle(providedTitle?: string): Promise<string> {\n if (providedTitle?.trim()) {\n return providedTitle\n }\n\n return input({\n message: 'Title of migration (e.g. \"Rename field from location to address\")',\n validate: (value) => {\n if (!value.trim()) {\n return 'Title cannot be empty'\n }\n\n return true\n },\n })\n }\n}\n"],"names":["access","mkdir","writeFile","path","styleText","Args","exitCodes","SanityCommand","confirm","input","select","MIGRATIONS_DIRECTORY","minimalAdvanced","minimalSimple","renameField","renameType","stringToPTE","TEMPLATES","name","template","CreateMigrationCommand","args","title","string","description","required","examples","command","hiddenAliases","run","parse","directory","workDir","getProjectRoot","promptForTitle","types","promptForDocumentTypes","promptForTemplate","renderedTemplate","documentTypes","split","map","t","trim","filter","Boolean","migrationName","sluggedName","toLowerCase","normalize","replaceAll","error","JSON","stringify","exit","RUNTIME_ERROR","destDir","join","definitionFile","dirCreated","createMigrationFile","log","dirExists","then","catch","shouldOverwrite","promptForOverwrite","recursive","message","Error","String","default","templatesByName","Object","fromEntries","templateName","choices","definedTemplate","value","providedTitle","validate"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { styleText } from 'node:util';
|
|
2
|
-
import { SanityCommand, subdebug } from '@sanity/cli-core';
|
|
2
|
+
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
3
|
import { Table } from 'console-table-printer';
|
|
4
4
|
import { resolveMigrations } from '../../actions/migration/resolveMigrations.js';
|
|
5
5
|
const listMigrationDebug = subdebug('migration:list');
|
|
@@ -55,7 +55,7 @@ export class ListMigrationCommand extends SanityCommand {
|
|
|
55
55
|
}
|
|
56
56
|
listMigrationDebug('Failed to list migrations:', error);
|
|
57
57
|
this.error(`List migrations failed: ${error instanceof Error ? error.message : String(error)}`, {
|
|
58
|
-
exit:
|
|
58
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/migrations/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {Table} from 'console-table-printer'\n\nimport {resolveMigrations} from '../../actions/migration/resolveMigrations.js'\n\nconst listMigrationDebug = subdebug('migration:list')\n\nexport class ListMigrationCommand extends SanityCommand<typeof ListMigrationCommand> {\n static override description = 'List available migrations'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all available migrations in the project',\n },\n ]\n\n static override hiddenAliases = ['migration:list']\n\n public async run(): Promise<void> {\n const {directory: workDir} = await this.getProjectRoot()\n\n try {\n const migrations = await resolveMigrations(workDir)\n\n if (migrations.length === 0) {\n this.log('No migrations found in migrations folder of the project')\n this.log(\n `\\nRun ${styleText('green', '`sanity migration create <NAME>`')} to create a new migration`,\n )\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'ID'},\n {alignment: 'left', name: 'title', title: 'Title'},\n ],\n title: `Found ${migrations.length} migrations in project`,\n })\n\n for (const definedMigration of migrations) {\n table.addRow({id: definedMigration.id, title: definedMigration.migration.title})\n }\n table.printTable()\n this.log('\\nRun `sanity migration run <ID>` to run a migration')\n listMigrationDebug(`Successfully listed ${migrations.length} migrations`)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n this.log('No migrations folder found in the project')\n this.log(\n `\\nRun ${styleText('green', '`sanity migration create <NAME>`')} to create a new migration`,\n )\n return\n }\n listMigrationDebug('Failed to list migrations:', error)\n this.error(\n `List migrations failed: ${error instanceof Error ? error.message : String(error)}`,\n {\n exit:
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/migrations/list.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {Table} from 'console-table-printer'\n\nimport {resolveMigrations} from '../../actions/migration/resolveMigrations.js'\n\nconst listMigrationDebug = subdebug('migration:list')\n\nexport class ListMigrationCommand extends SanityCommand<typeof ListMigrationCommand> {\n static override description = 'List available migrations'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'List all available migrations in the project',\n },\n ]\n\n static override hiddenAliases = ['migration:list']\n\n public async run(): Promise<void> {\n const {directory: workDir} = await this.getProjectRoot()\n\n try {\n const migrations = await resolveMigrations(workDir)\n\n if (migrations.length === 0) {\n this.log('No migrations found in migrations folder of the project')\n this.log(\n `\\nRun ${styleText('green', '`sanity migration create <NAME>`')} to create a new migration`,\n )\n return\n }\n\n const table = new Table({\n columns: [\n {alignment: 'left', name: 'id', title: 'ID'},\n {alignment: 'left', name: 'title', title: 'Title'},\n ],\n title: `Found ${migrations.length} migrations in project`,\n })\n\n for (const definedMigration of migrations) {\n table.addRow({id: definedMigration.id, title: definedMigration.migration.title})\n }\n table.printTable()\n this.log('\\nRun `sanity migration run <ID>` to run a migration')\n listMigrationDebug(`Successfully listed ${migrations.length} migrations`)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n this.log('No migrations folder found in the project')\n this.log(\n `\\nRun ${styleText('green', '`sanity migration create <NAME>`')} to create a new migration`,\n )\n return\n }\n listMigrationDebug('Failed to list migrations:', error)\n this.error(\n `List migrations failed: ${error instanceof Error ? error.message : String(error)}`,\n {\n exit: exitCodes.RUNTIME_ERROR,\n },\n )\n }\n }\n}\n"],"names":["styleText","exitCodes","SanityCommand","subdebug","Table","resolveMigrations","listMigrationDebug","ListMigrationCommand","description","examples","command","hiddenAliases","run","directory","workDir","getProjectRoot","migrations","length","log","table","columns","alignment","name","title","definedMigration","addRow","id","migration","printTable","error","code","Error","message","String","exit","RUNTIME_ERROR"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,KAAK,QAAO,wBAAuB;AAE3C,SAAQC,iBAAiB,QAAO,+CAA8C;AAE9E,MAAMC,qBAAqBH,SAAS;AAEpC,OAAO,MAAMI,6BAA6BL;IACxC,OAAgBM,cAAc,4BAA2B;IAEzD,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTF,aAAa;QACf;KACD,CAAA;IAED,OAAgBG,gBAAgB;QAAC;KAAiB,CAAA;IAElD,MAAaC,MAAqB;QAChC,MAAM,EAACC,WAAWC,OAAO,EAAC,GAAG,MAAM,IAAI,CAACC,cAAc;QAEtD,IAAI;YACF,MAAMC,aAAa,MAAMX,kBAAkBS;YAE3C,IAAIE,WAAWC,MAAM,KAAK,GAAG;gBAC3B,IAAI,CAACC,GAAG,CAAC;gBACT,IAAI,CAACA,GAAG,CACN,CAAC,MAAM,EAAElB,UAAU,SAAS,oCAAoC,0BAA0B,CAAC;gBAE7F;YACF;YAEA,MAAMmB,QAAQ,IAAIf,MAAM;gBACtBgB,SAAS;oBACP;wBAACC,WAAW;wBAAQC,MAAM;wBAAMC,OAAO;oBAAI;oBAC3C;wBAACF,WAAW;wBAAQC,MAAM;wBAASC,OAAO;oBAAO;iBAClD;gBACDA,OAAO,CAAC,MAAM,EAAEP,WAAWC,MAAM,CAAC,sBAAsB,CAAC;YAC3D;YAEA,KAAK,MAAMO,oBAAoBR,WAAY;gBACzCG,MAAMM,MAAM,CAAC;oBAACC,IAAIF,iBAAiBE,EAAE;oBAAEH,OAAOC,iBAAiBG,SAAS,CAACJ,KAAK;gBAAA;YAChF;YACAJ,MAAMS,UAAU;YAChB,IAAI,CAACV,GAAG,CAAC;YACTZ,mBAAmB,CAAC,oBAAoB,EAAEU,WAAWC,MAAM,CAAC,WAAW,CAAC;QAC1E,EAAE,OAAOY,OAAO;YACd,IAAI,AAACA,MAAgCC,IAAI,KAAK,UAAU;gBACtD,IAAI,CAACZ,GAAG,CAAC;gBACT,IAAI,CAACA,GAAG,CACN,CAAC,MAAM,EAAElB,UAAU,SAAS,oCAAoC,0BAA0B,CAAC;gBAE7F;YACF;YACAM,mBAAmB,8BAA8BuB;YACjD,IAAI,CAACA,KAAK,CACR,CAAC,wBAAwB,EAAEA,iBAAiBE,QAAQF,MAAMG,OAAO,GAAGC,OAAOJ,QAAQ,EACnF;gBACEK,MAAMjC,UAAUkC,aAAa;YAC/B;QAEJ;IACF;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { styleText } from 'node:util';
|
|
3
3
|
import { Args, Flags } from '@oclif/core';
|
|
4
|
-
import { getProjectCliClient, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
4
|
+
import { exitCodes, getProjectCliClient, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
5
5
|
import { confirm, spinner } from '@sanity/cli-core/ux';
|
|
6
6
|
import { DEFAULT_MUTATION_CONCURRENCY, dryRun, MAX_MUTATION_CONCURRENCY, run } from '@sanity/migrate';
|
|
7
7
|
import { Table } from 'console-table-printer';
|
|
@@ -86,14 +86,14 @@ export class RunMigrationCommand extends SanityCommand {
|
|
|
86
86
|
// any other failure (e.g. a syntax error in a migration file).
|
|
87
87
|
if (error.code !== 'ENOENT') {
|
|
88
88
|
this.error(`Failed to list migrations: ${error instanceof Error ? error.message : String(error)}`, {
|
|
89
|
-
exit:
|
|
89
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
if (migrations.length === 0) {
|
|
94
94
|
this.log('\nNo migrations found in the project');
|
|
95
95
|
this.log(`Run ${styleText('green', '`sanity migration create <NAME>`')} to create a new migration`);
|
|
96
|
-
this.exit(
|
|
96
|
+
this.exit(exitCodes.RUNTIME_ERROR);
|
|
97
97
|
}
|
|
98
98
|
const table = new Table({
|
|
99
99
|
columns: [
|
|
@@ -118,7 +118,7 @@ export class RunMigrationCommand extends SanityCommand {
|
|
|
118
118
|
}
|
|
119
119
|
table.printTable();
|
|
120
120
|
this.log('\nRun `sanity migration run <ID>` to run a migration');
|
|
121
|
-
this.exit(
|
|
121
|
+
this.exit(exitCodes.RUNTIME_ERROR);
|
|
122
122
|
}
|
|
123
123
|
const cliConfig = await this.getCliConfig();
|
|
124
124
|
const projectId = await this.getProjectId({
|
|
@@ -132,17 +132,17 @@ export class RunMigrationCommand extends SanityCommand {
|
|
|
132
132
|
const apiVersion = ensureApiVersionFormat(flags['api-version'] ?? DEFAULT_API_VERSION);
|
|
133
133
|
if (dataset && !project || project && !dataset) {
|
|
134
134
|
this.error('If either --dataset or --project is provided, both must be provided', {
|
|
135
|
-
exit:
|
|
135
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
138
|
if (!project && !projectId) {
|
|
139
139
|
this.error('sanity.cli.js does not contain a project identifier ("api.projectId") and no --project option was provided.', {
|
|
140
|
-
exit:
|
|
140
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
if (!dataset && !datasetFromConfig) {
|
|
144
144
|
this.error('sanity.cli.js does not contain a dataset identifier ("api.dataset") and no --dataset option was provided.', {
|
|
145
|
-
exit:
|
|
145
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
148
|
const candidates = await resolveMigrationScript(workDir, id);
|
|
@@ -150,14 +150,14 @@ export class RunMigrationCommand extends SanityCommand {
|
|
|
150
150
|
if (resolvedScripts.length > 1) {
|
|
151
151
|
// todo: consider prompt user about which one to run? note: it's likely a mistake if multiple files resolve to the same name
|
|
152
152
|
this.error(`Found multiple migrations for "${id}" in ${styleText('cyan', migrationsDirectoryPath)}: \n - ${candidates.map((candidate)=>path.relative(migrationsDirectoryPath, candidate.absolutePath)).join('\n - ')}`, {
|
|
153
|
-
exit:
|
|
153
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
156
|
const script = resolvedScripts[0];
|
|
157
157
|
if (!script) {
|
|
158
158
|
this.error(`No migration found for "${id}" in ${styleText('cyan', migrationsDirectoryPath)}. Make sure that the migration file exists and exports a valid migration as its default export.\n
|
|
159
159
|
Tried the following files:\n - ${candidates.map((candidate)=>path.relative(migrationsDirectoryPath, candidate.absolutePath)).join('\n - ')}`, {
|
|
160
|
-
exit:
|
|
160
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
163
|
const mod = script.mod;
|
|
@@ -165,25 +165,25 @@ export class RunMigrationCommand extends SanityCommand {
|
|
|
165
165
|
// todo: consider adding support for up/down as separate named exports
|
|
166
166
|
// For now, make sure we reserve the names for future use
|
|
167
167
|
this.error('Named "up"/"down" migration exports are not supported at this time, please export your migration as the default export', {
|
|
168
|
-
exit:
|
|
168
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
169
169
|
});
|
|
170
170
|
}
|
|
171
171
|
const migration = mod.default;
|
|
172
172
|
if (fromExport && !dry) {
|
|
173
173
|
this.error('Can only dry run migrations from a dataset export file', {
|
|
174
|
-
exit:
|
|
174
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
175
175
|
});
|
|
176
176
|
}
|
|
177
177
|
const concurrency = flags.concurrency;
|
|
178
178
|
if (concurrency !== undefined) {
|
|
179
179
|
if (concurrency > MAX_MUTATION_CONCURRENCY) {
|
|
180
180
|
this.error(`Concurrency exceeds the maximum allowed value of ${MAX_MUTATION_CONCURRENCY}`, {
|
|
181
|
-
exit:
|
|
181
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
182
182
|
});
|
|
183
183
|
}
|
|
184
184
|
if (concurrency < 1) {
|
|
185
185
|
this.error(`Concurrency must be a positive number, got ${concurrency}`, {
|
|
186
|
-
exit:
|
|
186
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
187
187
|
});
|
|
188
188
|
}
|
|
189
189
|
}
|
|
@@ -298,7 +298,7 @@ export class RunMigrationCommand extends SanityCommand {
|
|
|
298
298
|
});
|
|
299
299
|
if (!response) {
|
|
300
300
|
runMigrationDebug('User aborted migration');
|
|
301
|
-
this.exit(
|
|
301
|
+
this.exit(exitCodes.RUNTIME_ERROR);
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
}
|