Skip to content

Commit 1416fe1

Browse files
committed
Ensure user provided flag values override defaults
Previously, default flag values were treated by multi environment command mapping as CLI values, which take precedence over .toml values. This commit ensures that flag values are selected in order: 1. User provided CLI args 2. User provided shopify.theme.toml values 3. Default flag values
1 parent b2a3d9a commit 1416fe1

File tree

4 files changed

+81
-8
lines changed

4 files changed

+81
-8
lines changed

.changeset/shy-islands-guess.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@shopify/cli-kit': minor
3+
'@shopify/theme': minor
4+
---
5+
6+
Ensure user provided flag values override defaults in commands with multiple environments

packages/cli-kit/src/public/node/base-command.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ function reportEnvironmentApplication<
281281
* If we parse using this configuration, the only specified flags will be those
282282
* the user actually passed on the command line.
283283
*/
284-
function noDefaultsOptions<TFlags extends FlagOutput, TGlobalFlags extends FlagOutput, TArgs extends ArgOutput>(
284+
export function noDefaultsOptions<TFlags extends FlagOutput, TGlobalFlags extends FlagOutput, TArgs extends ArgOutput>(
285285
options: Input<TFlags, TGlobalFlags, TArgs> | undefined,
286286
): Input<TFlags, TGlobalFlags, TArgs> | undefined {
287287
if (!options?.flags) return options

packages/theme/src/cli/utilities/theme-command.test.ts

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ class TestThemeCommand extends ThemeCommand {
2727
password: Flags.string({
2828
env: 'SHOPIFY_FLAG_PASSWORD',
2929
}),
30+
path: Flags.string({
31+
env: 'SHOPIFY_FLAG_PATH',
32+
default: 'current/working/directory',
33+
}),
34+
'no-color': Flags.boolean({
35+
env: 'SHOPIFY_FLAG_NO_COLOR',
36+
default: false,
37+
}),
3038
}
3139

3240
static multiEnvironmentsFlags: RequiredFlags = ['store']
@@ -119,7 +127,9 @@ describe('ThemeCommand', () => {
119127
await command.run()
120128

121129
// Then
122-
expect(loadEnvironment).toHaveBeenCalledWith('development', 'shopify.theme.toml', {from: undefined})
130+
expect(loadEnvironment).toHaveBeenCalledWith('development', 'shopify.theme.toml', {
131+
from: 'current/working/directory',
132+
})
123133
expect(ensureAuthenticatedThemes).toHaveBeenCalledTimes(1)
124134
expect(renderConcurrent).not.toHaveBeenCalled()
125135
expect(command.commandCalls).toHaveLength(1)
@@ -149,8 +159,14 @@ describe('ThemeCommand', () => {
149159
await command.run()
150160

151161
// Then
152-
expect(loadEnvironment).toHaveBeenCalledWith('development', 'shopify.theme.toml', {from: undefined, silent: true})
153-
expect(loadEnvironment).toHaveBeenCalledWith('staging', 'shopify.theme.toml', {from: undefined, silent: true})
162+
expect(loadEnvironment).toHaveBeenCalledWith('development', 'shopify.theme.toml', {
163+
from: 'current/working/directory',
164+
silent: true,
165+
})
166+
expect(loadEnvironment).toHaveBeenCalledWith('staging', 'shopify.theme.toml', {
167+
from: 'current/working/directory',
168+
silent: true,
169+
})
154170

155171
expect(renderConcurrent).toHaveBeenCalledOnce()
156172
expect(renderConcurrent).toHaveBeenCalledWith(
@@ -433,5 +449,51 @@ describe('ThemeCommand', () => {
433449
}),
434450
)
435451
})
452+
453+
test('CLI and shopify.theme.toml flag values take precedence over defaults', async () => {
454+
// Given
455+
vi.mocked(loadEnvironment)
456+
.mockResolvedValueOnce({store: 'store1.myshopify.com', theme: 'theme1.myshopify.com', path: 'theme/path'})
457+
.mockResolvedValueOnce({store: 'store2.myshopify.com', development: true, path: 'development/path'})
458+
.mockResolvedValueOnce({store: 'store3.myshopify.com', live: true, 'no-color': false})
459+
460+
vi.mocked(renderConcurrent).mockImplementation(async ({processes}) => {
461+
for (const process of processes) {
462+
// eslint-disable-next-line no-await-in-loop
463+
await process.action({} as Writable, {} as Writable, {} as any)
464+
}
465+
})
466+
467+
await CommandConfig.load()
468+
const command = new TestThemeCommand(
469+
['--environment', 'theme', '--environment', 'development', '--environment', 'live', '--no-color'],
470+
CommandConfig,
471+
)
472+
473+
// When
474+
await command.run()
475+
476+
// Then
477+
const commandCalls = command.commandCalls
478+
expect(commandCalls).toHaveLength(3)
479+
480+
const themeEnvFlags = commandCalls[0]?.flags
481+
expect(themeEnvFlags?.path).toEqual('theme/path')
482+
expect(themeEnvFlags?.store).toEqual('store1.myshopify.com')
483+
expect(themeEnvFlags?.theme).toEqual('theme1.myshopify.com')
484+
expect(themeEnvFlags?.['no-color']).toEqual(true)
485+
486+
const developmentEnvFlags = commandCalls[1]?.flags
487+
expect(developmentEnvFlags?.path).toEqual('development/path')
488+
expect(developmentEnvFlags?.store).toEqual('store2.myshopify.com')
489+
expect(developmentEnvFlags?.development).toEqual(true)
490+
expect(developmentEnvFlags?.['no-color']).toEqual(true)
491+
492+
const liveEnvFlags = commandCalls[2]?.flags
493+
expect(liveEnvFlags?.path).toEqual('current/working/directory')
494+
expect(liveEnvFlags?.store).toEqual('store3.myshopify.com')
495+
expect(liveEnvFlags?.live).toEqual(true)
496+
expect(liveEnvFlags?.['no-color']).toEqual(true)
497+
})
436498
})
437499
})

packages/theme/src/cli/utilities/theme-command.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {configurationFileName} from '../constants.js'
33
import {useThemeStoreContext} from '../services/local-storage.js'
44
import {hashString} from '@shopify/cli-kit/node/crypto'
55
import {Input} from '@oclif/core/interfaces'
6-
import Command, {ArgOutput, FlagOutput} from '@shopify/cli-kit/node/base-command'
6+
import Command, {ArgOutput, FlagOutput, noDefaultsOptions} from '@shopify/cli-kit/node/base-command'
77
import {AdminSession, ensureAuthenticatedThemes} from '@shopify/cli-kit/node/session'
88
import {loadEnvironment} from '@shopify/cli-kit/node/environments'
99
import {
@@ -103,7 +103,7 @@ export default abstract class ThemeCommand extends Command {
103103
return
104104
}
105105

106-
const environmentsMap = await this.loadEnvironments(environments, flags)
106+
const environmentsMap = await this.loadEnvironments(environments, flags, klass)
107107
const validationResults = await this.validateEnvironments(environmentsMap, requiredFlags)
108108

109109
const commandAllowsForceFlag = 'force' in klass.flags
@@ -119,13 +119,17 @@ export default abstract class ThemeCommand extends Command {
119119
/**
120120
* Create a map of environments from the shopify.theme.toml file
121121
* @param environments - Names of environments to load
122-
* @param flags - Flags provided via the CLI
122+
* @param flags - Flags provided via the CLI or by default
123+
* @param klass - The command class
123124
* @returns The map of environments
124125
*/
125126
private async loadEnvironments(
126127
environments: EnvironmentName[],
127128
flags: FlagValues,
129+
klass: Input<FlagOutput, FlagOutput, ArgOutput>,
128130
): Promise<Map<EnvironmentName, FlagValues>> {
131+
const {flags: flagsWithoutDefaults} = await this.parse(noDefaultsOptions(klass))
132+
129133
const environmentMap = new Map<EnvironmentName, FlagValues>()
130134

131135
for (const environmentName of environments) {
@@ -136,8 +140,9 @@ export default abstract class ThemeCommand extends Command {
136140
})
137141

138142
environmentMap.set(environmentName, {
139-
...environmentFlags,
140143
...flags,
144+
...environmentFlags,
145+
...flagsWithoutDefaults,
141146
environment: [environmentName],
142147
})
143148
}

0 commit comments

Comments
 (0)