Skip to content

Commit

Permalink
Merge pull request #663 from Shopify/functions-matching-flag
Browse files Browse the repository at this point in the history
Functions matching behind a flag
  • Loading branch information
isaacroldan committed Oct 24, 2022
2 parents 0a35aca + 968ed2f commit d3089f6
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 9 deletions.
4 changes: 0 additions & 4 deletions fixtures/app/extensions/product-discount/input.graphql
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
{
# select fields on MerchandiseDiscountRoot
# or delete this file if the script requires no input
}
29 changes: 29 additions & 0 deletions packages/app/src/cli/services/environment/identifiers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {FunctionExtension, UIExtension} from '../../models/app/extensions.js'
import {testApp} from '../../models/app/app.test-data.js'
import {beforeEach, describe, expect, it, vi} from 'vitest'
import {err, ok} from '@shopify/cli-kit/common/result'
import {environment} from '@shopify/cli-kit'

const REGISTRATION_A: RemoteSource = {
uuid: 'UUID_A',
Expand Down Expand Up @@ -117,6 +118,7 @@ beforeEach(() => {
...cliKit,
session: {ensureAuthenticatedPartners: async () => 'token'},
ui: {prompt: vi.fn()},
environment: {local: {useFunctionMatching: vi.fn()}},
}
})
vi.mock('../dev/fetch')
Expand All @@ -130,6 +132,7 @@ beforeEach(() => {
describe('ensureDeploymentIdsPresence: matchmaking returns invalid', () => {
it('throw an invalid environment error if functions is invalid', async () => {
// Given
vi.mocked(environment.local.useFunctionMatching).mockReturnValue(true)
vi.mocked(ensureFunctionsIds).mockResolvedValue(err('invalid-environment'))
vi.mocked(ensureExtensionsIds).mockResolvedValue(ok({extensions: {}, extensionIds: {}}))

Expand All @@ -142,6 +145,7 @@ describe('ensureDeploymentIdsPresence: matchmaking returns invalid', () => {

it('throw an invalid environment error if there are pending remote matches', async () => {
// Given
vi.mocked(environment.local.useFunctionMatching).mockReturnValue(true)
vi.mocked(ensureFunctionsIds).mockResolvedValue(err('pending-remote'))
vi.mocked(ensureExtensionsIds).mockResolvedValue(ok({extensions: {}, extensionIds: {}}))

Expand All @@ -154,6 +158,7 @@ describe('ensureDeploymentIdsPresence: matchmaking returns invalid', () => {

it('throw an invalid environment error if extensions is invalid', async () => {
// Given
vi.mocked(environment.local.useFunctionMatching).mockReturnValue(true)
vi.mocked(ensureFunctionsIds).mockResolvedValue(ok({}))
vi.mocked(ensureExtensionsIds).mockResolvedValue(err('invalid-environment'))

Expand All @@ -168,6 +173,7 @@ describe('ensureDeploymentIdsPresence: matchmaking returns invalid', () => {
describe('ensureDeploymentIdsPresence: matchmaking is valid', () => {
it('returns the combination of functions and extensions', async () => {
// Given
vi.mocked(environment.local.useFunctionMatching).mockReturnValue(true)
vi.mocked(ensureFunctionsIds).mockResolvedValue(ok({FUNCTION_A: 'ID_A', FUNCTION_B: 'ID_B'}))
vi.mocked(ensureExtensionsIds).mockResolvedValue(
ok({extensions: {EXTENSION_A: 'UUID_A'}, extensionIds: {EXTENSION_A: 'ID_A'}}),
Expand All @@ -184,3 +190,26 @@ describe('ensureDeploymentIdsPresence: matchmaking is valid', () => {
})
})
})

describe('ensureDeploymentIdsPresence: when not using function matchmaking', () => {
it('returns the combination of functions in .env and extensions', async () => {
// Given
vi.mocked(environment.local.useFunctionMatching).mockReturnValue(false)
vi.mocked(ensureExtensionsIds).mockResolvedValue(
ok({extensions: {EXTENSION_A: 'UUID_A'}, extensionIds: {EXTENSION_A: 'ID_A'}}),
)

// When
const got = await ensureDeploymentIdsPresence(
options([EXTENSION_A, EXTENSION_A_2], [FUNCTION_C], {FUNCTION_C: 'ID_C'}),
)

// Then
await expect(got).toEqual({
app: 'appId',
extensions: {EXTENSION_A: 'UUID_A', FUNCTION_C: 'ID_C'},
extensionIds: {EXTENSION_A: 'ID_A'},
})
expect(vi.mocked(ensureFunctionsIds)).not.toHaveBeenCalled()
})
})
31 changes: 26 additions & 5 deletions packages/app/src/cli/services/environment/identifiers.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {ensureFunctionsIds} from './identifiers-functions.js'
import {ensureExtensionsIds} from './identifiers-extensions.js'
import {AppInterface} from '../../models/app/app.js'
import {Identifiers} from '../../models/app/identifiers.js'
import {Identifiers, IdentifiersExtensions} from '../../models/app/identifiers.js'
import {fetchAppExtensionRegistrations} from '../dev/fetch.js'
import {ExtensionTypes} from '../../constants.js'
import {output, error} from '@shopify/cli-kit'
import {output, error, environment} from '@shopify/cli-kit'
import {PackageManager} from '@shopify/cli-kit/node/node-package-manager'

export interface EnsureDeploymentIdsPresenceOptions {
Expand Down Expand Up @@ -37,19 +37,40 @@ export async function ensureDeploymentIdsPresence(options: EnsureDeploymentIdsPr

const remoteSpecifications = await fetchAppExtensionRegistrations({token: options.token, apiKey: options.appId})

const functions = await ensureFunctionsIds(options, remoteSpecifications.app.functions)
if (functions.isErr()) throw handleIdsError(functions.error, options.appName, options.app.packageManager)
let functions: IdentifiersExtensions
if (environment.local.useFunctionMatching()) {
const result = await ensureFunctionsIds(options, remoteSpecifications.app.functions)
if (result.isErr()) throw handleIdsError(result.error, options.appName, options.app.packageManager)
functions = result.value
} else {
functions = unmatchedFunctionIdentifiers(options)
}

const extensions = await ensureExtensionsIds(options, remoteSpecifications.app.extensionRegistrations)
if (extensions.isErr()) throw handleIdsError(extensions.error, options.appName, options.app.packageManager)

return {
app: options.appId,
extensions: {...functions.value, ...extensions.value.extensions},
extensions: {...functions, ...extensions.value.extensions},
extensionIds: extensions.value.extensionIds,
}
}

function unmatchedFunctionIdentifiers(options: EnsureDeploymentIdsPresenceOptions) {
const validIdentifiers = options.envIdentifiers.extensions ?? {}
const functionLocalIdentifiers: IdentifiersExtensions = Object.fromEntries(
options.app.extensions.function
.map((extension) => extension.localIdentifier)
.map((extensionIdentifier) => {
return validIdentifiers[extensionIdentifier]
? [extensionIdentifier, validIdentifiers[extensionIdentifier]]
: undefined
})
.filter((entry) => entry !== undefined) as string[][],
)
return functionLocalIdentifiers
}

function handleIdsError(errorType: MatchingError, appName: string, packageManager: PackageManager) {
switch (errorType) {
case 'pending-remote':
Expand Down
1 change: 1 addition & 0 deletions packages/cli-kit/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const constants = {
themeToken: 'SHOPIFY_CLI_THEME_TOKEN',
unitTest: 'SHOPIFY_UNIT_TEST',
verbose: 'SHOPIFY_FLAG_VERBOSE',
functionMatching: 'SHOPIFY_CLI_FUNCTION_MATCHING',
// Variables to detect if the CLI is running in a cloud environment
codespaceName: 'CODESPACE_NAME',
codespaces: 'CODESPACES',
Expand Down
4 changes: 4 additions & 0 deletions packages/cli-kit/src/environment/local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ export function useDeviceAuth(env = process.env): boolean {
return isTruthy(env[constants.environmentVariables.deviceAuth]) || isCloudEnvironment(env)
}

export function useFunctionMatching(env = process.env): boolean {
return isTruthy(env[constants.environmentVariables.functionMatching])
}

// https://www.gitpod.io/docs/environment-variables#default-environment-variables
export function gitpodURL(env = process.env): string | undefined {
return env[constants.environmentVariables.gitpod]
Expand Down

0 comments on commit d3089f6

Please sign in to comment.