Skip to content

Commit

Permalink
refactor: reorganize and document feature flags (#22771)
Browse files Browse the repository at this point in the history
Require feature flag information to be more structured, and generate a Markdown report automatically that people can refer to if they need to review their feature flag setup.

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
rix0rrr committed Nov 4, 2022
1 parent 1ae800c commit dfcfb8d
Show file tree
Hide file tree
Showing 40 changed files with 1,242 additions and 481 deletions.
21 changes: 15 additions & 6 deletions CONTRIBUTING.md
Expand Up @@ -953,9 +953,17 @@ changes are only allowed in major versions and those are rare.
To address this need, we have a feature flags pattern/mechanism. It allows us to
introduce new breaking behavior which is disabled by default (so existing
projects will not be affected) but enabled automatically for new projects
created through `cdk init`.
created through `cdk init`. Existing users can selectively opt in to new
behavior on their own schedule.

The pattern is simple:
Whenever a change leads to CloudFormation template differences that cause any of
the following during an update, it is not safe to apply the new behavior
automatically, and we have to use a feature flag:

- Resources replacement leading to service disruption; or
- Users could have taken assumptions on the old setup and the change will break them.

Adding a new flag looks as follows:

1. Define a new const under
[cx-api/lib/features.ts](https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/cx-api/lib/features.ts)
Expand All @@ -964,10 +972,11 @@ The pattern is simple:
form `module.Type:feature` (e.g. `@aws-cdk/core:enableStackNameDuplicates`).
2. Use `FeatureFlags.of(construct).isEnabled(cxapi.ENABLE_XXX)` to check if this feature is enabled
in your code. If it is not defined, revert to the legacy behavior.
3. Add your feature flag to the `FUTURE_FLAGS` map in
[cx-api/lib/features.ts](https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/cx-api/lib/features.ts).
This map is inserted to generated `cdk.json` files for new projects created
through `cdk init`.
3. Add your feature flag to the `FLAGS` map in
[cx-api/lib/features.ts](https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/cx-api/lib/features.ts). In
your description, be sure to cover the following:
- Consciously pick the type of feature flag. Can the flag be removed in a future major version, or not?
- Motivate why the feature flag exists. What is the change to existing infrastructure and why is it not safe?
4. Add an entry for your feature flag in the [README](https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/cx-api/README.md) file.
5. In your tests, ensure that you test your feature with and without the feature flag enabled. You can do this by passing the feature flag to the `context` property when instantiating an `App`.
```ts
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/assert-internal/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"target":"es2018",
"lib": ["es2016", "es2017.object", "es2017.string"],
"target":"es2020",
"lib": ["es2020"],
"module": "commonjs",
"composite": true,
"declaration": true,
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/assert/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"target":"ES2018",
"lib": ["es2018"],
"target":"ES2020",
"lib": ["es2020"],
"module": "CommonJS",
"declaration": true,
"strict": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/cfnspec/tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target":"ES2018",
"target":"ES2020",
"module": "commonjs",
"lib": ["es2016", "es2017.object", "es2017.string"],
"declaration": true,
Expand Down
8 changes: 7 additions & 1 deletion packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts
Expand Up @@ -181,7 +181,13 @@ export class Manifest {
}

private static loadManifest(filePath: string, schema: jsonschema.Schema, preprocess?: (obj: any) => any, options?: LoadManifestOptions) {
let obj = JSON.parse(fs.readFileSync(filePath, { encoding: 'utf-8' }));
const contents = fs.readFileSync(filePath, { encoding: 'utf-8' });
let obj;
try {
obj = JSON.parse(contents);
} catch (e) {
throw new Error(`${e.message}, while parsing ${JSON.stringify(contents)}`);
}
if (preprocess) {
obj = preprocess(obj);
}
Expand Down
4 changes: 2 additions & 2 deletions packages/@aws-cdk/cloudformation-diff/tsconfig.json
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"target":"ES2018",
"target":"ES2020",
"module": "commonjs",
"lib": ["es2016", "es2017.object", "es2017.string"],
"lib": ["es2020"],
"declaration": true,
"composite": true,
"strict": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/core/lib/feature-flags.ts
Expand Up @@ -25,7 +25,7 @@ export class FeatureFlags {
*/
public isEnabled(featureFlag: string): boolean | undefined {
const context = Node.of(this.construct).tryGetContext(featureFlag);
if (cxapi.FUTURE_FLAGS_EXPIRED.includes(featureFlag)) {
if (cxapi.CURRENT_VERSION_EXPIRED_FLAGS.includes(featureFlag)) {
if (context !== undefined) {
throw new Error(`Unsupported feature flag '${featureFlag}'. This flag existed on CDKv1 but has been removed in CDKv2.`
+ ' CDK will now behave as the same as when the flag is enabled.');
Expand Down

0 comments on commit dfcfb8d

Please sign in to comment.