Skip to content

Commit

Permalink
feat: add prefixers for apigatewayv2 api and stage resources (#38)
Browse files Browse the repository at this point in the history
* add prefixers for apigatewayv2 api and stage resources

* feat: drop commit lint on commits

* update resource prefixers README to show where tests fixtures can be found

* Fix linting

Co-authored-by: MalcyL <[email protected]>
  • Loading branch information
maddocash and malcyL authored Feb 7, 2022
1 parent 9d7ba39 commit 4960f94
Show file tree
Hide file tree
Showing 15 changed files with 260 additions and 13 deletions.
8 changes: 0 additions & 8 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,6 @@ jobs:
- "ee:b4:00:e6:23:5b:55:bb:fd:07:bc:73:9e:f7:89:9c" # [email protected] 'talis-cdk-constructs Deploy Key'
- checkout
- node/install-packages
- run:
name: Define environment variable with lastest commit's message
command: |
echo 'export COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")' >> $BASH_ENV
source $BASH_ENV
- run:
name: Lint commit message
command: echo "$COMMIT_MESSAGE" | npx commitlint
- run:
name: Lint code before building, to lint only source files
command: npm run lint
Expand Down
4 changes: 4 additions & 0 deletions lib/aspects/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ const stack = new TalisCdkStack(app, "my-stack", props);
// I.e. a dynamodb table called 'archive' in the stack will now be named 'dev-xx-archive'
Aspects.of(stack).add(new ResourcePrefixer("dev-xx-"));
```

### Note

When adding new prefixers you can find an example input for the test fixture files in the CDK docs e.g. in the example shown here https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-apigatewayv2.CfnApi.html#example
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { CfnApi } from "@aws-cdk/aws-apigatewayv2";
import { IConstruct } from "@aws-cdk/core";
import { CfnResourcePrefixer } from "../cfn_resource_prefixer";

export class Apigatewayv2CfnApiPrefixer implements CfnResourcePrefixer {
private node: CfnApi;
private resourcePrefix: string;

constructor(node: IConstruct, resourcePrefix: string) {
if (!(node instanceof CfnApi)) {
throw new Error(
"Specified node is not an instance of CfnApi and cannot be prefixed using this prefixer"
);
}
this.node = node;
this.resourcePrefix = resourcePrefix;
}

public prefix(): void {
this.node.addPropertyOverride(
"Name",
`${this.resourcePrefix}${this.node.name}`
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { CfnStage } from "@aws-cdk/aws-apigatewayv2";
import { IConstruct } from "@aws-cdk/core";
import { CfnResourcePrefixer } from "../cfn_resource_prefixer";

export class Apigatewayv2CfnStagePrefixer implements CfnResourcePrefixer {
private node: CfnStage;
private resourcePrefix: string;

constructor(node: IConstruct, resourcePrefix: string) {
if (!(node instanceof CfnStage)) {
throw new Error(
"Specified node is not an instance of CfnStage and cannot be prefixed using this prefixer"
);
}
this.node = node;
this.resourcePrefix = resourcePrefix;
}

// eslint-disable-next-line @typescript-eslint/no-empty-function
public prefix(): void {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class DynamoDbCfnTablePrefixer implements CfnResourcePrefixer {
this.resourcePrefix = resourcePrefix;
}

public prefix() {
public prefix(): void {
this.node.addPropertyOverride(
"TableName",
`${this.resourcePrefix}${this.node.tableName}`
Expand Down
2 changes: 2 additions & 0 deletions lib/aspects/resource_prefixer/prefixers/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from "./apigatewayv2_cfn_api_prefixer";
export * from "./apigatewayv2_cfn_stage_prefixer";
export * from "./dynamodb_cfn_table_prefixer";
9 changes: 8 additions & 1 deletion lib/aspects/resource_prefixer/resource_prefixer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { CfnResource, IAspect, IConstruct } from "@aws-cdk/core";
import { DynamoDbCfnTablePrefixer } from "./prefixers/dynamodb_cfn_table_prefixer";
import {
Apigatewayv2CfnApiPrefixer,
Apigatewayv2CfnStagePrefixer,
DynamoDbCfnTablePrefixer,
} from "./prefixers";
import { CfnResourcePrefixer } from "./cfn_resource_prefixer";
import { CfnTable } from "@aws-cdk/aws-dynamodb";
import { CfnApi, CfnStage } from "@aws-cdk/aws-apigatewayv2";

export type Constructor<T> = { new (...args: any[]): T };

Expand All @@ -20,6 +25,8 @@ export class ResourcePrefixer implements IAspect {
>();

this.registerPrefixer(CfnTable, DynamoDbCfnTablePrefixer);
this.registerPrefixer(CfnApi, Apigatewayv2CfnApiPrefixer);
this.registerPrefixer(CfnStage, Apigatewayv2CfnStagePrefixer);
}

public visit(node: IConstruct): void {
Expand Down
33 changes: 33 additions & 0 deletions test/fixtures/infra/aws-apigatewayv2/cfn_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { CfnApiProps } from "@aws-cdk/aws-apigatewayv2";

export const CfnApiProperties: CfnApiProps = {
apiKeySelectionExpression: "apiKeySelectionExpression",
basePath: "basePath",
body: {},
bodyS3Location: {
bucket: "bucket",
etag: "etag",
key: "key",
version: "version",
},
corsConfiguration: {
allowCredentials: false,
allowHeaders: ["allowHeaders"],
allowMethods: ["allowMethods"],
allowOrigins: ["allowOrigins"],
exposeHeaders: ["exposeHeaders"],
maxAge: 123,
},
credentialsArn: "credentialsArn",
description: "description",
disableExecuteApiEndpoint: false,
disableSchemaValidation: false,
failOnWarnings: false,
name: "apiName",
protocolType: "protocolType",
routeKey: "routeKey",
routeSelectionExpression: "routeSelectionExpression",
tags: {},
target: "target",
version: "version",
};
27 changes: 27 additions & 0 deletions test/fixtures/infra/aws-apigatewayv2/cfn_stage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { CfnStageProps } from "@aws-cdk/aws-apigatewayv2";

export const CfnStageProperties: CfnStageProps = {
apiId: "apiId",
stageName: "stageName",

// the properties below are optional
accessLogSettings: {
destinationArn: "destinationArn",
format: "format",
},
accessPolicyId: "accessPolicyId",
autoDeploy: false,
clientCertificateId: "clientCertificateId",
defaultRouteSettings: {
dataTraceEnabled: false,
detailedMetricsEnabled: false,
loggingLevel: "loggingLevel",
throttlingBurstLimit: 123,
throttlingRateLimit: 123,
},
deploymentId: "deploymentId",
description: "description",
routeSettings: {},
stageVariables: {},
tags: {},
};
File renamed without changes.
14 changes: 14 additions & 0 deletions test/fixtures/infra/resource_prefixer_test_cases.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as dynamodb from "@aws-cdk/aws-dynamodb";
import * as apigatewayv2 from "@aws-cdk/aws-apigatewayv2";
import * as cdk from "@aws-cdk/core";
import { Constructor } from "../../../lib";

Expand All @@ -25,4 +26,17 @@ export const ResourcePrefixerTestCases: Array<ResourcePrefixerTestCase> = [
TableName: "test-prefix-tableName",
},
},
{
resourceType: apigatewayv2.HttpApi,
resourceProps: {
apiName: "api-name",
},
expectedType: "AWS::ApiGatewayV2::Api",
expectedPropsUnprefixed: {
Name: "api-name",
},
expectedPropsPrefixed: {
Name: "test-prefix-api-name",
},
},
];
62 changes: 62 additions & 0 deletions test/infra/aspects/prefixers/apigatewayv2_cfn_api_prefixer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as apigatewayv2 from "@aws-cdk/aws-apigatewayv2";
import * as cdk from "@aws-cdk/core";

import { expect as expectCDK, haveResource } from "@aws-cdk/assert";
import { Apigatewayv2CfnApiPrefixer } from "../../../../lib";
import { CfnApiProperties } from "../../../fixtures/infra/aws-apigatewayv2/cfn_api";
import { EmptyResource } from "../../../fixtures/infra/empty_resource";

describe("Apigatewayv2 CfnApi Prefixer", () => {
let app: cdk.App;
let stack: cdk.Stack;
let cfnApi: apigatewayv2.CfnApi;
let prefixer: Apigatewayv2CfnApiPrefixer;
let emptyPrefixer: Apigatewayv2CfnApiPrefixer;

beforeEach(() => {
app = new cdk.App();
stack = new cdk.Stack(app, "AspectTestStack", {});
cfnApi = new apigatewayv2.CfnApi(stack, "api1", CfnApiProperties);
prefixer = new Apigatewayv2CfnApiPrefixer(cfnApi, "test-prefix-");
emptyPrefixer = new Apigatewayv2CfnApiPrefixer(cfnApi, "");
});

describe("Empty Prefix", () => {
test("Keeps api name the same", () => {
emptyPrefixer.prefix();

expectCDK(stack).to(
haveResource("AWS::ApiGatewayV2::Api", {
Name: "apiName",
})
);
});
});

describe("With Prefix", () => {
test("Adds prefix to the start of the api name", () => {
prefixer.prefix();

expectCDK(stack).to(
haveResource("AWS::ApiGatewayV2::Api", {
Name: "test-prefix-apiName",
})
);
});
test.todo("Truncates the api name if too long");
});

describe("Undefined Resource", () => {
test("Raises error if no prefixer defined for resource", () => {
const unknownResource = new EmptyResource(stack, "empty", {
type: "EmptyResource",
});

expect(() => {
new Apigatewayv2CfnApiPrefixer(unknownResource, "prefix");
}).toThrowError(
"Specified node is not an instance of CfnApi and cannot be prefixed using this prefixer"
);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as apigatewayv2 from "@aws-cdk/aws-apigatewayv2";
import * as cdk from "@aws-cdk/core";

import { expect as expectCDK, haveResource } from "@aws-cdk/assert";
import { Apigatewayv2CfnStagePrefixer } from "../../../../lib";
import { CfnStageProperties } from "../../../fixtures/infra/aws-apigatewayv2/cfn_stage";
import { EmptyResource } from "../../../fixtures/infra/empty_resource";

describe("Apigatewayv2 CfnStage Prefixer", () => {
let app: cdk.App;
let stack: cdk.Stack;
let cfnStage: apigatewayv2.CfnStage;
let prefixer: Apigatewayv2CfnStagePrefixer;
let emptyPrefixer: Apigatewayv2CfnStagePrefixer;

beforeEach(() => {
app = new cdk.App();
stack = new cdk.Stack(app, "AspectTestStack", {});
cfnStage = new apigatewayv2.CfnStage(stack, "api1", CfnStageProperties);
prefixer = new Apigatewayv2CfnStagePrefixer(cfnStage, "test-prefix-");
emptyPrefixer = new Apigatewayv2CfnStagePrefixer(cfnStage, "");
});

describe("Empty Prefix", () => {
test("Keeps api name the same", () => {
emptyPrefixer.prefix();

expectCDK(stack).to(
haveResource("AWS::ApiGatewayV2::Stage", {
StageName: "stageName",
})
);
});
});

describe("With Prefix", () => {
test("Keeps api stage name the same", () => {
prefixer.prefix();

expectCDK(stack).to(
haveResource("AWS::ApiGatewayV2::Stage", {
StageName: "stageName",
})
);
});
test.todo("Truncates the api name if too long");
});

describe("Undefined Resource", () => {
test("Raises error if no prefixer defined for resource", () => {
const unknownResource = new EmptyResource(stack, "empty", {
type: "EmptyResource",
});

expect(() => {
new Apigatewayv2CfnStagePrefixer(unknownResource, "prefix");
}).toThrowError(
"Specified node is not an instance of CfnStage and cannot be prefixed using this prefixer"
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as cdk from "@aws-cdk/core";

import { expect as expectCDK, haveResource } from "@aws-cdk/assert";
import { DynamoDbCfnTablePrefixer } from "../../../../lib";
import { CfnTableProperties } from "../../../fixtures/infra/cfn_table";
import { CfnTableProperties } from "../../../fixtures/infra/aws-dynamodb/cfn_table";
import { EmptyResource } from "../../../fixtures/infra/empty_resource";

describe("DynamoDB CfnTable Prefixer", () => {
Expand Down
2 changes: 0 additions & 2 deletions test/infra/aspects/resource_prefixer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ describe("Resource Prefixer", () => {
resourceProps,
expectedType,
expectedPropsUnprefixed,
expectedPropsPrefixed,
}) => {
new resourceType(stack, "test-item", resourceProps);
Aspects.of(stack).add(emptyResourcePrefixer);
Expand All @@ -46,7 +45,6 @@ describe("Resource Prefixer", () => {
resourceType,
resourceProps,
expectedType,
expectedPropsUnprefixed,
expectedPropsPrefixed,
}) => {
new resourceType(stack, "test-item", resourceProps);
Expand Down

0 comments on commit 4960f94

Please sign in to comment.