CI/CD with a simple NestJS server
Tags: javascript, tutorial, node
Published: 2022-03-16 09:34:59

In this tutorial, we will see how we can make a CI/CD (Continuous Integration and Continuous Delivery) script with GitHub Actions and a simple NestJS server.
 

## Introduction

[NestJS](https://nestjs.com/) is a Framework for building Node.js server side application. It is built with TypeScript and use Express or Fastify HTTP server framework under the hood. It's architecture is heavily inspired by Angular. It integrates a lot of features and is very easy to use.

[GitHub Actions](https://github.com/features/actions) is GitHub take on CI/CD. It allows you to automate your build process and deploy your code directly from your GitHub repository.

## Goals

Our goal is to create a simple NestJS server with the Nest CLI, deploy it using ScaleDynamics cloud platform and then automate it with GitHub Actions. We'll learn how you can use GitHub Actions to deploy with the ScaleDynamics platform.

## Prerequisites

To follow along, you will need:

- A [GitHub](https://github.com/) account and a repository ready to be used with GitHub Actions.
- Knowledge of [Git](https://git-scm.com/) and have it installed on your machine.
- Node.js and yarn / npm installed. You can go [here](https://nodejs.org/en/download/) to download the latest version of Node.js and npm.

## Creating the project

To create the project, we can use the [Nest CLI](https://docs.nestjs.com/#installation) or clone a project starter from GitHub:

```shell
npm i -g @nestjs/cli
nest new my-server
```

or

```shell
git clone https://github.com/nestjs/typescript-starter.git my-server
```

Move into the project folder:

```shell
cd my-server
```

You can test if the project is working locally by running:

```shell
npm run start
```

You can check you receive `Hello World!` by running:

```shell
curl localhost:3000
```

Now that we saw the project working, we just need to make a change in the scripts of the `package.json` file. When the server is deployed with ScaleDynamics, the server is started with the `start`command. We will change it so it launch the server in production mode by default and not in dev mode.

```json
// package.json
"scripts": {
    "prebuild": "rimraf dist",
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "dev": "nest start",
    "dev:watch": "nest start --watch",
    "dev:debug": "nest start --debug --watch",
    "start": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
```

Everything is ready to be deployed !

## Account creation and ressource selection

To deploy this server on ScaleDynamics's cloud, you need an account and create an environment with a ressource for it. The cloud resource provides virtual CPU and storage capacities used to execute the app. In this tutorial we will use a free shared resource available on ScaleDynamics’s cloud. These are the best one for testing. In this tutorial we will see later how you can upgrade to a dedicated production resource on the public cloud provider and region of your choice.

If you don't have an account, feel free to create one [here](https://console.scaledynamics.com/auth/signup/) (it's free and no credit card are required). Once your account is created, sign in.

Let's create a project and an environment on the ScaleDynamics's [console](https://scaledynamics.com/console). Select your organization, create a new project, then create a new environmnent. Now we need to choose what kind of service we need for our deployment. There are four types:

- managed HTTP docker
- managed Node.js server
- managed Node.js module
- static assets hosting

For our NestJS server, we need a (surprise) server. Let's pick the managed Node.js server. You can learn more on the other types in the [ScaleDynamics documentation](https://docs.scaledynamics.com/).

![Environment creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/juhgnbeo3lumwl555708.gif)

## Deployment

The environment is ready to run our application, let's deploy on it.

### Configuration file

First, let's add a configuration to tell the SDK what type of application we want to deploy. At the root of the project, create a `warp.config.js` file:

```javascript
// warp.config.js
module.exports = {
  server: "nest",
};
```

### Build

Build the project to let Nest compile TypeScript and optimize and bundle everything for us:

```shell
yarn build
```

### Login

Log into your account and select your organization via the prompt:

```shell
npx warp login
```

### Deploy

Finally, we can run the deployment command:

```shell
npx warp deploy
```

This command will dump something like this:


![Deploy dump](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d23qdf323ahl7ju6vigy.png)

You can see that a server was detected from your configuration file. Now follow the prompt, select the project you created, then the environment. The prompt will also ask you for a hostname, you can leave it blank for a random name or use the one you want. Finally, you can select a host.

The deployment will be done in a few minutes. At the end, the command will dump something like this:


![Deploy end dump](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zbb4ad5zeo62j7swqero.png)

You can now open test it by visiting the URL dumped or doing a curl request.

## Automation with GitHub Actions

To simplify and automate this process, let's use GitHub Actions.

### Create a GitHub repository

Before we can automate the process, you need to create a GitHub repository and upload the project there.
You can learn more about it on the [GitHub documentation](https://docs.github.com/).

### Define our workflow

Now let's think about what workflow we want to automate. Our final goal is to deploy our server, but before deploying, we need to check the quality of the code, test it, build the project and finally deploy it. For this example there will be four steps:

- Lint our code with ESLint
- Test our code with Jest
- Build our project
- Deploy it

The NestJS startup project we use got everything to do so.

### Create the workflow

Let's create a new workflow by creating a new folder at the root of the project called `.github` and an other folder inside called `workflows`. Inside `workflows`, create a `main.yml` file and copy this code:

```yml
name: Deploy

# Controls when the workflow will run
on:
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    env:
      # replace with your project/env name
      ORG_PROJECT: nest-test
      DEPLOY_ENV: dev
    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      - name: Install dependencies
        run: yarn

      - name: Lint the codebase
        run: yarn lint

      - name: Test our code
        run: yarn test

      - name: Build
        run: yarn build

      - name: Login
        run: npx warp login --api-key=${{ secrets.SD_API_KEY }}

      - name: Deploy
        run: npx warp deploy --project ${ORG_PROJECT} --env ${DEPLOY_ENV}
```

### API key for login

Your workflow is ready, but for the login step, we need an API key to authenticate with ScaleDynamics. This API key can be created on the [ScaleDynamics console](https://console.scaledynamics.com):

![API key creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cs83zmrrjicm5uxefrkx.gif)

Once your API key is created, we can create a secret in your repository so we can use it in our workflow:

![GitHub secret creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/em1hk2x43ba7layzkmob.png)

### Test it

Now you can try it by going into the Actions tab on your repository and trigger the workflow:


![Trigger workflow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w9mfjvo8blv7qkntjrhl.png)

The workflow will run and you will be able to see the job `deploy`. Click on it and you can see all the steps that are executed. At the end if all go well you should have something like:

![Workflow results](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7je3akz0r2cbusu62jih.png)

If there is an error along the way you will be able to easily spot it and fix it.

## Go further

This was a simple example of setting up CI/CD to deploy an server with ScaleDynamics, but you can do way more things with it. For exemple, you could lint the code on every commit to ensure styling coherence and ensure no mistake are present in your codebase, or you could deploy you code in preproduction at every commit on a branch `preprod`. The sky is the limit.

If you want to know more, I encourage you to read this [JetBrains guide](https://www.jetbrains.com/teamcity/ci-cd-guide/). It's related to their TeamCity CI/CD platform but they perfectly explain the principles and what you can do with CI/CD in general.

Enjoy !