UNPKG

eas-cli

Version:
151 lines (150 loc) 7.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const core_1 = require("@oclif/core"); const chalk_1 = tslib_1.__importDefault(require("chalk")); const dotenv_1 = tslib_1.__importDefault(require("dotenv")); const fs_extra_1 = tslib_1.__importDefault(require("fs-extra")); const path_1 = tslib_1.__importDefault(require("path")); const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand")); const flags_1 = require("../../commandUtils/flags"); const generated_1 = require("../../graphql/generated"); const EnvironmentSecretMutation_1 = require("../../graphql/mutations/EnvironmentSecretMutation"); const EnvironmentSecretsQuery_1 = require("../../graphql/queries/EnvironmentSecretsQuery"); const log_1 = tslib_1.__importDefault(require("../../log")); const ora_1 = require("../../ora"); const projectUtils_1 = require("../../project/projectUtils"); const prompts_1 = require("../../prompts"); const intersection_1 = tslib_1.__importDefault(require("../../utils/expodash/intersection")); class EnvironmentSecretPush extends EasCommand_1.default { static description = 'read environment secrets from env file and store on the server'; static hidden = true; static flags = { scope: core_1.Flags.enum({ description: 'Scope for the secrets', options: [EnvironmentSecretsQuery_1.EnvironmentSecretScope.ACCOUNT, EnvironmentSecretsQuery_1.EnvironmentSecretScope.PROJECT], default: EnvironmentSecretsQuery_1.EnvironmentSecretScope.PROJECT, }), 'env-file': core_1.Flags.string({ description: 'Env file with secrets', }), force: core_1.Flags.boolean({ description: 'Delete and recreate existing secrets', default: false, }), ...flags_1.EASNonInteractiveFlag, }; static contextDefinition = { ...this.ContextOptions.ProjectId, ...this.ContextOptions.LoggedIn, }; async runAsync() { log_1.default.warn('This command is deprecated. Use eas env:push instead.'); log_1.default.newLine(); const { flags: { scope, force, 'env-file': maybeEnvFilePath, 'non-interactive': nonInteractive }, } = await this.parse(EnvironmentSecretPush); const { projectId, loggedIn: { graphqlClient }, } = await this.getContextAsync(EnvironmentSecretPush, { nonInteractive, }); const projectDisplayName = await (0, projectUtils_1.getDisplayNameForProjectIdAsync)(graphqlClient, projectId); const ownerAccount = await (0, projectUtils_1.getOwnerAccountForProjectIdAsync)(graphqlClient, projectId); const envFilePath = await resolveEnvFilePathAsync(maybeEnvFilePath, nonInteractive); if (!(await fs_extra_1.default.pathExists(envFilePath))) { throw new Error(`File "${envFilePath}" does not exist`); } const newSecrets = dotenv_1.default.parse(await fs_extra_1.default.readFile(envFilePath)); await ensureSecretsDontExistOnServerAsync(graphqlClient, { projectId, scope, force }, newSecrets); await createSecretsAsync(graphqlClient, { scope, accountId: ownerAccount.id, accountName: ownerAccount.name, projectId, projectDisplayName, }, newSecrets); log_1.default.withTick(`Created the following secrets on ${scope} ${chalk_1.default.bold(scope === EnvironmentSecretsQuery_1.EnvironmentSecretScope.ACCOUNT ? ownerAccount.name : projectDisplayName)}:`); for (const secretName of Object.keys(newSecrets)) { log_1.default.log(`- ${secretName}`); } } } exports.default = EnvironmentSecretPush; async function resolveEnvFilePathAsync(maybeEnvFilePath, nonInteractive) { if (maybeEnvFilePath) { return maybeEnvFilePath; } const validationMessage = 'Env file must be passed.'; if (nonInteractive) { throw new Error(validationMessage); } const { envFilePath } = await (0, prompts_1.promptAsync)({ type: 'text', name: 'envFilePath', message: 'Path to the env file with secrets:', // eslint-disable-next-line async-protect/async-suffix validate: async (secretValueRaw) => { if (!secretValueRaw) { return validationMessage; } const envFilePath = path_1.default.resolve(secretValueRaw); if (!(await fs_extra_1.default.pathExists(envFilePath))) { return `File "${envFilePath}" does not exist.`; } return true; }, }); return envFilePath; } async function ensureSecretsDontExistOnServerAsync(graphqlClient, { projectId, scope, force }, secrets) { const serverSecrets = await readAllSecretsFromServerAsync(graphqlClient, projectId, scope); const commonSecretNames = findCommonSecretNames(serverSecrets, secrets); if (commonSecretNames.length > 0) { if (!force) { log_1.default.log(`This ${scope} already has environment secrets with the following names:`); for (const name of commonSecretNames) { log_1.default.log(`- ${name}`); } log_1.default.error('Run with --force flag to proceed'); core_1.Errors.exit(1); } else { const spinner = (0, ora_1.ora)('Deleting secrets already present on server...').start(); const commonSecretNameSet = new Set(commonSecretNames); const commonServerSecrets = serverSecrets.filter(({ name }) => commonSecretNameSet.has(name)); await deleteSecretsAsync(graphqlClient, commonServerSecrets); spinner.succeed(); } } } async function readAllSecretsFromServerAsync(graphqlClient, projectId, scope) { const { appSecrets, accountSecrets } = await EnvironmentSecretsQuery_1.EnvironmentSecretsQuery.byAppIdAsync(graphqlClient, projectId); return scope === EnvironmentSecretsQuery_1.EnvironmentSecretScope.ACCOUNT ? accountSecrets : appSecrets; } function findCommonSecretNames(serverSecrets, newSecrets) { const serverSecretKeys = serverSecrets.map(({ name }) => name); const newSecretKeys = Object.keys(newSecrets); const commonKeys = (0, intersection_1.default)(serverSecretKeys, newSecretKeys); return commonKeys; } async function deleteSecretsAsync(graphqlClient, secrets) { const promises = secrets.map(secret => EnvironmentSecretMutation_1.EnvironmentSecretMutation.deleteAsync(graphqlClient, secret.id)); await Promise.all(promises); } async function createSecretsAsync(graphqlClient, { scope, accountId, accountName, projectId, projectDisplayName, }, secrets) { const promises = []; const spinner = (0, ora_1.ora)(`Creating secrets on ${scope} ${chalk_1.default.bold(scope === EnvironmentSecretsQuery_1.EnvironmentSecretScope.ACCOUNT ? accountName : projectDisplayName)}...`).start(); for (const [secretName, secretValue] of Object.entries(secrets)) { if (scope === EnvironmentSecretsQuery_1.EnvironmentSecretScope.ACCOUNT) { promises.push(EnvironmentSecretMutation_1.EnvironmentSecretMutation.createForAccountAsync(graphqlClient, { name: secretName, value: secretValue, type: generated_1.EnvironmentSecretType.String }, accountId)); } else { promises.push(EnvironmentSecretMutation_1.EnvironmentSecretMutation.createForAppAsync(graphqlClient, { name: secretName, value: secretValue, type: generated_1.EnvironmentSecretType.String }, projectId)); } } try { await Promise.all(promises); spinner.succeed(); } catch (err) { spinner.fail(); throw err; } }