Skip to content

Commit acf3248

Browse files
committed
Update theme check command for multi-environment
Previously theme check command could only be run in a single environment at a time. This commit allows check to be run in multiple environments in a single command run
1 parent 415d367 commit acf3248

File tree

4 files changed

+36
-19
lines changed

4 files changed

+36
-19
lines changed

.changeset/seven-goats-agree.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/theme': minor
3+
---
4+
5+
Allow theme check command to be called with multiple environments

packages/cli/oclif.manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5095,6 +5095,9 @@
50955095
"hiddenAliases": [
50965096
],
50975097
"id": "theme:check",
5098+
"multiEnvironmentsFlags": [
5099+
"path"
5100+
],
50985101
"pluginAlias": "@shopify/cli",
50995102
"pluginName": "@shopify/cli",
51005103
"pluginType": "core",

packages/theme/src/cli/commands/theme/check.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ import {themeFlags} from '../../flags.js'
22
import {
33
formatOffensesJson,
44
formatSummary,
5-
handleExit,
65
initConfig,
76
outputActiveChecks,
87
outputActiveConfig,
98
performAutoFixes,
109
renderOffensesText,
1110
sortOffenses,
1211
isExtendedWriteStream,
12+
handleExit,
1313
type FailLevel,
1414
} from '../../services/check.js'
15-
import ThemeCommand from '../../utilities/theme-command.js'
15+
import ThemeCommand, {RequiredFlags} from '../../utilities/theme-command.js'
1616
import {Flags} from '@oclif/core'
1717
import {globalFlags} from '@shopify/cli-kit/node/cli'
1818
import {outputResult, outputDebug} from '@shopify/cli-kit/node/output'
@@ -21,7 +21,10 @@ import {themeCheckRun, LegacyIdentifiers} from '@shopify/theme-check-node'
2121
import {findPathUp} from '@shopify/cli-kit/node/fs'
2222
import {moduleDirectory, joinPath} from '@shopify/cli-kit/node/path'
2323
import {getPackageVersion} from '@shopify/cli-kit/node/node-package-manager'
24+
import {InferredFlags} from '@oclif/core/interfaces'
25+
import {AdminSession} from '@shopify/cli-kit/node/session'
2426

27+
type CheckFlags = InferredFlags<typeof Check.flags>
2528
export default class Check extends ThemeCommand {
2629
static summary = 'Validate the theme.'
2730

@@ -86,11 +89,12 @@ export default class Check extends ThemeCommand {
8689
environment: themeFlags.environment,
8790
}
8891

89-
async run(): Promise<void> {
90-
const {flags} = await this.parse(Check)
92+
static multiEnvironmentsFlags: RequiredFlags = ['path']
9193

94+
async command(flags: CheckFlags, _session: AdminSession, multiEnvironment: boolean): Promise<void> {
9295
// Its not clear to typescript that path will always be defined
9396
const path = flags.path
97+
const environment = flags.environment?.[0]
9498
// To support backwards compatibility for legacy configs
9599
const isLegacyConfig = flags.config?.startsWith(':') && LegacyIdentifiers.has(flags.config.slice(1))
96100
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -121,30 +125,32 @@ export default class Check extends ThemeCommand {
121125
}
122126

123127
if (flags.print) {
124-
await outputActiveConfig(path, config)
128+
await outputActiveConfig(path, config, environment)
125129

126130
// --print should not trigger full theme check operation
127131
return
128132
}
129133

130134
if (flags.list) {
131-
await outputActiveChecks(path, config)
135+
await outputActiveChecks(path, config, environment)
132136

133137
// --list should not trigger full theme check operation
134138
return
135139
}
136140

137-
const {offenses, theme} = await runThemeCheck(path, flags.output, config)
141+
const {offenses, theme} = await runThemeCheck(path, flags.output, config, environment)
138142

139143
if (flags['auto-correct']) {
140144
await performAutoFixes(theme, offenses)
141145
}
142146

143-
return handleExit(offenses, flags['fail-level'] as FailLevel)
147+
if (!multiEnvironment) {
148+
return handleExit(offenses, flags['fail-level'] as FailLevel)
149+
}
144150
}
145151
}
146152

147-
export async function runThemeCheck(path: string, outputFormat: string, config?: string) {
153+
export async function runThemeCheck(path: string, outputFormat: string, config?: string, environment?: string) {
148154
const {offenses, theme} = await themeCheckRun(path, config, (message) => {
149155
if (process.env.SHOPIFY_TMP_FLAG_DEBUG) {
150156
outputDebug(message)
@@ -154,13 +160,13 @@ export async function runThemeCheck(path: string, outputFormat: string, config?:
154160
const offensesByFile = sortOffenses(offenses)
155161

156162
if (outputFormat === 'text') {
157-
renderOffensesText(offensesByFile, path)
163+
renderOffensesText(offensesByFile, path, environment)
158164

159165
// Use renderSuccess when theres no offenses
160166
const render = offenses.length ? renderInfo : renderSuccess
161167

162168
render({
163-
headline: 'Theme Check Summary.',
169+
headline: environment ? `[${environment}] Theme Check Summary.` : 'Theme Check Summary.',
164170
body: formatSummary(offenses, offensesByFile, theme),
165171
})
166172
}
@@ -181,7 +187,7 @@ export async function runThemeCheck(path: string, outputFormat: string, config?:
181187
stdout._handle.setBlocking(true)
182188
}
183189

184-
outputResult(JSON.stringify(formatOffensesJson(offensesByFile)))
190+
outputResult(JSON.stringify(formatOffensesJson(offensesByFile, environment)))
185191
}
186192

187193
return {offenses, theme}

packages/theme/src/cli/services/check.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ export function formatSummary(offenses: Offense[], offensesByFile: OffenseMap, t
194194
return summary
195195
}
196196

197-
export function renderOffensesText(offensesByFile: OffenseMap, themeRootPath: string) {
197+
export function renderOffensesText(offensesByFile: OffenseMap, themeRootPath: string, environment?: string) {
198198
const fileNames = Object.keys(offensesByFile).sort()
199199

200200
fileNames.forEach((filePath) => {
@@ -203,13 +203,13 @@ export function renderOffensesText(offensesByFile: OffenseMap, themeRootPath: st
203203
const headlineFilePath = filePath.replace(themeRootPath, '').slice(1)
204204

205205
renderInfo({
206-
headline: headlineFilePath,
206+
headline: environment ? `[${environment}] ${headlineFilePath}` : headlineFilePath,
207207
body: formatOffenses(offensesByFile[filePath]!),
208208
})
209209
})
210210
}
211211

212-
export function formatOffensesJson(offensesByFile: OffenseMap): TransformedOffenseMap[] {
212+
export function formatOffensesJson(offensesByFile: OffenseMap, environment?: string): TransformedOffenseMap[] {
213213
return Object.entries(offensesByFile).map(([path, offenses]) => {
214214
const transformedOffenses = offenses.map((offense: Offense) => {
215215
return {
@@ -226,6 +226,7 @@ export function formatOffensesJson(offensesByFile: OffenseMap): TransformedOffen
226226
const counts = countOffenseTypes(offenses)
227227

228228
return {
229+
environment,
229230
path,
230231
offenses: transformedOffenses,
231232
errorCount: counts[Severity.ERROR] ?? 0,
@@ -288,7 +289,7 @@ export async function performAutoFixes(sourceCodes: Theme, offenses: Offense[])
288289
await autofix(sourceCodes, offenses, saveToDiskFixApplicator)
289290
}
290291

291-
export async function outputActiveConfig(themeRoot: string, configPath?: string) {
292+
export async function outputActiveConfig(themeRoot: string, configPath?: string, environment?: string) {
292293
const {ignore, settings, rootUri} = await loadConfig(configPath, themeRoot)
293294

294295
const config = {
@@ -304,10 +305,11 @@ export async function outputActiveConfig(themeRoot: string, configPath?: string)
304305
// Dump out the active settings for all checks.
305306
...settings,
306307
}
307-
outputResult(YAML.stringify(config))
308+
const output = environment ? {[environment]: config} : config
309+
outputResult(YAML.stringify(output))
308310
}
309311

310-
export async function outputActiveChecks(root: string, configPath?: string) {
312+
export async function outputActiveChecks(root: string, configPath?: string, environment?: string) {
311313
const {settings, ignore, checks} = await loadConfig(configPath, root)
312314
// Depending on how the configs were merged during loadConfig, there may be
313315
// duplicate patterns to ignore. We can clean them before outputting.
@@ -343,7 +345,8 @@ export async function outputActiveChecks(root: string, configPath?: string) {
343345
return acc
344346
}, {})
345347

346-
outputResult(YAML.stringify(checksList))
348+
const output = environment ? {[environment]: checksList} : checksList
349+
outputResult(YAML.stringify(output))
347350
}
348351

349352
interface ExtendedWriteStream extends NodeJS.WriteStream {

0 commit comments

Comments
 (0)