From 2f3ae6c8d4a716b04269fd58d049818c55309470 Mon Sep 17 00:00:00 2001 From: Shaun Stanworth Date: Mon, 24 Nov 2025 10:34:54 +0000 Subject: [PATCH] shopify app import-custom-data-definitions --- .changeset/bumpy-doors-change.md | 5 + .../app-import-custom-data-definitions.doc.ts | 34 ++++++ ...-import-custom-data-definitions.example.sh | 1 + ...mport-custom-data-definitions.interface.ts | 50 ++++++++ .../generated/generated_docs_data.json | 110 ++++++++++++++++++ .../app/import-custom-data-definitions.ts | 69 +++++++++++ packages/app/src/cli/index.ts | 2 + packages/cli/README.md | 27 +++++ packages/cli/oclif.manifest.json | 94 +++++++++++++++ packages/features/snapshots/commands.txt | 1 + 10 files changed, 393 insertions(+) create mode 100644 .changeset/bumpy-doors-change.md create mode 100644 docs-shopify.dev/commands/app-import-custom-data-definitions.doc.ts create mode 100644 docs-shopify.dev/commands/examples/app-import-custom-data-definitions.example.sh create mode 100644 docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts create mode 100644 packages/app/src/cli/commands/app/import-custom-data-definitions.ts diff --git a/.changeset/bumpy-doors-change.md b/.changeset/bumpy-doors-change.md new file mode 100644 index 00000000000..d09811253b6 --- /dev/null +++ b/.changeset/bumpy-doors-change.md @@ -0,0 +1,5 @@ +--- +'@shopify/app': minor +--- + +Add `shopify app import-custom-data-definitions` -- a command to automatically convert existing metafields and metaobjects to declarative TOML. diff --git a/docs-shopify.dev/commands/app-import-custom-data-definitions.doc.ts b/docs-shopify.dev/commands/app-import-custom-data-definitions.doc.ts new file mode 100644 index 00000000000..a1b101a5295 --- /dev/null +++ b/docs-shopify.dev/commands/app-import-custom-data-definitions.doc.ts @@ -0,0 +1,34 @@ +// This is an autogenerated file. Don't edit this file manually. +import {ReferenceEntityTemplateSchema} from '@shopify/generate-docs' + +const data: ReferenceEntityTemplateSchema = { + name: 'app import-custom-data-definitions', + description: `Import metafield and metaobject definitions from your development store. [Read more about declarative custom data definitions](/docs/apps/build/custom-data/declarative-custom-data-definitions).`, + overviewPreviewDescription: `Import metafield and metaobject definitions.`, + type: 'command', + isVisualComponent: false, + defaultExample: { + codeblock: { + tabs: [ + { + title: 'app import-custom-data-definitions', + code: './examples/app-import-custom-data-definitions.example.sh', + language: 'bash', + }, + ], + title: 'app import-custom-data-definitions', + }, + }, + definitions: [ + { + title: 'Flags', + description: 'The following flags are available for the `app import-custom-data-definitions` command:', + type: 'appimportcustomdatadefinitions', + }, + ], + category: 'app', + related: [ + ], +} + +export default data \ No newline at end of file diff --git a/docs-shopify.dev/commands/examples/app-import-custom-data-definitions.example.sh b/docs-shopify.dev/commands/examples/app-import-custom-data-definitions.example.sh new file mode 100644 index 00000000000..a7af8e11b25 --- /dev/null +++ b/docs-shopify.dev/commands/examples/app-import-custom-data-definitions.example.sh @@ -0,0 +1 @@ +shopify app import-custom-data-definitions [flags] \ No newline at end of file diff --git a/docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts b/docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts new file mode 100644 index 00000000000..bb6c131bef9 --- /dev/null +++ b/docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts @@ -0,0 +1,50 @@ +// This is an autogenerated file. Don't edit this file manually. +export interface appimportcustomdatadefinitions { + /** + * The Client ID of your app. + * @environment SHOPIFY_FLAG_CLIENT_ID + */ + '--client-id '?: string + + /** + * The name of the app configuration. + * @environment SHOPIFY_FLAG_APP_CONFIG + */ + '-c, --config '?: string + + /** + * Include existing declared definitions in the output. + * @environment SHOPIFY_FLAG_INCLUDE_EXISTING + */ + '--include-existing'?: '' + + /** + * Disable color output. + * @environment SHOPIFY_FLAG_NO_COLOR + */ + '--no-color'?: '' + + /** + * The path to your app directory. + * @environment SHOPIFY_FLAG_PATH + */ + '--path '?: string + + /** + * Reset all your settings. + * @environment SHOPIFY_FLAG_RESET + */ + '--reset'?: '' + + /** + * Store URL. Must be an existing development or Shopify Plus sandbox store. + * @environment SHOPIFY_FLAG_STORE + */ + '-s, --store '?: string + + /** + * Increase the verbosity of the output. + * @environment SHOPIFY_FLAG_VERBOSE + */ + '--verbose'?: '' +} diff --git a/docs-shopify.dev/generated/generated_docs_data.json b/docs-shopify.dev/generated/generated_docs_data.json index 382f2cedb57..f566b109f0c 100644 --- a/docs-shopify.dev/generated/generated_docs_data.json +++ b/docs-shopify.dev/generated/generated_docs_data.json @@ -1887,6 +1887,116 @@ "category": "app", "related": [] }, + { + "name": "app import-custom-data-definitions", + "description": "Import metafield and metaobject definitions from your development store. [Read more about declarative custom data definitions](/docs/apps/build/custom-data/declarative-custom-data-definitions).", + "overviewPreviewDescription": "Import metafield and metaobject definitions.", + "type": "command", + "isVisualComponent": false, + "defaultExample": { + "codeblock": { + "tabs": [ + { + "title": "app import-custom-data-definitions", + "code": "shopify app import-custom-data-definitions [flags]", + "language": "bash" + } + ], + "title": "app import-custom-data-definitions" + } + }, + "definitions": [ + { + "title": "Flags", + "description": "The following flags are available for the `app import-custom-data-definitions` command:", + "type": "appimportcustomdatadefinitions", + "typeDefinitions": { + "appimportcustomdatadefinitions": { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "name": "appimportcustomdatadefinitions", + "description": "", + "members": [ + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--client-id ", + "value": "string", + "description": "The Client ID of your app.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_CLIENT_ID" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--include-existing", + "value": "\"\"", + "description": "Include existing declared definitions in the output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_INCLUDE_EXISTING" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-color", + "value": "\"\"", + "description": "Disable color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_COLOR" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--path ", + "value": "string", + "description": "The path to your app directory.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_PATH" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--reset", + "value": "\"\"", + "description": "Reset all your settings.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_RESET" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "\"\"", + "description": "Increase the verbosity of the output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-c, --config ", + "value": "string", + "description": "The name of the app configuration.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_APP_CONFIG" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/app-import-custom-data-definitions.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-s, --store ", + "value": "string", + "description": "Store URL. Must be an existing development or Shopify Plus sandbox store.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_STORE" + } + ], + "value": "export interface appimportcustomdatadefinitions {\n /**\n * The Client ID of your app.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id '?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config '?: string\n\n /**\n * Include existing declared definitions in the output.\n * @environment SHOPIFY_FLAG_INCLUDE_EXISTING\n */\n '--include-existing'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path '?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Store URL. Must be an existing development or Shopify Plus sandbox store.\n * @environment SHOPIFY_FLAG_STORE\n */\n '-s, --store '?: string\n\n /**\n * Increase the verbosity of the output.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" + } + } + } + ], + "category": "app", + "related": [] + }, { "name": "app import-extensions", "description": "Import dashboard-managed extensions into your app.", diff --git a/packages/app/src/cli/commands/app/import-custom-data-definitions.ts b/packages/app/src/cli/commands/app/import-custom-data-definitions.ts new file mode 100644 index 00000000000..fcf95a8760f --- /dev/null +++ b/packages/app/src/cli/commands/app/import-custom-data-definitions.ts @@ -0,0 +1,69 @@ +import {appFlags} from '../../flags.js' +import {checkFolderIsValidApp} from '../../models/app/loader.js' +import AppLinkedCommand, {AppLinkedCommandOutput} from '../../utilities/app-linked-command.js' +import {linkedAppContext} from '../../services/app-context.js' +import {storeContext} from '../../services/store-context.js' +import {importDeclarativeDefinitions} from '../../services/generate/shop-import/declarative-definitions.js' +import {Flags} from '@oclif/core' +import {normalizeStoreFqdn} from '@shopify/cli-kit/node/context/fqdn' +import {globalFlags} from '@shopify/cli-kit/node/cli' +import {renderSingleTask} from '@shopify/cli-kit/node/ui' +import {outputContent} from '@shopify/cli-kit/node/output' + +export default class ImportCustomDataDefinitions extends AppLinkedCommand { + static summary = 'Import metafield and metaobject definitions.' + + static descriptionWithMarkdown = `Import metafield and metaobject definitions from your development store. [Read more about declarative custom data definitions](https://shopify.dev/docs/apps/build/custom-data/declarative-custom-data-definitions).` + + static description = this.descriptionWithoutMarkdown() + + static flags = { + ...globalFlags, + ...appFlags, + store: Flags.string({ + char: 's', + description: 'Store URL. Must be an existing development or Shopify Plus sandbox store.', + env: 'SHOPIFY_FLAG_STORE', + parse: async (input) => normalizeStoreFqdn(input), + }), + 'include-existing': Flags.boolean({ + description: 'Include existing declared definitions in the output.', + default: false, + env: 'SHOPIFY_FLAG_INCLUDE_EXISTING', + }), + } + + public async run(): Promise { + const {appContextResult, ...options} = await renderSingleTask({ + title: outputContent`Loading application`, + task: async () => { + const {flags} = await this.parse(ImportCustomDataDefinitions) + + await checkFolderIsValidApp(flags.path) + + const appContextResult = await linkedAppContext({ + directory: flags.path, + clientId: flags['client-id'], + forceRelink: flags.reset, + userProvidedConfigName: flags.config, + }) + const store = await storeContext({ + appContextResult, + storeFqdn: flags.store, + forceReselectStore: flags.reset, + }) + + return { + appContextResult, + appConfiguration: appContextResult.app.configuration, + remoteApp: appContextResult.remoteApp, + store, + includeExistingDeclaredDefinitions: flags['include-existing'], + } + }, + }) + await importDeclarativeDefinitions(options) + + return {app: appContextResult.app} + } +} diff --git a/packages/app/src/cli/index.ts b/packages/app/src/cli/index.ts index a40d683c418..d06dfd49652 100644 --- a/packages/app/src/cli/index.ts +++ b/packages/app/src/cli/index.ts @@ -33,6 +33,7 @@ import AppLinkedCommand from './utilities/app-linked-command.js' import DevClean from './commands/app/dev/clean.js' import AppUnlinkedCommand from './utilities/app-unlinked-command.js' import FunctionInfo from './commands/app/function/info.js' +import ImportCustomDataDefinitions from './commands/app/import-custom-data-definitions.js' /** * All app commands should extend AppCommand. @@ -45,6 +46,7 @@ export const commands: {[key: string]: typeof AppLinkedCommand | typeof AppUnlin 'app:dev:clean': DevClean, 'app:logs': Logs, 'app:logs:sources': Sources, + 'app:import-custom-data-definitions': ImportCustomDataDefinitions, 'app:import-extensions': ImportExtensions, 'app:info': AppInfo, 'app:init': Init, diff --git a/packages/cli/README.md b/packages/cli/README.md index e3724c7aca7..28bfedaaefe 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -17,6 +17,7 @@ * [`shopify app function schema`](#shopify-app-function-schema) * [`shopify app function typegen`](#shopify-app-function-typegen) * [`shopify app generate extension`](#shopify-app-generate-extension) +* [`shopify app import-custom-data-definitions`](#shopify-app-import-custom-data-definitions) * [`shopify app import-extensions`](#shopify-app-import-extensions) * [`shopify app info`](#shopify-app-info) * [`shopify app init`](#shopify-app-init) @@ -578,6 +579,32 @@ DESCRIPTION refer to "App structure" (https://shopify.dev/docs/apps/tools/cli/structure) and the documentation for your extension. ``` +## `shopify app import-custom-data-definitions` + +Import metafield and metaobject definitions. + +``` +USAGE + $ shopify app import-custom-data-definitions [--client-id | -c ] [--include-existing] [--no-color] [--path ] + [--reset | ] [-s ] [--verbose] + +FLAGS + -c, --config= The name of the app configuration. + -s, --store= Store URL. Must be an existing development or Shopify Plus sandbox store. + --client-id= The Client ID of your app. + --include-existing Include existing declared definitions in the output. + --no-color Disable color output. + --path= The path to your app directory. + --reset Reset all your settings. + --verbose Increase the verbosity of the output. + +DESCRIPTION + Import metafield and metaobject definitions. + + Import metafield and metaobject definitions from your development store. "Read more about declarative custom data + definitions" (https://shopify.dev/docs/apps/build/custom-data/declarative-custom-data-definitions). +``` + ## `shopify app import-extensions` Import dashboard-managed extensions into your app. diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json index 809e0e4ccfd..81a3e15a490 100644 --- a/packages/cli/oclif.manifest.json +++ b/packages/cli/oclif.manifest.json @@ -2016,6 +2016,100 @@ "pluginType": "core", "summary": "Fetch the latest GraphQL schema for a function." }, + "app:import-custom-data-definitions": { + "aliases": [ + ], + "args": { + }, + "customPluginName": "@shopify/app", + "description": "Import metafield and metaobject definitions from your development store. \"Read more about declarative custom data definitions\" (https://shopify.dev/docs/apps/build/custom-data/declarative-custom-data-definitions).", + "descriptionWithMarkdown": "Import metafield and metaobject definitions from your development store. [Read more about declarative custom data definitions](https://shopify.dev/docs/apps/build/custom-data/declarative-custom-data-definitions).", + "flags": { + "client-id": { + "description": "The Client ID of your app.", + "env": "SHOPIFY_FLAG_CLIENT_ID", + "exclusive": [ + "config" + ], + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "client-id", + "type": "option" + }, + "config": { + "char": "c", + "description": "The name of the app configuration.", + "env": "SHOPIFY_FLAG_APP_CONFIG", + "hasDynamicHelp": false, + "hidden": false, + "multiple": false, + "name": "config", + "type": "option" + }, + "include-existing": { + "allowNo": false, + "description": "Include existing declared definitions in the output.", + "env": "SHOPIFY_FLAG_INCLUDE_EXISTING", + "name": "include-existing", + "type": "boolean" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "path": { + "description": "The path to your app directory.", + "env": "SHOPIFY_FLAG_PATH", + "hasDynamicHelp": false, + "multiple": false, + "name": "path", + "noCacheDefault": true, + "type": "option" + }, + "reset": { + "allowNo": false, + "description": "Reset all your settings.", + "env": "SHOPIFY_FLAG_RESET", + "exclusive": [ + "config" + ], + "hidden": false, + "name": "reset", + "type": "boolean" + }, + "store": { + "char": "s", + "description": "Store URL. Must be an existing development or Shopify Plus sandbox store.", + "env": "SHOPIFY_FLAG_STORE", + "hasDynamicHelp": false, + "multiple": false, + "name": "store", + "type": "option" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" + } + }, + "hasDynamicHelp": false, + "hiddenAliases": [ + ], + "id": "app:import-custom-data-definitions", + "pluginAlias": "@shopify/cli", + "pluginName": "@shopify/cli", + "pluginType": "core", + "strict": true, + "summary": "Import metafield and metaobject definitions." + }, "app:import-extensions": { "aliases": [ ], diff --git a/packages/features/snapshots/commands.txt b/packages/features/snapshots/commands.txt index 604f5ac81d5..14f6dd48c24 100644 --- a/packages/features/snapshots/commands.txt +++ b/packages/features/snapshots/commands.txt @@ -20,6 +20,7 @@ │ │ └─ typegen │ ├─ generate │ │ └─ extension +│ ├─ import-custom-data-definitions │ ├─ import-extensions │ ├─ info │ ├─ init