Skip to content

Commit 967ee9d

Browse files
authored
chore(enum-updater): support adding manual static enum mappings (#34441)
### Issue # (if applicable) Closes #<issue number here>. ### Reason for this change Manual changes to the `static-enum-mapping.json` would be overwritten the next time the workflow was run. ### Description of changes Add a new file `manual-enum-mapping.json` that allows maintainers to add manual mappings that will be used over any matching mapping that the script calculates. Manual mappings should be added in the form: ``` { "serviceName": { "CdkEnumName": { "cdk_path": "path/to/cdkEnum", "sdk_service": "serviceName", "sdk_enum_name": "AwsEnumThatWeWantThisToMapTo", "match_percentage": 1.0, "manual": true } } } ``` For example: ``` { "ec2": { "VpcEndpointIpAddressType": { "cdk_path": "aws-cdk/packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts", "sdk_service": "ec2", "sdk_enum_name": "IpAddressType", "match_percentage": 1.0, "manual": true } } } ``` ### Description of how you validated changes Manual + unit testing ### 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*
1 parent a1226db commit 967ee9d

File tree

5 files changed

+164
-15
lines changed

5 files changed

+164
-15
lines changed

.github/workflows/enum-static-mapping-updater.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ jobs:
5252
git checkout -b "$branchName"
5353
5454
git add . # Add all files changed
55-
git commit -m "chore: update enum static mapping"
55+
git commit -m "chore(enum-updater): update enum static mapping"
5656
git push -f origin "$branchName"
5757
58-
gh pr create --title "chore: update enum static mapping" \
58+
gh pr create --title "chore(enum-updater): update enum static mapping" \
5959
--body "This PR updates the CDK enum mapping file." \
6060
--base main \
6161
--head "$branchName" \

tools/@aws-cdk/enum-updater/README.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# CDK Enum Updater
22

3-
This tool updates CDK enums with missing enum values on a weekly basis.
3+
This tool updates CDK enums with missing enum values on a weekly basis. It is triggered by the following two Github workflows:
4+
* [Update Enum Static Mapping](../../../.github/workflows/enum-static-mapping-updater.yml) - Runs every week on Monday 12am
5+
* [Update Missing Enum Values](../../../.github/workflows/enum-auto-updater.yml) - Runs every week on Monday 1pm
46

57
To run the tool locally, run the following commands to install dependencies and build:
68

@@ -101,4 +103,50 @@ All exclusions for a module should be listed together. For example if you want t
101103
}
102104
}
103105
}
106+
```
107+
108+
### Manual Static Mapping Overrides
109+
Sometimes the script will calculate the wrong static enum mapping. You can override this value by adding an entry to the `lib/manual-enum-mapping.json` file.
110+
111+
Manual mappings should be added in the form:
112+
```
113+
{
114+
"serviceName": {
115+
"CdkEnumName": {
116+
"cdk_path": "path/to/cdkEnum",
117+
"sdk_service": "serviceName",
118+
"sdk_enum_name": "AwsEnumThatWeWantThisToMapTo",
119+
"match_percentage": 1.0,
120+
}
121+
}
122+
}
123+
```
124+
125+
For example:
126+
```
127+
{
128+
"ec2": {
129+
"VpcEndpointIpAddressType": {
130+
"cdk_path": "aws-cdk/packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts",
131+
"sdk_service": "ec2",
132+
"sdk_enum_name": "IpAddressType",
133+
"match_percentage": 1.0,
134+
}
135+
}
136+
}
137+
```
138+
139+
The entry that is overwritten in the `lib/static-enum-mapping.json` file will contain a field `manual: true`:
140+
```
141+
{
142+
"ec2": {
143+
"VpcEndpointIpAddressType": {
144+
"cdk_path": "aws-cdk/packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts",
145+
"sdk_service": "ec2",
146+
"sdk_enum_name": "IpAddressType",
147+
"match_percentage": 1.0,
148+
"manual": true,
149+
}
150+
}
151+
}
104152
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"ec2": {
3+
"VpcEndpointIpAddressType": {
4+
"cdk_path": "aws-cdk/packages/aws-cdk-lib/aws-ec2/lib/vpc-endpoint.ts",
5+
"sdk_service": "ec2",
6+
"sdk_enum_name": "IpAddressType",
7+
"match_percentage": 1.0
8+
}
9+
}
10+
}

tools/@aws-cdk/enum-updater/lib/static-enum-mapping-updater.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import * as extract from 'extract-zip';
77
const ENUMS_URL = "https://raw.githubusercontent.com/aws/aws-cdk/main/packages/aws-cdk-lib/core/lib/analytics-data-source/enums/module-enums.json";
88
const ENUM_LIKE_CLASSES_URL = "https://raw.githubusercontent.com/aws/aws-cdk/main/packages/aws-cdk-lib/core/lib/analytics-data-source/enums/module-enumlikes.json";
99
const CFN_LINT_URL = "https://github.com/aws-cloudformation/cfn-lint/archive/refs/heads/main.zip"
10-
const MODULE_MAPPING = path.join(__dirname, "module-mapping.json");
11-
const STATIC_MAPPING_FILE_NAME = "static-enum-mapping.json";
10+
export const STATIC_MAPPING_FILE_NAME = "static-enum-mapping.json";
1211
const PARSED_CDK_ENUMS_FILE_NAME = "cdk-enums.json";
1312
const EXCLUDE_FILE = "exclude-values.json";
14-
export const PARSED_SDK_ENUMS_FILE_NAME = "sdk-enums.json";
13+
const MODULE_MAPPING = path.join(__dirname, "module-mapping.json");
14+
const PARSED_SDK_ENUMS_FILE_NAME = "sdk-enums.json";
15+
export const MANUAL_MAPPING_FILE_NAME = "manual-enum-mapping.json";
16+
export const MANUAL_MAPPING = path.join(__dirname, MANUAL_MAPPING_FILE_NAME);
1517
export const STATIC_MAPPING = path.join(__dirname, STATIC_MAPPING_FILE_NAME);
1618
export const CDK_ENUMS = path.join(__dirname, PARSED_CDK_ENUMS_FILE_NAME);
1719
export const SDK_ENUMS = path.join(__dirname, PARSED_SDK_ENUMS_FILE_NAME);
@@ -31,7 +33,6 @@ export interface SdkEnums {
3133
};
3234
}
3335

34-
3536
function extractEnums(schema: Record<string, any>, enums: { [enumName: string]: (string | number)[] }) {
3637
// Helper function to process a property and its potential enum values
3738
function processProperty(propertyName: string, property: any) {
@@ -85,6 +86,7 @@ export interface StaticMappingEntry {
8586
sdk_service: string;
8687
sdk_enum_name: string;
8788
match_percentage: number;
89+
manual?: boolean;
8890
}
8991

9092
export interface StaticMapping {
@@ -453,19 +455,22 @@ function isValidMatch(cdkValues: Set<string>, sdkValues: Set<string>): boolean {
453455
*
454456
* @param {CdkEnums} cdkEnums - The extracted CDK enums.
455457
* @param {SdkEnums} sdkEnums - The extracted AWS SDK enums.
456-
* @param {Record<string, string[]>} manualMappings - The manually defined service mappings.
458+
* @param {Record<string, string[]>} moduleMappings - The manually defined service mappings.
459+
* @param {StaticMapping} manualEnumMappings - Manually defined overrides for the static enum mappings.
457460
* @returns {Promise<void>}
458461
*/
459462
export async function generateAndSaveStaticMapping(
460463
cdkEnums: CdkEnums,
461464
sdkEnums: SdkEnums,
462-
manualMappings: Record<string, string[]>,
465+
moduleMappings: Record<string, string[]>,
466+
manualEnumMappings: StaticMapping
463467
): Promise<void> {
464468
const staticMapping: StaticMapping = {};
465469
const unmatchedEnums: UnmatchedEnums = {};
466470

471+
// Process CDK enums as before
467472
for (const [module, enums] of Object.entries(cdkEnums)) {
468-
if (!manualMappings[module]) {
473+
if (!moduleMappings[module]) {
469474
// Add to unmatched if no SDK mapping exists
470475
unmatchedEnums[module] = Object.fromEntries(
471476
Object.entries(enums).map(([enumName, enumData]) => [
@@ -476,9 +481,21 @@ export async function generateAndSaveStaticMapping(
476481
continue;
477482
}
478483

479-
const sdkServices = manualMappings[module];
484+
const sdkServices = moduleMappings[module];
480485

481486
for (const [enumName, enumData] of Object.entries(enums)) {
487+
// Check if we have a manual mapping for this enum
488+
if (manualEnumMappings && manualEnumMappings[module]?.[enumName]) {
489+
// Use the manual mapping
490+
if (!staticMapping[module]) {
491+
staticMapping[module] = {};
492+
}
493+
staticMapping[module][enumName] = manualEnumMappings[module][enumName];
494+
staticMapping[module][enumName]["manual"] = true;
495+
continue;
496+
}
497+
498+
// Otherwise, proceed with automatic mapping
482499
const match = findMatchingEnum(
483500
enumName,
484501
enumData.values,
@@ -519,7 +536,7 @@ export async function generateAndSaveStaticMapping(
519536
fs.writeFileSync(`lib/${STATIC_MAPPING_FILE_NAME}`, JSON.stringify(staticMapping, null, 2));
520537
fs.writeFileSync('lib/unmatched-enums.json', JSON.stringify(unmatchedEnums, null, 2));
521538

522-
console.log(`Total matched enums: ${Object.values(staticMapping).reduce((sum, moduleEnums) =>
539+
console.log(`Total matched enums: ${Object.values(staticMapping).reduce((sum, moduleEnums) =>
523540
sum + Object.keys(moduleEnums).length, 0)}`);
524541
}
525542

@@ -547,9 +564,10 @@ export async function entryMethod(): Promise<void> {
547564
const cdkEnums: CdkEnums = JSON.parse(fs.readFileSync(CDK_ENUMS, 'utf8'));
548565
const sdkEnums: SdkEnums = JSON.parse(fs.readFileSync(SDK_ENUMS, 'utf8'));
549566
const manualMappings: Record<string, string[]> = JSON.parse(fs.readFileSync(MODULE_MAPPING, 'utf8'));
567+
const manualEnumMappings = JSON.parse(fs.readFileSync(MANUAL_MAPPING, 'utf8'));
550568

551569
// Generate and save static mapping
552-
await generateAndSaveStaticMapping(cdkEnums, sdkEnums, manualMappings);
570+
await generateAndSaveStaticMapping(cdkEnums, sdkEnums, manualMappings, manualEnumMappings);
553571

554572
console.log("Static mapping and missing values analysis completed.");
555573

tools/@aws-cdk/enum-updater/test/static-enum-mapping-updater.test.ts

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import axios from 'axios';
22
import * as fs from 'fs';
33
import * as tmp from 'tmp';
4-
import {
4+
import {
55
normalizeValue,
66
normalizeEnumValues,
77
extractModuleName,
88
entryMethod,
99
generateAndSaveStaticMapping,
10-
findMatchingEnum
10+
findMatchingEnum,
1111
} from '../lib/static-enum-mapping-updater';
1212

1313
jest.mock('axios');
@@ -146,6 +146,7 @@ describe('Static Mapping Generation', () => {
146146
mockCdkEnums,
147147
mockSdkEnums,
148148
mockManualMappings,
149+
{}
149150
);
150151

151152
// Verify the file write operation
@@ -162,6 +163,7 @@ describe('Static Mapping Generation', () => {
162163
mockCdkEnums,
163164
mockSdkEnums,
164165
{},
166+
{}
165167
);
166168

167169
// Verify the file write operation
@@ -171,6 +173,77 @@ describe('Static Mapping Generation', () => {
171173

172174
expect(writtenContent.service1).toBeUndefined();
173175
});
176+
177+
178+
it('should prioritize manual mappings over automatic ones', async () => {
179+
// Setup test data
180+
const mockCdkEnums = {
181+
amplify: {
182+
ManualEnum: {
183+
path: "path/to/enum",
184+
enumLike: false,
185+
values: ['VALUE1', 'VALUE2']
186+
},
187+
AutoEnum: {
188+
path: "path/to/auto/enum",
189+
enumLike: false,
190+
values: ['AUTO1', 'AUTO2']
191+
}
192+
}
193+
};
194+
195+
const mockSdkEnums = {
196+
amplify: {
197+
SomeEnum: ['VALUE1', 'VALUE2', 'VALUE3'],
198+
AutoEnum: ['AUTO1', 'AUTO2', 'AUTO3']
199+
}
200+
};
201+
202+
const mockModuleMappings = {
203+
amplify: ['amplify']
204+
};
205+
206+
const testManualEnumMappings = {
207+
amplify: {
208+
ManualEnum: {
209+
cdk_path: "path/to/enum",
210+
sdk_service: "amplify",
211+
sdk_enum_name: "OverrideManualEnum",
212+
match_percentage: 1.0,
213+
}
214+
}
215+
};
216+
217+
// Execute the functionI
218+
await generateAndSaveStaticMapping(
219+
mockCdkEnums,
220+
mockSdkEnums,
221+
mockModuleMappings,
222+
testManualEnumMappings
223+
);
224+
225+
// Find the call that writes to static-enum-mapping.json
226+
const writeCall = (fs.writeFileSync as jest.Mock).mock.calls.find(
227+
call => String(call[0]).includes('static-enum-mapping.json')
228+
);
229+
expect(writeCall).toBeDefined();
230+
231+
const writtenContent = JSON.parse(writeCall[1]);
232+
233+
// Check that the manual mapping was used for ManualEnum
234+
expect(writtenContent.amplify.ManualEnum).toBeDefined();
235+
expect(writtenContent.amplify.ManualEnum.sdk_service).toBe('amplify');
236+
expect(writtenContent.amplify.ManualEnum.sdk_enum_name).toBe('OverrideManualEnum');
237+
expect(writtenContent.amplify.ManualEnum.cdk_path).toBe('path/to/enum');
238+
expect(writtenContent.amplify.ManualEnum.manual).toBe(true);
239+
240+
// Check that automatic mapping was used for AutoEnum
241+
expect(writtenContent.amplify.AutoEnum).toBeDefined();
242+
expect(writtenContent.amplify.AutoEnum.sdk_service).toBe('amplify');
243+
expect(writtenContent.amplify.AutoEnum.sdk_enum_name).toBe('AutoEnum');
244+
expect(writtenContent.amplify.AutoEnum.cdk_path).toBe('path/to/auto/enum');
245+
expect(writtenContent.amplify.AutoEnum.manual).toBeUndefined();
246+
});
174247
});
175248

176249

0 commit comments

Comments
 (0)