Skip to content

Commit a6d2260

Browse files
mrgrainmoelasmar
authored andcommitted
fix(cx-api): cannot detect CloudAssembly across different libraries (#32998)
### Reason for this change We are publishing the `cx-api` package twice: Once as a standalone package `@aws-cdk/cx-api` and once as part of the construct library under `aws-cdk-lib/cx-api`. The code is copied during the release and the same versions of the packages will have the same code. However this makes it difficult for other packages to take a type dependency on types from this package. The most common class that's used from `cx-api` is `CloudAssembly` - the result of `app.synth()`. Previously a package had to take a dependency on the very large `aws-cdk-lib` just to use a single type. It would be better if other packages could instead depend on the smaller, much more focused `@aws-cdk/cx-api` package. ### Description of changes This adds the same mechanism to `CloudAssembly` to detect cross-library compatibility, that we already use for constructs like `Stack` or `App`. In TypeScript, it's now possible for a consuming package to receive an object from either package and check at runtime if it satisfies the requirements. We cannot get around type checking with this. Instead we introduce a new type `ICloudAssembly` into the Cloud Assembly Schema package (cdklabs/cloud-assembly-schema#133). This interface only declares a single property: `directory`. Consumers can use this type to indicate where they would like to receive a `CloudAssembly`. They can then use runtime code to either confirm a provided object already satisfies the requirements or fallback to creating a new `CloudAssembly` from the directory. Because the `CloudAssembly` in `cxapi` implements the new interface, this approach will work in all jsii languages. In TypeScript it's even compatible with older version of `aws-cdk-lib`. Jsii language will only support this going forward. #### Allowed breaking changes ``` weakened:aws-cdk-lib.cloud_assembly_schema.MetadataEntry weakened:aws-cdk-lib.cx_api.MetadataEntryResult ``` This PR updates the version of `@aws-cdk/cloud-assembly-schema` to make new of the new interface. However the update also includes a change to `MetadataEntry` which was introduced in cdklabs/cloud-assembly-schema#121. That change is weakening a type, because in #31041, the CDK started emitting booleans and numbers as metadata values. But since these types weren't officially declared in the schema, jsii runtime type checking failed to load them. The fix was to officially extend the type union to include `boolean` and `number` primitive values. This is considered breaking, because when used as an output any consuming code will now need to account for the possibility of the value being a `boolean` or `number`. In static languages, the type would already have been treated as a generic Object with required runtime checks. ### Describe any new or updated permissions being added n/a ### Description of how you validated changes Unit tests. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* (cherry picked from commit 94ba772)
1 parent 58db902 commit a6d2260

File tree

17 files changed

+314
-10762
lines changed

17 files changed

+314
-10762
lines changed

allowed-breaking-changes.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -942,4 +942,12 @@ change-return-type:aws-cdk-lib.aws_lambda.FilterRule.null
942942
# output property was mistakenly marked as required even though it should have allowed
943943
# for undefined, i.e optional
944944
changed-type:@aws-cdk/cx-api.CloudFormationStackArtifact.notificationArns
945-
changed-type:aws-cdk-lib.cx_api.CloudFormationStackArtifact.notificationArns
945+
changed-type:aws-cdk-lib.cx_api.CloudFormationStackArtifact.notificationArns
946+
947+
# In aws/aws-cdk#31041, the CDK started emitting booleans and numbers as metadata values.
948+
# Since these types weren't officially declared in the schema, jsii runtime type checking failed to load them.
949+
# The type has now weakened, and when it's used as an output any consuming code will need to account for the possibility of the value being a boolean or number.
950+
# In static languages, the type would already have been treated as a generic Object with required runtime checks.
951+
# See: https://github.com/cdklabs/cloud-assembly-schema/pull/121
952+
weakened:aws-cdk-lib.cloud_assembly_schema.MetadataEntry
953+
weakened:aws-cdk-lib.cx_api.MetadataEntryResult

packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES

Lines changed: 252 additions & 10738 deletions
Large diffs are not rendered by default.

packages/@aws-cdk/cx-api/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"gen": "cdk-copy cx-api",
6363
"watch": "cdk-watch",
6464
"lint": "cdk-lint && madge --circular --extensions js lib",
65-
"test": "cdk-test",
65+
"test": "jest",
6666
"pkglint": "pkglint -f",
6767
"package": "cdk-package",
6868
"awslint": "cdk-awslint",
@@ -82,12 +82,12 @@
8282
"semver": "^7.6.3"
8383
},
8484
"peerDependencies": {
85-
"@aws-cdk/cloud-assembly-schema": "^39.0.0"
85+
"@aws-cdk/cloud-assembly-schema": "^39.2.0"
8686
},
8787
"license": "Apache-2.0",
8888
"devDependencies": {
8989
"@aws-cdk/cdk-build-tools": "0.0.0",
90-
"@aws-cdk/cloud-assembly-schema": "^39.0.1",
90+
"@aws-cdk/cloud-assembly-schema": "^39.2.0",
9191
"@aws-cdk/pkglint": "0.0.0",
9292
"@types/jest": "^29.5.14",
9393
"@types/mock-fs": "^4.13.4",
@@ -120,4 +120,4 @@
120120
"publishConfig": {
121121
"tag": "latest"
122122
}
123-
}
123+
}

packages/@aws-cdk/integ-runner/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
},
7373
"dependencies": {
7474
"chokidar": "^3.6.0",
75-
"@aws-cdk/cloud-assembly-schema": "^39.0.0",
75+
"@aws-cdk/cloud-assembly-schema": "^39.2.0",
7676
"@aws-cdk/cloudformation-diff": "0.0.0",
7777
"@aws-cdk/cx-api": "0.0.0",
7878
"@aws-cdk/aws-service-spec": "^0.1.49",
@@ -109,4 +109,4 @@
109109
"publishConfig": {
110110
"tag": "latest"
111111
}
112-
}
112+
}

packages/@aws-cdk/toolkit/lib/api/cloud-assembly/private/source-builder.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as cxapi from '@aws-cdk/cx-api';
12
import * as fs from 'fs-extra';
23
import type { ICloudAssemblySource } from '../';
34
import { ContextAwareCloudAssembly, ContextAwareCloudAssemblyProps } from './context-aware-source';
@@ -10,7 +11,6 @@ import { debug } from '../../io/private';
1011
import { AssemblyBuilder, CdkAppSourceProps } from '../source-builder';
1112

1213
export abstract class CloudAssemblySourceBuilder {
13-
1414
/**
1515
* Helper to provide the CloudAssemblySourceBuilder with required toolkit services
1616
* @deprecated this should move to the toolkit really.
@@ -40,13 +40,19 @@ export abstract class CloudAssemblySourceBuilder {
4040
produce: async () => {
4141
const outdir = determineOutputDirectory(props.outdir);
4242
const env = await prepareDefaultEnvironment(services, { outdir });
43-
return changeDir(async () =>
43+
const assembly = await changeDir(async () =>
4444
withContext(context.all, env, props.synthOptions ?? {}, async (envWithContext, ctx) =>
4545
withEnv(envWithContext, () => builder({
4646
outdir,
4747
context: ctx,
4848
})),
4949
), props.workingDirectory);
50+
51+
if (cxapi.CloudAssembly.isCloudAssembly(assembly)) {
52+
return assembly;
53+
}
54+
55+
return new cxapi.CloudAssembly(assembly.directory);
5056
},
5157
},
5258
contextAssemblyProps,

packages/@aws-cdk/toolkit/lib/api/cloud-assembly/source-builder.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type * as cxapi from '@aws-cdk/cx-api';
1+
import type * as cxschema from '@aws-cdk/cloud-assembly-schema';
22

33
export interface AppProps {
44
/**
@@ -12,7 +12,7 @@ export interface AppProps {
1212
readonly context?: { [key: string]: any };
1313
}
1414

15-
export type AssemblyBuilder = (props: AppProps) => Promise<cxapi.CloudAssembly>;
15+
export type AssemblyBuilder = (props: AppProps) => Promise<cxschema.ICloudAssembly>;
1616

1717
/**
1818
* Configuration for creating a CLI from an AWS CDK App directory

packages/@aws-cdk/toolkit/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
"typescript": "~5.6.3"
5858
},
5959
"dependencies": {
60-
"@aws-cdk/cloud-assembly-schema": "^39.0.1",
60+
"@aws-cdk/cloud-assembly-schema": "^39.2.0",
6161
"@aws-cdk/cloudformation-diff": "0.0.0",
6262
"@aws-cdk/cx-api": "0.0.0",
6363
"@aws-cdk/region-info": "0.0.0",

packages/@aws-cdk/toolkit/test/_fixtures/external-context/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ export default async () => {
77
new s3.Bucket(stack, 'MyBucket', {
88
bucketName: app.node.tryGetContext('externally-provided-bucket-name'),
99
});
10-
return app.synth() as any;
10+
return app.synth();
1111
};

packages/@aws-cdk/toolkit/test/_fixtures/stack-with-bucket/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/@aws-cdk/toolkit/test/_fixtures/stack-with-bucket/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ export default async () => {
55
const app = new core.App();
66
const stack = new core.Stack(app, 'Stack1');
77
new s3.Bucket(stack, 'MyBucket');
8-
return app.synth() as any;
8+
return app.synth();
99
};

0 commit comments

Comments
 (0)