diff --git a/packages/eas-cli/graphql.schema.json b/packages/eas-cli/graphql.schema.json index d6917dcb90..bcfac94c27 100644 --- a/packages/eas-cli/graphql.schema.json +++ b/packages/eas-cli/graphql.schema.json @@ -27480,6 +27480,18 @@ "defaultValue": null, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "appId", + "description": null, + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null } ], "type": { @@ -27581,7 +27593,20 @@ { "name": "value", "description": null, - "args": [], + "args": [ + { + "name": "includeFileContent", + "description": null, + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], "type": { "kind": "SCALAR", "name": "String", diff --git a/packages/eas-cli/src/commands/env/__tests__/EnvironmentVariableCreate.test.ts b/packages/eas-cli/src/commands/env/__tests__/EnvironmentVariableCreate.test.ts new file mode 100644 index 0000000000..060857811a --- /dev/null +++ b/packages/eas-cli/src/commands/env/__tests__/EnvironmentVariableCreate.test.ts @@ -0,0 +1,354 @@ +import { Config } from '@oclif/core'; + +import { getMockAppFragment } from '../../../__tests__/commands/utils'; +import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient'; +import { testProjectId } from '../../../credentials/__tests__/fixtures-constants'; +import { + EnvironmentSecretType, + EnvironmentVariableEnvironment, + EnvironmentVariableScope, + EnvironmentVariableVisibility, +} from '../../../graphql/generated'; +import { EnvironmentVariableMutation } from '../../../graphql/mutations/EnvironmentVariableMutation'; +import { AppQuery } from '../../../graphql/queries/AppQuery'; +import { EnvironmentVariablesQuery } from '../../../graphql/queries/EnvironmentVariablesQuery'; +import { + promptVariableEnvironmentAsync, + promptVariableNameAsync, + promptVariableValueAsync, +} from '../../../utils/prompts'; +import EnvironmentVariableCreate from '../create'; + +jest.mock('../../../graphql/mutations/EnvironmentVariableMutation'); +jest.mock('../../../graphql/queries/AppQuery'); +jest.mock('../../../graphql/queries/EnvironmentVariablesQuery'); +jest.mock('../../../utils/prompts'); + +describe(EnvironmentVariableCreate, () => { + const graphqlClient = {} as any as ExpoGraphqlClient; + const mockConfig = {} as unknown as Config; + const variableId = 'testId'; + const testAccountId = 'test-account-id'; + + beforeEach(() => { + jest.resetAllMocks(); + jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment()); + jest + .mocked(EnvironmentVariableMutation.createForAppAsync) + .mockImplementation(async (_client, input, _appId) => ({ + ...input, + id: variableId, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + scope: EnvironmentVariableScope.Project, + })); + jest + .mocked(EnvironmentVariableMutation.createSharedVariableAsync) + .mockImplementation(async (_client, input, _appId) => ({ + ...input, + id: variableId, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + scope: EnvironmentVariableScope.Shared, + })); + jest + .mocked(EnvironmentVariableMutation.updateAsync) + .mockImplementation(async (_client, input) => ({ + ...input, + id: variableId, + name: 'VarName', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + scope: EnvironmentVariableScope.Shared, + })); + jest.mocked(EnvironmentVariablesQuery.byAppIdAsync).mockImplementation(async () => []); + jest.mocked(EnvironmentVariablesQuery.sharedAsync).mockImplementation(async () => []); + }); + + describe('in interactive mode', () => { + it('creates a project variable', async () => { + const command = new EnvironmentVariableCreate( + ['--name', 'VarName', '--value', 'VarValue', '--environment', 'production'], + mockConfig + ); + + // @ts-expect-error + jest.spyOn(command, 'getContextAsync').mockReturnValue({ + loggedIn: { graphqlClient }, + privateProjectConfig: { projectId: testProjectId }, + }); + + await command.runAsync(); + + expect(EnvironmentVariableMutation.createForAppAsync).toHaveBeenCalledWith( + graphqlClient, + { + name: 'VarName', + value: 'VarValue', + environments: [EnvironmentVariableEnvironment.Production], + visibility: EnvironmentVariableVisibility.Public, + type: EnvironmentSecretType.String, + }, + testProjectId + ); + }); + + it('updates an existing variable in the same environment', async () => { + const command = new EnvironmentVariableCreate( + ['--name', 'VarName', '--value', 'VarValue', '--environment', 'production'], + mockConfig + ); + + // @ts-expect-error + jest.spyOn(command, 'getContextAsync').mockReturnValue({ + loggedIn: { graphqlClient }, + privateProjectConfig: { projectId: testProjectId }, + }); + + const otherVariableId = 'otherId'; + + jest + .mocked(EnvironmentVariablesQuery.byAppIdAsync) + // @ts-expect-error + .mockImplementation(async () => [ + { + id: otherVariableId, + environments: [EnvironmentVariableEnvironment.Production], + scope: EnvironmentVariableScope.Project, + }, + ]); + + // @ts-expect-error + jest.spyOn(command, 'promptForOverwriteAsync').mockResolvedValue(true); + jest + .mocked(EnvironmentVariableMutation.updateAsync) + // @ts-expect-error + .mockImplementation(async (_client, input) => ({ + ...input, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + scope: EnvironmentVariableScope.Project, + })); + + await command.runAsync(); + + expect(EnvironmentVariablesQuery.byAppIdAsync).toHaveBeenCalledWith(graphqlClient, { + appId: testProjectId, + filterNames: ['VarName'], + }); + + expect(EnvironmentVariableMutation.updateAsync).toHaveBeenCalledWith(graphqlClient, { + id: otherVariableId, + name: 'VarName', + value: 'VarValue', + environments: [EnvironmentVariableEnvironment.Production], + visibility: EnvironmentVariableVisibility.Public, + }); + }); + + it('creates a shared variable', async () => { + const command = new EnvironmentVariableCreate( + [ + '--name', + 'VarName', + '--value', + 'VarValue', + '--environment', + 'production', + '--scope', + 'shared', + ], + mockConfig + ); + + // @ts-expect-error + jest.spyOn(command, 'getContextAsync').mockReturnValue({ + loggedIn: { graphqlClient }, + privateProjectConfig: { projectId: testProjectId }, + }); + + await command.runAsync(); + + expect(EnvironmentVariableMutation.createSharedVariableAsync).toHaveBeenCalledWith( + graphqlClient, + { + name: 'VarName', + value: 'VarValue', + environments: [EnvironmentVariableEnvironment.Production], + visibility: EnvironmentVariableVisibility.Public, + type: EnvironmentSecretType.String, + }, + 'test-account-id' + ); + }); + + it('throws if a shared variable already exists', async () => { + const command = new EnvironmentVariableCreate( + [ + '--name', + 'VarName', + '--value', + 'VarValue', + '--environment', + 'production', + '--scope', + 'shared', + ], + mockConfig + ); + + // @ts-expect-error + jest.spyOn(command, 'getContextAsync').mockReturnValue({ + loggedIn: { graphqlClient }, + privateProjectConfig: { projectId: testProjectId }, + }); + + jest + .mocked(EnvironmentVariablesQuery.sharedAsync) + // @ts-expect-error + .mockImplementation(async () => [ + { + id: 'otherId', + environments: [EnvironmentVariableEnvironment.Production], + scope: EnvironmentVariableScope.Shared, + }, + ]); + + await expect(command.runAsync()).rejects.toThrow(); + }); + + it('updates if a shared variable already exists and --force flag is set', async () => { + const command = new EnvironmentVariableCreate( + [ + '--name', + 'VarName', + '--value', + 'VarValue', + '--environment', + 'production', + '--force', + '--scope', + 'shared', + ], + mockConfig + ); + + const otherVariableId = 'otherId'; + + // @ts-expect-error + jest.spyOn(command, 'getContextAsync').mockReturnValue({ + loggedIn: { graphqlClient }, + privateProjectConfig: { projectId: testProjectId }, + }); + + jest + .mocked(EnvironmentVariablesQuery.sharedAsync) + // @ts-expect-error + .mockImplementation(async () => [ + { + id: otherVariableId, + environments: [EnvironmentVariableEnvironment.Production], + scope: EnvironmentVariableScope.Shared, + }, + ]); + + await command.runAsync(); + + expect(EnvironmentVariableMutation.updateAsync).toHaveBeenCalledWith(graphqlClient, { + id: otherVariableId, + name: 'VarName', + value: 'VarValue', + environments: [EnvironmentVariableEnvironment.Production], + visibility: EnvironmentVariableVisibility.Public, + }); + }); + + it('creates a shared variable and links it', async () => { + const command = new EnvironmentVariableCreate( + [ + '--name', + 'VarName', + '--value', + 'VarValue', + '--environment', + 'production', + '--environment', + 'development', + '--scope', + 'shared', + '--link', + ], + mockConfig + ); + + // @ts-expect-error + jest.spyOn(command, 'getContextAsync').mockReturnValue({ + loggedIn: { graphqlClient }, + privateProjectConfig: { projectId: testProjectId }, + }); + + await command.runAsync(); + + expect(EnvironmentVariableMutation.createSharedVariableAsync).toHaveBeenCalledWith( + graphqlClient, + { + name: 'VarName', + value: 'VarValue', + environments: [ + EnvironmentVariableEnvironment.Production, + EnvironmentVariableEnvironment.Development, + ], + visibility: EnvironmentVariableVisibility.Public, + type: EnvironmentSecretType.String, + }, + testAccountId + ); + expect(EnvironmentVariableMutation.linkSharedEnvironmentVariableAsync).toHaveBeenCalledWith( + graphqlClient, + 'testId', + testProjectId, + EnvironmentVariableEnvironment.Production + ); + expect(EnvironmentVariableMutation.linkSharedEnvironmentVariableAsync).toHaveBeenCalledWith( + graphqlClient, + 'testId', + testProjectId, + EnvironmentVariableEnvironment.Development + ); + }); + + it('prompts for missing arguments', async () => { + const command = new EnvironmentVariableCreate([], mockConfig); + + jest.mocked(promptVariableNameAsync).mockImplementation(async () => 'VarName'); + jest.mocked(promptVariableValueAsync).mockImplementation(async () => 'VarValue'); + jest + .mocked(promptVariableEnvironmentAsync) + // @ts-expect-error + .mockImplementation(async () => [EnvironmentVariableEnvironment.Production]); + + // @ts-expect-error + jest.spyOn(command, 'getContextAsync').mockReturnValue({ + loggedIn: { graphqlClient }, + privateProjectConfig: { projectId: testProjectId }, + }); + + await command.runAsync(); + + expect(promptVariableNameAsync).toHaveBeenCalled(); + expect(promptVariableValueAsync).toHaveBeenCalled(); + expect(promptVariableEnvironmentAsync).toHaveBeenCalled(); + expect(EnvironmentVariableMutation.createForAppAsync).toHaveBeenCalledWith( + graphqlClient, + { + name: 'VarName', + value: 'VarValue', + environments: [EnvironmentVariableEnvironment.Production], + visibility: EnvironmentVariableVisibility.Public, + type: EnvironmentSecretType.String, + }, + testProjectId + ); + }); + }); +}); diff --git a/packages/eas-cli/src/commands/env/create.ts b/packages/eas-cli/src/commands/env/create.ts index e07039a2e6..cf45de2c34 100644 --- a/packages/eas-cli/src/commands/env/create.ts +++ b/packages/eas-cli/src/commands/env/create.ts @@ -3,7 +3,7 @@ import chalk from 'chalk'; import EasCommand from '../../commandUtils/EasCommand'; import { - EASEnvironmentFlag, + EASMultiEnvironmentFlag, EASNonInteractiveFlag, EASVariableScopeFlag, EASVariableVisibilityFlag, @@ -27,6 +27,7 @@ import { promptVariableNameAsync, promptVariableValueAsync, } from '../../utils/prompts'; +import { performForEnvironmentsAsync } from '../../utils/variableUtils'; type CreateFlags = { name?: string; @@ -35,7 +36,7 @@ type CreateFlags = { force?: boolean; visibility?: EnvironmentVariableVisibility; scope?: EnvironmentVariableScope; - environment?: EnvironmentVariableEnvironment; + environment?: EnvironmentVariableEnvironment[]; 'non-interactive': boolean; }; @@ -61,7 +62,7 @@ export default class EnvironmentVariableCreate extends EasCommand { }), ...EASVariableVisibilityFlag, ...EASVariableScopeFlag, - ...EASEnvironmentFlag, + ...EASMultiEnvironmentFlag, ...EASNonInteractiveFlag, }; @@ -74,16 +75,18 @@ export default class EnvironmentVariableCreate extends EasCommand { async runAsync(): Promise { const { flags } = await this.parse(EnvironmentVariableCreate); - let { + const validatedFlags = this.validateFlags(flags); + + const { name, value, scope, 'non-interactive': nonInteractive, - environment, + environment: environments, visibility, link, force, - } = this.validateFlags(flags); + } = await this.promptForMissingFlagsAsync(validatedFlags); const { privateProjectConfig: { projectId }, @@ -97,103 +100,74 @@ export default class EnvironmentVariableCreate extends EasCommand { getOwnerAccountForProjectIdAsync(graphqlClient, projectId), ]); - if (!name) { - name = await promptVariableNameAsync(nonInteractive); - } - let overwrite = false; - visibility = visibility ?? EnvironmentVariableVisibility.Public; - - if (!value) { - value = await promptVariableValueAsync({ - nonInteractive, - hidden: visibility !== EnvironmentVariableVisibility.Public, - }); - } - - if (!environment) { - environment = await promptVariableEnvironmentAsync({ nonInteractive }); - } - - const environments = [environment]; if (scope === EnvironmentVariableScope.Project) { const existingVariables = await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, { appId: projectId, - environment, + filterNames: [name], }); - const existingVariable = existingVariables.find(variable => variable.name === name); + + const existingVariable = existingVariables.find( + variable => !environments || variable.environments?.some(env => environments?.includes(env)) + ); if (existingVariable) { + if (existingVariable.scope === EnvironmentVariableScope.Project) { + await this.promptForOverwriteAsync({ + nonInteractive, + force, + message: `Variable ${name} already exists on this project.`, + suggestion: 'Do you want to overwrite it?', + }); + overwrite = true; + } if (existingVariable.scope === EnvironmentVariableScope.Shared) { - if (!nonInteractive) { - const confirmation = await confirmAsync({ - message: `Shared variable ${name} already exists on this project. Do you want to unlink it first?`, - }); - - if (!confirmation) { - Log.log('Aborting'); - throw new Error(`Shared variable ${name} already exists on this project.`); - } - } else if (!force) { - throw new Error( - `Shared variable ${name} already exists on this project. Use --force to overwrite it.` - ); - } + await this.promptForOverwriteAsync({ + nonInteractive, + force, + message: `Shared variable with ${name} name already exists on this account.`, + suggestion: 'Do you want to unlink it first?', + }); - await EnvironmentVariableMutation.unlinkSharedEnvironmentVariableAsync( - graphqlClient, - existingVariable.id, - projectId, - environment - ); Log.withTick( `Unlinking shared variable ${chalk.bold(name)} on project ${chalk.bold( projectDisplayName )}.` ); - } else { - if (!nonInteractive) { - const confirmation = await confirmAsync({ - message: `Variable ${name} already exists on this project. Do you want to overwrite it?`, - }); - - if (!confirmation) { - Log.log('Aborting'); - throw new Error( - `Variable ${name} already exists on this project. Use --force to overwrite it.` - ); - } - } else if (!force) { - throw new Error( - `Variable ${name} already exists on this project. Use --force to overwrite it.` + + await performForEnvironmentsAsync(environments, async environment => { + await EnvironmentVariableMutation.unlinkSharedEnvironmentVariableAsync( + graphqlClient, + existingVariable.id, + projectId, + environment ); - } - overwrite = true; + }); } } - let variable; - if (overwrite && existingVariable) { - variable = await EnvironmentVariableMutation.updateAsync(graphqlClient, { - id: existingVariable.id, - name, - value, - visibility, - environments, - }); - } else { - variable = await EnvironmentVariableMutation.createForAppAsync( - graphqlClient, - { - name, - value, - environments, - visibility, - type: EnvironmentSecretType.String, - }, - projectId - ); - } + + const variable = + overwrite && existingVariable + ? await EnvironmentVariableMutation.updateAsync(graphqlClient, { + id: existingVariable.id, + name, + value, + visibility, + environments, + }) + : await EnvironmentVariableMutation.createForAppAsync( + graphqlClient, + { + name, + value, + environments, + visibility, + type: EnvironmentSecretType.String, + }, + projectId + ); + if (!variable) { throw new Error( `Could not create variable with name ${name} on project ${projectDisplayName}` @@ -204,39 +178,46 @@ export default class EnvironmentVariableCreate extends EasCommand { `Created a new variable ${chalk.bold(name)} on project ${chalk.bold(projectDisplayName)}.` ); } else if (scope === EnvironmentVariableScope.Shared) { - const sharedVariables = await EnvironmentVariablesQuery.sharedAsync(graphqlClient, { + const existingVariables = await EnvironmentVariablesQuery.sharedAsync(graphqlClient, { appId: projectId, + filterNames: [name], }); - const existingVariable = sharedVariables.find(variable => variable.name === name); - if (existingVariable) { - throw new Error( - `Shared variable with ${name} name already exists on this account.\n` + - `Use a different name or delete the existing variable on website or by using eas env:delete --name ${name} --scope shared command.` - ); - } - if (environment && !link) { - const confirmation = await confirmAsync({ - message: `Unexpected argument: --environment can only be used with --link flag. Do you want to link the variable to the current project?`, - }); + const existingVariable = existingVariables.find( + variable => !environments || variable.environments?.some(env => environments?.includes(env)) + ); - if (!confirmation) { - Log.log('Aborting'); - throw new Error('Unexpected argument: --environment can only be used with --link flag.'); + if (existingVariable) { + if (force) { + overwrite = true; + } else { + throw new Error( + `Shared variable with ${name} name already exists on this account.\n` + + `Use a different name or delete the existing variable on website or by using eas env:delete --name ${name} --scope shared command.` + ); } } - const variable = await EnvironmentVariableMutation.createSharedVariableAsync( - graphqlClient, - { - name, - value, - visibility, - environments, - type: EnvironmentSecretType.String, - }, - ownerAccount.id - ); + const variable = + overwrite && existingVariable + ? await EnvironmentVariableMutation.updateAsync(graphqlClient, { + id: existingVariable.id, + name, + value, + visibility, + environments, + }) + : await EnvironmentVariableMutation.createSharedVariableAsync( + graphqlClient, + { + name, + value, + visibility, + environments, + type: EnvironmentSecretType.String, + }, + ownerAccount.id + ); if (!variable) { throw new Error( @@ -248,18 +229,22 @@ export default class EnvironmentVariableCreate extends EasCommand { `Created a new variable ${chalk.bold(name)} on account ${chalk.bold(ownerAccount.name)}.` ); - if (link && environment) { + if (link) { Log.withTick( `Linking shared variable ${chalk.bold(name)} to project ${chalk.bold( projectDisplayName )}.` ); - await EnvironmentVariableMutation.linkSharedEnvironmentVariableAsync( - graphqlClient, - variable.id, - projectId, - environment - ); + + await performForEnvironmentsAsync(environments, async environment => { + await EnvironmentVariableMutation.linkSharedEnvironmentVariableAsync( + graphqlClient, + variable.id, + projectId, + environment + ); + }); + Log.withTick( `Linked shared variable ${chalk.bold(name)} to project ${chalk.bold(projectDisplayName)}.` ); @@ -267,6 +252,67 @@ export default class EnvironmentVariableCreate extends EasCommand { } } + private async promptForOverwriteAsync({ + nonInteractive, + force, + message, + suggestion, + }: { + nonInteractive: boolean; + force: boolean; + message: string; + suggestion: string; + }): Promise { + if (!nonInteractive) { + const confirmation = await confirmAsync({ + message: `${message} ${suggestion}`, + }); + + if (!confirmation) { + Log.log('Aborting'); + throw new Error(`${message}`); + } + } else if (!force) { + throw new Error(`${message} Use --force to overwrite it.`); + } + } + + private async promptForMissingFlagsAsync({ + name, + value, + environment, + visibility = EnvironmentVariableVisibility.Public, + 'non-interactive': nonInteractive, + ...rest + }: CreateFlags): Promise> { + if (!name) { + name = await promptVariableNameAsync(nonInteractive); + } + + if (!value) { + value = await promptVariableValueAsync({ + nonInteractive, + hidden: visibility !== EnvironmentVariableVisibility.Public, + }); + } + + if (!environment) { + environment = await promptVariableEnvironmentAsync({ nonInteractive, multiple: true }); + } + + return { + name, + value, + environment, + visibility, + link: rest.link ?? false, + force: rest.force ?? false, + scope: rest.scope ?? EnvironmentVariableScope.Project, + 'non-interactive': nonInteractive, + ...rest, + }; + } + private validateFlags(flags: CreateFlags): CreateFlags { if (flags.scope !== EnvironmentVariableScope.Shared && flags.link) { throw new Error( diff --git a/packages/eas-cli/src/commands/env/get.ts b/packages/eas-cli/src/commands/env/get.ts index bcfdfbc19a..4963d57ee0 100644 --- a/packages/eas-cli/src/commands/env/get.ts +++ b/packages/eas-cli/src/commands/env/get.ts @@ -16,8 +16,8 @@ import { } from '../../graphql/generated'; import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery'; import Log from '../../log'; -import { formatVariable } from '../../utils/formatVariable'; import { promptVariableEnvironmentAsync, promptVariableNameAsync } from '../../utils/prompts'; +import { formatVariable } from '../../utils/variableUtils'; type GetFlags = { name?: string; diff --git a/packages/eas-cli/src/commands/env/list.ts b/packages/eas-cli/src/commands/env/list.ts index b5fd7875d7..8b1e4797f9 100644 --- a/packages/eas-cli/src/commands/env/list.ts +++ b/packages/eas-cli/src/commands/env/list.ts @@ -15,8 +15,8 @@ import { } from '../../graphql/generated'; import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery'; import Log from '../../log'; -import { formatVariable } from '../../utils/formatVariable'; import { promptVariableEnvironmentAsync } from '../../utils/prompts'; +import { formatVariable } from '../../utils/variableUtils'; export default class EnvironmentValueList extends EasCommand { static override description = 'list environment variables for the current project'; diff --git a/packages/eas-cli/src/graphql/generated.ts b/packages/eas-cli/src/graphql/generated.ts index 634f8afe5e..470882b677 100644 --- a/packages/eas-cli/src/graphql/generated.ts +++ b/packages/eas-cli/src/graphql/generated.ts @@ -4064,6 +4064,12 @@ export type EnvironmentVariableWithSecret = { export type EnvironmentVariableWithSecretLinkedEnvironmentsArgs = { appFullName?: InputMaybe; + appId?: InputMaybe; +}; + + +export type EnvironmentVariableWithSecretValueArgs = { + includeFileContent?: InputMaybe; }; export type EstimatedOverageAndCost = { @@ -8430,7 +8436,7 @@ export type LinkSharedEnvironmentVariableMutationVariables = Exact<{ }>; -export type LinkSharedEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', linkSharedEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environment?: EnvironmentVariableEnvironment | null, createdAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; +export type LinkSharedEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', linkSharedEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; export type UnlinkSharedEnvironmentVariableMutationVariables = Exact<{ appId: Scalars['ID']['input']; @@ -8439,7 +8445,7 @@ export type UnlinkSharedEnvironmentVariableMutationVariables = Exact<{ }>; -export type UnlinkSharedEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', unlinkSharedEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environment?: EnvironmentVariableEnvironment | null, createdAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; +export type UnlinkSharedEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', unlinkSharedEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; export type CreateEnvironmentVariableForAccountMutationVariables = Exact<{ input: CreateSharedEnvironmentVariableInput; @@ -8447,7 +8453,7 @@ export type CreateEnvironmentVariableForAccountMutationVariables = Exact<{ }>; -export type CreateEnvironmentVariableForAccountMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', createEnvironmentVariableForAccount: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environment?: EnvironmentVariableEnvironment | null, createdAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; +export type CreateEnvironmentVariableForAccountMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', createEnvironmentVariableForAccount: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; export type CreateEnvironmentVariableForAppMutationVariables = Exact<{ input: CreateEnvironmentVariableInput; @@ -8455,14 +8461,14 @@ export type CreateEnvironmentVariableForAppMutationVariables = Exact<{ }>; -export type CreateEnvironmentVariableForAppMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', createEnvironmentVariableForApp: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environment?: EnvironmentVariableEnvironment | null, createdAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; +export type CreateEnvironmentVariableForAppMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', createEnvironmentVariableForApp: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; export type UpdateEnvironmentVariableMutationVariables = Exact<{ input: UpdateEnvironmentVariableInput; }>; -export type UpdateEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', updateEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environment?: EnvironmentVariableEnvironment | null, createdAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; +export type UpdateEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', updateEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } }; export type DeleteEnvironmentVariableMutationVariables = Exact<{ id: Scalars['ID']['input']; @@ -8725,7 +8731,7 @@ export type EnvironmentVariablesByAppIdQueryVariables = Exact<{ }>; -export type EnvironmentVariablesByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, environmentVariables: Array<{ __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environment?: EnvironmentVariableEnvironment | null, createdAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null }> } } }; +export type EnvironmentVariablesByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, environmentVariables: Array<{ __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null }> } } }; export type EnvironmentVariablesSharedQueryVariables = Exact<{ appId: Scalars['String']['input']; @@ -8734,7 +8740,7 @@ export type EnvironmentVariablesSharedQueryVariables = Exact<{ }>; -export type EnvironmentVariablesSharedQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariables: Array<{ __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environment?: EnvironmentVariableEnvironment | null, createdAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null }> } } } }; +export type EnvironmentVariablesSharedQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariables: Array<{ __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null }> } } } }; export type EnvironmentVariablesSharedWithSensitiveQueryVariables = Exact<{ appId: Scalars['String']['input']; @@ -8862,7 +8868,7 @@ export type BuildWithSubmissionsFragment = { __typename?: 'Build', id: string, s export type EnvironmentSecretFragment = { __typename?: 'EnvironmentSecret', id: string, name: string, type: EnvironmentSecretType, createdAt: any }; -export type EnvironmentVariableFragment = { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environment?: EnvironmentVariableEnvironment | null, createdAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null }; +export type EnvironmentVariableFragment = { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null }; export type RuntimeFragment = { __typename?: 'Runtime', id: string, version: string }; diff --git a/packages/eas-cli/src/graphql/types/EnvironmentVariable.ts b/packages/eas-cli/src/graphql/types/EnvironmentVariable.ts index f4ca4ce1bd..47927460ea 100644 --- a/packages/eas-cli/src/graphql/types/EnvironmentVariable.ts +++ b/packages/eas-cli/src/graphql/types/EnvironmentVariable.ts @@ -5,8 +5,9 @@ export const EnvironmentVariableFragmentNode = gql` id name value - environment + environments createdAt + updatedAt scope visibility } diff --git a/packages/eas-cli/src/utils/formatVariable.ts b/packages/eas-cli/src/utils/formatVariable.ts deleted file mode 100644 index 6ec318c9a5..0000000000 --- a/packages/eas-cli/src/utils/formatVariable.ts +++ /dev/null @@ -1,14 +0,0 @@ -import dateFormat from 'dateformat'; - -import formatFields from './formatFields'; -import { EnvironmentVariableFragment } from '../graphql/generated'; - -export function formatVariable(variable: EnvironmentVariableFragment): string { - return formatFields([ - { label: 'ID', value: variable.id }, - { label: 'Name', value: variable.name }, - { label: 'Value', value: variable.value ?? '(secret)' }, - { label: 'Scope', value: variable.scope }, - { label: 'Created at', value: dateFormat(variable.createdAt, 'mmm dd HH:MM:ss') }, - ]); -} diff --git a/packages/eas-cli/src/utils/variableUtils.ts b/packages/eas-cli/src/utils/variableUtils.ts new file mode 100644 index 0000000000..8cb38751f6 --- /dev/null +++ b/packages/eas-cli/src/utils/variableUtils.ts @@ -0,0 +1,23 @@ +import dateFormat from 'dateformat'; + +import formatFields from './formatFields'; +import { EnvironmentVariableEnvironment, EnvironmentVariableFragment } from '../graphql/generated'; + +export async function performForEnvironmentsAsync( + environments: EnvironmentVariableEnvironment[] | null, + fun: (environment: EnvironmentVariableEnvironment | undefined) => Promise +): Promise { + const selectedEnvironments = environments ?? [undefined]; + return await Promise.all(selectedEnvironments.map(env => fun(env))); +} + +export function formatVariable(variable: EnvironmentVariableFragment): string { + return formatFields([ + { label: 'ID', value: variable.id }, + { label: 'Name', value: variable.name }, + { label: 'Value', value: variable.value ?? '(secret)' }, + { label: 'Scope', value: variable.scope }, + { label: 'Created at', value: dateFormat(variable.createdAt, 'mmm dd HH:MM:ss') }, + { label: 'Updated at', value: dateFormat(variable.updatedAt, 'mmm dd HH:MM:ss') }, + ]); +}