Skip to content

Commit 0261bd7

Browse files
Update authentication requirements for CLI commands (typegen + run)
1 parent fc2f380 commit 0261bd7

File tree

8 files changed

+124
-194
lines changed

8 files changed

+124
-194
lines changed

packages/app/src/cli/commands/app/function/replay.ts

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import {functionFlags, inFunctionContext} from '../../../services/function/common.js'
1+
import {chooseFunction, functionFlags} from '../../../services/function/common.js'
22
import {replay} from '../../../services/function/replay.js'
33
import {appFlags} from '../../../flags.js'
44
import {showApiKeyDeprecationWarning} from '../../../prompts/deprecation-warnings.js'
55
import AppLinkedCommand, {AppLinkedCommandOutput} from '../../../utilities/app-linked-command.js'
6+
import {linkedAppContext} from '../../../services/app-context.js'
67
import {globalFlags, jsonFlag} from '@shopify/cli-kit/node/cli'
78
import {Flags} from '@oclif/core'
89

@@ -45,25 +46,25 @@ export default class FunctionReplay extends AppLinkedCommand {
4546
if (flags['api-key']) {
4647
await showApiKeyDeprecationWarning()
4748
}
48-
const apiKey = flags['client-id'] ?? flags['api-key']
4949

50-
const app = await inFunctionContext({
51-
path: flags.path,
52-
apiKey,
50+
const {app} = await linkedAppContext({
51+
directory: flags.path,
52+
clientId: flags['client-id'] ?? flags['api-key'],
53+
forceRelink: flags.reset,
5354
userProvidedConfigName: flags.config,
54-
reset: flags.reset,
55-
callback: async (app, _, ourFunction) => {
56-
await replay({
57-
app,
58-
extension: ourFunction,
59-
path: flags.path,
60-
log: flags.log,
61-
json: flags.json,
62-
watch: flags.watch,
63-
})
64-
return app
65-
},
6655
})
56+
57+
const ourFunction = await chooseFunction(app, flags.path)
58+
59+
await replay({
60+
app,
61+
extension: ourFunction,
62+
path: flags.path,
63+
log: flags.log,
64+
json: flags.json,
65+
watch: flags.watch,
66+
})
67+
6768
return {app}
6869
}
6970
}

packages/app/src/cli/commands/app/function/run.ts

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import {functionFlags, inFunctionContext, getOrGenerateSchemaPath} from '../../../services/function/common.js'
1+
import {chooseFunction, functionFlags, getOrGenerateSchemaPath} from '../../../services/function/common.js'
22
import {runFunction} from '../../../services/function/runner.js'
33
import {appFlags} from '../../../flags.js'
4-
import AppLinkedCommand, {AppLinkedCommandOutput} from '../../../utilities/app-linked-command.js'
4+
import AppUnlinkedCommand, {AppUnlinkedCommandOutput} from '../../../utilities/app-unlinked-command.js'
5+
import {localAppContext} from '../../../services/app-context.js'
56
import {globalFlags, jsonFlag} from '@shopify/cli-kit/node/cli'
67
import {Flags} from '@oclif/core'
78
import {renderAutocompletePrompt, isTTY} from '@shopify/cli-kit/node/ui'
89
import {outputDebug} from '@shopify/cli-kit/node/output'
910

1011
const DEFAULT_FUNCTION_EXPORT = '_start'
1112

12-
export default class FunctionRun extends AppLinkedCommand {
13+
export default class FunctionRun extends AppUnlinkedCommand {
1314
static summary = 'Run a function locally for testing.'
1415

1516
static descriptionWithMarkdown = `Runs the function from your current directory for [testing purposes](https://shopify.dev/docs/apps/functions/testing-and-debugging). To learn how you can monitor and debug functions when errors occur, refer to [Shopify Functions error handling](https://shopify.dev/docs/api/functions/errors).`
@@ -34,62 +35,64 @@ export default class FunctionRun extends AppLinkedCommand {
3435
}),
3536
}
3637

37-
public async run(): Promise<AppLinkedCommandOutput> {
38+
public async run(): Promise<AppUnlinkedCommandOutput> {
3839
const {flags} = await this.parse(FunctionRun)
39-
const app = await inFunctionContext({
40-
path: flags.path,
41-
userProvidedConfigName: flags.config,
42-
apiKey: flags['client-id'],
43-
reset: flags.reset,
44-
callback: async (app, developerPlatformClient, ourFunction, orgId) => {
45-
let functionExport = DEFAULT_FUNCTION_EXPORT
4640

47-
if (flags.export !== undefined) {
48-
outputDebug(`Using export ${flags.export} from the --export flag.`)
49-
functionExport = flags.export
50-
} else if (
51-
ourFunction.configuration.targeting !== undefined &&
52-
ourFunction.configuration.targeting.length > 0
53-
) {
54-
const targeting = ourFunction.configuration.targeting
41+
let functionExport = DEFAULT_FUNCTION_EXPORT
42+
43+
const app = await localAppContext({
44+
directory: flags.path,
45+
userProvidedConfigName: flags.config,
46+
})
5547

56-
if (targeting.length > 1 && isTTY({})) {
57-
const targets = targeting.map((target) => ({
58-
label: target.target,
59-
value: target.export || DEFAULT_FUNCTION_EXPORT,
60-
}))
48+
const ourFunction = await chooseFunction(app, flags.path)
6149

62-
functionExport = await renderAutocompletePrompt({
63-
message: `Which target would you like to execute?`,
64-
choices: targets,
65-
})
66-
} else {
67-
functionExport = targeting?.[0]?.export || DEFAULT_FUNCTION_EXPORT
68-
outputDebug(
69-
`Using export '${functionExport}'. Use the --export flag or an interactive terminal to select a different export.`,
70-
)
71-
}
72-
} else {
73-
outputDebug(
74-
`No targeting information found. Using the default export '${functionExport}'. Use the --export flag or an interactive terminal to select a different export.`,
75-
)
76-
}
50+
if (flags.export !== undefined) {
51+
outputDebug(`Using export ${flags.export} from the --export flag.`)
52+
functionExport = flags.export
53+
} else if (ourFunction.configuration.targeting !== undefined && ourFunction.configuration.targeting.length > 0) {
54+
const targeting = ourFunction.configuration.targeting
7755

78-
const inputQueryPath = ourFunction?.configuration.targeting?.[0]?.input_query
79-
const queryPath = inputQueryPath && `${ourFunction?.directory}/${inputQueryPath}`
80-
const schemaPath = await getOrGenerateSchemaPath(ourFunction, app, developerPlatformClient, orgId)
56+
if (targeting.length > 1 && isTTY({})) {
57+
const targets = targeting.map((target) => ({
58+
label: target.target,
59+
value: target.export || DEFAULT_FUNCTION_EXPORT,
60+
}))
8161

82-
await runFunction({
83-
functionExtension: ourFunction,
84-
json: flags.json,
85-
inputPath: flags.input,
86-
export: functionExport,
87-
stdin: 'inherit',
88-
schemaPath,
89-
queryPath,
62+
functionExport = await renderAutocompletePrompt({
63+
message: `Which target would you like to execute?`,
64+
choices: targets,
9065
})
91-
return app
92-
},
66+
} else {
67+
functionExport = targeting?.[0]?.export || DEFAULT_FUNCTION_EXPORT
68+
outputDebug(
69+
`Using export '${functionExport}'. Use the --export flag or an interactive terminal to select a different export.`,
70+
)
71+
}
72+
} else {
73+
outputDebug(
74+
`No targeting information found. Using the default export '${functionExport}'. Use the --export flag or an interactive terminal to select a different export.`,
75+
)
76+
}
77+
78+
const inputQueryPath = ourFunction?.configuration.targeting?.[0]?.input_query
79+
const queryPath = inputQueryPath && `${ourFunction?.directory}/${inputQueryPath}`
80+
const schemaPath = await getOrGenerateSchemaPath(
81+
ourFunction,
82+
flags.path,
83+
flags['client-id'],
84+
flags.reset,
85+
flags.config,
86+
)
87+
88+
await runFunction({
89+
functionExtension: ourFunction,
90+
json: flags.json,
91+
inputPath: flags.input,
92+
export: functionExport,
93+
stdin: 'inherit',
94+
schemaPath,
95+
queryPath,
9396
})
9497

9598
return {app}

packages/app/src/cli/commands/app/function/schema.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import {generateSchemaService} from '../../../services/generate-schema.js'
2-
import {functionFlags, inFunctionContext} from '../../../services/function/common.js'
2+
import {chooseFunction, functionFlags} from '../../../services/function/common.js'
33
import {showApiKeyDeprecationWarning} from '../../../prompts/deprecation-warnings.js'
44
import {appFlags} from '../../../flags.js'
55
import AppLinkedCommand, {AppLinkedCommandOutput} from '../../../utilities/app-linked-command.js'
6+
import {linkedAppContext} from '../../../services/app-context.js'
67
import {Flags} from '@oclif/core'
78
import {globalFlags} from '@shopify/cli-kit/node/cli'
89

@@ -41,22 +42,21 @@ export default class FetchSchema extends AppLinkedCommand {
4142
}
4243
const apiKey = flags['client-id'] ?? flags['api-key']
4344

44-
const app = await inFunctionContext({
45-
path: flags.path,
46-
apiKey,
47-
reset: flags.reset,
45+
const {app, developerPlatformClient, organization} = await linkedAppContext({
46+
directory: flags.path,
47+
clientId: apiKey,
48+
forceRelink: flags.reset,
4849
userProvidedConfigName: flags.config,
49-
callback: async (app, developerPlatformClient, ourFunction, orgId) => {
50-
await generateSchemaService({
51-
app,
52-
extension: ourFunction,
53-
developerPlatformClient,
54-
stdout: flags.stdout,
55-
path: flags.path,
56-
orgId,
57-
})
58-
return app
59-
},
50+
})
51+
52+
const ourFunction = await chooseFunction(app, flags.path)
53+
54+
await generateSchemaService({
55+
app,
56+
extension: ourFunction,
57+
stdout: flags.stdout,
58+
developerPlatformClient,
59+
orgId: organization.id,
6060
})
6161

6262
return {app}
Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import {functionFlags, inFunctionContext} from '../../../services/function/common.js'
1+
import {chooseFunction, functionFlags} from '../../../services/function/common.js'
22
import {buildGraphqlTypes} from '../../../services/function/build.js'
33
import {appFlags} from '../../../flags.js'
4-
import AppLinkedCommand from '../../../utilities/app-linked-command.js'
4+
import AppUnlinkedCommand, {AppUnlinkedCommandOutput} from '../../../utilities/app-unlinked-command.js'
5+
import {localAppContext} from '../../../services/app-context.js'
56
import {globalFlags} from '@shopify/cli-kit/node/cli'
67
import {renderSuccess} from '@shopify/cli-kit/node/ui'
78

8-
export default class FunctionTypegen extends AppLinkedCommand {
9+
export default class FunctionTypegen extends AppUnlinkedCommand {
910
static summary = 'Generate GraphQL types for a JavaScript function.'
1011

1112
static descriptionWithMarkdown = `Creates GraphQL types based on your [input query](https://shopify.dev/docs/apps/functions/input-output#input) for a function written in JavaScript.`
@@ -18,19 +19,19 @@ export default class FunctionTypegen extends AppLinkedCommand {
1819
...functionFlags,
1920
}
2021

21-
public async run() {
22+
public async run(): Promise<AppUnlinkedCommandOutput> {
2223
const {flags} = await this.parse(FunctionTypegen)
23-
const app = await inFunctionContext({
24-
path: flags.path,
25-
apiKey: flags['client-id'],
26-
reset: flags.reset,
24+
25+
const app = await localAppContext({
26+
directory: flags.path,
2727
userProvidedConfigName: flags.config,
28-
callback: async (app, _, ourFunction) => {
29-
await buildGraphqlTypes(ourFunction, {stdout: process.stdout, stderr: process.stderr, app})
30-
renderSuccess({headline: 'GraphQL types generated successfully.'})
31-
return app
32-
},
3328
})
29+
30+
const ourFunction = await chooseFunction(app, flags.path)
31+
32+
await buildGraphqlTypes(ourFunction, {stdout: process.stdout, stderr: process.stderr, app})
33+
renderSuccess({headline: 'GraphQL types generated successfully.'})
34+
3435
return {app}
3536
}
3637
}

packages/app/src/cli/services/function/common.test.ts

Lines changed: 8 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {getOrGenerateSchemaPath, inFunctionContext, chooseFunction} from './common.js'
1+
import {getOrGenerateSchemaPath, chooseFunction} from './common.js'
22
import {
33
testAppLinked,
44
testDeveloperPlatformClient,
@@ -42,54 +42,6 @@ beforeEach(async () => {
4242
vi.mocked(isTerminalInteractive).mockReturnValue(true)
4343
})
4444

45-
describe('inFunctionContext integration', () => {
46-
test('passes correct parameters to callback when function is found', async () => {
47-
// Given
48-
const callback = vi.fn().mockResolvedValue(app)
49-
50-
// When
51-
await inFunctionContext({
52-
path: joinPath(app.directory, 'extensions/my-function'),
53-
callback,
54-
})
55-
56-
// Then
57-
expect(callback).toHaveBeenCalledWith(
58-
app,
59-
// developerPlatformClient
60-
expect.any(Object),
61-
ourFunction,
62-
// orgId
63-
expect.any(String),
64-
)
65-
})
66-
67-
test('calls linkedAppContext with correct parameters', async () => {
68-
// Given
69-
const callback = vi.fn().mockResolvedValue(app)
70-
const path = 'some/path'
71-
const apiKey = 'test-api-key'
72-
const userProvidedConfigName = 'test-config'
73-
74-
// When
75-
await inFunctionContext({
76-
path,
77-
apiKey,
78-
userProvidedConfigName,
79-
reset: true,
80-
callback,
81-
})
82-
83-
// Then
84-
expect(linkedAppContext).toHaveBeenCalledWith({
85-
directory: path,
86-
clientId: apiKey,
87-
forceRelink: true,
88-
userProvidedConfigName,
89-
})
90-
})
91-
})
92-
9345
describe('getOrGenerateSchemaPath', () => {
9446
let extension: ExtensionInstance<FunctionConfigType>
9547
let app: AppLinkedInterface
@@ -110,7 +62,8 @@ describe('getOrGenerateSchemaPath', () => {
11062
vi.mocked(fileExists).mockResolvedValue(true)
11163

11264
// When
113-
const result = await getOrGenerateSchemaPath(extension, app, developerPlatformClient, '123')
65+
// Pass extension, app.directory, clientId, forceRelink, userProvidedConfigName
66+
const result = await getOrGenerateSchemaPath(extension, app.directory, '123', false, undefined)
11467

11568
// Then
11669
expect(result).toBe(expectedPath)
@@ -120,12 +73,14 @@ describe('getOrGenerateSchemaPath', () => {
12073
test('generates the schema file if it does not exist', async () => {
12174
// Given
12275
const expectedPath = joinPath(extension.directory, 'schema.graphql')
123-
vi.mocked(fileExists).mockResolvedValue(false)
124-
vi.mocked(generateSchemaService).mockResolvedValueOnce()
76+
vi.mocked(fileExists).mockResolvedValueOnce(false)
12577
vi.mocked(fileExists).mockResolvedValueOnce(true)
12678

79+
vi.mocked(generateSchemaService).mockResolvedValueOnce()
80+
12781
// When
128-
const result = await getOrGenerateSchemaPath(extension, app, developerPlatformClient, '123')
82+
// Pass extension, app.directory, clientId, forceRelink, userProvidedConfigName
83+
const result = await getOrGenerateSchemaPath(extension, app.directory, '123', false, undefined)
12984

13085
// Then
13186
expect(result).toBe(expectedPath)

0 commit comments

Comments
 (0)