DEV Community

hayao-k for AWS Community Builders

Posted on • Updated on

A Beginner's Guide to Create AWS CDK Construct Library with projen

Introduction

AWS CDK allows you to create your own Construct Library and publish it to npm or PyPI.

Using projen makes the development of Construct Library very comfortable.

The content of this article has been tested with the following versions

  • projen: v0.34.12
  • AWS CDK: v1.133.0

What is the projen?

projen is a tool for defining and managing increasingly complex project configurations in code.

https://github.com/projen/projen

With projen, you no longer need to manage files such as package.json by yourself.

projen does not only generate various files during project creation but also continuously updates and maintains these settings.

You can easily start a new project using the pre-defined project types.
As of November 2021, the following project types are supported.

Commands:
  projen new awscdk-app-java   AWS CDK app in Java.
  projen new awscdk-app-ts     AWS CDK app in TypeScript.
  projen new awscdk-construct  AWS CDK construct library project.
  projen new cdk8s-app-ts      CDK8s app in TypeScript.
  projen new cdk8s-construct   CDK8s construct library project.
  projen new cdktf-construct   CDKTF construct library project.
  projen new java              Java project.
  projen new jsii              Multi-language jsii library project.
  projen new nextjs            Next.js project without TypeScript.
  projen new nextjs-ts         Next.js project with TypeScript.
  projen new node              Node.js project.
  projen new project           Base project.
  projen new python            Python project.
  projen new react             React project without TypeScript.
  projen new react-ts          React project with TypeScript.
  projen new typescript        TypeScript project.
  projen new typescript-app    TypeScript app.
Enter fullscreen mode Exit fullscreen mode

awscdk-construct creates an environment for building Contruct using jsii.
jsii allows you to generate libraries from TypeScript code to work in Python, Java, and .NET.

Create project

Create a Construct Library project with projen new awscdk-construct.

$ mkdir cdk-sample-lib && cd cdk-sample-lib

$ npx projen new awscdk-construct
πŸ‘Ύ Project definition file was created at /home/xxxx/cdk-sample-lib/.projenrc.js
yarn install v1.22.17
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 51.58s.

> cdk-sample-lib@0.0.0 eslint
> npx projen eslint

Initialized empty Git repository in /home/xxxx/cdk-sample-lib/.git/
[master (root-commit) 6e585e1] chore: project created with projen
 Committer: EC2 Default User <ec2-user@ip-172-31-12-138.ap-northeast-1.compute.internal>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 21 files changed, 7934 insertions(+)
 create mode 100644 .eslintrc.json
 create mode 100644 .gitattributes
 create mode 100644 .github/pull_request_template.md
 create mode 100644 .github/workflows/build.yml
 create mode 100644 .github/workflows/pull-request-lint.yml
 create mode 100644 .github/workflows/release.yml
 create mode 100644 .github/workflows/stale.yml
 create mode 100644 .github/workflows/upgrade-main.yml
 create mode 100644 .gitignore
 create mode 100644 .mergify.yml
 create mode 100644 .npmignore
 create mode 100644 .projen/deps.json
 create mode 100644 .projen/tasks.json
 create mode 100644 .projenrc.js
 create mode 100644 LICENSE
 create mode 100644 README.md
 create mode 100644 package.json
 create mode 100644 src/index.ts
 create mode 100644 test/hello.test.ts
 create mode 100644 tsconfig.dev.json
 create mode 100644 yarn.lock
Enter fullscreen mode Exit fullscreen mode

Under the project directory, .projenrc.js has been created.

const { AwsCdkConstructLibrary } = require('projen');
const project = new AwsCdkConstructLibrary({
  author: 'user',
  authorAddress: 'user@domain.com',
  cdkVersion: '1.129.0',
  defaultReleaseBranch: 'main',
  name: 'cdk-sample-lib',
  repositoryUrl: 'https://github.com/user/cdk-sample-lib.git',

  // cdkDependencies: undefined,      /* Which AWS CDK modules (those that start with "@aws-cdk/") does this library require when consumed? */
  // cdkTestDependencies: undefined,  /* AWS CDK modules required for testing. */
  // deps: [],                        /* Runtime dependencies of this module. */
  // description: undefined,          /* The description is just a string that helps people understand the purpose of the package. */
  // devDeps: [],                     /* Build dependencies for this module. */
  // packageName: undefined,          /* The "name" in package.json. */
  // release: undefined,              /* Add release management to this project. */
});
project.synth();
Enter fullscreen mode Exit fullscreen mode

You can add dependencies on AWS CDKs and other modules to be used.

  cdkDependencies: [
    '@aws-cdk/core',
    '@aws-cdk/aws-apigatewayv2',
    '@aws-cdk/aws-apigatewayv2-integrations',
    '@aws-cdk/aws-lambda'
  ],
  deps: [ 
    'super-useful-lib' 
  ]
Enter fullscreen mode Exit fullscreen mode

If you want to cross-compile to languages other than TypeScript with jsii, add the target language.

  python: {
    distName: 'cdk-sample-lib',
    module: 'cdk_sample_lib',
  },
Enter fullscreen mode Exit fullscreen mode

See API.md for other available options.
As an example, the modified file looks like this

const { AwsCdkConstructLibrary } = require('projen');

const PROJECT_NAME = "cdk-sample-lib" 

const project = new AwsCdkConstructLibrary({
  authorAddress: "hayaok333@gmail.com",
  authorName: "hayao-k",
  cdkVersion: "1.333.0",
  name: PROJECT_NAME,
  repository: "https://github.com/hayao-k/cdk-sample-lib.git",
  defaultReleaseBranch: 'main',
  cdkDependencies: [ 
    '@aws-cdk/core',
    '@aws-cdk/aws-apigatewayv2',
    '@aws-cdk/aws-apigatewayv2-integrations',
    '@aws-cdk/aws-lambda'
  ],
  python: {
    distName: PROJECT_NAME,
    module: 'cdk_sample_lib',
  },
});

project.synth();
Enter fullscreen mode Exit fullscreen mode

Once you have edited .projenrc.js, run the projen command to reflect the changes (yarn is required).

$ npx projen
πŸ‘Ύ default | node .projenrc.js
yarn install v1.22.17
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 22.33s.
Enter fullscreen mode Exit fullscreen mode

You will see that projen automatically generates the package.json, the .gitignore, .npmignore, eslint, jsii configuration, license files, etc., as well as the creation and installation of the package.json.

You no longer have to copy from an existing project every time you create a new project.

Whenever you edit these files, you need to modify the .projenrc.js file and re-run the projen command.
If you edit them manually, the build will fail.

$ tree -L 1 -a
.
β”œβ”€β”€ .eslintrc.json
β”œβ”€β”€ .git
β”œβ”€β”€ .gitattributes
β”œβ”€β”€ .github
β”œβ”€β”€ .gitignore
β”œβ”€β”€ LICENSE
β”œβ”€β”€ .mergify.yml
β”œβ”€β”€ node_modules
β”œβ”€β”€ .npmignore
β”œβ”€β”€ package.json
β”œβ”€β”€ .projen
β”œβ”€β”€ .projenrc.js
β”œβ”€β”€ README.md
β”œβ”€β”€ src
β”œβ”€β”€ test
β”œβ”€β”€ tsconfig.dev.json
└── yarn.lock
Enter fullscreen mode Exit fullscreen mode

Development

Let's try a simple example of calling Hello World's Lambda from the API Gateway (HTTP API).
Please note that the HTTP API L2 Constructs has an Experimental status as of November 2020.

The following directory has already been created by projen.

.
β”œβ”€β”€ lib/ 
β”œβ”€β”€ src/
β”œβ”€β”€ test/
Enter fullscreen mode Exit fullscreen mode

The lib directory will contain the compiled files.

The code for the Lambda functions can also be inserted inline into the CDK code, but in this example create index.js in the functions directory.

  • functions/index.js
exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};
Enter fullscreen mode Exit fullscreen mode

Create the following two files in the src directory

  • src/index.ts
import { HttpApi } from '@aws-cdk/aws-apigatewayv2';
import { LambdaProxyIntegration } from '@aws-cdk/aws-apigatewayv2-integrations';
import { Code, Function, Runtime } from '@aws-cdk/aws-lambda';
import * as cdk from '@aws-cdk/core';

export class CdkSampleLib extends cdk.Construct {
  constructor(scope: cdk.Construct, id: string) {
    super(scope, id);

    const handler = new Function(this, 'HelloWorld', {
      handler: 'index.handler',
      code: Code.fromAsset('functions'),
      runtime: Runtime.NODEJS_12_X,
    });

    const api = new HttpApi(this, 'API', {
      defaultIntegration: new LambdaProxyIntegration({ handler }),
    });

    new cdk.CfnOutput(this, 'ApiURL', { value: api.url! });
  }
}
Enter fullscreen mode Exit fullscreen mode
  • src/integ.default.ts
import * as cdk from '@aws-cdk/core';
import { CdkSampleLib } from './index';

const app = new cdk.App();
const stack = new cdk.Stack(app, 'MyStack');

new CdkSampleLib(stack, 'Cdk-Sample-Lib');
Enter fullscreen mode Exit fullscreen mode

Create the following files in the test directory

  • test/hello.test.ts
import * as cdk from '@aws-cdk/core';
import { CdkSampleLib } from '../src/index';
import '@aws-cdk/assert/jest';

test('create app', () => {
  const app = new cdk.App();
  const stack = new cdk.Stack(app);
  new CdkSampleLib(stack, 'TestStack');
  expect(stack).toHaveResource('AWS::Lambda::Function');
  expect(stack).toHaveResource('AWS::ApiGatewayV2::Api');
  expect(stack).toHaveResource('AWS::ApiGatewayV2::Integration');
});
Enter fullscreen mode Exit fullscreen mode

Unit Test

Various scripts are predefined in the package.json generated from projen.

Run the test with yarn test.
yarn build also run test, so omit the example output here.

Build

Run yarn build and compile TypeScript to the jsii module.

jsii-docgen generates API documentation (API.md) from comments in the code.

In addition, jsii-pacmak creates language-specific public packages in the dist directory.

$ yarn build
yarn run v1.22.17
warning ../../package.json: No license field
$ npx projen build
πŸ‘Ύ build Β» default | node .projenrc.js
[1/4] Resolving packages...
success Already up-to-date.
πŸ‘Ύ build Β» compile | jsii --silence-warnings=reserved-word --no-fix-peer-dependencies
warning JSII6: A "peerDependency" on "@aws-cdk/aws-apigatewayv2" at "^1.133.0" means you should take a "devDependency" on "@aws-cdk/aws-apigatewayv2" at "1.133.0" (found "undefined")"
warning JSII6: A "peerDependency" on "@aws-cdk/aws-apigatewayv2-integrations" at "^1.133.0" means you should take a "devDependency" on "@aws-cdk/aws-apigatewayv2-integrations" at "1.133.0" (found "undefined")"
warning JSII6: A "peerDependency" on "@aws-cdk/aws-lambda" at "^1.133.0" means you should take a "devDependency" on "@aws-cdk/aws-lambda" at "1.133.0" (found "undefined")"
warning JSII6: A "peerDependency" on "@aws-cdk/core" at "^1.133.0" means you should take a "devDependency" on "@aws-cdk/core" at "1.133.0" (found "undefined")"
warning JSII6: A "peerDependency" on "constructs" at "^3.2.27" means you should take a "devDependency" on "constructs" at "3.2.27" (found "undefined")"
πŸ‘Ύ build Β» post-compile Β» docgen | jsii-docgen
πŸ‘Ύ build Β» test | jest --passWithNoTests --all --updateSnapshot
 PASS  test/hello.test.ts
  βœ“ create app (258 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 index.ts |     100 |      100 |     100 |     100 |                   
---------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.971 s, estimated 6 s
Ran all test suites.
πŸ‘Ύ build Β» test Β» eslint | eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern src test build-tools .projenrc.js
πŸ‘Ύ build Β» package | jsii-pacmak
Done in 81.53s.
Enter fullscreen mode Exit fullscreen mode

Once the build is successful, let's try deploying locally.

$ cdk deploy --app='./lib/integ.default.js'
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   β”‚ Resource                                     β”‚ Effect β”‚ Action                β”‚ Principal                        β”‚ Condition                                                                                                                           β”‚
β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ + β”‚ ${Cdk-Sample-Lib/HelloWorld.Arn}             β”‚ Allow  β”‚ lambda:InvokeFunction β”‚ Service:apigateway.amazonaws.com β”‚ "ArnLike": {                                                                                                                        β”‚
β”‚   β”‚                                              β”‚        β”‚                       β”‚                                  β”‚   "AWS:SourceArn": "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${CdkSampleLibAPI6FD5D6E6}/*/*"              β”‚
β”‚   β”‚                                              β”‚        β”‚                       β”‚                                  β”‚ }                                                                                                                                   β”‚
β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ + β”‚ ${Cdk-Sample-Lib/HelloWorld/ServiceRole.Arn} β”‚ Allow  β”‚ sts:AssumeRole        β”‚ Service:lambda.amazonaws.com     β”‚                                                                                                                                     β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
IAM Policy Changes
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   β”‚ Resource                                 β”‚ Managed Policy ARN                                                             β”‚
β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ + β”‚ ${Cdk-Sample-Lib/HelloWorld/ServiceRole} β”‚ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Do you wish to deploy these changes (y/n)? y
MyStack: deploying...
[0%] start: Publishing 20472c64d312cc547a9359d36b04cfc75633027c0b13c3c07b96dfdf1b1c428f:current
[100%] success: Published 20472c64d312cc547a9359d36b04cfc75633027c0b13c3c07b96dfdf1b1c428f:current
MyStack: creating CloudFormation changeset...
[β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] (9/9)

 βœ…  MyStack

Outputs:
MyStack.CdkSampleLibApiURL32C6192A = https://4p9zte6ny8.execute-api.ap-northeast-1.amazonaws.com/

Stack ARN:
arn:aws:cloudformation:ap-northeast-1:123456789012:stack/MyStack/8fc38650-2a78-11eb-8d53-0a6e476ede30
Enter fullscreen mode Exit fullscreen mode

You can check the response of the Lambda function from the output API URL.

$ curl https://4p9zte6ny8.execute-api.ap-northeast-1.amazonaws.com/
"Hello from Lambda!"
Enter fullscreen mode Exit fullscreen mode

To remove it, run the cdk destory.

$ cdk destroy --app='./lib/integ.default.js'                                        
Are you sure you want to delete: MyStack (y/n)? y
MyStack: destroying...
5:27:29 PM | DELETE_IN_PROGRESS   | AWS::CloudFormation::Stack | MyStack

 βœ…  MyStack: destroyed
Enter fullscreen mode Exit fullscreen mode

Release

First, commit the changes.

$ git add . 
$ git commit -m "feat: release 0.0.1"
Enter fullscreen mode Exit fullscreen mode

yarn release bumps the version and automatically updates CANGELOG.md.
Then push to the release branch of GitHub.

$ yarn release
yarn run v1.22.5
$ yarn run --silent no-changes || (yarn run bump && git push --follow-tags origin main)
$ yarn run --silent no-changes || standard-version
βœ” bumping version in version.json from 0.0.0 to 0.0.1
βœ” Running lifecycle script "postbump"
β„Ή - execute command: "yarn run projen && git add ."
πŸ€– yarn install --check-files
πŸ€– Synthesis complete

---------------------------------------------------------------------------------------------------------
Commands:

BUILD
compile          Only compile
watch            Watch & compile in the background
build            Full release build (test+compile)

TEST
test             Run tests
test:watch       Run jest in watch mode
eslint           Runs eslint against the codebase

RELEASE
compat           Perform API compatibility check against latest version
release          Bumps version & push to main
docgen           Generate API.md from .jsii manifest
bump             Commits a bump to the package version based on conventional commits
package          Create an npm tarball

MAINTAIN
projen           Synthesize project configuration from .projenrc.js
projen:upgrade   upgrades projen to the latest version

MISC
start            Shows this menu

Tips:
πŸ’‘ The VSCode jest extension watches in the background and shows inline test results
πŸ’‘ Install Mergify in your GitHub repository to enable automatic merges of approved PRs
πŸ’‘ Set `autoUpgradeSecret` to enable automatic projen upgrade pull requests
πŸ’‘ `API.md` includes the API reference for your library
πŸ’‘ Set "compat" to "true" to enable automatic API breaking-change validation

βœ” created CHANGELOG.md
βœ” outputting changes to CHANGELOG.md
βœ” committing version.json and CHANGELOG.md and all staged files
βœ” tagging release v0.0.1
β„Ή Run `git push --follow-tags origin master` to publish
Enter fullscreen mode Exit fullscreen mode

Or you can bump to any version by running yarn bump.

$ yarn bump --release-as 1.0.0 && git push --follow-tags origin main
Enter fullscreen mode Exit fullscreen mode

The Github Actions workflow definition is also generated when the projen command is executed, which makes it easy to automate the release to the package repository.

  • Build workflow (.github/workflows/build.yaml)
    Runs when a pull request is created.
    Builds the library and checks for tampering (i.e., manual modification).

  • Release workflow (.github/workflows/release.yaml):
    It is triggered by push to the release branch.
    After building in the release branch, it automatically publishes to the repositories, such as npm and PyPI by jsii-release.

Alt Text

In order for the Release job to work properly, you need to register the Secrets for the language you want to publish in the GitHub repository.

  • npm: NPM_TOKEN
  • .NET: NUGET_API_KEY
  • Java: MAVEN_GPG_PRIVATE_KEY, MAVEN_GPG_PRIVATE_KEY_PASSPHRASE, MAVEN_PASSWORD, MAVEN_USERNAME, MAVEN_STAGING_PROFILE_ID
  • Python: TWINE_USERNAME, TWINE_PASSWORD

Try It!

With projen, you can focus on the implementation of the Construct Library (and of course, on the regular CDK App).

Do you want to understand how to use projen in videos?
The following video published by @pahud, an AWS Developer Advocate, is very helpful.

I recently published a construct library called cdk-ecr-image-scan-notify using projen.

GitHub logo hayao-k / cdk-ecr-image-scan-notify

cdk-ecr-image-scan-notify is an AWS CDK construct library that notify the slack channel of Amazon ECR image scan results.

NPM version PyPI version Release

cdk-ecr-image-scan-notify

cdk-ecr-image-scan-notify is an AWS CDK construct library that notify the slack channel of Amazon ECR image scan results.

Click on an image name to go to the scan results page.

Getting Started

TypeScript

Installation

$ yarn add cdk-ecr-image-scan-notify

Usage

import * as cdk from '@aws-cdk/core';
import { EcrImageScanNotify } from 'cdk-ecr-image-scan-notify';

const mockApp = new cdk.App();
const stack = new cdk.Stack(mockApp, '<your-stack-name>');

new EcrImageScanNotify(stack, 'ecr-image-scan-notify', {
  webhookUrl: '<your-incoming-webhook-url>',
  channel: '<your-slack-channel-name>',
});
Enter fullscreen mode Exit fullscreen mode

Deploy!

$ cdk deploy

Python

Installation

$ pip install cdk-ecr-image-scan-notify

Usage

import aws_cdk.core as cdk
from cdk_ecr_image_scan_notify import EcrImageScanNotify
app = cdk.App()
stack = cdk.Stack(app, "<your-stack-name>", env={'region': 'ap-northeast-1'})

EcrImageScanNotify(stack, "EcrImageScanNotify",
    webhook_url = '<your-incoming-webhook-url>',
    
…
Enter fullscreen mode Exit fullscreen mode

I hope this article will help you.

Discussion (1)

Collapse
guan840912 profile image
Neil Kuan

awesome