From 6a5b1b98f0fdfd21752d175a8f399de802693617 Mon Sep 17 00:00:00 2001 From: dzchen22 Date: Wed, 12 Nov 2025 20:38:14 +0000 Subject: [PATCH 1/2] feat(appconfig): add typeAsString escape hatch for custom configuration types --- .../integ.configuration-type-as-string.ts | 33 ++++++++++++ .../aws-appconfig/lib/configuration.ts | 32 +++++++++++- .../aws-appconfig/test/configuration.test.ts | 52 +++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-appconfig/test/integ.configuration-type-as-string.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-appconfig/test/integ.configuration-type-as-string.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-appconfig/test/integ.configuration-type-as-string.ts new file mode 100644 index 0000000000000..c8cb1efcf517e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-appconfig/test/integ.configuration-type-as-string.ts @@ -0,0 +1,33 @@ +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; +import { App, Stack } from 'aws-cdk-lib'; +import { + Application, + ConfigurationContent, + HostedConfiguration, +} from 'aws-cdk-lib/aws-appconfig'; + +const app = new App(); +const stack = new Stack(app, 'aws-appconfig-configuration-type-as-string'); + +const appConfigApp = new Application(stack, 'MyAppConfig', { + applicationName: 'AppForTypeAsStringTest', +}); + +// Test typeAsString with existing enum value +new HostedConfiguration(stack, 'MyConfigWithTypeAsString', { + application: appConfigApp, + name: 'TestConfigWithTypeAsString', + typeAsString: 'AWS.AppConfig.FeatureFlags', + content: ConfigurationContent.fromInlineText('This is my configuration content.'), +}); + +new IntegTest(app, 'appconfig-configuration-type-as-string', { + testCases: [stack], + cdkCommandOptions: { + destroy: { + args: { + force: true, + }, + }, + }, +}); diff --git a/packages/aws-cdk-lib/aws-appconfig/lib/configuration.ts b/packages/aws-cdk-lib/aws-appconfig/lib/configuration.ts index 38ff271162d9a..4f79ee34d3e5e 100644 --- a/packages/aws-cdk-lib/aws-appconfig/lib/configuration.ts +++ b/packages/aws-cdk-lib/aws-appconfig/lib/configuration.ts @@ -58,6 +58,16 @@ export interface ConfigurationOptions { */ readonly type?: ConfigurationType; + /** + * The type of configuration as a string. Use this to specify custom configuration types + * that are not available in the ConfigurationType enum. + * + * This property takes precedence over the 'type' property if both are specified. + * + * @default - Uses the 'type' property value + */ + readonly typeAsString?: string; + /** * The list of environments to deploy the configuration to. * @@ -136,6 +146,11 @@ export interface IConfiguration extends IConstruct { */ readonly type?: ConfigurationType; + /** + * The configuration type as a string. + */ + readonly typeAsString?: string; + /** * The environments to deploy to. */ @@ -186,6 +201,11 @@ abstract class ConfigurationBase extends Construct implements IConfiguration, IE */ public readonly type?: ConfigurationType; + /** + * The configuration type as a string. + */ + public readonly typeAsString?: string; + /** * The deployment key for the configuration. */ @@ -210,6 +230,7 @@ abstract class ConfigurationBase extends Construct implements IConfiguration, IE this.application = props.application; this.applicationId = this.application.applicationId; this.type = props.type; + this.typeAsString = props.typeAsString; this.validators = props.validators; this.description = props.description; this.deployTo = props.deployTo; @@ -349,6 +370,13 @@ abstract class ConfigurationBase extends Construct implements IConfiguration, IE environment.addDeployment(this); }); } + + /** + * Gets the effective configuration type, with typeAsString taking precedence over type. + */ + protected effectiveType(): string | undefined { + return this.typeAsString || this.type; + } } /** @@ -469,7 +497,7 @@ export class HostedConfiguration extends ConfigurationBase { locationUri: 'hosted', name: this.name!, description: this.description, - type: this.type, + type: this.effectiveType(), validators: this.validators, deletionProtectionCheck: this.deletionProtectionCheck, kmsKeyIdentifier: props.kmsKey?.keyRef.keyArn, @@ -609,7 +637,7 @@ export class SourcedConfiguration extends ConfigurationBase { name: this.name!, description: this.description, retrievalRoleArn: this.retrievalRole?.roleArn, - type: this.type, + type: this.effectiveType(), validators: this.validators, deletionProtectionCheck: this.deletionProtectionCheck, }); diff --git a/packages/aws-cdk-lib/aws-appconfig/test/configuration.test.ts b/packages/aws-cdk-lib/aws-appconfig/test/configuration.test.ts index c5fc7ab8c35a6..8419bb983b10f 100644 --- a/packages/aws-cdk-lib/aws-appconfig/test/configuration.test.ts +++ b/packages/aws-cdk-lib/aws-appconfig/test/configuration.test.ts @@ -705,6 +705,58 @@ describe('configuration', () => { Template.fromStack(stack).resourceCountIs('AWS::AppConfig::Deployment', 0); }); + test('configuration profile with typeAsString feature flags', () => { + const stack = new cdk.Stack(); + const app = new Application(stack, 'MyAppConfig'); + new HostedConfiguration(stack, 'MyConfigurationProfile', { + name: 'TestConfigProfile', + application: app, + typeAsString: 'AWS.AppConfig.FeatureFlags', + content: ConfigurationContent.fromInlineText('This is my content'), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ConfigurationProfile', { + Name: 'TestConfigProfile', + Type: 'AWS.AppConfig.FeatureFlags', + LocationUri: 'hosted', + }); + }); + + test('configuration profile with typeAsString freeform', () => { + const stack = new cdk.Stack(); + const app = new Application(stack, 'MyAppConfig'); + new HostedConfiguration(stack, 'MyConfigurationProfile', { + name: 'TestConfigProfile', + application: app, + typeAsString: 'AWS.Freeform', + content: ConfigurationContent.fromInlineText('This is my content'), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ConfigurationProfile', { + Name: 'TestConfigProfile', + Type: 'AWS.Freeform', + LocationUri: 'hosted', + }); + }); + + test('configuration profile typeAsString takes precedence over type', () => { + const stack = new cdk.Stack(); + const app = new Application(stack, 'MyAppConfig'); + new HostedConfiguration(stack, 'MyConfigurationProfile', { + name: 'TestConfigProfile', + application: app, + type: ConfigurationType.FEATURE_FLAGS, + typeAsString: 'AWS.Freeform', + content: ConfigurationContent.fromInlineText('This is my content'), + }); + + Template.fromStack(stack).hasResourceProperties('AWS::AppConfig::ConfigurationProfile', { + Name: 'TestConfigProfile', + Type: 'AWS.Freeform', + LocationUri: 'hosted', + }); + }); + test('configuration profile with description', () => { const stack = new cdk.Stack(); const app = new Application(stack, 'MyAppConfig'); From fc46aad2e41fe17757c55a88ca386149e85430c9 Mon Sep 17 00:00:00 2001 From: dzchen22 Date: Thu, 13 Nov 2025 18:11:06 +0000 Subject: [PATCH 2/2] remove unwanted integration test file --- .../integ.configuration-type-as-string.ts | 33 ------------------- 1 file changed, 33 deletions(-) delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-appconfig/test/integ.configuration-type-as-string.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-appconfig/test/integ.configuration-type-as-string.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-appconfig/test/integ.configuration-type-as-string.ts deleted file mode 100644 index c8cb1efcf517e..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-appconfig/test/integ.configuration-type-as-string.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { IntegTest } from '@aws-cdk/integ-tests-alpha'; -import { App, Stack } from 'aws-cdk-lib'; -import { - Application, - ConfigurationContent, - HostedConfiguration, -} from 'aws-cdk-lib/aws-appconfig'; - -const app = new App(); -const stack = new Stack(app, 'aws-appconfig-configuration-type-as-string'); - -const appConfigApp = new Application(stack, 'MyAppConfig', { - applicationName: 'AppForTypeAsStringTest', -}); - -// Test typeAsString with existing enum value -new HostedConfiguration(stack, 'MyConfigWithTypeAsString', { - application: appConfigApp, - name: 'TestConfigWithTypeAsString', - typeAsString: 'AWS.AppConfig.FeatureFlags', - content: ConfigurationContent.fromInlineText('This is my configuration content.'), -}); - -new IntegTest(app, 'appconfig-configuration-type-as-string', { - testCases: [stack], - cdkCommandOptions: { - destroy: { - args: { - force: true, - }, - }, - }, -});