Skip to content
Closed
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
6 changes: 6 additions & 0 deletions .changeset/json-upgrade-output.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@shopify/cli': patch
'@shopify/cli-kit': patch
---

Keep automatic upgrade output on stderr during JSON commands.
53 changes: 52 additions & 1 deletion packages/cli-kit/src/public/node/upgrade.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
} from './upgrade.js'
import {Notification, fetchNotifications} from './notifications-system.js'
import {globalCLIVersion, isPreReleaseVersion} from './version.js'
import {mockAndCaptureOutput} from './testing/output.js'
import {mockAndCaptureOutput, withCapturedStandardStreams} from './testing/output.js'
import {runWithCommandEventsForCommand} from './command-events.js'
import {outputResult} from './output.js'
import {getAutoUpgradeEnabled} from '../../private/node/conf-store.js'
import {CLI_KIT_VERSION} from '../common/version.js'
import {SemVer} from 'semver'
Expand Down Expand Up @@ -171,6 +173,55 @@ describe('runCLIUpgrade', () => {
expect(exec).toHaveBeenCalledWith('npm', ['install', '-g', '@shopify/cli@latest'], {stdio: 'inherit'})
})

test.each([false, true])('JSON auto-upgrade keeps stdout clear when the install fails: %s', async (fails) => {
vi.mocked(isUnitTest).mockReturnValue(false)
vi.mocked(currentProcessIsGlobal).mockReturnValue(true)
vi.mocked(inferPackageManagerForGlobalCLI).mockReturnValue('npm')
const failure = new Error('Install failed')
vi.mocked(exec).mockImplementationOnce(async (_command, _args, options) => {
if (options?.stdio === 'inherit') {
process.stdout.write('added 1 package\n')
process.stderr.write('package manager warning\n')
} else {
if (options?.stdout && options.stdout !== 'inherit') options.stdout.write('added 1 package\n')
if (options?.stderr && options.stderr !== 'inherit') options.stderr.write('package manager warning')
}
if (fails) throw failure
})

await withCapturedStandardStreams(async ({stdout, stderr}) => {
await runWithCommandEventsForCommand(['--json'], async () => {
outputResult('{"status":"success"}')
const upgrade = runCLIUpgrade({autoupgrade: true})
if (fails) await expect(upgrade).rejects.toBe(failure)
else await upgrade
})

expect(stdout()).toBe('{"status":"success"}\n')
const events = stderr()
.trim()
.split('\n')
.map((line) => JSON.parse(line))
expect(events).toContainEqual(expect.objectContaining({type: 'diagnostic', message: 'npm: added 1 package'}))
expect(events).toContainEqual(
expect.objectContaining({type: 'diagnostic', message: 'npm: package manager warning'}),
)
if (!fails) {
expect(events).toContainEqual(
expect.objectContaining({
type: 'diagnostic',
message: `Shopify CLI upgraded. You're now on version ${CLI_KIT_VERSION}.`,
}),
)
}
expect(exec).toHaveBeenCalledWith('npm', ['install', '-g', '@shopify/cli@latest'], {
stdin: 'inherit',
stdout: expect.anything(),
stderr: expect.anything(),
})
})
})

test('runs the install command via exec for a global yarn install', async () => {
// Given
vi.mocked(currentProcessIsGlobal).mockReturnValue(true)
Expand Down
30 changes: 24 additions & 6 deletions packages/cli-kit/src/public/node/upgrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
getPackageManager,
} from './node-package-manager.js'
import {outputContent, outputDebug, outputInfo, outputToken, outputWarn} from './output.js'
import {renderSuccess} from './ui.js'
import {renderConcurrent, renderSuccess} from './ui.js'
import {commandEventOutputMode} from './command-events.js'
import {cwd, moduleDirectory, sniffForPath} from './path.js'
import {exec, isCI} from './system.js'
import {globalCLIVersion, isPreReleaseVersion} from './version.js'
Expand Down Expand Up @@ -105,7 +106,20 @@ export async function runCLIUpgrade(options: RunCLIUpgradeOptions = {}): Promise
outputContent`${headline}
Now upgrading by running: ${outputToken.genericShellCommand(installCommand)}...`,
)
await exec(command, args, {stdio: 'inherit'})
const jsonOutput = commandEventOutputMode() === 'json'
if (jsonOutput) {
await renderConcurrent({
processes: [
{
prefix: command,
action: async (stdout, stderr) => exec(command, args, {stdin: 'inherit', stdout, stderr}),
},
],
showTimestamps: false,
})
} else {
await exec(command, args, {stdio: 'inherit'})
}

// A zero exit code doesn't guarantee the right version landed: the version check above
// queries the public npm registry, while the install goes through whatever registry the
Expand All @@ -126,10 +140,14 @@ export async function runCLIUpgrade(options: RunCLIUpgradeOptions = {}): Promise
'Your package manager may be resolving @shopify/cli from a registry with outdated versions. Check your npm registry configuration and try again.',
)
}
renderSuccess({
headline: 'Shopify CLI upgraded.',
body: `You're now on version ${installedVersion}.`,
})
if (jsonOutput) {
outputInfo(`Shopify CLI upgraded. You're now on version ${installedVersion}.`)
} else {
renderSuccess({
headline: 'Shopify CLI upgraded.',
body: `You're now on version ${installedVersion}.`,
})
}
} else if (projectDir) {
await upgradeLocalShopify(projectDir, CLI_KIT_VERSION)
} else {
Expand Down
Loading