From 51b781532ae74e805fa15ddc66b04204b2366f26 Mon Sep 17 00:00:00 2001 From: Gonzalo Riestra Date: Mon, 25 May 2026 14:22:17 +0200 Subject: [PATCH] Allow app config validate to target config by client ID --- .../cli/commands/app/config/validate.test.ts | 20 +++++++++++++++++++ .../src/cli/commands/app/config/validate.ts | 6 ++++++ packages/cli/README.md | 2 +- packages/cli/oclif.manifest.json | 3 --- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/app/src/cli/commands/app/config/validate.test.ts b/packages/app/src/cli/commands/app/config/validate.test.ts index 98fdd12ce00..000c3458d44 100644 --- a/packages/app/src/cli/commands/app/config/validate.test.ts +++ b/packages/app/src/cli/commands/app/config/validate.test.ts @@ -72,6 +72,26 @@ describe('app config validate command', () => { await expectValidationMetadataCalls({cmd_app_validate_json: true}) }) + test('accepts --client-id with --config to validate a specific linked app configuration', async () => { + const app = testAppLinked() + mockHealthyProject() + vi.mocked(linkedAppContext).mockResolvedValue({app} as Awaited>) + vi.mocked(validateApp).mockResolvedValue() + + await Validate.run(['--client-id', 'api-key', '--config', 'staging'], import.meta.url) + + expect(selectActiveConfig).toHaveBeenCalledWith(expect.anything(), 'staging') + expect(linkedAppContext).toHaveBeenCalledWith({ + directory: expect.any(String), + clientId: 'api-key', + forceRelink: false, + userProvidedConfigName: 'staging', + unsafeTolerateErrors: true, + }) + expect(validateApp).toHaveBeenCalledWith(app, {json: false}) + await expectValidationMetadataCalls({cmd_app_validate_json: false}) + }) + test('outputs JSON issues when active config has TOML parse errors', async () => { vi.mocked(Project.load).mockResolvedValue({errors: []} as unknown as Project) vi.mocked(selectActiveConfig).mockResolvedValue({file: new TomlFile('shopify.app.toml', {})} as any) diff --git a/packages/app/src/cli/commands/app/config/validate.ts b/packages/app/src/cli/commands/app/config/validate.ts index 4da9ddc48ba..95a800cc033 100644 --- a/packages/app/src/cli/commands/app/config/validate.ts +++ b/packages/app/src/cli/commands/app/config/validate.ts @@ -10,6 +10,7 @@ import {globalFlags, jsonFlag} from '@shopify/cli-kit/node/cli' import {AbortError, AbortSilentError} from '@shopify/cli-kit/node/error' import {outputResult, stringifyMessage, unstyled} from '@shopify/cli-kit/node/output' import {renderError} from '@shopify/cli-kit/node/ui' +import {Flags} from '@oclif/core' async function recordValidationFailure(issueCount: number, fileCount: number) { await metadata.addPublicMetadata(() => ({ @@ -29,6 +30,11 @@ export default class Validate extends AppLinkedCommand { static flags = { ...globalFlags, ...appFlags, + 'client-id': Flags.string({ + hidden: false, + description: 'The Client ID of your app.', + env: 'SHOPIFY_FLAG_CLIENT_ID', + }), ...jsonFlag, } diff --git a/packages/cli/README.md b/packages/cli/README.md index e903c4e7b79..5a09522a617 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -317,7 +317,7 @@ Validate your app configuration and extensions. ``` USAGE - $ shopify app config validate [--client-id | -c ] [-j] [--no-color] [--path ] [--reset | ] + $ shopify app config validate [--client-id ] [-j] [--no-color] [--path ] [--reset | -c ] [--verbose] FLAGS diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json index deade50bdac..db618ce811f 100644 --- a/packages/cli/oclif.manifest.json +++ b/packages/cli/oclif.manifest.json @@ -668,9 +668,6 @@ "client-id": { "description": "The Client ID of your app.", "env": "SHOPIFY_FLAG_CLIENT_ID", - "exclusive": [ - "config" - ], "hasDynamicHelp": false, "hidden": false, "multiple": false,