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/auto-upgrade-status-json.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/cli': minor
---

Add typed JSON output to `config autoupgrade status`.
38 changes: 37 additions & 1 deletion docs-shopify.dev/generated/generated_docs_data_v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -4401,9 +4401,45 @@
"description": "Print the command's JSON schemas.",
"isOptional": true,
"environmentValue": "SHOPIFY_FLAG_JSON_SCHEMA"
},
{
"filePath": "docs-shopify.dev/commands/interfaces/config-autoupgrade-status.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-status.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-status.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-status.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 configautoupgradestatus {\n /**\n * Print the command's JSON schemas.\n * @environment SHOPIFY_FLAG_JSON_SCHEMA\n */\n '--json-schema'?: ''\n}"
"value": "export interface configautoupgradestatus {\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}"
}
},
"docfetch": {
Expand Down
40 changes: 39 additions & 1 deletion packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3902,13 +3902,29 @@ Check whether auto-upgrade is enabled, disabled, or not yet configured.

```
USAGE
$ shopify config autoupgrade status [--json-schema]
$ shopify config autoupgrade status [-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
Check whether auto-upgrade is enabled, disabled, or not yet configured.

Expand All @@ -3917,6 +3933,28 @@ DESCRIPTION
When auto-upgrade is enabled, Shopify CLI automatically updates to the latest version after each command.

Run `shopify config autoupgrade on` or `shopify config autoupgrade off` to configure it.


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 doc fetch`
Expand Down
34 changes: 33 additions & 1 deletion packages/cli/oclif.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5858,16 +5858,48 @@
],
"args": {
},
"description": "Check whether auto-upgrade is enabled, disabled, or not yet configured.\n\n When auto-upgrade is enabled, Shopify CLI automatically updates to the latest version after each command.\n\n Run `shopify config autoupgrade on` or `shopify config autoupgrade off` to configure it.\n",
"description": "Check whether auto-upgrade is enabled, disabled, or not yet configured.\n\n When auto-upgrade is enabled, Shopify CLI automatically updates to the latest version after each command.\n\n Run `shopify config autoupgrade on` or `shopify config autoupgrade off` to configure it.\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": "Check whether auto-upgrade is enabled, disabled, or not yet configured.\n\n When auto-upgrade is enabled, Shopify CLI automatically updates to the latest version after each command.\n\n Run `shopify config autoupgrade on` or `shopify config autoupgrade off` to configure it.\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,
Expand Down
142 changes: 142 additions & 0 deletions packages/cli/src/cli/commands/config/autoupgrade/autoupgrade.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import AutoupgradeStatus from './status.js'
import {autoUpgradeJsonOutputSchema} from '../../../services/commands/config/autoupgrade/types.js'
import {getAutoUpgradeEnabled, setAutoUpgradeEnabled} from '@shopify/cli-kit/node/upgrade'
import {launchCLI} from '@shopify/cli-kit/node/cli-launcher'
import {ShopifyConfig} from '@shopify/cli-kit/node/custom-oclif-loader'
import {AbortError} from '@shopify/cli-kit/node/error'
import {outputWarn} from '@shopify/cli-kit/node/output'
import {mockAndCaptureOutput, withCapturedStandardStreams} from '@shopify/cli-kit/node/testing/output'
import {beforeEach, afterEach, expect, test, vi} from 'vitest'

vi.mock('@shopify/cli-kit/node/upgrade')

beforeEach(() => {
vi.stubEnv('CI', '1')
vi.stubEnv('SHOPIFY_CLI_NO_ANALYTICS', '1')
vi.spyOn(ShopifyConfig.prototype, 'runHook').mockResolvedValue({successes: [], failures: []})
})

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

const commands = [{name: 'status', command: AutoupgradeStatus, enabled: false}]

test.each(commands)('$name exposes the result schema and JSON flags in help', ({command}) => {
expect(command.jsonOutputSchema).toBe(autoUpgradeJsonOutputSchema)
expect(command.flags.json.char).toBe('j')
expect(command.description).toContain('Output from `--json` conforms to the `AutoUpgradeResult` schema.')
expect(command.description).toContain('"enabled"')
})

test.each(commands)('$name writes one JSON document through the real launcher', async ({name, command, enabled}) => {
vi.mocked(getAutoUpgradeEnabled).mockReturnValue(enabled)

await withCapturedStandardStreams(async ({stdout, stderr}) => {
await launchCLI({
moduleURL: import.meta.url,
argv: ['config', 'autoupgrade', name, '--json'],
lazyCommandLoader: async () => command,
})

expect(stdout()).toBe(`${JSON.stringify({enabled}, null, 2)}\n`)
expect(JSON.parse(stdout())).toEqual({enabled})
expect(stderr()).toBe('')
if (name === 'status') {
expect(setAutoUpgradeEnabled).not.toHaveBeenCalled()
} else {
expect(setAutoUpgradeEnabled).toHaveBeenCalledExactlyOnceWith(enabled)
}
})
})

test.each(commands)('$name discovers the schema without changing configuration', async ({name, command}) => {
await withCapturedStandardStreams(async ({stdout, stderr}) => {
await launchCLI({
moduleURL: import.meta.url,
argv: ['config', 'autoupgrade', name, '--json-schema'],
lazyCommandLoader: async () => command,
})

expect(JSON.parse(stdout()).definitions.Result).toMatchObject({
type: 'object',
properties: {enabled: {type: 'boolean'}},
required: ['enabled'],
additionalProperties: false,
})
expect(stderr()).toBe('')
expect(setAutoUpgradeEnabled).not.toHaveBeenCalled()
expect(getAutoUpgradeEnabled).not.toHaveBeenCalled()
})
})

test.each([
{args: ['-j'], json: true},
{args: ['--json', '--no-input'], json: true},
{args: ['--no-input'], json: false},
])('selects JSON independently from input policy for $args', async ({args, json}) => {
vi.mocked(getAutoUpgradeEnabled).mockReturnValue(true)

await withCapturedStandardStreams(async ({stdout, stderr}) => {
await AutoupgradeStatus.run(args, import.meta.url)

if (json) {
expect(JSON.parse(stdout())).toEqual({enabled: true})
expect(stderr()).toBe('')
} else {
expect(stdout()).toBe('')
expect(stderr()).toContain('Auto-upgrade on.')
}
})
})

test('selects JSON from SHOPIFY_FLAG_JSON', async () => {
vi.stubEnv('SHOPIFY_FLAG_JSON', '1')
vi.mocked(getAutoUpgradeEnabled).mockReturnValue(true)

await withCapturedStandardStreams(async ({stdout, stderr}) => {
await AutoupgradeStatus.run([], import.meta.url)

expect(JSON.parse(stdout())).toEqual({enabled: true})
expect(stderr()).toBe('')
})
})

test('keeps diagnostic events on stderr and out of the final result', async () => {
vi.mocked(getAutoUpgradeEnabled).mockImplementation(() => {
outputWarn('Configuration diagnostic')
return false
})

await withCapturedStandardStreams(async ({stdout, stderr}) => {
await AutoupgradeStatus.run(['--json'], import.meta.url)

expect(JSON.parse(stdout())).toEqual({enabled: false})
expect(JSON.parse(stderr())).toMatchObject({
type: 'diagnostic',
level: 'warning',
message: 'Configuration diagnostic',
})
})
})

test.each(commands)('$name uses the standard fatal error output without a success result', async ({command, name}) => {
vi.stubEnv('SHOPIFY_FLAG_JSON', '1')
const error = new AbortError('Cannot access auto-upgrade preference.')
const exit = vi.spyOn(process, 'exit').mockReturnValue(undefined as never)
const operation = name === 'status' ? getAutoUpgradeEnabled : setAutoUpgradeEnabled
vi.mocked(operation).mockImplementation(() => {
throw error
})

await withCapturedStandardStreams(async ({stdout, stderr}) => {
await command.run(['--json'], import.meta.url)

expect(JSON.parse(stdout())).toEqual({
error: {type: 'abort', message: 'Cannot access auto-upgrade preference.'},
})
expect(stderr()).toBe('')
expect(exit).toHaveBeenCalledExactlyOnceWith(1)
})
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import AutoupgradeStatus from './status.js'
import {getAutoUpgradeEnabled} 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'

Expand All @@ -10,12 +9,11 @@ describe('AutoupgradeStatus', () => {
test('displays auto-upgrade on message when enabled', async () => {
// Given
vi.mocked(getAutoUpgradeEnabled).mockReturnValue(true)
const config = new Config({root: __dirname})
const outputMock = mockAndCaptureOutput()
outputMock.clear()

// When
await new AutoupgradeStatus([], config).run()
await AutoupgradeStatus.run([], import.meta.url)

// Then
expect(outputMock.info()).toMatchInlineSnapshot(`
Expand All @@ -31,12 +29,11 @@ describe('AutoupgradeStatus', () => {
test('displays auto-upgrade off message when disabled', async () => {
// Given
vi.mocked(getAutoUpgradeEnabled).mockReturnValue(false)
const config = new Config({root: __dirname})
const outputMock = mockAndCaptureOutput()
outputMock.clear()

// When
await new AutoupgradeStatus([], config).run()
await AutoupgradeStatus.run([], import.meta.url)

// Then
expect(outputMock.info()).toMatchInlineSnapshot(`
Expand All @@ -52,12 +49,11 @@ describe('AutoupgradeStatus', () => {
test('displays auto-upgrade on message when never explicitly set (default enabled)', async () => {
// Given
vi.mocked(getAutoUpgradeEnabled).mockReturnValue(true)
const config = new Config({root: __dirname})
const outputMock = mockAndCaptureOutput()
outputMock.clear()

// When
await new AutoupgradeStatus([], config).run()
await AutoupgradeStatus.run([], import.meta.url)

// Then
expect(outputMock.info()).toMatchInlineSnapshot(`
Expand Down
25 changes: 16 additions & 9 deletions packages/cli/src/cli/commands/config/autoupgrade/status.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {autoUpgradeStatus} from './constants.js'
import {getAutoUpgradeEnabled} from '@shopify/cli-kit/node/upgrade'
import {getAutoUpgradeStatus} 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 AutoupgradeStatus extends Command {
static summary = 'Check whether auto-upgrade is enabled, disabled, or not yet configured.'
Expand All @@ -15,12 +16,18 @@ export default class AutoupgradeStatus extends Command {

static description = this.descriptionForHelp()

static flags = {
...globalFlags,
...jsonFlag,
}

static get jsonOutputSchema() {
return autoUpgradeJsonOutputSchema
}

async run(): Promise<void> {
const enabled = getAutoUpgradeEnabled()
if (enabled) {
renderInfo({body: autoUpgradeStatus.on})
} else {
renderInfo({body: autoUpgradeStatus.off})
}
const {flags} = await this.parse(AutoupgradeStatus)
const result = getAutoUpgradeStatus()
presentAutoUpgradeResult(result, flags.json ? 'json' : 'text')
}
}
Loading
Loading