From 57f112845029e0241585de6de643a2bcd0decca5 Mon Sep 17 00:00:00 2001 From: Cedric van Putten Date: Mon, 31 Oct 2022 18:47:56 +0100 Subject: [PATCH] [eas-cli] Extract entity utilities from update command class (#1478) * refactor(update): remove default non-interactive value to rely on falsy values Co-authored-by: Will Schurman * refactor(updates): make non interactive optional to rely on falsy values * Revert "refactor(update): remove default non-interactive value to rely on falsy values" This reverts commit 23ac36d36e35b7a87724229234d41dcac8cf02db. * Revert "refactor(updates): make non interactive optional to rely on falsy values" This reverts commit 94ae7cc039c94f28b74a5cfd9857f79e5a11e82c. * refactor(update): move ensure methods outside the update command * fix(update): add back log about channel pointing to branch * refactor(branch): reuse query from shared utilsin `branch:create` * refactor(channel): reuse query from shared utilsin `channel:create` Co-authored-by: Will Schurman --- packages/eas-cli/src/branch/queries.ts | 72 +++++++++++++++- packages/eas-cli/src/channel/queries.ts | 65 +++++++++++++++ .../eas-cli/src/commands/branch/create.ts | 40 +-------- .../eas-cli/src/commands/channel/create.ts | 53 +----------- packages/eas-cli/src/commands/update/index.ts | 82 +++---------------- 5 files changed, 150 insertions(+), 162 deletions(-) diff --git a/packages/eas-cli/src/branch/queries.ts b/packages/eas-cli/src/branch/queries.ts index c7a74c21b6..34c35b7d6e 100644 --- a/packages/eas-cli/src/branch/queries.ts +++ b/packages/eas-cli/src/branch/queries.ts @@ -1,8 +1,15 @@ import chalk from 'chalk'; +import gql from 'graphql-tag'; import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient'; import { PaginatedQueryOptions } from '../commandUtils/pagination'; -import { UpdateBranchFragment } from '../graphql/generated'; +import { withErrorHandlingAsync } from '../graphql/client'; +import { + CreateUpdateBranchForAppMutation, + CreateUpdateBranchForAppMutationVariables, + UpdateBranch, + UpdateBranchFragment, +} from '../graphql/generated'; import { BranchQuery } from '../graphql/queries/BranchQuery'; import Log from '../log'; import { formatBranch, getBranchDescription } from '../update/utils'; @@ -11,6 +18,7 @@ import { paginatedQueryWithConfirmPromptAsync, paginatedQueryWithSelectPromptAsync, } from '../utils/queries'; +import { BranchNotFoundError } from './utils'; export const BRANCHES_LIMIT = 50; @@ -111,3 +119,65 @@ function renderPageOfBranches( ); } } + +export async function createUpdateBranchOnAppAsync( + graphqlClient: ExpoGraphqlClient, + { appId, name }: CreateUpdateBranchForAppMutationVariables +): Promise> { + const result = await withErrorHandlingAsync( + graphqlClient + .mutation( + gql` + mutation createUpdateBranchForApp($appId: ID!, $name: String!) { + updateBranch { + createUpdateBranchForApp(appId: $appId, name: $name) { + id + name + } + } + } + `, + { + appId, + name, + } + ) + .toPromise() + ); + const newBranch = result.updateBranch.createUpdateBranchForApp; + if (!newBranch) { + throw new Error(`Could not create branch ${name}.`); + } + return newBranch; +} + +export async function ensureBranchExistsAsync( + graphqlClient: ExpoGraphqlClient, + { + appId, + branchName, + }: { + appId: string; + branchName: string; + } +): Promise<{ branchId: string }> { + try { + const updateBranch = await BranchQuery.getBranchByNameAsync(graphqlClient, { + appId, + name: branchName, + }); + + const { id } = updateBranch; + return { branchId: id }; + } catch (error) { + if (error instanceof BranchNotFoundError) { + const newUpdateBranch = await createUpdateBranchOnAppAsync(graphqlClient, { + appId, + name: branchName, + }); + return { branchId: newUpdateBranch.id }; + } else { + throw error; + } + } +} diff --git a/packages/eas-cli/src/channel/queries.ts b/packages/eas-cli/src/channel/queries.ts index a1b116e5f6..21b07e6fe0 100644 --- a/packages/eas-cli/src/channel/queries.ts +++ b/packages/eas-cli/src/channel/queries.ts @@ -1,8 +1,12 @@ import chalk from 'chalk'; +import gql from 'graphql-tag'; import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient'; import { PaginatedQueryOptions } from '../commandUtils/pagination'; +import { withErrorHandlingAsync } from '../graphql/client'; import { + CreateUpdateChannelOnAppMutation, + CreateUpdateChannelOnAppMutationVariables, ViewBranchesOnUpdateChannelQueryVariables, ViewUpdateChannelsOnAppQueryVariables, } from '../graphql/generated'; @@ -197,3 +201,64 @@ function renderChannelHeaderContent({ Log.addNewLineIfNone(); Log.log(chalk`{bold Branches pointed at this channel and their most recent update group:}`); } + +export async function createChannelOnAppAsync( + graphqlClient: ExpoGraphqlClient, + { + appId, + branchId, + channelName, + }: { + appId: string; + branchId: string; + channelName: string; + } +): Promise { + // Point the new channel at a branch with its same name. + const branchMapping = JSON.stringify({ + data: [{ branchId, branchMappingLogic: 'true' }], + version: 0, + }); + return await withErrorHandlingAsync( + graphqlClient + .mutation( + gql` + mutation CreateUpdateChannelOnApp($appId: ID!, $name: String!, $branchMapping: String!) { + updateChannel { + createUpdateChannelForApp(appId: $appId, name: $name, branchMapping: $branchMapping) { + id + name + branchMapping + } + } + } + `, + { + appId, + name: channelName, + branchMapping, + } + ) + .toPromise() + ); +} + +export async function ensureChannelExistsAsync( + graphqlClient: ExpoGraphqlClient, + { appId, branchId, channelName }: { appId: string; branchId: string; channelName: string } +): Promise { + try { + await createChannelOnAppAsync(graphqlClient, { + appId, + channelName, + branchId, + }); + } catch (e: any) { + const isIgnorableError = + e.graphQLErrors?.length === 1 && + e.graphQLErrors[0].extensions.errorCode === 'CHANNEL_ALREADY_EXISTS'; + if (!isIgnorableError) { + throw e; + } + } +} diff --git a/packages/eas-cli/src/commands/branch/create.ts b/packages/eas-cli/src/commands/branch/create.ts index 046bad9d26..0c07e886dc 100644 --- a/packages/eas-cli/src/commands/branch/create.ts +++ b/packages/eas-cli/src/commands/branch/create.ts @@ -1,52 +1,14 @@ import chalk from 'chalk'; -import gql from 'graphql-tag'; +import { createUpdateBranchOnAppAsync } from '../../branch/queries'; import { getDefaultBranchNameAsync } from '../../branch/utils'; import EasCommand from '../../commandUtils/EasCommand'; -import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient'; import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags'; -import { withErrorHandlingAsync } from '../../graphql/client'; -import { - CreateUpdateBranchForAppMutation, - CreateUpdateBranchForAppMutationVariables, - UpdateBranch, -} from '../../graphql/generated'; import Log from '../../log'; import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils'; import { promptAsync } from '../../prompts'; import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json'; -export async function createUpdateBranchOnAppAsync( - graphqlClient: ExpoGraphqlClient, - { appId, name }: CreateUpdateBranchForAppMutationVariables -): Promise> { - const result = await withErrorHandlingAsync( - graphqlClient - .mutation( - gql` - mutation createUpdateBranchForApp($appId: ID!, $name: String!) { - updateBranch { - createUpdateBranchForApp(appId: $appId, name: $name) { - id - name - } - } - } - `, - { - appId, - name, - } - ) - .toPromise() - ); - const newBranch = result.updateBranch.createUpdateBranchForApp; - if (!newBranch) { - throw new Error(`Could not create branch ${name}.`); - } - return newBranch; -} - export default class BranchCreate extends EasCommand { static override description = 'create a branch'; diff --git a/packages/eas-cli/src/commands/channel/create.ts b/packages/eas-cli/src/commands/channel/create.ts index 9a64daaa24..e135111a0d 100644 --- a/packages/eas-cli/src/commands/channel/create.ts +++ b/packages/eas-cli/src/commands/channel/create.ts @@ -1,63 +1,16 @@ import chalk from 'chalk'; -import gql from 'graphql-tag'; +import { createUpdateBranchOnAppAsync } from '../../branch/queries'; import { BranchNotFoundError } from '../../branch/utils'; +import { createChannelOnAppAsync } from '../../channel/queries'; import EasCommand from '../../commandUtils/EasCommand'; -import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient'; import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags'; -import { withErrorHandlingAsync } from '../../graphql/client'; -import { - CreateUpdateChannelOnAppMutation, - CreateUpdateChannelOnAppMutationVariables, -} from '../../graphql/generated'; import { BranchQuery } from '../../graphql/queries/BranchQuery'; import Log from '../../log'; import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils'; import { promptAsync } from '../../prompts'; import formatFields from '../../utils/formatFields'; import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json'; -import { createUpdateBranchOnAppAsync } from '../branch/create'; - -export async function createUpdateChannelOnAppAsync( - graphqlClient: ExpoGraphqlClient, - { - appId, - channelName, - branchId, - }: { - appId: string; - channelName: string; - branchId: string; - } -): Promise { - // Point the new channel at a branch with its same name. - const branchMapping = JSON.stringify({ - data: [{ branchId, branchMappingLogic: 'true' }], - version: 0, - }); - return await withErrorHandlingAsync( - graphqlClient - .mutation( - gql` - mutation CreateUpdateChannelOnApp($appId: ID!, $name: String!, $branchMapping: String!) { - updateChannel { - createUpdateChannelForApp(appId: $appId, name: $name, branchMapping: $branchMapping) { - id - name - branchMapping - } - } - } - `, - { - appId, - name: channelName, - branchMapping, - } - ) - .toPromise() - ); -} export default class ChannelCreate extends EasCommand { static override description = 'create a channel'; @@ -132,7 +85,7 @@ export default class ChannelCreate extends EasCommand { const { updateChannel: { createUpdateChannelForApp: newChannel }, - } = await createUpdateChannelOnAppAsync(graphqlClient, { + } = await createChannelOnAppAsync(graphqlClient, { appId: projectId, channelName, branchId, diff --git a/packages/eas-cli/src/commands/update/index.ts b/packages/eas-cli/src/commands/update/index.ts index 88970c087c..a53381aee4 100644 --- a/packages/eas-cli/src/commands/update/index.ts +++ b/packages/eas-cli/src/commands/update/index.ts @@ -7,9 +7,10 @@ import chalk from 'chalk'; import nullthrows from 'nullthrows'; import { getEASUpdateURL } from '../../api'; -import { selectBranchOnAppAsync } from '../../branch/queries'; -import { BranchNotFoundError, getDefaultBranchNameAsync } from '../../branch/utils'; +import { ensureBranchExistsAsync, selectBranchOnAppAsync } from '../../branch/queries'; +import { getDefaultBranchNameAsync } from '../../branch/utils'; import { getUpdateGroupUrl } from '../../build/utils/url'; +import { ensureChannelExistsAsync } from '../../channel/queries'; import EasCommand from '../../commandUtils/EasCommand'; import { DynamicConfigContextFn } from '../../commandUtils/context/DynamicProjectConfigContextField'; import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient'; @@ -22,10 +23,8 @@ import { Update, UpdateInfoGroup, UpdatePublishMutation, - ViewBranchQueryVariables, } from '../../graphql/generated'; import { PublishMutation } from '../../graphql/mutations/PublishMutation'; -import { BranchQuery } from '../../graphql/queries/BranchQuery'; import { UpdateQuery } from '../../graphql/queries/UpdateQuery'; import Log, { learnMore, link } from '../../log'; import { ora } from '../../ora'; @@ -57,8 +56,6 @@ import formatFields from '../../utils/formatFields'; import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json'; import { maybeWarnAboutEasOutagesAsync } from '../../utils/statuspageService'; import { getVcsClient } from '../../vcs'; -import { createUpdateBranchOnAppAsync } from '../branch/create'; -import { createUpdateChannelOnAppAsync } from '../channel/create'; import { configureAppJSONForEASUpdateAsync, configureNativeFilesForEASUpdateAsync, @@ -95,71 +92,6 @@ type UpdateFlags = { nonInteractive: boolean; }; -async function ensureChannelExistsAsync( - graphqlClient: ExpoGraphqlClient, - { - appId, - branchId, - channelName, - }: { - appId: string; - branchId: string; - channelName: string; - } -): Promise { - try { - await createUpdateChannelOnAppAsync(graphqlClient, { - appId, - channelName, - branchId, - }); - Log.withTick( - `Created a channel: ${chalk.bold(channelName)} pointed at branch: ${chalk.bold(channelName)}.` - ); - } catch (e: any) { - const isIgnorableError = - e.graphQLErrors?.length === 1 && - e.graphQLErrors[0].extensions.errorCode === 'CHANNEL_ALREADY_EXISTS'; - if (!isIgnorableError) { - throw e; - } - } -} - -export async function ensureBranchExistsAsync( - graphqlClient: ExpoGraphqlClient, - { appId, name: branchName }: ViewBranchQueryVariables -): Promise<{ - branchId: string; -}> { - try { - const updateBranch = await BranchQuery.getBranchByNameAsync(graphqlClient, { - appId, - name: branchName, - }); - - const { id } = updateBranch; - await ensureChannelExistsAsync(graphqlClient, { appId, branchId: id, channelName: branchName }); - return { branchId: id }; - } catch (error) { - if (error instanceof BranchNotFoundError) { - const newUpdateBranch = await createUpdateBranchOnAppAsync(graphqlClient, { - appId, - name: branchName, - }); - Log.withTick(`Created branch: ${chalk.bold(branchName)}`); - await ensureChannelExistsAsync(graphqlClient, { - appId, - branchId: newUpdateBranch.id, - channelName: branchName, - }); - return { branchId: newUpdateBranch.id }; - } else { - throw error; - } - } -} - export default class UpdatePublish extends EasCommand { static override description = 'publish an update group'; @@ -484,8 +416,14 @@ export default class UpdatePublish extends EasCommand { const { branchId } = await ensureBranchExistsAsync(graphqlClient, { appId: projectId, - name: branchName, + branchName, + }); + await ensureChannelExistsAsync(graphqlClient, { + appId: projectId, + branchId, + channelName: branchName, }); + Log.withTick(`Channel: ${chalk.bold(branchName)} pointed at branch: ${chalk.bold(branchName)}`); // Sort the updates into different groups based on their platform specific runtime versions const updateGroups: PublishUpdateGroupInput[] = Object.entries(runtimeToPlatformMapping).map(