Skip to content

Commit 4126f48

Browse files
authored
Merge pull request #5004 from Shopify/12-02-remove_all_conditional_logic_around_app_management_being_disabled
Remove all conditional logic around App Management being disabled
2 parents 06833b2 + de4d15e commit 4126f48

File tree

14 files changed

+69
-199
lines changed

14 files changed

+69
-199
lines changed

.github/workflows/shopify-cli.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ env:
4949
PNPM_VERSION: '8.15.7'
5050
BUNDLE_WITHOUT: 'test:development'
5151
SHOPIFY_FLAG_CLIENT_ID: ${{ secrets.SHOPIFY_FLAG_CLIENT_ID }}
52-
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
5352
GH_TOKEN: ${{ secrets.SHOPIFY_GH_READ_CONTENT_TOKEN }}
5453

5554
jobs:
@@ -87,6 +86,8 @@ jobs:
8786
run: pnpm nx run-many --all --skip-nx-cache --target=test --exclude=features --output-style=stream
8887
- name: Acceptance tests
8988
if: ${{ matrix.node == '18.20.3' }}
89+
env:
90+
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
9091
run: pnpm nx run features:test
9192
- name: Send Slack notification on failure
9293
uses: slackapi/slack-github-action@007b2c3c751a190b6f0f040e47ed024deaa72844 # [email protected]
@@ -305,6 +306,8 @@ jobs:
305306
with:
306307
node-version: ${{ matrix.node }}
307308
- name: Acceptance tests
309+
env:
310+
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
308311
run: pnpm test:features --output-style=stream
309312

310313
pr-test-coverage:
@@ -355,6 +358,8 @@ jobs:
355358
- name: Unit tests
356359
run: pnpm test:unit --output-style=stream
357360
- name: Acceptance tests
361+
env:
362+
SHOPIFY_CLI_PARTNERS_TOKEN: ${{ secrets.SHOPIFY_CLI_PARTNERS_TOKEN }}
358363
run: pnpm test:features --output-style=stream
359364
- name: Setup tmate session
360365
if: ${{ failure() && inputs.debug-enabled }}

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

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ import {joinPath} from '@shopify/cli-kit/node/path'
88
describe('bundleAndBuildExtensions', () => {
99
let app: AppInterface
1010

11-
test('generates a manifest.json when App Management is enabled', async () => {
11+
test('generates a manifest.json', async () => {
1212
await file.inTemporaryDirectory(async (tmpDir: string) => {
1313
// Given
1414
vi.spyOn(file, 'writeFileSync').mockResolvedValue(undefined)
15-
const envVars = {USE_APP_MANAGEMENT_API: 'true'}
1615
const bundlePath = joinPath(tmpDir, 'bundle.zip')
1716

1817
const uiExtension = await testUIExtension({type: 'web_pixel_extension'})
@@ -60,7 +59,7 @@ describe('bundleAndBuildExtensions', () => {
6059
}
6160

6261
// When
63-
await bundleAndBuildExtensions({app, identifiers, bundlePath}, envVars)
62+
await bundleAndBuildExtensions({app, identifiers, bundlePath})
6463

6564
// Then
6665
expect(extensionBundleMock).toHaveBeenCalledTimes(2)
@@ -73,41 +72,6 @@ describe('bundleAndBuildExtensions', () => {
7372
})
7473
})
7574

76-
test('does not generate the manifest.json when App Management is disabled', async () => {
77-
await file.inTemporaryDirectory(async (tmpDir: string) => {
78-
// Given
79-
vi.spyOn(file, 'writeFileSync').mockResolvedValue(undefined)
80-
const bundlePath = joinPath(tmpDir, 'bundle.zip')
81-
82-
const uiExtension = await testUIExtension({type: 'web_pixel_extension'})
83-
const extensionBundleMock = vi.fn()
84-
uiExtension.buildForBundle = extensionBundleMock
85-
const themeExtension = await testThemeExtensions()
86-
themeExtension.buildForBundle = extensionBundleMock
87-
app = testApp({allExtensions: [uiExtension, themeExtension]})
88-
89-
const extensions: {[key: string]: string} = {}
90-
for (const extension of app.allExtensions) {
91-
extensions[extension.localIdentifier] = extension.localIdentifier
92-
}
93-
const identifiers = {
94-
app: 'app-id',
95-
extensions,
96-
extensionIds: {},
97-
extensionsNonUuidManaged: {},
98-
}
99-
100-
// When
101-
await bundleAndBuildExtensions({app, identifiers, bundlePath}, {})
102-
103-
// Then
104-
expect(extensionBundleMock).toHaveBeenCalledTimes(2)
105-
expect(file.writeFileSync).not.toHaveBeenCalled()
106-
107-
await expect(file.fileExists(bundlePath)).resolves.toBeTruthy()
108-
})
109-
})
110-
11175
test('creates a zip file for a function extension', async () => {
11276
await file.inTemporaryDirectory(async (tmpDir: string) => {
11377
// Given
@@ -132,7 +96,7 @@ describe('bundleAndBuildExtensions', () => {
13296
}
13397

13498
// When
135-
await bundleAndBuildExtensions({app, identifiers, bundlePath}, {})
99+
await bundleAndBuildExtensions({app, identifiers, bundlePath})
136100

137101
// Then
138102
await expect(file.fileExists(bundlePath)).resolves.toBeTruthy()

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

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {AbortSignal} from '@shopify/cli-kit/node/abort'
66
import {inTemporaryDirectory, mkdirSync, touchFile, writeFileSync} from '@shopify/cli-kit/node/fs'
77
import {joinPath} from '@shopify/cli-kit/node/path'
88
import {renderConcurrent} from '@shopify/cli-kit/node/ui'
9-
import {isAppManagementEnabled} from '@shopify/cli-kit/node/context/local'
109
import {Writable} from 'stream'
1110

1211
interface BundleOptions {
@@ -15,18 +14,16 @@ interface BundleOptions {
1514
identifiers?: Identifiers
1615
}
1716

18-
export async function bundleAndBuildExtensions(options: BundleOptions, systemEnvironment = process.env) {
17+
export async function bundleAndBuildExtensions(options: BundleOptions) {
1918
await inTemporaryDirectory(async (tmpDir) => {
2019
const bundleDirectory = joinPath(tmpDir, 'bundle')
2120
mkdirSync(bundleDirectory)
2221
await touchFile(joinPath(bundleDirectory, '.shopify'))
2322

24-
if (isAppManagementEnabled(systemEnvironment)) {
25-
// Include manifest in bundle
26-
const appManifest = await options.app.manifest()
27-
const manifestPath = joinPath(bundleDirectory, 'manifest.json')
28-
writeFileSync(manifestPath, JSON.stringify(appManifest, null, 2))
29-
}
23+
// Include manifest in bundle
24+
const appManifest = await options.app.manifest()
25+
const manifestPath = joinPath(bundleDirectory, 'manifest.json')
26+
writeFileSync(manifestPath, JSON.stringify(appManifest, null, 2))
3027

3128
// Force the download of the javy binary in advance to avoid later problems,
3229
// as it might be done multiple times in parallel. https://github.com/Shopify/cli/issues/2877

packages/app/src/cli/services/dev/fetch.test.ts

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ afterEach(() => {
5454
})
5555

5656
describe('fetchOrganizations', async () => {
57-
test('returns fetched organizations from Partners when App Management is disabled', async () => {
57+
test('returns fetched organizations from Partners and App Management', async () => {
5858
// Given
5959
const partnersClient: PartnersClient = testDeveloperPlatformClient({
6060
organizations: () => Promise.resolve([ORG1]),
@@ -68,27 +68,6 @@ describe('fetchOrganizations', async () => {
6868
// When
6969
const got = await fetchOrganizations()
7070

71-
// Then
72-
expect(got).toEqual([ORG1])
73-
expect(partnersClient.organizations).toHaveBeenCalled()
74-
expect(appManagementClient.organizations).not.toHaveBeenCalled()
75-
})
76-
77-
test('returns fetched organizations from Partners and App Management when App Management is enabled', async () => {
78-
// Given
79-
vi.stubEnv('USE_APP_MANAGEMENT_API', '1')
80-
const partnersClient: PartnersClient = testDeveloperPlatformClient({
81-
organizations: () => Promise.resolve([ORG1]),
82-
}) as PartnersClient
83-
const appManagementClient: AppManagementClient = testDeveloperPlatformClient({
84-
organizations: () => Promise.resolve([ORG2]),
85-
}) as AppManagementClient
86-
vi.mocked(PartnersClient).mockReturnValue(partnersClient)
87-
vi.mocked(AppManagementClient).mockReturnValue(appManagementClient)
88-
89-
// When
90-
const got = await fetchOrganizations()
91-
9271
// Then
9372
expect(got).toEqual([ORG1, ORG2])
9473
expect(partnersClient.organizations).toHaveBeenCalled()
@@ -100,14 +79,19 @@ describe('fetchOrganizations', async () => {
10079
const partnersClient: PartnersClient = testDeveloperPlatformClient({
10180
organizations: () => Promise.resolve([]),
10281
}) as PartnersClient
82+
const appManagementClient: AppManagementClient = testDeveloperPlatformClient({
83+
organizations: () => Promise.resolve([]),
84+
}) as AppManagementClient
10385
vi.mocked(PartnersClient).mockReturnValue(partnersClient)
86+
vi.mocked(AppManagementClient).mockReturnValue(appManagementClient)
10487

10588
// When
10689
const got = fetchOrganizations()
10790

10891
// Then
10992
await expect(got).rejects.toThrow(new NoOrgError(testPartnersUserSession.accountInfo))
11093
expect(partnersClient.organizations).toHaveBeenCalled()
94+
expect(appManagementClient.organizations).toHaveBeenCalled()
11195
})
11296
})
11397

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

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ import {
5555
import {DevSessionCreateMutation} from '../api/graphql/app-dev/generated/dev-session-create.js'
5656
import {DevSessionUpdateMutation} from '../api/graphql/app-dev/generated/dev-session-update.js'
5757
import {DevSessionDeleteMutation} from '../api/graphql/app-dev/generated/dev-session-delete.js'
58-
import {isAppManagementEnabled} from '@shopify/cli-kit/node/context/local'
58+
import {isAppManagementDisabled} from '@shopify/cli-kit/node/context/local'
5959

6060
export enum ClientName {
6161
AppManagement = 'app-management',
@@ -77,9 +77,7 @@ export interface AppVersionIdentifiers {
7777
}
7878

7979
export function allDeveloperPlatformClients(): DeveloperPlatformClient[] {
80-
const clients: DeveloperPlatformClient[] = [new PartnersClient()]
81-
if (isAppManagementEnabled()) clients.push(new AppManagementClient())
82-
return clients
80+
return isAppManagementDisabled() ? [new PartnersClient()] : [new PartnersClient(), new AppManagementClient()]
8381
}
8482

8583
/**
@@ -118,11 +116,9 @@ export function selectDeveloperPlatformClient({
118116
configuration,
119117
organization,
120118
}: SelectDeveloperPlatformClientOptions = {}): DeveloperPlatformClient {
121-
if (isAppManagementEnabled()) {
122-
if (organization) return selectDeveloperPlatformClientByOrg(organization)
123-
return selectDeveloperPlatformClientByConfig(configuration)
124-
}
125-
return new PartnersClient()
119+
if (isAppManagementDisabled()) return new PartnersClient()
120+
if (organization) return selectDeveloperPlatformClientByOrg(organization)
121+
return selectDeveloperPlatformClientByConfig(configuration)
126122
}
127123

128124
function selectDeveloperPlatformClientByOrg(organization: Organization): DeveloperPlatformClient {

packages/cli-kit/src/private/node/api/headers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {Environment, serviceEnvironment} from '../context/service.js'
44
import {ExtendableError} from '../../../public/node/error.js'
55
import https from 'https'
66

7-
export class RequestClientError extends ExtendableError {
7+
class RequestClientError extends ExtendableError {
88
statusCode: number
99
public constructor(message: string, statusCode: number) {
1010
super(message)

packages/cli-kit/src/private/node/constants.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ export const environmentVariables = {
4545
otelURL: 'SHOPIFY_CLI_OTEL_EXPORTER_OTLP_ENDPOINT',
4646
themeKitAccessDomain: 'SHOPIFY_CLI_THEME_KIT_ACCESS_DOMAIN',
4747
json: 'SHOPIFY_FLAG_JSON',
48-
useAppManagement: 'USE_APP_MANAGEMENT_API',
4948
}
5049

5150
export const defaultThemeKitAccessDomain = 'theme-kit-access.shopifyapps.com'

packages/cli-kit/src/private/node/session.ts

Lines changed: 3 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,14 @@ import {
1212
import {IdentityToken, Session} from './session/schema.js'
1313
import * as secureStore from './session/store.js'
1414
import {pollForDeviceAuthorization, requestDeviceAuthorization} from './session/device-authorization.js'
15-
import {RequestClientError} from './api/headers.js'
16-
import {getCachedPartnerAccountStatus, setCachedPartnerAccountStatus} from './conf-store.js'
1715
import {isThemeAccessSession} from './api/rest.js'
1816
import {outputContent, outputToken, outputDebug} from '../../public/node/output.js'
19-
import {firstPartyDev, isAppManagementEnabled, themeToken} from '../../public/node/context/local.js'
17+
import {firstPartyDev, themeToken} from '../../public/node/context/local.js'
2018
import {AbortError, BugError} from '../../public/node/error.js'
21-
import {partnersRequest} from '../../public/node/api/partners.js'
22-
import {normalizeStoreFqdn, partnersFqdn, identityFqdn} from '../../public/node/context/fqdn.js'
23-
import {openURL} from '../../public/node/system.js'
24-
import {keypress} from '../../public/node/ui.js'
19+
import {normalizeStoreFqdn, identityFqdn} from '../../public/node/context/fqdn.js'
2520
import {getIdentityTokenInformation, getPartnersToken} from '../../public/node/environment.js'
26-
import {gql} from 'graphql-request'
2721
import {AdminSession} from '@shopify/cli-kit/node/session'
28-
import {outputCompleted, outputInfo, outputWarn} from '@shopify/cli-kit/node/output'
22+
import {outputCompleted} from '@shopify/cli-kit/node/output'
2923
import {isSpin} from '@shopify/cli-kit/node/context/spin'
3024
import {nonRandomUUID} from '@shopify/cli-kit/node/crypto'
3125

@@ -247,9 +241,6 @@ The CLI is currently unable to prompt for reauthentication.`,
247241
if (envToken && applications.partnersApi) {
248242
tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken
249243
}
250-
if (!envToken && tokens.partners) {
251-
await ensureUserHasPartnerAccount(tokens.partners, tokens.userId)
252-
}
253244

254245
setLastSeenAuthMethod(envToken ? 'partners_token' : 'device_auth')
255246
setLastSeenUserIdAfterAuth(tokens.userId)
@@ -301,74 +292,6 @@ async function executeCompleteFlow(applications: OAuthApplications, identityFqdn
301292
return session
302293
}
303294

304-
/**
305-
* If the user creates an account from the Identity website, the created
306-
* account won't get a Partner organization created. We need to detect that
307-
* and take the user to create a partner organization.
308-
*
309-
* @param partnersToken - Partners token.
310-
*/
311-
async function ensureUserHasPartnerAccount(partnersToken: string, userId: string | undefined) {
312-
if (isAppManagementEnabled()) return
313-
314-
outputDebug(outputContent`Verifying that the user has a Partner organization`)
315-
if (!(await hasPartnerAccount(partnersToken, userId))) {
316-
outputInfo(`\nA Shopify Partners organization is needed to proceed.`)
317-
outputInfo(`👉 Press any key to create one`)
318-
await keypress()
319-
await openURL(`https://${await partnersFqdn()}/signup`)
320-
outputInfo(outputContent`👉 Press any key when you have ${outputToken.cyan('created the organization')}`)
321-
outputWarn(outputContent`Make sure you've confirmed your Shopify and the Partner organization from the email`)
322-
await keypress()
323-
if (!(await hasPartnerAccount(partnersToken, userId))) {
324-
throw new AbortError(
325-
`Couldn't find your Shopify Partners organization`,
326-
`Have you confirmed your accounts from the emails you received?`,
327-
)
328-
}
329-
}
330-
}
331-
332-
// eslint-disable-next-line @shopify/cli/no-inline-graphql
333-
const getFirstOrganization = gql`
334-
{
335-
organizations(first: 1) {
336-
nodes {
337-
id
338-
}
339-
}
340-
}
341-
`
342-
343-
/**
344-
* Validate if the current token is valid for partners API.
345-
*
346-
* @param partnersToken - Partners token.
347-
* @returns A promise that resolves to true if the token is valid for partners API.
348-
*/
349-
async function hasPartnerAccount(partnersToken: string, userId?: string): Promise<boolean> {
350-
const cacheKey = userId ?? partnersToken
351-
const cachedStatus = getCachedPartnerAccountStatus(cacheKey)
352-
353-
if (cachedStatus) {
354-
outputDebug(`Confirmed partner account exists from cache`)
355-
return true
356-
}
357-
358-
try {
359-
await partnersRequest(getFirstOrganization, partnersToken)
360-
setCachedPartnerAccountStatus(cacheKey)
361-
return true
362-
// eslint-disable-next-line no-catch-all/no-catch-all
363-
} catch (error) {
364-
if (error instanceof RequestClientError && error.statusCode === 404) {
365-
return false
366-
} else {
367-
return true
368-
}
369-
}
370-
}
371-
372295
/**
373296
* Refresh the tokens for a given session.
374297
*

packages/cli-kit/src/private/node/session/exchange.test.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,18 @@ describe('exchange identity token for application tokens', () => {
5555

5656
test('returns tokens for all APIs if a store is passed', async () => {
5757
// Given
58-
const response = new Response(JSON.stringify(data))
59-
60-
// Need to do it 3 times because a Response can only be used once
61-
vi.mocked(shopifyFetch)
62-
.mockResolvedValue(response)
63-
.mockResolvedValueOnce(response.clone())
64-
.mockResolvedValueOnce(response.clone())
65-
.mockResolvedValueOnce(response.clone())
58+
vi.mocked(shopifyFetch).mockImplementation(async () => Promise.resolve(new Response(JSON.stringify(data))))
6659

6760
// When
6861
const got = await exchangeAccessForApplicationTokens(identityToken, scopes, 'storeFQDN')
6962

7063
// Then
7164
const expected = {
65+
'app-management': {
66+
accessToken: 'access_token',
67+
expiresAt: expiredDate,
68+
scopes: ['scope', 'scope2'],
69+
},
7270
partners: {
7371
accessToken: 'access_token',
7472
expiresAt: expiredDate,
@@ -109,6 +107,11 @@ describe('exchange identity token for application tokens', () => {
109107

110108
// Then
111109
const expected = {
110+
'app-management': {
111+
accessToken: 'access_token',
112+
expiresAt: expiredDate,
113+
scopes: ['scope', 'scope2'],
114+
},
112115
partners: {
113116
accessToken: 'access_token',
114117
expiresAt: expiredDate,

0 commit comments

Comments
 (0)