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

Move link uses api client config as fallback #3648

Merged
Merged
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
5 changes: 5 additions & 0 deletions .changeset/grumpy-ravens-arrive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/app': patch
---

Link uses api client config as fallback when the app doesnt have an active app version or the existing one doesn't include any configuration app module
2 changes: 1 addition & 1 deletion packages/app/src/cli/api/graphql/app_active_version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export interface AppModuleVersion {

export interface ActiveAppVersionQuerySchema {
app: {
activeAppVersion: {
activeAppVersion?: {
appModuleVersions: AppModuleVersion[]
}
}
Expand Down
31 changes: 31 additions & 0 deletions packages/app/src/cli/api/graphql/create_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@ export const CreateAppQuery = gql`
}
appType
grantedScopes
applicationUrl
redirectUrlWhitelist
requestedAccessScopes
webhookApiVersion
embedded
posEmbedded
preferencesUrl
gdprWebhooks {
customerDeletionUrl
customerDataRequestUrl
shopDeletionUrl
}
appProxy {
subPath
subPathPrefix
url
}
disabledFlags
}
userErrors {
Expand Down Expand Up @@ -63,6 +80,20 @@ export interface CreateAppQuerySchema {
applicationUrl: string
redirectUrlWhitelist: string[]
requestedAccessScopes?: string[]
webhookApiVersion: string
embedded: boolean
posEmbedded?: boolean
preferencesUrl?: string
gdprWebhooks?: {
customerDeletionUrl?: string
customerDataRequestUrl?: string
shopDeletionUrl?: string
}
appProxy?: {
subPath: string
subPathPrefix: string
url: string
}
disabledFlags: string[]
}
userErrors: {
Expand Down
34 changes: 34 additions & 0 deletions packages/app/src/cli/api/graphql/find_app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ export const FindAppQuery = gql`
}
appType
grantedScopes
applicationUrl
redirectUrlWhitelist
requestedAccessScopes
webhookApiVersion
embedded
posEmbedded
preferencesUrl
gdprWebhooks {
customerDeletionUrl
customerDataRequestUrl
shopDeletionUrl
}
appProxy {
subPath
subPathPrefix
url
}
developmentStorePreviewEnabled
disabledFlags
}
Expand All @@ -29,6 +46,23 @@ export interface FindAppQuerySchema {
}[]
appType: string
grantedScopes: string[]
applicationUrl: string
redirectUrlWhitelist: string[]
requestedAccessScopes?: string[]
webhookApiVersion: string
embedded: boolean
posEmbedded?: boolean
preferencesUrl?: string
gdprWebhooks?: {
customerDeletionUrl?: string
customerDataRequestUrl?: string
shopDeletionUrl?: string
}
appProxy?: {
subPath: string
subPathPrefix: string
url: string
}
developmentStorePreviewEnabled: boolean
disabledFlags: string[]
}
Expand Down
17 changes: 17 additions & 0 deletions packages/app/src/cli/models/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ export type OrganizationApp = MinimalOrganizationApp & {
newApp?: boolean
grantedScopes: string[]
developmentStorePreviewEnabled?: boolean
applicationUrl?: string
redirectUrlWhitelist?: string[]
requestedAccessScopes?: string[]
webhookApiVersion?: string
embedded?: boolean
posEmbedded?: boolean
preferencesUrl?: string
gdprWebhooks?: {
customerDeletionUrl?: string
customerDataRequestUrl?: string
shopDeletionUrl?: string
}
appProxy?: {
subPath: string
subPathPrefix: string
url: string
}
configuration?: SpecsAppConfiguration
flags: Flag[]
}
Expand Down
127 changes: 123 additions & 4 deletions packages/app/src/cli/services/app/config/link.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,38 @@ describe('link', () => {
})
})

test('creates a new shopify.app.toml file when it does not exist', async () => {
test('creates a new shopify.app.toml file when it does not exist using existing app version configuration instead of the api client configuration', async () => {
await inTemporaryDirectory(async (tmp) => {
// Given
const options: LinkOptions = {
directory: tmp,
developerPlatformClient: buildDeveloperPlatformClient(),
}
vi.mocked(loadApp).mockRejectedValue('App not found')
vi.mocked(fetchOrCreateOrganizationApp).mockResolvedValue({...mockRemoteApp(), newApp: true})
const apiClientConfiguration = {
title: 'new-title',
applicationUrl: 'https://api-client-config.com',
redirectUrlWhitelist: ['https://api-client-config.com/callback'],
requestedAccessScopes: ['write_products'],
webhookApiVersion: '2023-07',
embedded: false,
posEmbedded: true,
preferencesUrl: 'https://api-client-config.com/preferences',
gdprWebhooks: {
customerDeletionUrl: 'https://api-client-config.com/customer-deletion',
customerDataRequestUrl: 'https://api-client-config.com/customer-data-request',
shopDeletionUrl: 'https://api-client-config.com/shop-deletion',
},
appProxy: {
subPath: '/api',
subPathPrefix: 'prefix',
url: 'https://api-client-config.com/proxy',
},
}
vi.mocked(fetchOrCreateOrganizationApp).mockResolvedValue({
...mockRemoteApp(apiClientConfiguration),
newApp: true,
})

// When
await link(options)
Expand Down Expand Up @@ -143,6 +166,102 @@ embedded = false
})
})

test('uses the api client configuration in case there is no configuration app modules', async () => {
await inTemporaryDirectory(async (tmp) => {
// Given
const options: LinkOptions = {
directory: tmp,
developerPlatformClient: buildDeveloperPlatformClient(),
}
vi.mocked(loadApp).mockRejectedValue('App not found')
const apiClientConfiguration = {
title: 'new-title',
applicationUrl: 'https://api-client-config.com',
redirectUrlWhitelist: ['https://api-client-config.com/callback'],
requestedAccessScopes: ['write_products'],
webhookApiVersion: '2023-07',
embedded: false,
posEmbedded: true,
preferencesUrl: 'https://api-client-config.com/preferences',
gdprWebhooks: {
customerDeletionUrl: 'https://api-client-config.com/customer-deletion',
customerDataRequestUrl: 'https://api-client-config.com/customer-data-request',
shopDeletionUrl: 'https://api-client-config.com/shop-deletion',
},
appProxy: {
subPath: '/api',
subPathPrefix: 'prefix',
url: 'https://api-client-config.com/proxy',
},
}
vi.mocked(fetchOrCreateOrganizationApp).mockResolvedValue({
...mockRemoteApp(apiClientConfiguration),
newApp: true,
})
vi.mocked(fetchAppRemoteConfiguration).mockResolvedValue(undefined)

// When
await link(options)

// Then
const content = await readFile(joinPath(tmp, 'shopify.app.toml'))
const expectedContent = `# Learn more about configuring your app at https://shopify.dev/docs/apps/tools/cli/configuration

client_id = "12345"
name = "new-title"
application_url = "https://api-client-config.com"
embedded = false

[build]
include_config_on_deploy = true

[access_scopes]
# Learn more at https://shopify.dev/docs/apps/tools/cli/configuration#access_scopes
scopes = "write_products"

[auth]
redirect_urls = [ "https://api-client-config.com/callback" ]

[webhooks]
api_version = "2023-07"

[webhooks.privacy_compliance]
customer_deletion_url = "https://api-client-config.com/customer-deletion"
customer_data_request_url = "https://api-client-config.com/customer-data-request"
shop_deletion_url = "https://api-client-config.com/shop-deletion"

[app_proxy]
url = "https://api-client-config.com/proxy"
subpath = "/api"
prefix = "prefix"

[pos]
embedded = true

[app_preferences]
url = "https://api-client-config.com/preferences"
`
expect(content).toEqual(expectedContent)
expect(saveCurrentConfig).toHaveBeenCalledWith({configFileName: 'shopify.app.toml', directory: tmp})
expect(renderSuccess).toHaveBeenCalledWith({
headline: 'shopify.app.toml is now linked to "new-title" on Shopify',
body: 'Using shopify.app.toml as your default config.',
nextSteps: [
[`Make updates to shopify.app.toml in your local project`],
['To upload your config, run', {command: 'npm run shopify app deploy'}],
],
reference: [
{
link: {
label: 'App configuration',
url: 'https://shopify.dev/docs/apps/tools/cli/configuration',
},
},
],
})
})
})

test('creates a new shopify.app.staging.toml file when shopify.app.toml already linked', async () => {
await inTemporaryDirectory(async (tmp) => {
// Given
Expand Down Expand Up @@ -909,8 +1028,8 @@ async function mockApp(
return localApp
}

function mockRemoteApp() {
function mockRemoteApp(extraRemoteAppFields: Partial<OrganizationApp> = {}) {
const remoteApp = testOrganizationApp()
remoteApp.apiKey = '12345'
return remoteApp
return {...remoteApp, ...extraRemoteAppFields}
}
Loading