genezio
Version:
Command line utility to interact with Genezio infrastructure.
144 lines (143 loc) • 6 kB
JavaScript
import inquirer from "inquirer";
import path from "path";
import colors from "colors";
import { fileExists, readEnvironmentVariablesFile } from "./file.js";
import { getEnvironmentVariables } from "../requests/getEnvironmentVariables.js";
import { EnvironmentResourceType, evaluateResource } from "../commands/deploy/utils.js";
import { DASHBOARD_URL } from "../constants.js";
import { log } from "./logging.js";
/**
* Parses a configuration variable string to extract the path and field.
*
* @param rawValue The raw string value of the configuration variable.
* @returns An object containing the path and field, or the key, or the value.
*
* @example
* parseConfigurationVariable("${{ backend.functions.<function-name>.url }}");
* // Returns { path: "backend.functions.<function-name>", field: "url" }
*
* @example
* parseConfigurationVariable("${{ env.MY_ENV_VAR }}");
* // Returns { key: "MY_ENV_VAR" }
*
* @example
* parseConfigurationVariable("my-value");
* // Returns { value: "my-value" }
*/
export async function parseConfigurationVariable(rawValue) {
const prefix = "${{";
const suffix = "}}";
const sanitizeVariable = (variable) => variable.slice(prefix.length, -suffix.length).replace(/\s/g, "");
// Format: ${{ env.<variable> }}
const regexEnv = /\$\{\{[ ]*env\.[ a-zA-Z0-9-._]+\}\}/;
const matchEnv = rawValue.match(regexEnv);
if (matchEnv) {
const variable = sanitizeVariable(matchEnv[0]);
// Split the string at the first period to get <variable>
const firstDotIndex = variable.indexOf(".");
const key = variable.substring(firstDotIndex + 1);
return { key };
}
// Format: ${{ backend.functions.<function-name>.url }}
const regex = /\$\{\{[ a-zA-Z0-9-._]+\}\}/;
const match = rawValue.match(regex);
if (match) {
// Sanitize the variable
const variable = sanitizeVariable(match[0]);
// Split the string at the last period to get the path `backend.functions.<function-name>` and field `url`
const lastDotIndex = variable.lastIndexOf(".");
const path = variable.substring(0, lastDotIndex);
const field = variable.substring(lastDotIndex + 1);
return { path, field };
}
return { value: rawValue };
}
export async function expandEnvironmentVariables(environment, configuration, stage, envFile, options) {
if (!environment) {
return {};
}
const resolveValue = async (key) => {
const value = await evaluateResource(configuration, [
EnvironmentResourceType.RemoteResourceReference,
EnvironmentResourceType.EnvironmentFileReference,
EnvironmentResourceType.LiteralValue,
], environment[key], stage, envFile, options);
return value !== "" ? [key, value] : null;
};
const resolvedEntries = await Promise.all(Object.keys(environment).map(async (key) => resolveValue(key)));
// Ensure `null` values are removed before calling Object.fromEntries
return Object.fromEntries(resolvedEntries.filter((entry) => entry !== null));
}
/**
* Detects if an environment variables file exists at the given path.
* @param path The path to the environment variables file.
*
* @returns A boolean indicating if the file exists.
*/
export async function detectEnvironmentVariablesFile(path) {
return await fileExists(path);
}
/**
* Prompts the user to confirm setting the detected environment variables.
*
* @param envVars The list of environment variables to set.
* @returns A boolean indicating if the user confirmed setting the environment variables.
*/
export async function promptToConfirmSettingEnvironmentVariables(envVars) {
const { confirmSetEnvVars } = await inquirer.prompt([
{
type: "confirm",
name: "confirmSetEnvVars",
message: `We detected that ${envVars.join(", ")} are not set remotely. Do you want us to set them for you?`,
default: false,
},
]);
if (!confirmSetEnvVars) {
return false;
}
return true;
}
export async function warningMissingEnvironmentVariables(cwd, projectId, projectEnvId) {
const envFileFullPath = path.join(cwd, ".env");
if (!(await fileExists(envFileFullPath))) {
return;
}
const envVars = await readEnvironmentVariablesFile(envFileFullPath);
if (envVars.length === 0) {
return;
}
const missingEnvVars = await getUnsetEnvironmentVariables(envVars.map((envVar) => envVar.name), projectId, projectEnvId);
if (missingEnvVars.length === 0) {
return;
}
log.warn(`Environment variables ${missingEnvVars.join(", ")} are not set remotely. Please set them using the dashboard ${colors.cyan(DASHBOARD_URL)}`);
}
/**
* Gets the list of environment variables that were found locally but not set remotely.
*
* @param local The list of environment variables found locally.
* @param projectId The project ID.
* @param projectEnvId The project environment ID.
* @returns The list of environment variables that were found locally but not set remotely.
*/
export async function getUnsetEnvironmentVariables(local, projectId, projectEnvId) {
const remoteEnvVars = await getEnvironmentVariables(projectId, projectEnvId);
const missingEnvVars = local.filter((envVar) => !remoteEnvVars.find((remoteEnvVar) => remoteEnvVar.name === envVar));
return missingEnvVars;
}
/**
* Finds an environment variables file in the given directory.
* @param cwd The directory to search for the environment variables file.
* @returns The path to the environment variables file.
*/
export async function findAnEnvFile(cwd) {
// These are the most common locations for the .env file
const possibleEnvFilePath = ["server/.env", ".env"];
for (const envFilePath of possibleEnvFilePath) {
const fullPath = path.join(cwd, envFilePath);
if (await fileExists(fullPath)) {
return fullPath;
}
}
return undefined;
}