Skip to content

Commit 3c224e3

Browse files
authored
Merge pull request #6252 from Shopify/08-13-fix_deploy_error_messaging
Fix deploy error messaging for dev dash
2 parents 904e00d + 7bf295a commit 3c224e3

File tree

3 files changed

+200
-23
lines changed

3 files changed

+200
-23
lines changed

packages/app/src/cli/services/deploy/upload.test.ts

Lines changed: 141 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -419,10 +419,14 @@ describe('deploymentErrorsToCustomSections', () => {
419419
]
420420

421421
// When
422-
const customSections = deploymentErrorsToCustomSections(errors, {
423-
'amortizable-marketplace-ext': '123',
424-
'amortizable-marketplace-ext-2': '456',
425-
})
422+
const customSections = deploymentErrorsToCustomSections(
423+
errors,
424+
{
425+
'amortizable-marketplace-ext': '123',
426+
'amortizable-marketplace-ext-2': '456',
427+
},
428+
[],
429+
)
426430

427431
// Then
428432
expect(customSections).toEqual([
@@ -480,10 +484,14 @@ describe('deploymentErrorsToCustomSections', () => {
480484
]
481485

482486
// When
483-
const customSections = deploymentErrorsToCustomSections(errors, {
484-
'amortizable-marketplace-ext': '123',
485-
'amortizable-marketplace-ext-2': '456',
486-
})
487+
const customSections = deploymentErrorsToCustomSections(
488+
errors,
489+
{
490+
'amortizable-marketplace-ext': '123',
491+
'amortizable-marketplace-ext-2': '456',
492+
},
493+
[],
494+
)
487495

488496
// Then
489497
expect(customSections).toEqual([
@@ -511,10 +519,14 @@ describe('deploymentErrorsToCustomSections', () => {
511519
]
512520

513521
// When
514-
const customSections = deploymentErrorsToCustomSections(errors, {
515-
'amortizable-marketplace-ext': '123',
516-
'amortizable-marketplace-ext-2': '456',
517-
})
522+
const customSections = deploymentErrorsToCustomSections(
523+
errors,
524+
{
525+
'amortizable-marketplace-ext': '123',
526+
'amortizable-marketplace-ext-2': '456',
527+
},
528+
[],
529+
)
518530

519531
// Then
520532
expect(customSections).toEqual([
@@ -546,6 +558,7 @@ describe('deploymentErrorsToCustomSections', () => {
546558
'amortizable-marketplace-ext': '123',
547559
'amortizable-marketplace-ext-2': '456',
548560
},
561+
[],
549562
{
550563
version: 'already-taken-version',
551564
},
@@ -581,9 +594,13 @@ describe('deploymentErrorsToCustomSections', () => {
581594
]
582595

583596
// When
584-
const customSections = deploymentErrorsToCustomSections(errors, {
585-
b05ef3d6a573863fa3b21fae7689f1: '686809612289',
586-
})
597+
const customSections = deploymentErrorsToCustomSections(
598+
errors,
599+
{
600+
b05ef3d6a573863fa3b21fae7689f1: '686809612289',
601+
},
602+
[],
603+
)
587604

588605
// Then
589606
expect(customSections).toEqual([
@@ -667,13 +684,17 @@ describe('deploymentErrorsToCustomSections', () => {
667684
]
668685

669686
// When
670-
const customSections = deploymentErrorsToCustomSections(errors as AppDeploySchema['appDeploy']['userErrors'], {
671-
'webhook-subscription-1': '1',
672-
'webhook-subscription-2': '2',
673-
'webhook-subscription-3': '3',
674-
'webhook-subscription-4': '4',
675-
'webhook-subscription-5': '5',
676-
})
687+
const customSections = deploymentErrorsToCustomSections(
688+
errors as AppDeploySchema['appDeploy']['userErrors'],
689+
{
690+
'webhook-subscription-1': '1',
691+
'webhook-subscription-2': '2',
692+
'webhook-subscription-3': '3',
693+
'webhook-subscription-4': '4',
694+
'webhook-subscription-5': '5',
695+
},
696+
[],
697+
)
677698

678699
// Then
679700
expect(customSections).toEqual([
@@ -695,4 +716,102 @@ describe('deploymentErrorsToCustomSections', () => {
695716
},
696717
])
697718
})
719+
720+
test('returns sections for app management validation errors with found appModules', () => {
721+
// Given
722+
const errors = [
723+
{
724+
field: ['supported_buyer_contexts', 'currency'],
725+
message: 'must be a valid uppercase alpha-3 ISO 4217 value, invalid value: CADs',
726+
category: 'invalid',
727+
on: [
728+
{
729+
type: 'app_module',
730+
app_module_uuid: '0198a414-9812-7907-820c-773de19dede3',
731+
version_uuid: '0198a7a2-81fd-733d-b63c-1afe052b7fb3',
732+
specification_identifier: 'payments_extension',
733+
user_identifier: 'my-payment-extension-uid',
734+
},
735+
],
736+
details: [],
737+
},
738+
{
739+
field: ['targeting', 'target'],
740+
message: 'is required',
741+
category: 'invalid',
742+
on: [
743+
{
744+
type: 'app_module',
745+
user_identifier: 'my-discount-extension-uid',
746+
},
747+
],
748+
details: [],
749+
},
750+
{
751+
field: ['name'],
752+
message: 'is too long',
753+
category: 'invalid',
754+
on: [
755+
{
756+
type: 'app_module',
757+
user_identifier: 'my-payment-extension-uid',
758+
},
759+
],
760+
details: [],
761+
},
762+
]
763+
764+
const appModules = [
765+
{
766+
uid: 'my-payment-extension-uid',
767+
handle: 'my-payment-extension',
768+
config: '{}',
769+
context: '',
770+
specificationIdentifier: 'payments_extension',
771+
},
772+
{
773+
uid: 'my-discount-extension-uid',
774+
handle: 'my-discount-function',
775+
config: '{}',
776+
context: '',
777+
specificationIdentifier: 'discounts_extension',
778+
},
779+
]
780+
781+
// When
782+
const customSections = deploymentErrorsToCustomSections(
783+
errors as any as AppDeploySchema['appDeploy']['userErrors'],
784+
{},
785+
appModules,
786+
)
787+
788+
// Then
789+
expect(customSections).toEqual([
790+
{
791+
title: 'my-payment-extension',
792+
body: [
793+
{
794+
list: {
795+
title: '\nValidation errors',
796+
items: [
797+
'supported_buyer_contexts.currency: must be a valid uppercase alpha-3 ISO 4217 value, invalid value: CADs',
798+
'name: is too long',
799+
],
800+
},
801+
},
802+
],
803+
},
804+
{
805+
title: 'my-discount-function',
806+
body: [
807+
{
808+
list: {
809+
title: '\nValidation errors',
810+
items: ['targeting.target: is required'],
811+
},
812+
},
813+
],
814+
},
815+
])
816+
})
698817
})

packages/app/src/cli/services/deploy/upload.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export async function uploadExtensionsBundle(
111111
const customSections: AlertCustomSection[] = deploymentErrorsToCustomSections(
112112
result.appDeploy.userErrors ?? [],
113113
options.extensionIds,
114+
options.appModules,
114115
{
115116
version: options.version,
116117
},
@@ -143,6 +144,7 @@ const GENERIC_ERRORS_TITLE = '\n'
143144
export function deploymentErrorsToCustomSections(
144145
errors: AppDeploySchema['appDeploy']['userErrors'],
145146
extensionIds: IdentifiersExtensions,
147+
appModules: AppModuleSettings[],
146148
flags: {
147149
version?: string
148150
} = {},
@@ -158,14 +160,22 @@ export function deploymentErrorsToCustomSections(
158160
return Object.values(extensionIds).includes(errorExtensionId.toString())
159161
}
160162

161-
const [extensionErrors, nonExtensionErrors] = partition(errors, (error) => isExtensionError(error))
163+
const isAppManagementValidationError = (error: (typeof errors)[0]) => {
164+
const on = error.on ? (error.on[0] as {user_identifier: unknown}) : undefined
165+
return appModules.some((module) => module.uid === on?.user_identifier)
166+
}
167+
168+
const [appManagementErrors, nonAppManagementErrors] = partition(errors, (err) => isAppManagementValidationError(err))
169+
170+
const [extensionErrors, nonExtensionErrors] = partition(nonAppManagementErrors, (error) => isExtensionError(error))
162171

163172
const [cliErrors, partnersErrors] = partition(extensionErrors, (error) => isCliError(error, extensionIds))
164173

165174
const customSections = [
166175
...generalErrorsSection(nonExtensionErrors, {version: flags.version}),
167176
...cliErrorsSections(cliErrors, extensionIds),
168177
...partnersErrorsSections(partnersErrors),
178+
...appManagementErrorsSection(appManagementErrors, appModules),
169179
]
170180
return customSections
171181
}
@@ -289,6 +299,52 @@ function cliErrorsSections(errors: AppDeploySchema['appDeploy']['userErrors'], i
289299
}, [])
290300
}
291301

302+
function appManagementErrorsSection(
303+
errors: AppDeploySchema['appDeploy']['userErrors'],
304+
appModules: AppModuleSettings[],
305+
) {
306+
return errors.reduce<ErrorCustomSection[]>((sections, error) => {
307+
// Find the app module that corresponds to this error
308+
const on = error.on ? (error.on[0] as {user_identifier: unknown}) : undefined
309+
const userIdentifier = on?.user_identifier as string | undefined
310+
const appModule = appModules.find((module) => module.uid === userIdentifier)
311+
312+
const fallBackName = userIdentifier ? `Extension with uid: ${userIdentifier}` : 'Unknown Extension'
313+
const extensionName = appModule?.handle ?? fallBackName
314+
315+
const field = (error.field ?? ['unknown']).join('.')
316+
const errorMessage = `${field}: ${error.message}`
317+
318+
// Find or create section for this extension
319+
const existingSection = sections.find((section) => section.title === extensionName)
320+
321+
if (existingSection) {
322+
const sectionBody = existingSection.body as ListToken[]
323+
const errorsList = sectionBody.find((listToken) => listToken.list.title === VALIDATION_ERRORS_TITLE)
324+
325+
if (errorsList) {
326+
if (!errorsList.list.items.includes(errorMessage)) {
327+
errorsList.list.items.push(errorMessage)
328+
}
329+
}
330+
} else {
331+
sections.push({
332+
title: extensionName,
333+
body: [
334+
{
335+
list: {
336+
title: VALIDATION_ERRORS_TITLE,
337+
items: [errorMessage],
338+
},
339+
},
340+
],
341+
})
342+
}
343+
344+
return sections
345+
}, [])
346+
}
347+
292348
function partnersErrorsSections(errors: AppDeploySchema['appDeploy']['userErrors']) {
293349
return errors
294350
.reduce<{title: string | undefined; errorCount: number}[]>((sections, error) => {

packages/app/src/cli/utilities/developer-platform-client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import {
6060
import {TokenItem} from '@shopify/cli-kit/node/ui'
6161
import {blockPartnersAccess} from '@shopify/cli-kit/node/environment'
6262
import {UnauthorizedHandler} from '@shopify/cli-kit/node/api/graphql'
63+
import {JsonMapType} from '@shopify/cli-kit/node/toml'
6364

6465
export enum ClientName {
6566
AppManagement = 'app-management',
@@ -205,6 +206,7 @@ export interface UserError {
205206
message: string
206207
category: string
207208
details: ErrorDetail[]
209+
on?: JsonMapType
208210
}
209211

210212
interface ErrorDetail {

0 commit comments

Comments
 (0)