Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/config-link-flag-error.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/app': patch
---

Clarify `app config link` flags and recommend `--file-name` when both `--config` and `--client-id` are provided
8 changes: 4 additions & 4 deletions docs-shopify.dev/generated/generated_docs_data_v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@
"syntaxKind": "PropertySignature",
"name": "--client-id <value>",
"value": "string",
"description": "The Client ID of your app. Required if non interactive.",
"description": "The Client ID of the remote app to link. Use --file-name to specify the destination configuration file. Required if non interactive.",
"isOptional": true,
"environmentValue": "SHOPIFY_FLAG_CLIENT_ID"
},
Expand All @@ -513,7 +513,7 @@
"syntaxKind": "PropertySignature",
"name": "--file-name <value>",
"value": "string",
"description": "The name of the app configuration file to create or overwrite.",
"description": "The name of the app configuration file to create or overwrite. Requires --force to overwrite an existing file.",
"isOptional": true,
"environmentValue": "SHOPIFY_FLAG_APP_CONFIG_FILE_NAME"
},
Expand Down Expand Up @@ -585,12 +585,12 @@
"syntaxKind": "PropertySignature",
"name": "-c, --config <value>",
"value": "string",
"description": "The name of the app configuration.",
"description": "The name of the local app configuration to read and overwrite. Use --file-name instead when specifying --client-id.",
"isOptional": true,
"environmentValue": "SHOPIFY_FLAG_APP_CONFIG"
}
],
"value": "export interface appconfiglink {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias <value>'?: string\n\n /**\n * The Client ID of your app. Required if non interactive.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id <value>'?: string\n\n /**\n * The name of the app configuration.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config <value>'?: string\n\n /**\n * The name of the app configuration file to create or overwrite.\n * @environment SHOPIFY_FLAG_APP_CONFIG_FILE_NAME\n */\n '--file-name <value>'?: string\n\n /**\n * Overwrite an existing configuration file without prompting.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '--force'?: ''\n\n /**\n * Print the command's JSON schemas.\n * @environment SHOPIFY_FLAG_JSON_SCHEMA\n */\n '--json-schema'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Disable interactive prompts and browser authentication.\n * @environment SHOPIFY_FLAG_NO_INPUT\n */\n '--no-input'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path <value>'?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output. May include sensitive data.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}"
"value": "export interface appconfiglink {\n /**\n * Alias of the Shopify account to use for authentication.\n * @environment SHOPIFY_FLAG_AUTH_ALIAS\n */\n '--auth-alias <value>'?: string\n\n /**\n * The Client ID of the remote app to link. Use --file-name to specify the destination configuration file. Required if non interactive.\n * @environment SHOPIFY_FLAG_CLIENT_ID\n */\n '--client-id <value>'?: string\n\n /**\n * The name of the local app configuration to read and overwrite. Use --file-name instead when specifying --client-id.\n * @environment SHOPIFY_FLAG_APP_CONFIG\n */\n '-c, --config <value>'?: string\n\n /**\n * The name of the app configuration file to create or overwrite. Requires --force to overwrite an existing file.\n * @environment SHOPIFY_FLAG_APP_CONFIG_FILE_NAME\n */\n '--file-name <value>'?: string\n\n /**\n * Overwrite an existing configuration file without prompting.\n * @environment SHOPIFY_FLAG_FORCE\n */\n '--force'?: ''\n\n /**\n * Print the command's JSON schemas.\n * @environment SHOPIFY_FLAG_JSON_SCHEMA\n */\n '--json-schema'?: ''\n\n /**\n * Disable color output.\n * @environment SHOPIFY_FLAG_NO_COLOR\n */\n '--no-color'?: ''\n\n /**\n * Disable interactive prompts and browser authentication.\n * @environment SHOPIFY_FLAG_NO_INPUT\n */\n '--no-input'?: ''\n\n /**\n * The path to your app directory.\n * @environment SHOPIFY_FLAG_PATH\n */\n '--path <value>'?: string\n\n /**\n * Reset all your settings.\n * @environment SHOPIFY_FLAG_RESET\n */\n '--reset'?: ''\n\n /**\n * Increase the verbosity of the output. May include sensitive data.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}"
}
},
"appconfigpull": {
Expand Down
32 changes: 31 additions & 1 deletion packages/app/src/cli/commands/app/config/link.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import ConfigLink from './link.js'
import link from '../../../services/app/config/link.js'
import {linkedAppContext} from '../../../services/app-context.js'
import {testAppLinked, testOrganizationApp} from '../../../models/app/app.test-data.js'
import {Config} from '@oclif/core'
import {inTemporaryDirectory} from '@shopify/cli-kit/node/fs'
import {terminalSupportsPrompting} from '@shopify/cli-kit/node/system'
import {beforeEach, describe, expect, test, vi} from 'vitest'
import {afterEach, beforeEach, describe, expect, test, vi} from 'vitest'

vi.mock('../../../services/app/config/link.js')
vi.mock('../../../services/app-context.js')
Expand All @@ -15,6 +16,35 @@ describe('app config link command', () => {
vi.mocked(link).mockReset()
vi.mocked(linkedAppContext).mockReset()
vi.mocked(terminalSupportsPrompting).mockReturnValue(true)
vi.stubEnv('SHOPIFY_FLAG_APP_CONFIG', undefined)
vi.stubEnv('SHOPIFY_FLAG_CLIENT_ID', undefined)
})

afterEach(() => {
vi.unstubAllEnvs()
})

test.each([
{name: 'both flags', args: ['--config', 'staging', '--client-id', 'api-key']},
{name: 'the short config flag', args: ['-c', 'staging', '--client-id', 'api-key']},
{name: 'an empty config value', args: ['--config', '', '--client-id', 'api-key']},
{name: 'config from the environment', args: ['--client-id', 'api-key'], config: 'staging'},
{name: 'client ID from the environment', args: ['--config', 'staging'], clientId: 'api-key'},
{name: 'both environment variables', args: [], config: 'staging', clientId: 'api-key'},
])('recommends --file-name when using $name', async ({args, config, clientId}) => {
vi.stubEnv('SHOPIFY_FLAG_APP_CONFIG', config)
vi.stubEnv('SHOPIFY_FLAG_CLIENT_ID', clientId)

await inTemporaryDirectory(async (tmp) => {
const command = new ConfigLink(['--path', tmp, ...args], await Config.load(import.meta.url))
await expect(command.run()).rejects.toMatchObject({
message: "The --config and --client-id flags can't be used together.",
tryMessage: 'Use --file-name instead of --config to choose the configuration file to create or overwrite.',
})

expect(link).not.toHaveBeenCalled()
expect(linkedAppContext).not.toHaveBeenCalled()
})
})

test('accepts --client-id with --file-name to link a specific app to a specific config file', async () => {
Expand Down
28 changes: 26 additions & 2 deletions packages/app/src/cli/commands/app/config/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import link, {LinkOptions} from '../../../services/app/config/link.js'
import AppLinkedCommand, {AppLinkedCommandOutput} from '../../../utilities/app-linked-command.js'
import {Flags} from '@oclif/core'
import {globalFlags, requiredIfNonInteractive} from '@shopify/cli-kit/node/cli'
import {AbortError} from '@shopify/cli-kit/node/error'

export default class ConfigLink extends AppLinkedCommand {
static summary = 'Fetch your app configuration from the Developer Dashboard.'
Expand All @@ -18,15 +19,31 @@ export default class ConfigLink extends AppLinkedCommand {
static flags = {
...globalFlags,
...appFlags,
config: Flags.string({
hidden: false,
char: 'c',
description:
'The name of the local app configuration to read and overwrite. Use --file-name instead when specifying --client-id.',
env: 'SHOPIFY_FLAG_APP_CONFIG',
}),
'organization-id': Flags.string({
hidden: true,
env: 'SHOPIFY_FLAG_ORGANIZATION_ID',
exclusive: ['client-id'],
}),
'client-id': requiredIfNonInteractive(appFlags['client-id']),
// Validate this conflict in run() so we can recommend --file-name.
'client-id': requiredIfNonInteractive(
Flags.string({
hidden: false,
description:
'The Client ID of the remote app to link. Use --file-name to specify the destination configuration file.',
env: 'SHOPIFY_FLAG_CLIENT_ID',
}),
),
'file-name': Flags.string({
hidden: false,
description: 'The name of the app configuration file to create or overwrite.',
description:
'The name of the app configuration file to create or overwrite. Requires --force to overwrite an existing file.',
env: 'SHOPIFY_FLAG_APP_CONFIG_FILE_NAME',
exclusive: ['config'],
}),
Expand All @@ -41,6 +58,13 @@ export default class ConfigLink extends AppLinkedCommand {
public async run(): Promise<AppLinkedCommandOutput> {
const {flags} = await this.parse(ConfigLink)

if (flags.config !== undefined && flags['client-id'] !== undefined) {
throw new AbortError(
"The --config and --client-id flags can't be used together.",
'Use --file-name instead of --config to choose the configuration file to create or overwrite.',
)
}

const options: LinkOptions = {
directory: flags.path,
apiKey: flags['client-id'],
Expand Down
11 changes: 6 additions & 5 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -410,24 +410,25 @@ Fetch your app configuration from the Developer Dashboard.

```
USAGE
$ shopify app config link [--auth-alias <value>] [--client-id <value> | -c <value>] [--force [--file-name <value> |
]] [--json-schema] [--no-color] [--no-input] [--path <value>] [--reset | ] [--verbose]
$ shopify app config link [--auth-alias <value>] [--client-id <value>] [--force [--file-name <value> | -c <value>]]
[--json-schema] [--no-color] [--no-input] [--path <value>] [--reset | ] [--verbose]

FLAGS
-c, --config=<value>
The name of the app configuration.
The name of the local app configuration to read and overwrite. Use --file-name instead when specifying --client-id.
[env: SHOPIFY_FLAG_APP_CONFIG]

--auth-alias=<value>
Alias of the Shopify account to use for authentication.
[env: SHOPIFY_FLAG_AUTH_ALIAS]

--client-id=<value>
The Client ID of your app. Required if non interactive.
The Client ID of the remote app to link. Use --file-name to specify the destination configuration file. Required if
non interactive.
[env: SHOPIFY_FLAG_CLIENT_ID]

--file-name=<value>
The name of the app configuration file to create or overwrite.
The name of the app configuration file to create or overwrite. Requires --force to overwrite an existing file.
[env: SHOPIFY_FLAG_APP_CONFIG_FILE_NAME]

--force
Expand Down
9 changes: 3 additions & 6 deletions packages/cli/oclif.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -536,11 +536,8 @@
"type": "option"
},
"client-id": {
"description": "The Client ID of your app. Required if non interactive.",
"description": "The Client ID of the remote app to link. Use --file-name to specify the destination configuration file. Required if non interactive.",
"env": "SHOPIFY_FLAG_CLIENT_ID",
"exclusive": [
"config"
],
"hasDynamicHelp": false,
"hidden": false,
"multiple": false,
Expand All @@ -549,7 +546,7 @@
},
"config": {
"char": "c",
"description": "The name of the app configuration.",
"description": "The name of the local app configuration to read and overwrite. Use --file-name instead when specifying --client-id.",
"env": "SHOPIFY_FLAG_APP_CONFIG",
"hasDynamicHelp": false,
"hidden": false,
Expand All @@ -558,7 +555,7 @@
"type": "option"
},
"file-name": {
"description": "The name of the app configuration file to create or overwrite.",
"description": "The name of the app configuration file to create or overwrite. Requires --force to overwrite an existing file.",
"env": "SHOPIFY_FLAG_APP_CONFIG_FILE_NAME",
"exclusive": [
"config"
Expand Down
Loading