Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ExecutionEnvironment, assemblyFromDirectory } from './prepare-source';
import type { ToolkitServices } from '../../../toolkit/private';
import { IO } from '../../io/private';
import { ToolkitError, AssemblyError } from '../../shared-public';
import type { AssemblyBuilder } from '../source-builder';
import type { AssemblyBuilder, FromCdkAppOptions } from '../source-builder';
import { ReadableCloudAssembly } from './readable-assembly';
import { Context } from '../../context';
import { RWLock } from '../../rwlock';
Expand Down Expand Up @@ -142,7 +142,7 @@ export abstract class CloudAssemblySourceBuilder {
* @param props additional configuration properties
* @returns the CloudAssembly source
*/
public async fromCdkApp(app: string, props: AssemblySourceProps = {}): Promise<ICloudAssemblySource> {
public async fromCdkApp(app: string, props: FromCdkAppOptions = {}): Promise<ICloudAssemblySource> {
const services: ToolkitServices = await this.sourceBuilderServices();
// @todo this definitely needs to read files from the CWD
const context = new Context({ bag: new Settings(props.context ?? {}) });
Expand Down Expand Up @@ -171,7 +171,10 @@ export abstract class CloudAssemblySourceBuilder {
await using execution = await ExecutionEnvironment.create(services, { outdir });

const commandLine = await execution.guessExecutable(app);
const env = await execution.defaultEnvVars();
const env = noUndefined({
...await execution.defaultEnvVars(),
...props.env,
});
return await execution.withContext(context.all, env, props.synthOptions, async (envWithContext, _ctx) => {
await execInChildProcess(commandLine.join(' '), {
eventPublisher: async (type, line) => {
Expand Down Expand Up @@ -200,3 +203,9 @@ export abstract class CloudAssemblySourceBuilder {
}
}

/**
* Remove undefined values from a dictionary
*/
function noUndefined<A>(xs: Record<string, A>): Record<string, NonNullable<A>> {
return Object.fromEntries(Object.entries(xs).filter(([_, v]) => v !== undefined)) as any;
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,20 @@ export interface AssemblySourceProps {
readonly loadAssemblyOptions?: LoadAssemblyOptions;
}

/**
* Options for the `fromCdkApp` Assembly Source constructor
*/
export interface FromCdkAppOptions extends AssemblySourceProps {
/**
* Additional environment variables
*
* These environment variables will be set in addition to the environment
* variables currently set in the process. A value of `undefined` will
* unset a particular environment variable.
*/
readonly env?: Record<string, string | undefined>;
}

/**
* Settings that are passed to a CDK app via the context
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as core from 'aws-cdk-lib/core';

const stackName = process.env.STACK_NAME;
if (!stackName) {
throw new Error('$STACK_NAME not set!');
}

const app = new core.App({ autoSynth: false });
const stack = new core.Stack(app, stackName);
new s3.Bucket(stack, 'MyBucket');
app.synth();
6 changes: 3 additions & 3 deletions packages/@aws-cdk/toolkit-lib/test/_helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import type { AssemblyDirectoryProps, ICloudAssemblySource } from '../../lib';
import type { AssemblyDirectoryProps, FromCdkAppOptions, ICloudAssemblySource } from '../../lib';
import { ToolkitError } from '../../lib';
import type { CloudAssemblySourceBuilder } from '../../lib/api/cloud-assembly/private';

Expand All @@ -12,7 +12,7 @@ function fixturePath(...parts: string[]): string {
return path.normalize(path.join(__dirname, '..', '_fixtures', ...parts));
}

export async function appFixture(toolkit: CloudAssemblySourceBuilder, name: string, context?: { [key: string]: any }) {
export async function appFixture(toolkit: CloudAssemblySourceBuilder, name: string, options?: Omit<FromCdkAppOptions, 'workingDirectory' | 'outdir'>) {
const appPath = fixturePath(name, 'app.js');
if (!fs.existsSync(appPath)) {
throw new ToolkitError(`App Fixture ${name} does not exist in ${appPath}`);
Expand All @@ -21,7 +21,7 @@ export async function appFixture(toolkit: CloudAssemblySourceBuilder, name: stri
return toolkit.fromCdkApp(app, {
workingDirectory: path.join(__dirname, '..', '..'),
outdir: tmpOutdir(),
context,
...options,
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ describe('fromCdkApp', () => {
test('can provide context', async () => {
// WHEN
const cx = await appFixture(toolkit, 'external-context', {
'externally-provided-bucket-name': 'amzn-s3-demo-bucket',
context: {
'externally-provided-bucket-name': 'amzn-s3-demo-bucket',
},
});
await using assembly = await cx.produce();
const stack = assembly.cloudAssembly.getStackByName('Stack1').template;
Expand All @@ -126,6 +128,20 @@ describe('fromCdkApp', () => {
expect(JSON.stringify(stack)).toContain('amzn-s3-demo-bucket');
});

test('can set environment variables', async () => {
// WHEN
const cx = await appFixture(toolkit, 'environment-variable', {
env: {
STACK_NAME: 'SomeStackName',
},
});
await using assembly = await cx.produce();
const stack = assembly.cloudAssembly.getStackByName('SomeStackName').template;

// THEN
expect(stack).toBeDefined();
});

test('will capture error output', async () => {
// WHEN
const cx = await appFixture(toolkit, 'validation-error');
Expand Down
Loading