Skip to content

Commit 6edd52f

Browse files
committed
[Themes] Store theme asset upload errors in the themeFileSystem
1 parent 7d889bd commit 6edd52f

File tree

7 files changed

+108
-6
lines changed

7 files changed

+108
-6
lines changed

packages/cli-kit/src/public/node/themes/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ export interface ThemeFileSystem extends VirtualFileSystem {
9999
* Applies filters to ignore files from .shopifyignore file, --ignore and --only flags.
100100
*/
101101
applyIgnoreFilters: <T extends {key: string}>(files: T[]) => T[]
102+
103+
/**
104+
* Stores upload errors returned when uploading files via the Asset API
105+
*/
106+
uploadErrors: Map<Key, string[]>
102107
}
103108

104109
/**

packages/theme/src/cli/utilities/theme-fs-empty.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function emptyFileSystem<T>(): T {
1313
root: '',
1414
files: new Map(),
1515
unsyncedFileKeys: new Set(),
16+
uploadErrors: new Map(),
1617
ready: () => Promise.resolve(),
1718
delete: async (_: string) => {},
1819
read: async (_: string) => '',

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ describe('theme-fs', () => {
5959
fsEntry({checksum: '64caf742bd427adcf497bffab63df30c', key: 'templates/404.json'}),
6060
]),
6161
unsyncedFileKeys: new Set(),
62+
uploadErrors: new Map(),
6263
ready: expect.any(Function),
6364
delete: expect.any(Function),
6465
write: expect.any(Function),
@@ -82,6 +83,7 @@ describe('theme-fs', () => {
8283
root,
8384
files: new Map(),
8485
unsyncedFileKeys: new Set(),
86+
uploadErrors: new Map(),
8587
ready: expect.any(Function),
8688
delete: expect.any(Function),
8789
write: expect.any(Function),

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const THEME_PARTITION_REGEX = {
4545

4646
export function mountThemeFileSystem(root: string, options?: ThemeFileSystemOptions): ThemeFileSystem {
4747
const files = new Map<string, ThemeAsset>()
48+
const uploadErrors = new Map<string, string[]>()
4849
const unsyncedFileKeys = new Set<string>()
4950
const filterPatterns = {
5051
ignoreFromFile: [] as string[],
@@ -147,12 +148,12 @@ export function mountThemeFileSystem(root: string, options?: ThemeFileSystemOpti
147148

148149
const [result] = await bulkUploadThemeAssets(Number(themeId), [{key: fileKey, value: content}], adminSession)
149150

150-
if (!result?.success) {
151-
throw new Error(
152-
result?.errors?.asset
153-
? `\n\n${result.errors.asset.map((error) => `- ${error}`).join('\n')}`
154-
: 'Response was not successful.',
155-
)
151+
if (result?.success) {
152+
uploadErrors.delete(fileKey)
153+
} else {
154+
const errors = result?.errors?.asset ?? ['Response was not successful.']
155+
uploadErrors.set(fileKey, errors)
156+
throw new Error(errors.join('\n'))
156157
}
157158

158159
unsyncedFileKeys.delete(fileKey)
@@ -223,6 +224,7 @@ export function mountThemeFileSystem(root: string, options?: ThemeFileSystemOpti
223224
root,
224225
files,
225226
unsyncedFileKeys,
227+
uploadErrors,
226228
ready: () => themeSetupPromise,
227229
delete: async (fileKey: string) => {
228230
files.delete(fileKey)

packages/theme/src/cli/utilities/theme-fs/theme-fs-mock-factory.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export function fakeThemeFileSystem(
1010
root,
1111
files,
1212
unsyncedFileKeys: new Set(),
13+
uploadErrors: new Map(),
1314
ready: () => Promise.resolve(),
1415
delete: async (fileKey: string) => {
1516
files.delete(fileKey)

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

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
MAX_UPLOAD_RETRY_COUNT,
55
MINIMUM_THEME_ASSETS,
66
uploadTheme,
7+
updateUploadErrors,
78
} from './theme-uploader.js'
89
import {fakeThemeFileSystem} from './theme-fs/theme-fs-mock-factory.js'
910
import {bulkUploadThemeAssets, deleteThemeAsset} from '@shopify/cli-kit/node/themes/api'
@@ -602,3 +603,83 @@ describe('theme-uploader', () => {
602603
)
603604
})
604605
})
606+
607+
describe('updateUploadErrors', () => {
608+
test('should clear error for successful upload', () => {
609+
// Given
610+
const themeFileSystem = fakeThemeFileSystem('tmp', new Map())
611+
const result: Result = {
612+
key: 'file1.liquid',
613+
success: true,
614+
errors: {},
615+
operation: Operation.Upload,
616+
asset: {key: 'file1.liquid', checksum: 'abc'},
617+
}
618+
619+
// Pre-existing error that should be cleared
620+
themeFileSystem.uploadErrors.set('file1.liquid', ['Old error'])
621+
622+
// When
623+
updateUploadErrors(result, themeFileSystem)
624+
625+
// Then
626+
expect(themeFileSystem.uploadErrors.has('file1.liquid')).toBe(false)
627+
})
628+
629+
test('should set error for failed upload', () => {
630+
// Given
631+
const themeFileSystem = fakeThemeFileSystem('tmp', new Map())
632+
const result: Result = {
633+
key: 'file1.liquid',
634+
success: false,
635+
errors: {asset: ['Upload failed']},
636+
operation: Operation.Upload,
637+
asset: {key: 'file1.liquid', checksum: 'abc'},
638+
}
639+
640+
// When
641+
updateUploadErrors(result, themeFileSystem)
642+
643+
// Then
644+
expect(themeFileSystem.uploadErrors.get('file1.liquid')).toEqual(['Upload failed'])
645+
})
646+
647+
test('should set default error when no specific error provided', () => {
648+
// Given
649+
const themeFileSystem = fakeThemeFileSystem('tmp', new Map())
650+
const result: Result = {
651+
key: 'file1.liquid',
652+
success: false,
653+
errors: {},
654+
operation: Operation.Upload,
655+
asset: {key: 'file1.liquid', checksum: 'abc'},
656+
}
657+
658+
// When
659+
updateUploadErrors(result, themeFileSystem)
660+
661+
// Then
662+
expect(themeFileSystem.uploadErrors.get('file1.liquid')).toEqual(['Response was not successful.'])
663+
})
664+
665+
test('should update existing error', () => {
666+
// Given
667+
const themeFileSystem = fakeThemeFileSystem('tmp', new Map())
668+
const result: Result = {
669+
key: 'file1.liquid',
670+
success: false,
671+
errors: {asset: ['New error']},
672+
operation: Operation.Upload,
673+
asset: {key: 'file1.liquid', checksum: 'abc'},
674+
}
675+
676+
// Pre-existing error that should be updated
677+
themeFileSystem.uploadErrors.set('file1.liquid', ['Old error'])
678+
679+
// When
680+
updateUploadErrors(result, themeFileSystem)
681+
682+
// Then
683+
expect(themeFileSystem.uploadErrors.get('file1.liquid')).toEqual(['New error'])
684+
})
685+
})

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,19 @@ async function uploadBatch(
370370
// store the results in uploadResults, overwriting any existing results
371371
results.forEach((result) => {
372372
uploadResults.set(result.key, result)
373+
updateUploadErrors(result, localThemeFileSystem)
373374
})
374375
}
375376

377+
export function updateUploadErrors(result: Result, localThemeFileSystem: ThemeFileSystem) {
378+
if (result.success) {
379+
localThemeFileSystem.uploadErrors.delete(result.key)
380+
} else {
381+
const errors = result.errors?.asset ?? ['Response was not successful.']
382+
localThemeFileSystem.uploadErrors.set(result.key, errors)
383+
}
384+
}
385+
376386
async function handleBulkUpload(
377387
uploadParams: AssetParams[],
378388
themeId: number,

0 commit comments

Comments
 (0)