diff --git a/packages/eas-cli/src/commandUtils/EasCommand.ts b/packages/eas-cli/src/commandUtils/EasCommand.ts index 9123f0c6de..f5ed2bcc0a 100644 --- a/packages/eas-cli/src/commandUtils/EasCommand.ts +++ b/packages/eas-cli/src/commandUtils/EasCommand.ts @@ -15,6 +15,7 @@ import MaybeLoggedInContextField from './context/MaybeLoggedInContextField'; import { OptionalPrivateProjectConfigContextField } from './context/OptionalPrivateProjectConfigContextField'; import { PrivateProjectConfigContextField } from './context/PrivateProjectConfigContextField'; import ProjectDirContextField from './context/ProjectDirContextField'; +import { ServerSideEnvironmentVariablesContextField } from './context/ServerSideEnvironmentVariablesContextField'; import SessionManagementContextField from './context/SessionManagementContextField'; import VcsClientContextField from './context/VcsClientContextField'; import { EasCommandError } from './errors'; @@ -23,6 +24,7 @@ import { CommandEvent, createAnalyticsAsync, } from '../analytics/AnalyticsManager'; +import { EnvironmentVariableEnvironment } from '../graphql/generated'; import Log from '../log'; import SessionManager from '../user/SessionManager'; import { Client } from '../vcs/vcs'; @@ -43,8 +45,26 @@ export type ContextOutput< [P in keyof T]: T[P]; }; +type GetContextType = { + [Property in keyof Type]: any; +}; + const BASE_GRAPHQL_ERROR_MESSAGE: string = 'GraphQL request failed.'; +interface BaseGetContextAsyncArgs { + nonInteractive: boolean; + vcsClientOverride?: Client; +} + +interface GetContextAsyncArgsWithRequiredServerSideEnvironmentArgument + extends BaseGetContextAsyncArgs { + withServerSideEnvironment: EnvironmentVariableEnvironment | null; +} + +interface GetContextAsyncArgsWithoutServerSideEnvironmentArgument extends BaseGetContextAsyncArgs { + withServerSideEnvironment?: never; +} + export default abstract class EasCommand extends Command { protected static readonly ContextOptions = { /** @@ -72,7 +92,7 @@ export default abstract class EasCommand extends Command { * run within a project directory, null otherwise. */ OptionalProjectConfig: { - privateProjectConfig: new OptionalPrivateProjectConfigContextField(), + optionalPrivateProjectConfig: new OptionalPrivateProjectConfigContextField(), }, /** * Require this command to be run in a project directory. Return the project directory in the context. @@ -107,6 +127,10 @@ export default abstract class EasCommand extends Command { Vcs: { vcsClient: new VcsClientContextField(), }, + ServerSideEnvironmentVariables: { + // eslint-disable-next-line async-protect/async-suffix + getServerSideEnvironmentVariablesAsync: new ServerSideEnvironmentVariablesContextField(), + }, }; /** @@ -141,7 +165,18 @@ export default abstract class EasCommand extends Command { } = object, >( commandClass: { contextDefinition: ContextInput }, - { nonInteractive, vcsClientOverride }: { nonInteractive: boolean; vcsClientOverride?: Client } + { + nonInteractive, + vcsClientOverride, + // if specified and not null, the env vars from the selected environment will be fetched from the server + // to resolve dynamic config (if dynamic config context is used) and enable getServerSideEnvironmentVariablesAsync function (if server side environment variables context is used) + withServerSideEnvironment, + }: C extends + | GetContextType + | GetContextType + | GetContextType + ? GetContextAsyncArgsWithRequiredServerSideEnvironmentArgument + : GetContextAsyncArgsWithoutServerSideEnvironmentArgument ): Promise> { const contextDefinition = commandClass.contextDefinition; @@ -155,6 +190,7 @@ export default abstract class EasCommand extends Command { sessionManager: this.sessionManager, analytics: this.analytics, vcsClientOverride, + withServerSideEnvironment, }), ]); } diff --git a/packages/eas-cli/src/commandUtils/context/ContextField.ts b/packages/eas-cli/src/commandUtils/context/ContextField.ts index 63ae384d1b..f8e937e694 100644 --- a/packages/eas-cli/src/commandUtils/context/ContextField.ts +++ b/packages/eas-cli/src/commandUtils/context/ContextField.ts @@ -1,4 +1,5 @@ import { Analytics } from '../../analytics/AnalyticsManager'; +import { EnvironmentVariableEnvironment } from '../../graphql/generated'; import SessionManager from '../../user/SessionManager'; import { Client } from '../../vcs/vcs'; @@ -7,6 +8,10 @@ export interface ContextOptions { analytics: Analytics; nonInteractive: boolean; vcsClientOverride?: Client; + /** + * If specified, env variables from the selected environment will be fetched from the server and used to evaluate the dynamic config. + */ + withServerSideEnvironment?: EnvironmentVariableEnvironment | null; } export default abstract class ContextField { diff --git a/packages/eas-cli/src/commandUtils/context/DynamicProjectConfigContextField.ts b/packages/eas-cli/src/commandUtils/context/DynamicProjectConfigContextField.ts index c6eef0033f..07ce38ea94 100644 --- a/packages/eas-cli/src/commandUtils/context/DynamicProjectConfigContextField.ts +++ b/packages/eas-cli/src/commandUtils/context/DynamicProjectConfigContextField.ts @@ -1,8 +1,10 @@ import { ExpoConfig } from '@expo/config'; import ContextField, { ContextOptions } from './ContextField'; +import { createGraphqlClient } from './contextUtils/createGraphqlClient'; import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync'; import { getProjectIdAsync } from './contextUtils/getProjectIdAsync'; +import { loadServerSideEnvironmentVariablesAsync } from './contextUtils/loadServerSideEnvironmentVariablesAsync'; import { ExpoConfigOptions, getPrivateExpoConfig, @@ -19,6 +21,7 @@ export class DynamicPublicProjectConfigContextField extends ContextField { const projectDir = await findProjectDirAndVerifyProjectSetupAsync(); return async (options?: ExpoConfigOptions) => { @@ -27,6 +30,24 @@ export class DynamicPublicProjectConfigContextField extends ContextField { const projectDir = await findProjectDirAndVerifyProjectSetupAsync(); return async (options?: ExpoConfigOptions) => { @@ -49,6 +71,24 @@ export class DynamicPrivateProjectConfigContextField extends ContextField { - async getValueAsync({ nonInteractive, sessionManager }: ContextOptions): Promise< + async getValueAsync({ + nonInteractive, + sessionManager, + withServerSideEnvironment, + }: ContextOptions): Promise< | { projectId: string; exp: ExpoConfig; @@ -39,7 +45,20 @@ export class OptionalPrivateProjectConfigContextField extends ContextField< const projectId = await getProjectIdAsync(sessionManager, expBefore, { nonInteractive, }); - const exp = getPrivateExpoConfig(projectDir); + let serverSideEnvVars: Record | undefined; + if (withServerSideEnvironment) { + const { authenticationInfo } = await sessionManager.ensureLoggedInAsync({ + nonInteractive, + }); + const graphqlClient = createGraphqlClient(authenticationInfo); + const serverSideEnvironmentVariables = await loadServerSideEnvironmentVariablesAsync({ + environment: withServerSideEnvironment, + projectId, + graphqlClient, + }); + serverSideEnvVars = serverSideEnvironmentVariables; + } + const exp = getPrivateExpoConfig(projectDir, { env: serverSideEnvVars }); return { exp, projectDir, diff --git a/packages/eas-cli/src/commandUtils/context/ServerSideEnvironmentVariablesContextField.ts b/packages/eas-cli/src/commandUtils/context/ServerSideEnvironmentVariablesContextField.ts new file mode 100644 index 0000000000..5977fe3a12 --- /dev/null +++ b/packages/eas-cli/src/commandUtils/context/ServerSideEnvironmentVariablesContextField.ts @@ -0,0 +1,42 @@ +import ContextField, { ContextOptions } from './ContextField'; +import { createGraphqlClient } from './contextUtils/createGraphqlClient'; +import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync'; +import { getProjectIdAsync } from './contextUtils/getProjectIdAsync'; +import { loadServerSideEnvironmentVariablesAsync } from './contextUtils/loadServerSideEnvironmentVariablesAsync'; +import { getPublicExpoConfig } from '../../project/expoConfig'; + +type GetServerSideEnvironmentVariablesFn = ( + maybeEnv?: Record +) => Promise>; + +export class ServerSideEnvironmentVariablesContextField extends ContextField { + async getValueAsync({ + nonInteractive, + sessionManager, + withServerSideEnvironment, + }: ContextOptions): Promise { + const projectDir = await findProjectDirAndVerifyProjectSetupAsync(); + return async (maybeEnv?: Record) => { + if (!withServerSideEnvironment) { + throw new Error( + 'withServerSideEnvironment parameter is required to evaluate ServerSideEnvironmentVariablesContextField' + ); + } + const exp = getPublicExpoConfig(projectDir, { env: maybeEnv }); + const projectId = await getProjectIdAsync(sessionManager, exp, { + nonInteractive, + env: maybeEnv, + }); + const { authenticationInfo } = await sessionManager.ensureLoggedInAsync({ + nonInteractive, + }); + const graphqlClient = createGraphqlClient(authenticationInfo); + const serverSideEnvironmentVariables = await loadServerSideEnvironmentVariablesAsync({ + environment: withServerSideEnvironment, + projectId, + graphqlClient, + }); + return serverSideEnvironmentVariables; + }; + } +} diff --git a/packages/eas-cli/src/commandUtils/context/contextUtils/loadServerSideEnvironmentVariablesAsync.ts b/packages/eas-cli/src/commandUtils/context/contextUtils/loadServerSideEnvironmentVariablesAsync.ts new file mode 100644 index 0000000000..88e21b4c8e --- /dev/null +++ b/packages/eas-cli/src/commandUtils/context/contextUtils/loadServerSideEnvironmentVariablesAsync.ts @@ -0,0 +1,68 @@ +import { ExpoGraphqlClient } from './createGraphqlClient'; +import { EnvironmentVariableEnvironment } from '../../../graphql/generated'; +import { EnvironmentVariablesQuery } from '../../../graphql/queries/EnvironmentVariablesQuery'; +import Log from '../../../log'; + +const cachedServerSideEnvironmentVariables: Record< + EnvironmentVariableEnvironment, + Record | null +> = { + [EnvironmentVariableEnvironment.Development]: null, + [EnvironmentVariableEnvironment.Preview]: null, + [EnvironmentVariableEnvironment.Production]: null, +}; + +export async function loadServerSideEnvironmentVariablesAsync({ + environment, + projectId, + graphqlClient, +}: { + environment: EnvironmentVariableEnvironment; + projectId: string; + graphqlClient: ExpoGraphqlClient; +}): Promise> { + // don't load environment variables if they were already loaded while executing a command + const cachedEnvVarsForEnvironment = cachedServerSideEnvironmentVariables[environment]; + if (cachedEnvVarsForEnvironment) { + return cachedEnvVarsForEnvironment; + } + + const environmentVariables = await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync( + graphqlClient, + { + appId: projectId, + environment, + } + ); + const serverEnvVars = Object.fromEntries( + environmentVariables + .filter(({ name, value }) => name && value) + .map(({ name, value }) => [name, value]) + ) as Record; + + if (Object.keys(serverEnvVars).length > 0) { + Log.log( + `Environment variables loaded from the "${environment.toLowerCase()}" environment on EAS servers: ${Object.keys( + serverEnvVars + ).join(', ')}.` + ); + } else { + Log.log( + `No environment variables found for the "${environment.toLowerCase()}" environment on EAS servers.` + ); + } + + const encryptedEnvVars = environmentVariables.filter(({ name, value }) => name && !value); + if (encryptedEnvVars.length > 0) { + Log.warn( + `Some environment variables defined in the "${environment.toLowerCase()}" environment on EAS servers are of "encrypted" type and cannot be read outside of the EAS servers (including EAS CLI): ${encryptedEnvVars + .map(({ name }) => name) + .join(', ')}. ` + ); + } + Log.newLine(); + + cachedServerSideEnvironmentVariables[environment] = serverEnvVars; + + return serverEnvVars; +} diff --git a/packages/eas-cli/src/commands/build/index.ts b/packages/eas-cli/src/commands/build/index.ts index eefefc0253..5c201f84ac 100644 --- a/packages/eas-cli/src/commands/build/index.ts +++ b/packages/eas-cli/src/commands/build/index.ts @@ -142,6 +142,7 @@ export default class Build extends EasCommand { vcsClient, } = await this.getContextAsync(Build, { nonInteractive: flags.nonInteractive, + withServerSideEnvironment: null, }); await handleDeprecatedEasJsonAsync(projectDir, flags.nonInteractive); diff --git a/packages/eas-cli/src/commands/build/inspect.ts b/packages/eas-cli/src/commands/build/inspect.ts index 42213bb61b..50c8450472 100644 --- a/packages/eas-cli/src/commands/build/inspect.ts +++ b/packages/eas-cli/src/commands/build/inspect.ts @@ -79,6 +79,7 @@ export default class BuildInspect extends EasCommand { vcsClient, } = await this.getContextAsync(BuildInspect, { nonInteractive: false, + withServerSideEnvironment: null, }); const outputDirectory = path.resolve(process.cwd(), flags.output); diff --git a/packages/eas-cli/src/commands/build/internal.ts b/packages/eas-cli/src/commands/build/internal.ts index 9aac620f86..d6c32240a6 100644 --- a/packages/eas-cli/src/commands/build/internal.ts +++ b/packages/eas-cli/src/commands/build/internal.ts @@ -64,6 +64,7 @@ export default class BuildInternal extends EasCommand { } = await this.getContextAsync(BuildInternal, { nonInteractive: true, vcsClientOverride: new GitNoCommitClient(), + withServerSideEnvironment: null, }); await handleDeprecatedEasJsonAsync(projectDir, flags.nonInteractive); diff --git a/packages/eas-cli/src/commands/build/resign.ts b/packages/eas-cli/src/commands/build/resign.ts index 8fea1d6790..717d33d637 100644 --- a/packages/eas-cli/src/commands/build/resign.ts +++ b/packages/eas-cli/src/commands/build/resign.ts @@ -120,6 +120,7 @@ export default class BuildResign extends EasCommand { vcsClient, } = await this.getContextAsync(BuildResign, { nonInteractive: flags.nonInteractive, + withServerSideEnvironment: null, }); const maybeBuild = flags.maybeBuildId diff --git a/packages/eas-cli/src/commands/build/version/get.ts b/packages/eas-cli/src/commands/build/version/get.ts index fd7b8c9c5e..97720941c6 100644 --- a/packages/eas-cli/src/commands/build/version/get.ts +++ b/packages/eas-cli/src/commands/build/version/get.ts @@ -54,6 +54,7 @@ export default class BuildVersionGetView extends EasCommand { vcsClient, } = await this.getContextAsync(BuildVersionGetView, { nonInteractive: true, + withServerSideEnvironment: null, }); if (!flags.platform && flags['non-interactive']) { diff --git a/packages/eas-cli/src/commands/build/version/set.ts b/packages/eas-cli/src/commands/build/version/set.ts index d7e8aa446c..92604120f6 100644 --- a/packages/eas-cli/src/commands/build/version/set.ts +++ b/packages/eas-cli/src/commands/build/version/set.ts @@ -54,6 +54,7 @@ export default class BuildVersionSetView extends EasCommand { vcsClient, } = await this.getContextAsync(BuildVersionSetView, { nonInteractive: false, + withServerSideEnvironment: null, }); const platform = await selectPlatformAsync(flags.platform); diff --git a/packages/eas-cli/src/commands/build/version/sync.ts b/packages/eas-cli/src/commands/build/version/sync.ts index 6eba97b069..d32a8225ab 100644 --- a/packages/eas-cli/src/commands/build/version/sync.ts +++ b/packages/eas-cli/src/commands/build/version/sync.ts @@ -73,6 +73,7 @@ export default class BuildVersionSyncView extends EasCommand { vcsClient, } = await this.getContextAsync(BuildVersionSyncView, { nonInteractive: true, + withServerSideEnvironment: null, }); const requestedPlatform = await selectRequestedPlatformAsync(flags.platform); diff --git a/packages/eas-cli/src/commands/config.ts b/packages/eas-cli/src/commands/config.ts index c1adad6eaf..32ea1e3f1f 100644 --- a/packages/eas-cli/src/commands/config.ts +++ b/packages/eas-cli/src/commands/config.ts @@ -51,6 +51,7 @@ export default class Config extends EasCommand { const { getDynamicPublicProjectConfigAsync, projectDir, sessionManager } = await this.getContextAsync(Config, { nonInteractive, + withServerSideEnvironment: null, }); const accessor = EasJsonAccessor.fromProjectPath(projectDir); diff --git a/packages/eas-cli/src/commands/credentials/configure-build.ts b/packages/eas-cli/src/commands/credentials/configure-build.ts index 1d164a0cc5..0508de522b 100644 --- a/packages/eas-cli/src/commands/credentials/configure-build.ts +++ b/packages/eas-cli/src/commands/credentials/configure-build.ts @@ -39,6 +39,7 @@ export default class InitializeBuildCredentials extends EasCommand { vcsClient, } = await this.getContextAsync(InitializeBuildCredentials, { nonInteractive: false, + withServerSideEnvironment: null, }); const platform = await selectPlatformAsync(flags.platform); diff --git a/packages/eas-cli/src/commands/credentials/index.ts b/packages/eas-cli/src/commands/credentials/index.ts index 2acfacb2c6..9f70018ce9 100644 --- a/packages/eas-cli/src/commands/credentials/index.ts +++ b/packages/eas-cli/src/commands/credentials/index.ts @@ -22,12 +22,13 @@ export default class Credentials extends EasCommand { const { flags } = await this.parse(Credentials); const { loggedIn: { actor, graphqlClient }, - privateProjectConfig, + optionalPrivateProjectConfig: privateProjectConfig, getDynamicPrivateProjectConfigAsync, analytics, vcsClient, } = await this.getContextAsync(Credentials, { nonInteractive: false, + withServerSideEnvironment: null, }); await new SelectPlatform( diff --git a/packages/eas-cli/src/commands/device/create.ts b/packages/eas-cli/src/commands/device/create.ts index 6af1d17e4c..830ccb0cd7 100644 --- a/packages/eas-cli/src/commands/device/create.ts +++ b/packages/eas-cli/src/commands/device/create.ts @@ -15,9 +15,10 @@ export default class DeviceCreate extends EasCommand { // this command is interactive by design const { loggedIn: { actor, graphqlClient }, - privateProjectConfig, + optionalPrivateProjectConfig: privateProjectConfig, } = await this.getContextAsync(DeviceCreate, { nonInteractive: false, + withServerSideEnvironment: null, }); const ctx = await createContextAsync({ diff --git a/packages/eas-cli/src/commands/update/__tests__/index.test.ts b/packages/eas-cli/src/commands/update/__tests__/index.test.ts index b942b30860..b8b477668b 100644 --- a/packages/eas-cli/src/commands/update/__tests__/index.test.ts +++ b/packages/eas-cli/src/commands/update/__tests__/index.test.ts @@ -12,6 +12,7 @@ import { DynamicPublicProjectConfigContextField, } from '../../../commandUtils/context/DynamicProjectConfigContextField'; import LoggedInContextField from '../../../commandUtils/context/LoggedInContextField'; +import { ServerSideEnvironmentVariablesContextField } from '../../../commandUtils/context/ServerSideEnvironmentVariablesContextField'; import VcsClientContextField from '../../../commandUtils/context/VcsClientContextField'; import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient'; import FeatureGateEnvOverrides from '../../../commandUtils/gating/FeatureGateEnvOverrides'; @@ -232,6 +233,11 @@ function mockTestProject({ projectId: configuredProjectId, }; }); + jest + .spyOn(ServerSideEnvironmentVariablesContextField.prototype, 'getValueAsync') + .mockResolvedValue(async () => { + return {}; + }); jest .spyOn(DynamicPublicProjectConfigContextField.prototype, 'getValueAsync') .mockResolvedValue(async () => { diff --git a/packages/eas-cli/src/commands/update/index.ts b/packages/eas-cli/src/commands/update/index.ts index e166e8afd7..4d92be1391 100644 --- a/packages/eas-cli/src/commands/update/index.ts +++ b/packages/eas-cli/src/commands/update/index.ts @@ -12,6 +12,7 @@ import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags'; import { getPaginatedQueryOptions } from '../../commandUtils/pagination'; import fetch from '../../fetch'; import { + EnvironmentVariableEnvironment, PublishUpdateGroupInput, StatuspageServiceName, UpdateInfoGroup, @@ -72,6 +73,7 @@ type RawUpdateFlags = { 'rollout-percentage'?: number; 'non-interactive': boolean; json: boolean; + 'with-eas-environment-variables-set'?: string; }; type UpdateFlags = { @@ -88,6 +90,7 @@ type UpdateFlags = { rolloutPercentage?: number; json: boolean; nonInteractive: boolean; + withEasEnvironmentVariablesSet?: EnvironmentVariableEnvironment; }; export default class UpdatePublish extends EasCommand { @@ -149,6 +152,18 @@ export default class UpdatePublish extends EasCommand { description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`, required: false, }), + 'with-eas-environment-variables-set': Flags.enum({ + description: 'Environment to use for EAS environment variables', + options: [ + EnvironmentVariableEnvironment.Development, + EnvironmentVariableEnvironment.Preview, + EnvironmentVariableEnvironment.Production, + ].map(env => env.toLowerCase()), + // eslint-disable-next-line async-protect/async-suffix + parse: async input => input.toUpperCase(), + required: false, + hidden: true, + }), ...EasNonInteractiveAndJsonFlags, }; @@ -156,6 +171,7 @@ export default class UpdatePublish extends EasCommand { ...this.ContextOptions.DynamicProjectConfig, ...this.ContextOptions.LoggedIn, ...this.ContextOptions.Vcs, + ...this.ContextOptions.ServerSideEnvironmentVariables, }; async runAsync(): Promise { @@ -175,6 +191,7 @@ export default class UpdatePublish extends EasCommand { branchName: branchNameArg, emitMetadata, rolloutPercentage, + withEasEnvironmentVariablesSet, } = this.sanitizeFlags(rawFlags); const { @@ -182,8 +199,10 @@ export default class UpdatePublish extends EasCommand { getDynamicPrivateProjectConfigAsync, loggedIn: { graphqlClient }, vcsClient, + getServerSideEnvironmentVariablesAsync, } = await this.getContextAsync(UpdatePublish, { nonInteractive, + withServerSideEnvironment: withEasEnvironmentVariablesSet ?? null, }); if (jsonFlag) { @@ -242,6 +261,11 @@ export default class UpdatePublish extends EasCommand { exp, platformFlag: requestedPlatform, clearCache, + extraEnv: { + ...(withEasEnvironmentVariablesSet + ? { ...(await getServerSideEnvironmentVariablesAsync()), EXPO_NO_DOTENV: '1' } + : {}), + }, }); bundleSpinner.succeed('Exported bundle(s)'); } catch (e) { @@ -637,6 +661,22 @@ export default class UpdatePublish extends EasCommand { ); } + if ( + flags['with-eas-environment-variables-set'] && + !Object.values(EnvironmentVariableEnvironment).includes( + flags['with-eas-environment-variables-set'] as EnvironmentVariableEnvironment + ) + ) { + Errors.error( + `--with-eas-environment-variables-set must be one of ${Object.values( + EnvironmentVariableEnvironment + ) + .map(env => `"${env.toLocaleLowerCase()}"`) + .join(', ')}`, + { exit: 1 } + ); + } + return { auto, branchName, @@ -644,13 +684,16 @@ export default class UpdatePublish extends EasCommand { updateMessage, inputDir: flags['input-dir'], skipBundler, - clearCache: flags['clear-cache'], + clearCache: flags['clear-cache'] ? true : !!flags['with-eas-environment-variables-set'], platform: flags.platform as RequestedPlatform, privateKeyPath: flags['private-key-path'], rolloutPercentage: flags['rollout-percentage'], nonInteractive, emitMetadata, json: flags.json ?? false, + withEasEnvironmentVariablesSet: flags[ + 'with-eas-environment-variables-set' + ] as EnvironmentVariableEnvironment, }; } } diff --git a/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts b/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts index 7e5c36e982..2db4c6ce40 100644 --- a/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts +++ b/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts @@ -134,6 +134,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand { vcsClient, } = await this.getContextAsync(UpdateRollBackToEmbedded, { nonInteractive, + withServerSideEnvironment: null, }); if (jsonFlag) { diff --git a/packages/eas-cli/src/commands/worker/alias.ts b/packages/eas-cli/src/commands/worker/alias.ts index c5edd96401..d97a47d184 100644 --- a/packages/eas-cli/src/commands/worker/alias.ts +++ b/packages/eas-cli/src/commands/worker/alias.ts @@ -80,6 +80,7 @@ export default class WorkerAlias extends EasCommand { loggedIn: { graphqlClient }, } = await this.getContextAsync(WorkerAlias, { nonInteractive: true, + withServerSideEnvironment: null, }); const { projectId } = await getDynamicPrivateProjectConfigAsync(); diff --git a/packages/eas-cli/src/commands/worker/deploy.ts b/packages/eas-cli/src/commands/worker/deploy.ts index 89d05bb408..0a6e47fa92 100644 --- a/packages/eas-cli/src/commands/worker/deploy.ts +++ b/packages/eas-cli/src/commands/worker/deploy.ts @@ -117,7 +117,7 @@ export default class WorkerDeploy extends EasCommand { getDynamicPrivateProjectConfigAsync, loggedIn: { graphqlClient }, projectDir, - } = await this.getContextAsync(WorkerDeploy, flags); + } = await this.getContextAsync(WorkerDeploy, { ...flags, withServerSideEnvironment: null }); const projectDist = await resolveExportedProjectAsync(flags, projectDir); const { projectId } = await getDynamicPrivateProjectConfigAsync(); diff --git a/packages/eas-cli/src/project/publish.ts b/packages/eas-cli/src/project/publish.ts index 966ad5877f..5e11c256ed 100644 --- a/packages/eas-cli/src/project/publish.ts +++ b/packages/eas-cli/src/project/publish.ts @@ -204,12 +204,14 @@ export async function buildBundlesAsync({ exp, platformFlag, clearCache, + extraEnv, }: { projectDir: string; inputDir: string; exp: Pick; platformFlag: ExpoCLIExportPlatformFlag; clearCache?: boolean; + extraEnv?: Record | undefined; }): Promise { const packageJSON = JsonFile.read(path.resolve(projectDir, 'package.json')); if (!packageJSON) { @@ -218,17 +220,23 @@ export async function buildBundlesAsync({ // Legacy global Expo CLI if (!shouldUseVersionedExpoCLI(projectDir, exp)) { - await expoCommandAsync(projectDir, [ - 'export', - '--output-dir', - inputDir, - '--experimental-bundle', - '--non-interactive', - '--dump-sourcemap', - '--dump-assetmap', - `--platform=${platformFlag}`, - ...(clearCache ? ['--clear'] : []), - ]); + await expoCommandAsync( + projectDir, + [ + 'export', + '--output-dir', + inputDir, + '--experimental-bundle', + '--non-interactive', + '--dump-sourcemap', + '--dump-assetmap', + `--platform=${platformFlag}`, + ...(clearCache ? ['--clear'] : []), + ], + { + extraEnv, + } + ); return; } @@ -240,15 +248,21 @@ export async function buildBundlesAsync({ ? ['--platform', 'ios', '--platform', 'android'] : ['--platform', platformFlag]; - await expoCommandAsync(projectDir, [ - 'export', - '--output-dir', - inputDir, - '--dump-sourcemap', - '--dump-assetmap', - ...platformArgs, - ...(clearCache ? ['--clear'] : []), - ]); + await expoCommandAsync( + projectDir, + [ + 'export', + '--output-dir', + inputDir, + '--dump-sourcemap', + '--dump-assetmap', + ...platformArgs, + ...(clearCache ? ['--clear'] : []), + ], + { + extraEnv, + } + ); return; } @@ -262,15 +276,21 @@ export async function buildBundlesAsync({ ); } - await expoCommandAsync(projectDir, [ - 'export', - '--output-dir', - inputDir, - '--dump-sourcemap', - '--dump-assetmap', - `--platform=${platformFlag}`, - ...(clearCache ? ['--clear'] : []), - ]); + await expoCommandAsync( + projectDir, + [ + 'export', + '--output-dir', + inputDir, + '--dump-sourcemap', + '--dump-assetmap', + `--platform=${platformFlag}`, + ...(clearCache ? ['--clear'] : []), + ], + { + extraEnv, + } + ); } export async function resolveInputDirectoryAsync( diff --git a/packages/eas-cli/src/utils/expoCli.ts b/packages/eas-cli/src/utils/expoCli.ts index aa82072d02..6c1e6fda00 100644 --- a/packages/eas-cli/src/utils/expoCli.ts +++ b/packages/eas-cli/src/utils/expoCli.ts @@ -80,7 +80,10 @@ export const shouldUseVersionedExpoCLIWithExplicitPlatforms = memoize( export async function expoCommandAsync( projectDir: string, args: string[], - { silent = false }: { silent?: boolean } = {} + { + silent = false, + extraEnv = {}, + }: { silent?: boolean; extraEnv?: Record } = {} ): Promise { let expoCliPath; try { @@ -99,6 +102,10 @@ export async function expoCommandAsync( const spawnPromise = spawnAsync(expoCliPath, args, { stdio: ['inherit', 'pipe', 'pipe'], // inherit stdin so user can install a missing expo-cli from inside this command + env: { + ...process.env, + ...extraEnv, + }, }); const { child: { stdout, stderr },