Skip to content

Commit 6192a19

Browse files
segfault79Matthias SefrinJefiozie
authored
feat: simple implementation to trigger an optional AWS CloudFront invalidation after files have been uploaded to AWS S3. (#393)
Resolves: #392 Co-authored-by: Matthias Sefrin <[email protected]> Co-authored-by: Jeffrey Bosch <[email protected]>
1 parent 96e6f7b commit 6192a19

File tree

10 files changed

+115
-6
lines changed

10 files changed

+115
-6
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,20 @@
4949
"options": {}
5050
}
5151
```
52+
5253
5. Due to security risk we have made the decision to never add any options to the `angular.json`. You should set the environments variable during the `ng deploy` command. Below is an example on how you could do this.
5354

5455
```bash
5556
npx cross-env NG_DEPLOY_AWS_ACCESS_KEY_ID=1234 NG_DEPLOY_AWS_SECRET_ACCESS_KEY=321ACCESS NG_DEPLOY_AWS_BUCKET=mys3bucket NG_DEPLOY_AWS_REGION=eu-1-region NG_DEPLOY_AWS_SUB_FOLDER=path/on/bucker ng deploy
5657
```
5758

58-
6. Run `ng deploy` to deploy your application to Amazon S3.
59+
6. To trigger an optional invalidation of the files in an AWS CloudFront distribution, add these parameters to the above command line:
60+
61+
```
62+
npx cross-env ... NG_DEPLOY_AWS_CF_DISTRIBUTION_ID=1234 ... ng deploy
63+
```
64+
65+
7. Run `ng deploy` to deploy your application to Amazon S3.
5966

6067
🚀**_Happy deploying!_** 🚀
6168

libs/ngx-aws-deploy/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@jefiozie/ngx-aws-deploy",
33
"version": "4.0.0",
4-
"description": "Deploy rou Angular app to Amazon S3 directly from the Angular CLI",
4+
"description": "Deploy an Angular app to Amazon S3 directly from the Angular CLI",
55
"main": "index.js",
66
"builders": "./builders.json",
77
"schematics": "./collection.json",
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { BuilderContext } from '@angular-devkit/architect';
2+
import * as AWS from 'aws-sdk';
3+
import { CreateInvalidationRequest } from 'aws-sdk/clients/cloudfront';
4+
import { Schema } from './schema';
5+
import {
6+
getAccessKeyId,
7+
getSecretAccessKey,
8+
getRegion,
9+
getSubFolder,
10+
getCfDistributionId
11+
} from './config';
12+
13+
export class CloudFront {
14+
private _builderConfig: Schema;
15+
private _context: BuilderContext;
16+
17+
private _cloudFront: AWS.CloudFront;
18+
19+
private _cfDistributionId: string;
20+
private _subFolder: string;
21+
private _region: string;
22+
23+
constructor(context: BuilderContext, builderConfig: Schema) {
24+
this._context = context;
25+
this._builderConfig = builderConfig;
26+
27+
this._region = getRegion(this._builderConfig);
28+
this._cfDistributionId = getCfDistributionId(this._builderConfig);
29+
this._subFolder = getSubFolder(this._builderConfig);
30+
31+
AWS.config.update({ region: this._region });
32+
this._cloudFront = new AWS.CloudFront({
33+
apiVersion: 'latest',
34+
secretAccessKey: getSecretAccessKey(),
35+
accessKeyId: getAccessKeyId()
36+
});
37+
}
38+
39+
public async invalidate(): Promise<boolean> {
40+
if (!this._cfDistributionId) {
41+
this._context.logger.info('⚠️ Skipping invalidation of CloudFront distribution');
42+
return true;
43+
}
44+
45+
const cf_path = this._subFolder ? `/${this._subFolder}/*` : '/*';
46+
const reference = `ngx-aws-deploy-${new Date().getTime()}`;
47+
48+
const params : CreateInvalidationRequest = {
49+
DistributionId: this._cfDistributionId,
50+
InvalidationBatch: {
51+
CallerReference: reference,
52+
Paths: {
53+
Quantity: 1,
54+
Items: [
55+
cf_path
56+
]
57+
}
58+
}
59+
};
60+
61+
this._context.logger.info(`Triggering invalidation of '${cf_path}' from CloudFront distribution ${this._cfDistributionId}`);
62+
63+
await this._cloudFront
64+
.createInvalidation(params)
65+
.promise()
66+
.then((data) => {
67+
this._context.logger.info(`Successfully triggered invalidation of '${cf_path}' from CloudFront distribution ${this._cfDistributionId}: current status is '${data.Invalidation.Status}'`);
68+
})
69+
.catch((error) => {
70+
this._context.logger.error(`❌ The following error was found during CloudFront invalidation ${error}`);
71+
throw error;
72+
});
73+
74+
return true;
75+
}
76+
}

libs/ngx-aws-deploy/src/lib/deploy/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@ export const getRegion = (builderConfig: Schema): string => {
1919
export const getSubFolder = (builderConfig: Schema): string => {
2020
return process.env.NG_DEPLOY_AWS_SUB_FOLDER || (builderConfig.subFolder as string);
2121
};
22+
23+
export const getCfDistributionId = (builderConfig: Schema): string => {
24+
return process.env.NG_DEPLOY_AWS_CF_DISTRIBUTION_ID || (builderConfig.cfDistributionId as string);
25+
};

libs/ngx-aws-deploy/src/lib/deploy/index.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
} from '@angular-devkit/architect';
77
import * as glob from 'glob';
88
import { getAccessKeyId, getSecretAccessKey } from './config';
9+
import { CloudFront } from './cloudfront';
910
import { Schema } from './schema';
1011
import { Uploader } from './uploader';
1112

@@ -95,14 +96,28 @@ export default createBuilder(
9596
const success = await uploader.upload(files, filesPath);
9697
if (success) {
9798
context.logger.info('✔ Finished uploading files...');
98-
return { success: true };
99+
100+
context.logger.info('Start CloudFront invalidation...');
101+
const cloudFront = new CloudFront(context, deployConfig);
102+
const success = await cloudFront.invalidate();
103+
if (success) {
104+
context.logger.info('✔ Finished CloudFront invalidation...');
105+
return { success: true };
106+
} else {
107+
context.logger.error(`❌ Error during CloudFront invalidation`);
108+
return {
109+
error: `❌ Error during CloudFront invalidation`,
110+
success: false,
111+
};
112+
}
99113
} else {
100114
return {
101115
error: `❌ Error during files upload`,
102116
success: false,
103117
};
104118
}
105119
} else {
120+
context.logger.error(`❌ Missing authentication settings for AWS`);
106121
return {
107122
error: `❌ Missing authentication settings for AWS`,
108123
success: false,

libs/ngx-aws-deploy/src/lib/deploy/schema.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export interface Schema {
88
region?: string;
99
bucket?: string;
1010
subFolder?: string;
11+
cfDistributionId?: string;
1112
}

libs/ngx-aws-deploy/src/lib/deploy/schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
"type": "string",
4343
"description": "Subfolder from AWS bucket."
4444
},
45+
"cfDistributionId": {
46+
"type": "string",
47+
"description": "Optional AWS CloudFront distribution id to create an invalidation."
48+
},
4549
"buildTarget": {
4650
"type": "string",
4751
"description": "A named build target, as specified in the `configurations` section of angular.json . Each named target is accompanied by a configuration of option defaults for that target. This is equivalent as calling the command `ng build --configuration=XXX`."

libs/ngx-aws-deploy/src/lib/deploy/uploader.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export class Uploader {
3939
try {
4040
if (!this._region || !this._bucket) {
4141
this._context.logger.error(
42-
`❌ Looks like you are missing some configuration`
42+
`❌ Looks like you are missing some upload configuration (need region, bucket)`
4343
);
4444
return false;
4545
}

libs/ngx-aws-deploy/src/lib/ng-add/schema.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export interface Schema {
33
region?: string;
44
bucket?: string;
55
subFolder?: string;
6-
}
6+
cfDistributionId?: string;
7+
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"help": "nx help",
2828
"symlinks": "npx symlink-dir ./dist/libs ./node_modules/@jefiozie",
2929
"workspace-generator": "nx workspace-generator",
30-
"generate:changelog": "npx standard-version"
30+
"generate:changelog": "npx standard-version",
31+
"deploy": "nx deploy"
3132
},
3233
"private": true,
3334
"dependencies": {

0 commit comments

Comments
 (0)