diff --git a/.changeset/auto-upgrade-on-json.md b/.changeset/auto-upgrade-on-json.md new file mode 100644 index 00000000000..7ec07f4302c --- /dev/null +++ b/.changeset/auto-upgrade-on-json.md @@ -0,0 +1,5 @@ +--- +'@shopify/cli': minor +--- + +Add typed JSON output to `config autoupgrade on`. diff --git a/docs-shopify.dev/generated/generated_docs_data_v2.json b/docs-shopify.dev/generated/generated_docs_data_v2.json index cb35de0a99a..6c801684173 100644 --- a/docs-shopify.dev/generated/generated_docs_data_v2.json +++ b/docs-shopify.dev/generated/generated_docs_data_v2.json @@ -4381,9 +4381,45 @@ "description": "Print the command's JSON schemas.", "isOptional": true, "environmentValue": "SHOPIFY_FLAG_JSON_SCHEMA" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/config-autoupgrade-on.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/config-autoupgrade-on.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--no-input", + "value": "''", + "description": "Disable interactive prompts and browser authentication.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_NO_INPUT" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/config-autoupgrade-on.interface.ts", + "syntaxKind": "PropertySignature", + "name": "--verbose", + "value": "''", + "description": "Increase the verbosity of the output. May include sensitive data.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_VERBOSE" + }, + { + "filePath": "docs-shopify.dev/commands/interfaces/config-autoupgrade-on.interface.ts", + "syntaxKind": "PropertySignature", + "name": "-j, --json", + "value": "''", + "description": "Output the result as JSON. Automatically disables color output.", + "isOptional": true, + "environmentValue": "SHOPIFY_FLAG_JSON" } ], - "value": "export interface configautoupgradeon {\n /**\n * Print the command's JSON schemas.\n * @environment SHOPIFY_FLAG_JSON_SCHEMA\n */\n '--json-schema'?: ''\n}" + "value": "export interface configautoupgradeon {\n /**\n * Output the result as JSON. Automatically disables color output.\n * @environment SHOPIFY_FLAG_JSON\n */\n '-j, --json'?: ''\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 * Increase the verbosity of the output. May include sensitive data.\n * @environment SHOPIFY_FLAG_VERBOSE\n */\n '--verbose'?: ''\n}" } }, "configautoupgradestatus": { diff --git a/packages/cli/README.md b/packages/cli/README.md index 4a506d0561d..b35006dae81 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -3878,13 +3878,29 @@ Enable automatic upgrades for Shopify CLI. ``` USAGE - $ shopify config autoupgrade on [--json-schema] + $ shopify config autoupgrade on [-j] [--json-schema] [--no-color] [--no-input] [--verbose] FLAGS + -j, --json + Output the result as JSON. Automatically disables color output. + [env: SHOPIFY_FLAG_JSON] + --json-schema Print the command's JSON schemas. [env: SHOPIFY_FLAG_JSON_SCHEMA] + --no-color + Disable color output. + [env: SHOPIFY_FLAG_NO_COLOR] + + --no-input + Disable interactive prompts and browser authentication. + [env: SHOPIFY_FLAG_NO_INPUT] + + --verbose + Increase the verbosity of the output. May include sensitive data. + [env: SHOPIFY_FLAG_VERBOSE] + DESCRIPTION Enable automatic upgrades for Shopify CLI. @@ -3894,6 +3910,28 @@ DESCRIPTION upgrades are skipped and must be done manually. To disable auto-upgrade, run `shopify config autoupgrade off`. + + + Use `--json-schema` to print the result, error, and event schemas. + + Output from `--json` conforms to the `AutoUpgradeResult` schema. + + ```json + { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false, + "title": "AutoUpgradeResult", + "$schema": "http://json-schema.org/draft-07/schema#" + } + ``` ``` ## `shopify config autoupgrade status` diff --git a/packages/cli/oclif.manifest.json b/packages/cli/oclif.manifest.json index 2afa43d8a84..ec92bdf391d 100644 --- a/packages/cli/oclif.manifest.json +++ b/packages/cli/oclif.manifest.json @@ -5831,16 +5831,48 @@ ], "args": { }, - "description": "Enable automatic upgrades for Shopify CLI.\n\n When auto-upgrade is enabled, Shopify CLI automatically updates to the latest version once per day. Major version upgrades are skipped and must be done manually.\n\n To disable auto-upgrade, run `shopify config autoupgrade off`.\n", + "description": "Enable automatic upgrades for Shopify CLI.\n\n When auto-upgrade is enabled, Shopify CLI automatically updates to the latest version once per day. Major version upgrades are skipped and must be done manually.\n\n To disable auto-upgrade, run `shopify config autoupgrade off`.\n\n\nUse `--json-schema` to print the result, error, and event schemas.\n\nOutput from `--json` conforms to the `AutoUpgradeResult` schema.\n\n```json\n{\n \"type\": \"object\",\n \"properties\": {\n \"enabled\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"enabled\"\n ],\n \"additionalProperties\": false,\n \"title\": \"AutoUpgradeResult\",\n \"$schema\": \"http://json-schema.org/draft-07/schema#\"\n}\n```", "descriptionWithMarkdown": "Enable automatic upgrades for Shopify CLI.\n\n When auto-upgrade is enabled, Shopify CLI automatically updates to the latest version once per day. Major version upgrades are skipped and must be done manually.\n\n To disable auto-upgrade, run `shopify config autoupgrade off`.\n", "enableJsonFlag": false, "flags": { + "json": { + "allowNo": false, + "char": "j", + "description": "Output the result as JSON. Automatically disables color output.", + "env": "SHOPIFY_FLAG_JSON", + "hidden": false, + "name": "json", + "type": "boolean" + }, "json-schema": { "allowNo": false, "description": "Print the command's JSON schemas.", "env": "SHOPIFY_FLAG_JSON_SCHEMA", "name": "json-schema", "type": "boolean" + }, + "no-color": { + "allowNo": false, + "description": "Disable color output.", + "env": "SHOPIFY_FLAG_NO_COLOR", + "hidden": false, + "name": "no-color", + "type": "boolean" + }, + "no-input": { + "allowNo": false, + "description": "Disable interactive prompts and browser authentication.", + "env": "SHOPIFY_FLAG_NO_INPUT", + "name": "no-input", + "type": "boolean" + }, + "verbose": { + "allowNo": false, + "description": "Increase the verbosity of the output. May include sensitive data.", + "env": "SHOPIFY_FLAG_VERBOSE", + "hidden": false, + "name": "verbose", + "type": "boolean" } }, "hasDynamicHelp": false, diff --git a/packages/cli/src/cli/commands/config/autoupgrade/autoupgrade.test.ts b/packages/cli/src/cli/commands/config/autoupgrade/autoupgrade.test.ts index 42f7ef95bcc..9b474bbe656 100644 --- a/packages/cli/src/cli/commands/config/autoupgrade/autoupgrade.test.ts +++ b/packages/cli/src/cli/commands/config/autoupgrade/autoupgrade.test.ts @@ -1,3 +1,4 @@ +import AutoupgradeOn from './on.js' import AutoupgradeStatus from './status.js' import {autoUpgradeJsonOutputSchema} from '../../../services/commands/config/autoupgrade/types.js' import {getAutoUpgradeEnabled, setAutoUpgradeEnabled} from '@shopify/cli-kit/node/upgrade' @@ -21,7 +22,10 @@ afterEach(() => { mockAndCaptureOutput().clear() }) -const commands = [{name: 'status', command: AutoupgradeStatus, enabled: false}] +const commands = [ + {name: 'status', command: AutoupgradeStatus, enabled: false}, + {name: 'on', command: AutoupgradeOn, enabled: true}, +] test.each(commands)('$name exposes the result schema and JSON flags in help', ({command}) => { expect(command.jsonOutputSchema).toBe(autoUpgradeJsonOutputSchema) diff --git a/packages/cli/src/cli/commands/config/autoupgrade/on.test.ts b/packages/cli/src/cli/commands/config/autoupgrade/on.test.ts index 76c4a83bd8d..18c46bf67e2 100644 --- a/packages/cli/src/cli/commands/config/autoupgrade/on.test.ts +++ b/packages/cli/src/cli/commands/config/autoupgrade/on.test.ts @@ -1,6 +1,5 @@ import AutoupgradeOn from './on.js' import {setAutoUpgradeEnabled} from '@shopify/cli-kit/node/upgrade' -import {Config} from '@oclif/core' import {describe, expect, vi, test} from 'vitest' import {mockAndCaptureOutput} from '@shopify/cli-kit/node/testing/output' @@ -9,11 +8,10 @@ vi.mock('@shopify/cli-kit/node/upgrade') describe('AutoupgradeOn', () => { test('enables auto-upgrade', async () => { // Given - const config = new Config({root: __dirname}) const outputMock = mockAndCaptureOutput() // When - await new AutoupgradeOn([], config).run() + await AutoupgradeOn.run([], import.meta.url) // Then expect(setAutoUpgradeEnabled).toBeCalledWith(true) diff --git a/packages/cli/src/cli/commands/config/autoupgrade/on.ts b/packages/cli/src/cli/commands/config/autoupgrade/on.ts index c9cc94aa089..9189a697e5d 100644 --- a/packages/cli/src/cli/commands/config/autoupgrade/on.ts +++ b/packages/cli/src/cli/commands/config/autoupgrade/on.ts @@ -1,7 +1,8 @@ -import {autoUpgradeStatus} from './constants.js' -import {setAutoUpgradeEnabled} from '@shopify/cli-kit/node/upgrade' +import {configureAutoUpgrade} from '../../../services/commands/config/autoupgrade/index.js' +import {presentAutoUpgradeResult} from '../../../services/commands/config/autoupgrade/result.js' +import {autoUpgradeJsonOutputSchema} from '../../../services/commands/config/autoupgrade/types.js' import Command from '@shopify/cli-kit/node/base-command' -import {renderInfo} from '@shopify/cli-kit/node/ui' +import {globalFlags, jsonFlag} from '@shopify/cli-kit/node/cli' export default class AutoupgradeOn extends Command { static summary = 'Enable automatic upgrades for Shopify CLI.' @@ -15,8 +16,18 @@ export default class AutoupgradeOn extends Command { static description = this.descriptionForHelp() + static flags = { + ...globalFlags, + ...jsonFlag, + } + + static get jsonOutputSchema() { + return autoUpgradeJsonOutputSchema + } + async run(): Promise { - setAutoUpgradeEnabled(true) - renderInfo({body: autoUpgradeStatus.on}) + const {flags} = await this.parse(AutoupgradeOn) + const result = configureAutoUpgrade(true) + presentAutoUpgradeResult(result, flags.json ? 'json' : 'text') } } diff --git a/packages/cli/src/cli/services/commands/config/autoupgrade/index.test.ts b/packages/cli/src/cli/services/commands/config/autoupgrade/index.test.ts index 3412c9784de..150fbd861d9 100644 --- a/packages/cli/src/cli/services/commands/config/autoupgrade/index.test.ts +++ b/packages/cli/src/cli/services/commands/config/autoupgrade/index.test.ts @@ -1,4 +1,4 @@ -import {getAutoUpgradeStatus} from './index.js' +import {configureAutoUpgrade, getAutoUpgradeStatus} from './index.js' import * as upgrade from '@shopify/cli-kit/node/upgrade' import {LocalStorage} from '@shopify/cli-kit/node/local-storage' import {inTemporaryDirectory} from '@shopify/cli-kit/node/fs' @@ -9,17 +9,18 @@ afterEach(() => { mockAndCaptureOutput().clear() }) -test('returns the default and persisted preferences without presenting output', async () => { +test('returns the default preference and persists each configured value without presenting output', async () => { await inTemporaryDirectory(async (directory) => { const storage = new LocalStorage<{sessionStore: string; autoUpgradeEnabled?: boolean}>({cwd: directory}) const {getAutoUpgradeEnabled, setAutoUpgradeEnabled} = upgrade vi.spyOn(upgrade, 'getAutoUpgradeEnabled').mockImplementation(() => getAutoUpgradeEnabled(storage)) + vi.spyOn(upgrade, 'setAutoUpgradeEnabled').mockImplementation((enabled) => setAutoUpgradeEnabled(enabled, storage)) const output = mockAndCaptureOutput() expect(getAutoUpgradeStatus()).toEqual({enabled: true}) for (const enabled of [false, true]) { - setAutoUpgradeEnabled(enabled, storage) + expect(configureAutoUpgrade(enabled)).toEqual({enabled}) expect(getAutoUpgradeStatus()).toEqual({enabled}) const reloadedStorage = new LocalStorage<{sessionStore: string; autoUpgradeEnabled?: boolean}>({cwd: directory}) expect(reloadedStorage.get('autoUpgradeEnabled')).toBe(enabled) @@ -30,6 +31,15 @@ test('returns the default and persisted preferences without presenting output', }) }) +test('propagates a configuration write failure', () => { + const error = new Error('Cannot save auto-upgrade preference.') + vi.spyOn(upgrade, 'setAutoUpgradeEnabled').mockImplementation(() => { + throw error + }) + + expect(() => configureAutoUpgrade(false)).toThrow(error) +}) + test('propagates a configuration read failure', () => { const error = new Error('Cannot read auto-upgrade preference.') vi.spyOn(upgrade, 'getAutoUpgradeEnabled').mockImplementation(() => { diff --git a/packages/cli/src/cli/services/commands/config/autoupgrade/index.ts b/packages/cli/src/cli/services/commands/config/autoupgrade/index.ts index 72e50603fcd..b6f059a62bc 100644 --- a/packages/cli/src/cli/services/commands/config/autoupgrade/index.ts +++ b/packages/cli/src/cli/services/commands/config/autoupgrade/index.ts @@ -1,6 +1,11 @@ -import {getAutoUpgradeEnabled} from '@shopify/cli-kit/node/upgrade' +import {getAutoUpgradeEnabled, setAutoUpgradeEnabled} from '@shopify/cli-kit/node/upgrade' import type {AutoUpgradeResult} from './types.js' export function getAutoUpgradeStatus(): AutoUpgradeResult { return {enabled: getAutoUpgradeEnabled()} } + +export function configureAutoUpgrade(enabled: boolean): AutoUpgradeResult { + setAutoUpgradeEnabled(enabled) + return {enabled} +} diff --git a/packages/eslint-plugin-cli/rules/json-output-command-exceptions.js b/packages/eslint-plugin-cli/rules/json-output-command-exceptions.js index 7a84b47bd83..5a54fb83c75 100644 --- a/packages/eslint-plugin-cli/rules/json-output-command-exceptions.js +++ b/packages/eslint-plugin-cli/rules/json-output-command-exceptions.js @@ -35,7 +35,6 @@ const commandExceptions = [ 'packages/cli/src/cli/commands/auth/login.ts', 'packages/cli/src/cli/commands/auth/logout.ts', 'packages/cli/src/cli/commands/config/autoupgrade/off.ts', - 'packages/cli/src/cli/commands/config/autoupgrade/on.ts', 'packages/cli/src/cli/commands/doc/fetch.ts', 'packages/cli/src/cli/commands/doc/search.ts', 'packages/cli/src/cli/commands/upgrade.ts',