Skip to content

Commit

Permalink
Implement eas env:load and env:unload
Browse files Browse the repository at this point in the history
  • Loading branch information
khamilowicz committed Aug 26, 2024
1 parent 3b71496 commit d6950fa
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 17 deletions.
35 changes: 18 additions & 17 deletions packages/eas-cli/src/commands/env/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ export default class EnvironmentVariableInit extends EasCommand {
await this.setupEnvrcFileAsync();
await this.addDirenvHookToShellConfigAsync();
await this.addToGitIgnoreAsync();
Log.log('Running direnv allow...');
await spawnAsync('direnv', ['allow']);
}

private async addDirenvHookToShellConfigAsync(): Promise<void> {
const direnvConfig = this.getShellDirenvConfig();

if (direnvConfig && (await pathExists(direnvConfig.shellConfigPath))) {
const { shellConfigPath, direnvHookCmd } = direnvConfig;
const { shellConfigPath, direnvHookCmd, direnvInitCmd } = direnvConfig;

const confirm = await confirmAsync({
message: `Do you want to add the direnv hook to ${shellConfigPath}?`,
Expand All @@ -61,14 +63,19 @@ export default class EnvironmentVariableInit extends EasCommand {

await appendFile(shellConfigPath, `\n${direnvHookCmd}\n`, 'utf8');
Log.log(`Added direnv hook to ${shellConfigPath}`);
await spawnAsync(direnvInitCmd[0], direnvInitCmd[1], { stdio: 'inherit' });
} else {
Log.log("Unable to determine the user's shell");
Log.log('You may need to add the direnv hook to your shell config manually.');
Log.log('Learn more: https://direnv.net/docs/hook.html');
}
}

private getShellDirenvConfig(): { shellConfigPath: string; direnvHookCmd: string } | null {
private getShellDirenvConfig(): {
shellConfigPath: string;
direnvHookCmd: string;
direnvInitCmd: [string, string[]];
} | null {
const shellEnv = process.env.SHELL;
if (!shellEnv) {
return null;
Expand All @@ -78,16 +85,19 @@ export default class EnvironmentVariableInit extends EasCommand {
return {
shellConfigPath: path.join(os.homedir(), '.bashrc'),
direnvHookCmd: 'eval "$(direnv hook bash)"',
direnvInitCmd: ['eval', ['"$(direnv hook bash)"']],
};
} else if (shellEnv.endsWith('zsh')) {
return {
shellConfigPath: path.join(os.homedir(), '.zshrc'),
direnvHookCmd: 'eval "$(direnv hook zsh)"',
direnvInitCmd: ['eval', ['"$(direnv hook zsh)"']],
};
} else if (shellEnv.endsWith('fish')) {
return {
shellConfigPath: path.join(os.homedir(), '.config/fish/config.fish'),
direnvHookCmd: 'direnv hook fish | source',
direnvInitCmd: ['direnv', ['hook', 'fish']],
};
} else {
return null;
Expand All @@ -97,24 +107,17 @@ export default class EnvironmentVariableInit extends EasCommand {
private async addToGitIgnoreAsync(): Promise<void> {
if (await pathExists('.gitignore')) {
const gitignoreContent = await readFile('.gitignore', 'utf8');
const envrcPresent = gitignoreContent.includes('.envrc');
const envLocalPresent =
gitignoreContent.includes('.env.local') || gitignoreContent.includes('.env.*');

if (!envrcPresent || !envLocalPresent) {
const filesToIgnore = ['.envrc', '.env.eas.local', '.env.eas.local.original'];
const linesToAdd = filesToIgnore.filter(file => !gitignoreContent.includes(file));

if (linesToAdd.length > 0) {
const confirm = await confirmAsync({
message: 'Do you want to add .envrc and .env.local to .gitignore?',
message: `Do you want to add ${linesToAdd.join(',')} to .gitignore?`,
});
if (confirm) {
const linesToAdd = [];
if (!envrcPresent) {
linesToAdd.push('.envrc');
}
if (!envLocalPresent) {
linesToAdd.push('.env.local');
}
await appendFile('.gitignore', linesToAdd.join('\n') + '\n', 'utf8');
Log.log('.envrc and .env.local added to .gitignore');
Log.log(`${linesToAdd.join(',')} added to .gitignore`);
} else {
Log.log('Skipping adding .envrc and .env.local to .gitignore');
}
Expand Down Expand Up @@ -148,8 +151,6 @@ export default class EnvironmentVariableInit extends EasCommand {
await writeFile('.envrc', ENVRC_TEMPLATE, 'utf8');
Log.log('.envrc file created');
}
Log.log('Running direnv allow...');
await spawnAsync('direnv', ['allow']);
}

private async ensureDirenvInstalledAsync(): Promise<void> {
Expand Down
67 changes: 67 additions & 0 deletions packages/eas-cli/src/commands/env/load.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import assert from 'assert';
import * as fs from 'fs-extra';
import { exists } from 'fs-extra';

import { withSudoModeAsync } from '../../authUtils';
import EasCommand from '../../commandUtils/EasCommand';
import { EASEnvironmentFlag, EASNonInteractiveFlag } from '../../commandUtils/flags';
import { EnvironmentVariableFragment } from '../../graphql/generated';
import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../log';

const EnvLocalFile = '.env.local';
const EnvOriginalLocalFile = `${EnvLocalFile}.original`;

export default class EnvironmentVariableLoad extends EasCommand {
static override description = 'change environment variables';

static override hidden = true;

static override flags = {
...EASEnvironmentFlag,
...EASNonInteractiveFlag,
};
static override contextDefinition = {
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
...this.ContextOptions.SessionManagment,
};

async runAsync(): Promise<void> {
const {
flags: { environment, 'non-interactive': nonInteractive },
} = await this.parse(EnvironmentVariableLoad);

const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
sessionManager,
} = await this.getContextAsync(EnvironmentVariableLoad, {
nonInteractive,
});

assert(environment, 'Environment is required');

if ((await exists(EnvLocalFile)) && !(await exists(EnvOriginalLocalFile))) {
await fs.rename(EnvLocalFile, EnvOriginalLocalFile);
}
Log.log('Pulling environment variables...');

const environmentVariables = await withSudoModeAsync(sessionManager, async () => {
assert(environment);
return await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync(graphqlClient, {
appId: projectId,
environment,
});
});

const envFileContent = environmentVariables
.filter((variable: EnvironmentVariableFragment) => variable.value !== null)
.map((variable: EnvironmentVariableFragment) => {
return `${variable.name}=${variable.value}`;
})
.join('\n');
await fs.writeFile(EnvLocalFile, envFileContent);
Log.log(`Environment variables for ${environment} have been loaded.`);
}
}
23 changes: 23 additions & 0 deletions packages/eas-cli/src/commands/env/unload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as fs from 'fs-extra';
import { exists } from 'fs-extra';

import EasCommand from '../../commandUtils/EasCommand';
import Log from '../../log';

const EnvLocalFile = '.env.local';
const EnvOriginalLocalFile = `${EnvLocalFile}.original`;

export default class EnvironmentVariableUnload extends EasCommand {
static override description = 'unload environment variables';

static override hidden = true;

async runAsync(): Promise<void> {
if (await exists(EnvOriginalLocalFile)) {
await fs.rename(EnvOriginalLocalFile, EnvLocalFile);
} else {
await fs.remove(EnvLocalFile);
}
Log.log(`Unloaded environment variables.`);
}
}

0 comments on commit d6950fa

Please sign in to comment.