Skip to content

Commit

Permalink
Support File type environment variables
Browse files Browse the repository at this point in the history
  • Loading branch information
khamilowicz committed Sep 27, 2024
1 parent eb99c90 commit 9a20a52
Show file tree
Hide file tree
Showing 14 changed files with 372 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { EnvironmentVariablesQuery } from '../../../graphql/queries/EnvironmentV
import {
promptVariableEnvironmentAsync,
promptVariableNameAsync,
promptVariableTypeAsync,
promptVariableValueAsync,
} from '../../../utils/prompts';
import EnvironmentVariableCreate from '../create';
Expand Down Expand Up @@ -60,6 +61,7 @@ describe(EnvironmentVariableCreate, () => {
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
scope: EnvironmentVariableScope.Shared,
type: EnvironmentSecretType.String,
}));
jest.mocked(EnvironmentVariablesQuery.byAppIdAsync).mockImplementation(async () => []);
jest.mocked(EnvironmentVariablesQuery.sharedAsync).mockImplementation(async () => []);
Expand Down Expand Up @@ -322,6 +324,10 @@ describe(EnvironmentVariableCreate, () => {

jest.mocked(promptVariableNameAsync).mockImplementation(async () => 'VarName');
jest.mocked(promptVariableValueAsync).mockImplementation(async () => 'VarValue');
jest
.mocked(promptVariableTypeAsync)
.mockImplementation(async () => EnvironmentSecretType.String);

jest
.mocked(promptVariableEnvironmentAsync)
// @ts-expect-error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { Config } from '@oclif/core';
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { testProjectId } from '../../../credentials/__tests__/fixtures-constants';
import {
EnvironmentSecretType,
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
EnvironmentVariableVisibility,
} from '../../../graphql/generated';
Expand All @@ -20,7 +22,7 @@ jest.mock('../../../utils/prompts');
describe(EnvironmentVariableGet, () => {
const graphqlClient = {} as any as ExpoGraphqlClient;
const mockConfig = {} as unknown as Config;
const mockVariables = [
const mockVariables: EnvironmentVariableFragment[] = [
{
id: 'var1',
name: 'TEST_VAR_1',
Expand All @@ -30,6 +32,7 @@ describe(EnvironmentVariableGet, () => {
updatedAt: new Date().toISOString(),
scope: EnvironmentVariableScope.Project,
visibility: EnvironmentVariableVisibility.Public,
type: EnvironmentSecretType.String,
},
];

Expand All @@ -55,6 +58,7 @@ describe(EnvironmentVariableGet, () => {
appId: testProjectId,
environment: undefined,
filterNames: ['TEST_VAR_1'],
includeFileContent: true,
}
);
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
Expand Down Expand Up @@ -99,6 +103,7 @@ describe(EnvironmentVariableGet, () => {
updatedAt: new Date().toISOString(),
scope: EnvironmentVariableScope.Project,
visibility: EnvironmentVariableVisibility.Public,
type: EnvironmentSecretType.String,
},
]);
await command.runAsync();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getMockAppFragment } from '../../../__tests__/commands/utils';
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { testProjectId } from '../../../credentials/__tests__/fixtures-constants';
import {
EnvironmentSecretType,
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
Expand All @@ -28,6 +29,7 @@ const mockVariables: EnvironmentVariableFragment[] = [
visibility: EnvironmentVariableVisibility.Public,
createdAt: undefined,
updatedAt: undefined,
type: EnvironmentSecretType.String,
},
{
id: 'var2',
Expand All @@ -38,6 +40,7 @@ const mockVariables: EnvironmentVariableFragment[] = [
visibility: EnvironmentVariableVisibility.Public,
createdAt: undefined,
updatedAt: undefined,
type: EnvironmentSecretType.String,
},
];

Expand Down Expand Up @@ -65,6 +68,7 @@ describe(EnvironmentVariableList, () => {
expect(EnvironmentVariablesQuery.byAppIdAsync).toHaveBeenCalledWith(graphqlClient, {
appId: testProjectId,
environment: undefined,
includeFileContent: false,
});
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_2'));
Expand All @@ -85,6 +89,7 @@ describe(EnvironmentVariableList, () => {
expect(EnvironmentVariablesQuery.byAppIdAsync).toHaveBeenCalledWith(graphqlClient, {
appId: testProjectId,
environment: EnvironmentVariableEnvironment.Production,
includeFileContent: false,
});
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_2'));
Expand All @@ -109,6 +114,7 @@ describe(EnvironmentVariableList, () => {
{
appId: testProjectId,
environment: undefined,
includeFileContent: false,
}
);
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
Expand All @@ -130,6 +136,7 @@ describe(EnvironmentVariableList, () => {
expect(EnvironmentVariablesQuery.sharedAsync).toHaveBeenCalledWith(graphqlClient, {
appId: testProjectId,
environment: undefined,
includeFileContent: false,
});
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_2'));
Expand All @@ -155,6 +162,7 @@ describe(EnvironmentVariableList, () => {
expect(EnvironmentVariablesQuery.sharedWithSensitiveAsync).toHaveBeenCalledWith(graphqlClient, {
appId: testProjectId,
environment: undefined,
includeFileContent: false,
});
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_2'));
Expand Down
49 changes: 44 additions & 5 deletions packages/eas-cli/src/commands/env/create.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import fs from 'fs-extra';
import path from 'path';

import EasCommand from '../../commandUtils/EasCommand';
import {
Expand All @@ -25,6 +27,7 @@ import { confirmAsync } from '../../prompts';
import {
promptVariableEnvironmentAsync,
promptVariableNameAsync,
promptVariableTypeAsync,
promptVariableValueAsync,
} from '../../utils/prompts';
import { performForEnvironmentsAsync } from '../../utils/variableUtils';
Expand All @@ -34,6 +37,7 @@ type CreateFlags = {
value?: string;
link?: boolean;
force?: boolean;
type?: 'string' | 'file';
visibility?: EnvironmentVariableVisibility;
scope?: EnvironmentVariableScope;
environment?: EnvironmentVariableEnvironment[];
Expand All @@ -60,6 +64,10 @@ export default class EnvironmentVariableCreate extends EasCommand {
description: 'Overwrite existing variable',
default: false,
}),
type: Flags.enum<'string' | 'file'>({
description: 'The type of variable',
options: ['string', 'file'],
}),
...EASVariableVisibilityFlag,
...EASVariableScopeFlag,
...EASMultiEnvironmentFlag,
Expand All @@ -86,6 +94,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
visibility,
link,
force,
type,
} = await this.promptForMissingFlagsAsync(validatedFlags);

const {
Expand Down Expand Up @@ -155,6 +164,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
value,
visibility,
environments,
type,
})
: await EnvironmentVariableMutation.createForAppAsync(
graphqlClient,
Expand All @@ -163,7 +173,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
value,
environments,
visibility,
type: EnvironmentSecretType.String,
type: type ?? EnvironmentSecretType.String,
},
projectId
);
Expand Down Expand Up @@ -206,6 +216,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
value,
visibility,
environments,
type,
})
: await EnvironmentVariableMutation.createSharedVariableAsync(
graphqlClient,
Expand All @@ -214,7 +225,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
value,
visibility,
environments,
type: EnvironmentSecretType.String,
type: type ?? EnvironmentSecretType.String,
},
ownerAccount.id
);
Expand Down Expand Up @@ -283,23 +294,48 @@ export default class EnvironmentVariableCreate extends EasCommand {
environment,
visibility = EnvironmentVariableVisibility.Public,
'non-interactive': nonInteractive,
type,
...rest
}: CreateFlags): Promise<Required<CreateFlags>> {
}: CreateFlags): Promise<
Required<Omit<CreateFlags, 'type'> & { type: EnvironmentSecretType | undefined }>
> {
if (!name) {
name = await promptVariableNameAsync(nonInteractive);
}

let newType;

if (type === 'file') {
newType = EnvironmentSecretType.FileBase64;
} else if (type === 'string') {
newType = EnvironmentSecretType.String;
}

if (!type && !value && !nonInteractive) {
newType = await promptVariableTypeAsync(nonInteractive);
}

if (!value) {
value = await promptVariableValueAsync({
nonInteractive,
hidden: visibility !== EnvironmentVariableVisibility.Public,
});
}

let environmentFilePath: string | undefined;

if (newType === EnvironmentSecretType.FileBase64) {
environmentFilePath = path.resolve(value);
if (!(await fs.pathExists(environmentFilePath))) {
throw new Error(`File "${value}" does not exist`);
}
}

value = environmentFilePath ? await fs.readFile(environmentFilePath, 'base64') : value;

if (!environment) {
environment = await promptVariableEnvironmentAsync({ nonInteractive, multiple: true });
}

return {
name,
value,
Expand All @@ -309,16 +345,18 @@ export default class EnvironmentVariableCreate extends EasCommand {
force: rest.force ?? false,
scope: rest.scope ?? EnvironmentVariableScope.Project,
'non-interactive': nonInteractive,
type: newType,
...rest,
};
}

private validateFlags(flags: CreateFlags): CreateFlags {
private validateFlags(flags: CreateFlags & { type?: string }): CreateFlags {
if (flags.scope !== EnvironmentVariableScope.Shared && flags.link) {
throw new Error(
`Unexpected argument: --link can only be used when creating shared variables`
);
}

if (
flags.scope === EnvironmentVariableScope.Shared &&
flags.environment &&
Expand All @@ -329,6 +367,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
'Unexpected argument: --environment in non-interactive mode can only be used with --link flag.'
);
}

return flags;
}
}
9 changes: 6 additions & 3 deletions packages/eas-cli/src/commands/env/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import {
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
EnvironmentVariableVisibility,
} from '../../graphql/generated';
import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../log';
import { promptVariableEnvironmentAsync, promptVariableNameAsync } from '../../utils/prompts';
import { formatVariable } from '../../utils/variableUtils';
import { formatVariable, formatVariableValue } from '../../utils/variableUtils';

type GetFlags = {
'variable-name'?: string;
Expand Down Expand Up @@ -108,7 +109,7 @@ export default class EnvironmentVariableGet extends EasCommand {
variable = variables[0];
}

if (!variable.value) {
if (variable.visibility === EnvironmentVariableVisibility.Secret) {
throw new Error(
`${chalk.bold(
variable.name
Expand All @@ -117,7 +118,7 @@ export default class EnvironmentVariableGet extends EasCommand {
}

if (format === 'short') {
Log.log(`${chalk.bold(variable.name)}=${variable.value}`);
Log.log(`${chalk.bold(variable.name)}=${formatVariableValue(variable)}`);
} else {
Log.log(formatVariable(variable));
}
Expand Down Expand Up @@ -156,6 +157,7 @@ async function getVariablesAsync(
appId: projectId,
environment,
filterNames: [name],
includeFileContent: true,
});
return appVariables;
} else {
Expand All @@ -164,6 +166,7 @@ async function getVariablesAsync(
{
appId: projectId,
filterNames: [name],
includeFileContent: true,
}
);
return sharedVariables;
Expand Down
Loading

0 comments on commit 9a20a52

Please sign in to comment.