improve the syncEnvVars output and adapt resolveEnvVars

This commit is contained in:
Eric Allam
2024-08-17 22:12:31 +01:00
committed by Eric Allam
parent 059f1887f7
commit e1370134e3
9 changed files with 147 additions and 57 deletions
+10 -5
View File
@@ -9,6 +9,7 @@ import { BuildManifest, BuildTarget } from "@trigger.dev/core/v3/schemas";
import * as esbuild from "esbuild";
import { logger } from "../utilities/logger.js";
import { resolveModule } from "./resolveModule.js";
import { log, spinner } from "@clack/prompts";
export interface InternalBuildContext extends BuildContext {
getLayers(): BuildLayer[];
@@ -98,6 +99,12 @@ export function createBuildContext(
debug: (...args) => logger.debug(...args),
log: (...args) => logger.log(...args),
warn: (...args) => logger.warn(...args),
progress: (message) => log.message(message),
spinner: (message) => {
const $spinner = spinner();
$spinner.start(message);
return $spinner;
},
},
};
}
@@ -130,6 +137,8 @@ function applyLayerToManifest(layer: BuildLayer, manifest: BuildManifest): Build
if (layer.deploy?.env) {
manifest.deploy.env ??= {};
manifest.deploy.sync ??= {};
manifest.deploy.sync.env ??= {};
for (const [key, value] of Object.entries(layer.deploy.env)) {
if (!value) {
@@ -137,15 +146,11 @@ function applyLayerToManifest(layer: BuildLayer, manifest: BuildManifest): Build
}
if (layer.deploy.override || manifest.deploy.env[key] === undefined) {
let needsSyncing = manifest.deploy.needsSyncing;
const existingValue = manifest.deploy.env[key];
if (existingValue !== value) {
needsSyncing = true;
manifest.deploy.sync.env[key] = value;
}
manifest.deploy.env[key] = value;
manifest.deploy.needsSyncing = needsSyncing;
}
}
}
+33 -33
View File
@@ -1,15 +1,13 @@
import { intro, log, outro } from "@clack/prompts";
import { DEFAULT_RUNTIME, ResolvedConfig } from "@trigger.dev/core/v3/build";
import {
BuildManifest,
InitializeDeploymentResponseBody,
TaskFile,
} from "@trigger.dev/core/v3/schemas";
import { intro, outro } from "@clack/prompts";
import { CORE_VERSION } from "@trigger.dev/core/v3";
import { DEFAULT_RUNTIME, ResolvedConfig } from "@trigger.dev/core/v3/build";
import { BuildManifest, InitializeDeploymentResponseBody } from "@trigger.dev/core/v3/schemas";
import { Command, Option as CommandOption } from "commander";
import { writeFile } from "node:fs/promises";
import { join, relative, resolve } from "node:path";
import { readPackageJSON, writePackageJSON } from "pkg-types";
import { z } from "zod";
import { CliApiClient } from "../apiClient.js";
import { bundleWorker } from "../build/bundle.js";
import {
createBuildContext,
@@ -31,22 +29,7 @@ import {
wrapCommandAction,
} from "../cli/common.js";
import { loadConfig } from "../config.js";
import { createTempDir, writeJSONFile } from "../utilities/fileSystem.js";
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
import { logger } from "../utilities/logger.js";
import { getProjectClient } from "../utilities/session.js";
import { getTmpDir } from "../utilities/tempDirectories.js";
import { login } from "./login.js";
import { updateTriggerPackages } from "./update.js";
import { spinner } from "../utilities/windows.js";
import { readFile, writeFile } from "node:fs/promises";
import { VERSION } from "../version.js";
import { resolveFileSources } from "../utilities/sourceFiles.js";
import { buildImage, generateContainerfile } from "../deploy/buildImage.js";
import { buildManifestToJSON } from "../utilities/buildManifest.js";
import { CliApiClient } from "../apiClient.js";
import { chalkError, chalkWarning, cliLink } from "../utilities/cliOutput.js";
import { docs, getInTouch } from "../utilities/links.js";
import {
checkLogsForErrors,
checkLogsForWarnings,
@@ -54,6 +37,19 @@ import {
printWarnings,
saveLogs,
} from "../deploy/logs.js";
import { buildManifestToJSON } from "../utilities/buildManifest.js";
import { chalkError, cliLink } from "../utilities/cliOutput.js";
import { writeJSONFile } from "../utilities/fileSystem.js";
import { printStandloneInitialBanner } from "../utilities/initialBanner.js";
import { logger } from "../utilities/logger.js";
import { getProjectClient } from "../utilities/session.js";
import { resolveFileSources } from "../utilities/sourceFiles.js";
import { getTmpDir } from "../utilities/tempDirectories.js";
import { spinner } from "../utilities/windows.js";
import { VERSION } from "../version.js";
import { login } from "./login.js";
import { updateTriggerPackages } from "./update.js";
import { loadDotEnvVars, resolveDotEnvVars } from "../utilities/dotEnv.js";
const DeployCommandOptions = CommonCommandOptions.extend({
dryRun: z.boolean().default(false),
@@ -210,6 +206,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
}
const serverEnvVars = await projectClient.client.getEnvironmentVariables(resolvedConfig.project);
loadDotEnvVars(resolvedConfig.workingDir);
const destination = getTmpDir(resolvedConfig.workingDir, "build", options.dryRun);
const externalsExtension = createExternalsBuildExtension("deploy", resolvedConfig);
@@ -293,18 +290,21 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
}
if (
buildManifest.deploy.env &&
Object.keys(buildManifest.deploy.env).length > 0 &&
buildManifest.deploy.needsSyncing
buildManifest.deploy.sync &&
buildManifest.deploy.sync.env &&
Object.keys(buildManifest.deploy.sync.env).length > 0
) {
const numberOfEnvVars = Object.keys(buildManifest.deploy.sync.env).length;
const vars = numberOfEnvVars === 1 ? "var" : "vars";
if (!options.skipSyncEnvVars) {
const $spinner = spinner();
$spinner.start("Syncing environment variables with the server");
$spinner.start(`Syncing ${numberOfEnvVars} env ${vars} with the server`);
const success = await syncEnvVarsWithServer(
projectClient.client,
resolvedConfig.project,
options.env,
buildManifest.deploy.env
buildManifest.deploy.sync.env
);
if (!success) {
@@ -313,19 +313,19 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
deployment,
{
name: "SyncEnvVarsError",
message: "Failed to sync environment variables with the server",
message: `Failed to sync ${numberOfEnvVars} env ${vars} with the server`,
},
"",
$spinner
);
} else {
$spinner.stop("Successfully synced environment variables with the server");
$spinner.stop(`Successfully synced ${numberOfEnvVars} env ${vars} with the server`);
}
} else {
logger.log(
"Skipping syncing env vars. The environment variables in your project have changed, but the --skip-sync-env-vars flag was provided."
);
}
logger.log(
"Skipping syncing environment variables. The environment variables in your project have changed, but the --skip-sync-env-vars flag was provided."
);
}
const version = deployment.version;
+27 -3
View File
@@ -1,4 +1,4 @@
import { TriggerConfig } from "@trigger.dev/core/v3";
import { ResolveEnvironmentVariablesFunction, TriggerConfig } from "@trigger.dev/core/v3";
import { DEFAULT_RUNTIME, ResolvedConfig } from "@trigger.dev/core/v3/build";
import * as c12 from "c12";
import { defu } from "defu";
@@ -8,7 +8,7 @@ import { basename, dirname, isAbsolute, join, relative } from "node:path";
import { findWorkspaceDir, resolveLockfile, resolvePackageJSON, resolveTSConfig } from "pkg-types";
import { generateCode, loadFile } from "./imports/magicast.js";
import { logger } from "./utilities/logger.js";
import { additionalFiles, additionalPackages } from "@trigger.dev/core/v3/extensions";
import { additionalFiles, additionalPackages, syncEnvVars } from "@trigger.dev/core/v3/extensions";
export type ResolveConfigOptions = {
cwd?: string;
@@ -99,6 +99,9 @@ export function configPlugin(resolvedConfig: ResolvedConfig): esbuild.Plugin | u
options.build = {};
// Remove export resolveEnvVars function as well
delete $mod.exports.resolveEnvVars;
const contents = generateCode($mod);
logger.debug("trigger-config-strip.onLoad.contents", contents);
@@ -247,7 +250,11 @@ function validateConfig(config: TriggerConfig, warn = true) {
`The "resolveEnvVars" option is deprecated and will be removed. Use the "syncEnvVars" build extension instead. See https://trigger.dev/docs/trigger-config#syncEnvVars for more information.`
);
//
const resolveEnvVarsFn = config.resolveEnvVars as ResolveEnvironmentVariablesFunction;
config.build ??= {};
config.build.extensions ??= [];
config.build.extensions.push(adaptResolveEnvVarsToSyncEnvVarsExtension(resolveEnvVarsFn));
}
if (config.runtime && config.runtime === "bun") {
@@ -255,3 +262,20 @@ function validateConfig(config: TriggerConfig, warn = true) {
logger.warn(`The "bun" runtime is currently experimental and may not work as expected.`);
}
}
function adaptResolveEnvVarsToSyncEnvVarsExtension(
resolveEnvVarsFn: ResolveEnvironmentVariablesFunction
) {
return syncEnvVars(
async (ctx) => {
const resolveEnvVarsResult = await resolveEnvVarsFn(ctx);
if (!resolveEnvVarsResult) {
return;
}
return resolveEnvVarsResult.variables;
},
{ override: true }
);
}
+8
View File
@@ -19,3 +19,11 @@ export function resolveDotEnvVars(cwd?: string) {
return result;
}
export function loadDotEnvVars(cwd?: string) {
dotenv.config({
path: [".env", ".env.local", ".env.development.local"].map((p) =>
resolve(cwd ?? process.cwd(), p)
),
});
}
+7
View File
@@ -24,10 +24,17 @@ export interface BuildExtension {
) => Promise<undefined | void> | undefined | void;
}
export interface BuildSpinner {
stop: (message: string, code?: number) => void;
message: (message: string) => void;
}
export interface BuildLogger {
debug: (...args: unknown[]) => void;
log: (...args: unknown[]) => void;
warn: (...args: unknown[]) => void;
progress: (message: string) => void;
spinner: (message: string) => BuildSpinner;
}
export interface BuildContext {
+1
View File
@@ -2,3 +2,4 @@ export * from "./emitDecoratorMetadata.js";
export * from "./additionalFiles.js";
export * from "./additionalPackages.js";
export * from "./prisma.js";
export * from "./syncEnvVars.js";
+29 -10
View File
@@ -1,4 +1,4 @@
import { BuildExtension } from "../build/extensions.js";
import { BuildContext, BuildExtension } from "../build/extensions.js";
export type SyncEnvVarsBody = Record<string, string> | Array<{ name: string; value: string }>;
@@ -77,14 +77,18 @@ export function syncEnvVars(fn: SyncEnvVarsFunction, options?: SyncEnvVarsOption
return;
}
const $spinner = context.logger.spinner("Invoking syncEnvVars callback");
const result = await callSyncEnvVarsFn(
fn,
manifest.deploy.env ?? {},
manifest.environment,
context.config.project
context
);
if (!result) {
$spinner.stop("No env vars detected");
return;
}
@@ -100,6 +104,18 @@ export function syncEnvVars(fn: SyncEnvVarsFunction, options?: SyncEnvVarsOption
{} as Record<string, string>
);
const numberOfEnvVars = Object.keys(env).length;
if (numberOfEnvVars === 0) {
$spinner.stop("No env vars detected");
return;
} else if (numberOfEnvVars === 1) {
$spinner.stop(`Found 1 env var`);
} else {
$spinner.stop(`Found ${numberOfEnvVars} env vars to sync`);
}
context.addLayer({
id: "sync-env-vars",
deploy: {
@@ -115,23 +131,26 @@ async function callSyncEnvVarsFn(
syncEnvVarsFn: SyncEnvVarsFunction | undefined,
env: Record<string, string>,
environment: string,
projectRef: string
context: BuildContext
): Promise<Record<string, string> | undefined> {
if (syncEnvVarsFn && typeof syncEnvVarsFn === "function") {
let resolvedEnvVars: Record<string, string> = {};
let result;
let result = syncEnvVarsFn({
projectRef,
environment,
env,
});
try {
result = await syncEnvVarsFn({
projectRef: context.config.project,
environment,
env,
});
} catch (error) {
context.logger.warn("Error calling syncEnvVars function", error);
}
if (!result) {
return;
}
result = await result;
if (Array.isArray(result)) {
for (const item of result) {
if (
+5 -1
View File
@@ -44,7 +44,11 @@ export const BuildManifest = z.object({
}),
deploy: z.object({
env: z.record(z.string()).optional(),
needsSyncing: z.boolean().optional(),
sync: z
.object({
env: z.record(z.string()).optional(),
})
.optional(),
}),
});
+27 -5
View File
@@ -1,12 +1,34 @@
import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
import { defineConfig, ResolveEnvironmentVariablesFunction } from "@trigger.dev/sdk/v3";
import { emitDecoratorMetadata } from "@trigger.dev/sdk/v3/extensions";
import { InfisicalClient } from "@infisical/sdk";
export const resolveEnvVars: ResolveEnvironmentVariablesFunction = async ({
projectRef,
env,
environment,
}) => {};
export const resolveEnvVars: ResolveEnvironmentVariablesFunction = async (ctx) => {
if (
process.env.INFISICAL_CLIENT_ID === undefined ||
process.env.INFISICAL_CLIENT_SECRET === undefined ||
process.env.INFISICAL_PROJECT_ID === undefined
) {
return;
}
const client = new InfisicalClient({
clientId: process.env.INFISICAL_CLIENT_ID,
clientSecret: process.env.INFISICAL_CLIENT_SECRET,
});
const secrets = await client.listSecrets({
environment: ctx.environment,
projectId: process.env.INFISICAL_PROJECT_ID,
});
return {
variables: secrets.map((secret) => ({
name: secret.secretKey,
value: secret.secretValue,
})),
};
};
export default defineConfig({
project: "yubjwjsfkxnylobaqvqz",