Giter Site home page Giter Site logo

aws-codepipeline-publish-nodejs-modules's Introduction

Publishing Node.js Modules on AWS CodeArtifact using AWS CodePipeline

Code reuse is hard. When writing code for Node.js, developers can take advantage of the Node.js Package Manager (NPM) Command Line Interface (CLI) that enables packaging code into modules which can then reused across projects. These modules or packages can be stored in AWS CodeArtifact and used throughout Node.js applications running on AWS. This pattern provides a continuous integration - continuous deployment pipeline via AWS CodePipeline to lint, test, and publish a new version of a Node.js module into a AWS CodeArtifact Repository. The publish stage of the pipeline uses semantic-release, a fully automated version management and package publishing tool. Semantic release automatically creates a CHANGELOG.md based off your commit messages and updates the version in your package.json via semantic version guidelines. The pipeline and supporting infrastructure is defined via the AWS Cloud Development Kit (CDK).

See the associated Amazon Prescriptive Guidance (APG) Pattern here for further information.

Prerequisites

Limitations

  • AWS CodeCommit is the only source control management service compatible with this pattern. GitHub or GitLab cannot be used.
  • Node.js packages are the only package format compatible with this pattern. PyPi packages cannot be used.

Product versions

  • AWS CLI Version 2 or greater
  • Node.js 14.X or greater
  • AWS CDK v2 or greater
  • Git 2.X or greater

Architecture

Architecture Diagram

Tools

Steps

Setup Domain and Repository

Create the AWS CodeArtifact Domain and Repository which will store packages. Change the variables in the script below and then run the script in your terminal. Make sure you follow the naming constraints for the domain and repository. To be safe, use kebab-case-like-this.

CA_DOMAIN=my-domain
CA_REPO=my-repo
aws codeartifact create-domain --domain $CA_DOMAIN
aws codeartifact create-repository --domain $CA_DOMAIN --repository $CA_REPO

Login to AWS CodeArtifact Repository by running the script below in your terminal. Note, it is a convention to prefix your namepsace with @.

CA_NAMESPACE=@my-namespace
aws codeartifact login --tool npm --domain $CA_DOMAIN --repository $CA_REPO --namespace $CA_NAMESPACE

This updates your ~/.npmrc telling NPM to look for packages with a namespace (prefix) of $CA_NAMESPACE within the AWS CodeArtifact Repository $CA_REPO.

Publish the CDK Construct Pipeline

Clone the repository from https://github.com/aws-samples/aws-codepipeline-publish-nodejs-modules and install dependencies.

git clone https://github.com/aws-samples/aws-codepipeline-publish-nodejs-modules.git
cd aws-codepipeline-publish-nodejs-modules
npm install

Deploy the AWS infrastructure required for the pipeline

cdk deploy

Push the code to CodeCommit. Note, the pipeline ran upon deploying in the previous step and failed because the repository wasn't initialized. Pushing code to the repository will cause the pipeline to run.

git add package-lock.json
git commit -m "feat: initial commit"
git remote set-url origin https://git-codecommit.us-east-1.amazonaws.com/v1/repos/nodejs-pkg-pipeline
git push origin --set-upstream main

Create Node.js Module to Publish

Initialize the CDK Construct with the CDK Toolkit in a new directory

cd ..
mkdir my-bucket
cd my-bucket
cdk init --language typescript

Delete the folders: bin, lib, and test and the file: .npmignore. Add the following file to build your bucket. This example is trivial but you can add more features later on.

// lib/my-bucket.ts
import { Bucket, BucketProps } from "aws-cdk-lib/aws-s3";
import { Construct } from 'constructs';

interface MyBucketProps extends BucketProps {}

export class MyBucket extends Construct {
  constructor(scope: Construct, id: string, props?: MyBucketProps) {
    super(scope, id);
    new Bucket(this, "MyBucket", props);
  }
}

First, install the module you created earlier with the command npm install @my-namespace/nodejs-pkg-pipeline which will install the module from CodeArtifact into your node_modules folder. If you get a 404 error, make sure the pipeline created in the previous epic has completed. Second, add the following file:

// bin/pkg-pipeline.ts
import { App, Stack } from "aws-cdk-lib";
import { Construct } from "constructs";
import { PkgPipeline } from "@my-namespace/nodejs-pkg-pipeline";

const app = new App();
const name = "my-bucket";
class PipelineStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    new PkgPipeline(this, "MyBucketPipeline", {
      name: id,
      repoDescription: "My Bucket",
      codeArtifactNamespace: "@my-namespace",
      codeArtifactRepo: "my-repo",
      codeArtifactDomain: "my-domain",
    });
  }
}

new PipelineStack(app, name);

Make sure you change "@my-namespace", "my-repo", and "my-domain" in the above code snippet to your values.

Third, update the app key of the cdk.json file so the CDK knows which stack to deploy.

// cdk.json
{
  "app": "npx ts-node --prefer-ts-exts bin/pkg-pipeline.ts",
  ...
}

Update the package.json to include the following:

{
  "name": "@my-namespace/my-bucket",
  "version": "0.1.0",
  "files": ["dist/**/*", "lib/**/*"],
  "main": "dist/my-bucket.js",
  "types": "dist/my-bucket.d.ts",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "echo \"TODO\"",
    "cdk": "cdk",
    "lint": "echo \"TODO\""
  },
  ...

Update the tsconfig.json to include the following:

{
  "compilerOptions": {
    ...
    "declarationMap": true,
    "outDir": "dist",
  },
  "include": ["lib"],
}

Also add dist to your .gitignore.

Finally, add a .releaserc.js which will tell semantic-release how to release your package

// .releaserc.js
module.exports = {
  branches: ["main"],
  plugins: [
    "@semantic-release/commit-analyzer", // analyzes commits with conventional-changelog standrd
    "@semantic-release/release-notes-generator", // generates changelog content based on conventional-changelog standard
    "@semantic-release/changelog", // updates CHANGELOG.md
    "@semantic-release/npm", // updates version in package.json based on commits
    "@semantic-release/git"
  ],
};

IMPORTANT: Since the default .gitignore ignores all .js files, you'll need to add !.releaserc.js to your .gitignore so it's pushed up to your repository.

Publish my-bucket

Deploy my-bucket pipeline with the CDK:

cdk deploy

Push the code to CodeCommit.

git add -A
git commit -m "feat: initial commit"
git remote add origin https://git-codecommit.us-east-1.amazonaws.com/v1/repos/my-bucket
git push origin --set-upstream main

Congratulations! You've created a Node.js package within CodeArtifact. Go to CodeArtifact in your console to view the package.

Update my-bucket

After a couple minutes when the pipeline completes for the first time, run git pull and look at the CHANGELOG.md and the version of your package.json to see the automatic updates.

Add default encryption to your bucket managed by S3.

// lib/my-bucket.ts
import { Bucket, BucketProps, BucketEncryption } from "aws-cdk-lib/aws-s3";
import { Construct } from 'constructs';

interface MyBucketProps extends BucketProps {}
export class MyBucket extends Construct {
  constructor(scope: Construct, id: string, props?: MyBucketProps) {
    super(scope, id);
    const defaultProps = { encryption: BucketEncryption.S3_MANAGED };
    const newProps = props ? { ...defaultProps, ...props } : defaultProps;
    new Bucket(this, "MyBucket", newProps);
  }
}

Commit your changes with a commit message that follows Conventional Commits. Using a commit message prefix of "feat" will create a feature release of your package incrementing Y in the version X.Y.Z. Note, if you needed to make a fix to your bucket you could prefix your commit message with "fix" which will create a patch release of your package incrementing Z in the version X.Y.Z.

git add lib/my-bucket.ts
git commit -m "feat: add default encryption on bucket"
git push

After a couple minutes when the pipeline completes, run git pull and look at the CHANGELOG.md and the version of your package.json to see the automatic updates.

You can now install my-bucket into another Node.js project with peace of mind that your bucket has default encryption. Install my-bucket by running npm install @my-namespace/my-bucket. Note, if you try to install the module more than 12 hours after you logged into AWS CodeArtifact initially, you'll need to login again with: aws codeartifact login --tool npm --domain $CA_DOMAIN --repository $CA_REPO --namespace $CA_NAMESPACE

Related Resources

Additional Information

Package Workflow: Produce to Consume

  1. Package producer pushes code and updates default branch of AWS CodeCommit repository.
  2. Amazon EventBridge event is triggered and sent to AWS Lambda function.
  3. AWS Lambda function triggers AWS CodePipeline to begin execution except for code updates with a commit message include "[skip ci]". Skipping pipeline executions with this message is important. because otherwise the pipeline would be triggered multiple times as semantic-release creates a new commit message on your default branch each time a new version is released.
  4. AWS CodePipeline begins the "Source" stage which downloads the code from AWS CodeCommit.
  5. AWS CodePipeline begins the "Lint" stage which runs the command npm run lint within AWS CodeBuild. This typically runs a static code analysis tool like ESLint ensuring high code quality.
  6. AWS CodePipeline begins the "Test" stage which runs the command npm run test within AWS CodeBuild. This typically starts a test runner like Jest to run unit tests.
  7. AWS CodePipeline begins the "Publish" stage which runs the command npx semantic-release within AWS CodeBuild. This kicks off a package release workflow that determines the next version number, generates release notes, and publishes the package to AWS CodeArtifact. See semantic-release for more information.
  8. Package consumer installs the updated package version into their Node.js project with npm install @my-namespace/my-package.

Additional Security Considerations:

  • Use AWS CodeCommit with interface VPC endpoints for network level access control. More information here.
  • Use AWS CodeArtifact with interface VPC endpoints for network level access control. More information here.
  • Connect to CodeCommit using git-remote-codecommit

Security

See CONTRIBUTING for more information.

License

This library is licensed under the MIT-0 License. See the LICENSE file.

aws-codepipeline-publish-nodejs-modules's People

Contributors

amazon-auto avatar bestickley avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

leon-1207

aws-codepipeline-publish-nodejs-modules's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.