Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update mutation variables for AppVersionCreate #5451

Open
wants to merge 1 commit into
base: dlm-app-create-mutation-variables
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import {TypedDocumentNode as DocumentNode} from '@graphql-typed-document-node/co

export type CreateAppVersionMutationVariables = Types.Exact<{
appId: Types.Scalars['ID']['input']
appSource: Types.AppSourceInput
name: Types.Scalars['String']['input']
version: Types.AppVersionInput
metadata?: Types.InputMaybe<Types.VersionMetadataInput>
}>

Expand Down Expand Up @@ -49,13 +48,8 @@ export const CreateAppVersion = {
},
{
kind: 'VariableDefinition',
variable: {kind: 'Variable', name: {kind: 'Name', value: 'appSource'}},
type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'AppSourceInput'}}},
},
{
kind: 'VariableDefinition',
variable: {kind: 'Variable', name: {kind: 'Name', value: 'name'}},
type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}},
variable: {kind: 'Variable', name: {kind: 'Name', value: 'version'}},
type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'AppVersionInput'}}},
},
{
kind: 'VariableDefinition',
Expand All @@ -77,13 +71,8 @@ export const CreateAppVersion = {
},
{
kind: 'Argument',
name: {kind: 'Name', value: 'appSource'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'appSource'}},
},
{
kind: 'Argument',
name: {kind: 'Name', value: 'name'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'name'}},
name: {kind: 'Name', value: 'version'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'version'}},
},
{
kind: 'Argument',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,28 +47,6 @@ export type Scalars = {
URL: {input: string; output: string}
}

/** The input fields for an app module. */
export type AppModuleInput = {
/** Configuration for the module. */
config: Scalars['JSON']['input']
/** Human-readable identifier for the module. */
handle?: InputMaybe<Scalars['String']['input']>
/** Identifier for the module's specification. */
specificationIdentifier: Scalars['String']['input']
/** The location where the module will be surfaced. */
target?: InputMaybe<Scalars['String']['input']>
/** User-specified identifier for the module, unique to the app. */
uid?: InputMaybe<Scalars['String']['input']>
}

/** The input fields for data and configuration that represent an app. */
export type AppSourceInput = {
/** Modules that make up the app. */
appModules: AppModuleInput[]
/** URL for app assets. */
assetsUrl?: InputMaybe<Scalars['URL']['input']>
}

/** The input fields used to create a new app version. */
export type AppVersionInput = {
/** The manifest from which to create the app version. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mutation CreateAppVersion($appId: ID!, $appSource: AppSourceInput!, $name: String!, $metadata: VersionMetadataInput) {
appVersionCreate(appId: $appId, appSource: $appSource, name: $name, metadata: $metadata) {
mutation CreateAppVersion($appId: ID!, $version: AppVersionInput!, $metadata: VersionMetadataInput) {
appVersionCreate(appId: $appId, version: $version, metadata: $metadata) {
version {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pulled name as well, on the theory that we're either going to pull name from the branding module (short-term), or update the manifest format to include it longer-term.

id
appModules {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {AvailableTopicsQuery} from '../../api/graphql/webhooks/generated/availab
import {CliTesting, CliTestingMutation} from '../../api/graphql/webhooks/generated/cli-testing.js'
import {SendSampleWebhookVariables} from '../../services/webhook/request-sample.js'
import {CreateApp} from '../../api/graphql/app-management/generated/create-app.js'
import {BrandingSpecIdentifier} from '../../models/extensions/specifications/app_config_branding.js'
import {describe, expect, test, vi} from 'vitest'
import {CLI_KIT_VERSION} from '@shopify/cli-kit/common/version'
import {fetch} from '@shopify/cli-kit/node/http'
Expand Down Expand Up @@ -558,3 +559,198 @@ describe('sendSampleWebhook', () => {
expect(result.sendSampleWebhook.userErrors).toEqual([{message: 'Invalid api_version', fields: []}])
})
})

describe('deploy', () => {
// Given
const client = new AppManagementClient()
client.token = () => Promise.resolve('token')

test('creates version with correct metadata and modules', async () => {
// Given
const versionTag = '1.0.0'
const message = 'Test deploy'
const commitReference = 'https://github.com/org/repo/commit/123'
const appModules = [
{
uid: 'branding',
config: JSON.stringify({name: 'Test App'}),
handle: 'test-app',
specificationIdentifier: BrandingSpecIdentifier,
context: 'unused-context',
},
]

const mockResponse = {
appVersionCreate: {
version: {
id: 'gid://shopify/Version/1',
metadata: {
versionTag,
message,
sourceControlUrl: commitReference,
},
appModules: [
{
uuid: 'some_uuid',
},
],
},
userErrors: [],
},
}
vi.mocked(appManagementRequestDoc).mockResolvedValueOnce(mockResponse)

// When
await client.deploy({
apiKey: 'api-key',
appId: 'gid://shopify/App/123',
name: 'Test App',
appModules,
organizationId: 'gid://shopify/Organization/123',
versionTag,
message,
commitReference,
skipPublish: true,
})

// Then
expect(appManagementRequestDoc).toHaveBeenCalledWith('gid://shopify/Organization/123', expect.anything(), 'token', {
appId: 'gid://shopify/App/123',
version: {
source: {
name: 'Test App',
modules: [
{
uid: 'branding',
type: BrandingSpecIdentifier,
handle: 'test-app',
config: {name: 'Test App'},
},
],
},
},
metadata: {
versionTag,
message,
sourceControlUrl: commitReference,
},
})
})

test('uses bundleUrl when provided instead of modules', async () => {
// Given
const bundleUrl = 'https://storage.test/bundle.zip'
const mockResponse = {
appVersionCreate: {
version: {
id: 'gid://shopify/Version/1',
metadata: {},
appModules: [],
},
userErrors: [],
},
}
vi.mocked(appManagementRequestDoc).mockResolvedValueOnce(mockResponse)

// When
await client.deploy({
apiKey: 'api-key',
appId: 'gid://shopify/App/123',
name: 'Test App',
organizationId: 'gid://shopify/Organization/123',
bundleUrl,
versionTag: '1.0.0',
skipPublish: true,
})

// Then
expect(appManagementRequestDoc).toHaveBeenCalledWith('gid://shopify/Organization/123', expect.anything(), 'token', {
appId: 'gid://shopify/App/123',
version: {
sourceUrl: bundleUrl,
},
metadata: expect.any(Object),
})
})

test('updates name from branding module if present', async () => {
// Given
const appModules = [
{
uuid: 'branding',
config: JSON.stringify({name: 'Updated App Name'}),
handle: 'branding',
specificationIdentifier: BrandingSpecIdentifier,
context: 'unused-context',
},
]
const mockResponse = {
appVersionCreate: {
version: {
id: 'gid://shopify/Version/1',
metadata: {},
appModules: [],
},
userErrors: [],
},
}
vi.mocked(appManagementRequestDoc).mockResolvedValueOnce(mockResponse)

// When
await client.deploy({
apiKey: 'api-key',
appId: 'gid://shopify/App/123',
name: 'Original Name',
appModules,
organizationId: 'gid://shopify/Organization/123',
versionTag: '1.0.0',
skipPublish: true,
})

// Then
expect(appManagementRequestDoc).toHaveBeenCalledWith(
'gid://shopify/Organization/123',
expect.anything(),
'token',
expect.objectContaining({
version: {
source: {
name: 'Updated App Name',
modules: expect.any(Array),
},
},
}),
)
})

test('handles version creation errors', async () => {
// Given
const mockResponse = {
appVersionCreate: {
version: null,
userErrors: [
{
field: ['version'],
message: 'Invalid version',
details: [],
},
],
},
}
vi.mocked(appManagementRequestDoc).mockResolvedValueOnce(mockResponse)

// When
const result = await client.deploy({
apiKey: 'api-key',
appId: 'gid://shopify/App/123',
name: 'Test App',
organizationId: 'gid://shopify/Organization/123',
versionTag: '1.0.0',
skipPublish: true,
})

// Then
expect(result.appDeploy.userErrors).toHaveLength(1)
expect(result.appDeploy.userErrors[0]?.message).toBe('Invalid version')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -582,22 +582,24 @@ export class AppManagementClient implements DeveloperPlatformClient {
if (brandingModule) {
updatedName = JSON.parse(brandingModule.config).name
}

const metadata = {versionTag, message, sourceControlUrl: commitReference}
const queryVersion: AppVersionSourceUrl | AppVersionSource = bundleUrl
? {sourceUrl: bundleUrl}
: {
source: {
name: updatedName,
modules: (appModules ?? []).map((mod) => ({
uid: mod.uid ?? mod.uuid ?? mod.handle,
type: mod.specificationIdentifier,
handle: mod.handle,
config: JSON.parse(mod.config),
})),
},
}
const variables = {
appId,
name: updatedName,
appSource: {
assetsUrl: bundleUrl,
appModules: (appModules ?? []).map((mod) => {
return {
uid: mod.uid ?? mod.uuid ?? mod.handle,
specificationIdentifier: mod.specificationIdentifier,
handle: mod.handle,
config: JSON.parse(mod.config),
}
}),
},
metadata: {versionTag, message, sourceControlUrl: commitReference},
version: queryVersion as unknown as JsonMapType,
metadata,
}

const result = await appManagementRequestDoc(organizationId, CreateAppVersion, await this.token(), variables)
Expand Down Expand Up @@ -914,6 +916,10 @@ interface AppVersionSource {
}
}

interface AppVersionSourceUrl {
sourceUrl: string
}

// this is a temporary solution for editions to support https://vault.shopify.io/gsd/projects/31406
// read more here: https://vault.shopify.io/gsd/projects/31406
const MAGIC_URL = 'https://shopify.dev/apps/default-app-home'
Expand Down
Loading