---
title: "Cloud Ready Series: Setting up a CI Pipeline"
description: Your JavaScript/Node API is containerized, but do you have a CI pipeline automating testing, building, & publishing images? Build one with GitHub workflows
image: https://www.bitovi.com/hubfs/Cloud%20Ready%20Series-%20Setting%20up%20a%20CI%20Pipeline.png
---

- ![AI implementation](https://www.bitovi.com/hubfs/AIConsultingIcon.svg)
  
  [AI implementation](https://www.bitovi.com/services/ai-consulting)
- ![Systems engineering](https://www.bitovi.com/hubfs/icon%20-%20backend.svg)
  
  [Systems engineering](https://www.bitovi.com/services/systems-engineering-consulting)
- ![Project Management](https://www.bitovi.com/hubfs/icon%20-%20PM.svg)
  
  [Project Management](https://www.bitovi.com/services/agile-project-management-consulting)
- ![Product Design](https://www.bitovi.com/hubfs/icon%20-%20design.svg)
  
  [Product Design](https://www.bitovi.com/services/product-design-consulting)
- ![Frontend development](https://www.bitovi.com/hubfs/icon%20-%20frontend.svg)
  
  [Frontend development](https://www.bitovi.com/services/frontend-development-consulting)
- [View more
  
  →
  
  ](https://www.bitovi.com/digital-consulting-services)

We're Experts in...

- [JavaScript](https://www.bitovi.com/services/frontend/javascript-consulting)
- [AI training](https://www.bitovi.com/ai-training-for-software-engineers)
- [Angular](https://www.bitovi.com/services/frontend/angular-consulting)
- [Design systems](https://www.bitovi.com/services/axure-figma-migration)
- [React](https://www.bitovi.com/services/frontend/react-consulting)
- [Temporal](https://www.bitovi.com/services/backend/temporal-consulting)
- [React Native](https://www.bitovi.com/services/frontend/react-consulting/react-native)
- [Node.js](https://www.bitovi.com/services/backend/nodejs-consulting)

Showcase

![Yum! Brands](https://www.bitovi.com/hubfs/yum-showcase-link-1.png)

[View case study](https://www.bitovi.com/en/bitovi-yum-case-study)

More Projects

- [![Levi's](https://www.bitovi.com/hubfs/levis.svg)](https://www.bitovi.com/web-application-consulting-work/levis-ecommerce-responsive-redesign)
- [![Christie's International Real Estate](https://www.bitovi.com/hubfs/christies.svg)](https://design.bitovi.com/christies)
- [![BAFS](https://www.bitovi.com/hubfs/bafs.svg)](https://www.bitovi.com/ux-design-consulting/ux-case-studies/bafs-ppp)
- [View more
  
  →
  
  ](https://www.bitovi.com/our-software-consulting-work)

Open Source Tools

We build powerful tools and open source them to support the community.

[See what we've built →](https://www.bitovi.com/open-source)

- [![Blog](https://www.bitovi.com/hubfs/icon%20-%20blog.svg)
  
  BlogWe post about delivering products and solving problems.
  
  ](https://www.bitovi.com/blog)
- [![Partnerships](https://www.bitovi.com/hubfs/Handshake-1.svg)
  
  PartnershipsLearn about Bitovi's technology partners
  
  ](https://www.bitovi.com/partnerships)
- [![Academy](https://www.bitovi.com/hubfs/icon%20-%20academy%20(4).svg)
  
  AcademyFree courses to build delivery skills
  
  ](https://www.bitovi.com/academy)
- [![Open source tools](https://www.bitovi.com/hubfs/icon%20-%20open%20source.svg)
  
  Open source toolsUse or contribute to our community
  
  ](https://www.bitovi.com/open-source)

Let's Connect

- [![Discord](https://www.bitovi.com/hubfs/DiscordLogo.svg)
  
  Discord
  
  ](https://discord.gg/J7ejFsZnJ4)
- [![LinkedIn](https://www.bitovi.com/hubfs/LinkedinLogo.svg)
  
  LinkedIn
  
  ](https://www.linkedin.com/company/bitovi/)
- [![GitHub](https://www.bitovi.com/hubfs/GithubLogo.svg)
  
  GitHub
  
  ](https://github.com/bitovi/)

![Eggbot](https://www.bitovi.com/hubfs/build_assets/bitovi-limbo-cms-react/338/js_client_assets/assets/eggbot-LTGhdSGL.png)

Name *

Work Email *

Phone

What's your project?

Send

### Contact Us

(312) 620-0386contact@bitovi.com

[ DevOps ](https://www.bitovi.com/blog/topic/devops) |  October 7, 2022

# Cloud Ready Series: Setting up a CI Pipeline

 Your JavaScript/Node API is containerized, but do you have a CI pipeline automating testing, building, & publishing images? Build one with GitHub workflows

![Phil Henning](https://app.hubspot.com/settings/avatar/52d76f692722774929e36cefd15167ec)

 Phil Henning

Share:

[![Twitter](https://www.bitovi.com/hubfs/limbo-generated/_astro/twitter-white.os3xLc3C_Z2nW4or.svg) ](https://twitter.com/intent/tweet?text=) [![Reddit](https://www.bitovi.com/hubfs/limbo-generated/imgs/icons/reddit.png) ](http://reddit.com/submit?url=)

[Continuous Integration (CI)](https://www.bitovi.com/blog/the-complete-guide-to-devops) is the process of automating the stages of testing, building, and publishing. It is considered one of the first steps toward creating a truly automated end-to-end deployment process. The aim of CI is to create an artifact that can be deployed into one or more systems, preferably with a Continuous Deployment (CD) pipeline.

Using a CI pipeline to test, build, and publish your JavaScript/Node API with Github workflows is accomplished by:

1. Writing a GitHub workflow—A YAML file that will define what **triggers** the CI pipeline, how the test and build steps are performed, and where the publish stage will publish to
2. Triggering the CI pipeline—Manually or through an event trigger

## Prerequisites

Just a quick reminder that a Github account and a repository storing your JavaScript/Node API are required at this point. If you haven't created a JavaScript/Node API application, check out our first blog in the [ Cloud Ready Series - Dockerize Your JavaScript & Node.js Apps ](https://www.bitovi.com/blog/cloud-ready-series-dockerize-javascript-and-node-apps) .

Optionally, though you can skip the publish step, or modify it to create a GitHub release, it is advised you follow along with the blog, which will require a [Dockerhub](https://hub.docker.com/) account.

## Adding Tests Using Jest and SuperTest

This post will run tests using Jest and SuperTest. If you’re interested in a more in-depth look at Jest and SuperTest, we have a much more in-depth blog about the [Anatomy of a Node API](https://www.bitovi.com/blog/backend-basics-anatomy-of-a-node-api#test).

So building on the [last cloud ready series ](https://www.bitovi.com/blog/cloud-ready-series-dockerize-javascript-and-node-apps)our goal this time is to:

- Update our existing code so that it supports our testing suite
- Create a simple endpoint unit test that will ensure our application is doing what we expect
- Create a CI pipeline that will automate the test, build, and publishing of our artifact

To begin open up your existing `index.js` file and comment out the following three lines. You’ll move them into a new file named `start.js`:

### start.js

```
const app = require("./index.js");
const port = process.env.PORT || 3000

app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
})
```

 

Additionally, you’ll need to modify the `index.js` file by adding the following line to the bottom of the script. This is done so that the testing frameworks we plan on using can mock the API for testing.

```
module.exports = app; 
```

Next, you’ll install *SuperTest* and *Jest* using the following command;

```
npm install jest --save-dev
npm install SuperTest --save-dev
```

The `--save-dev` flag will add the *SuperTest* and *Jest* packages to the *devDependencies* section in the applications `package.json`. This means that when you create packages for higher environments, packages within the *devDependencies* will not be installed.

After that open your `package.json` file and modify our scripts section to include the following code. These additional options will enable you to start our testing by calling `npm test` and `npm test:watch`

### package.json

```
"scripts": {
        "start": "node start.js",
        "test": "jest",
        "test:watch": "jest --watch"
    },
```

Finally, add in our endpoint test. Create the following folder and file (`tests/app.test.js`).

```
tests/
    app.test.js
Dockerfile
index.js
package.json
start.js
```

### tests/app.test.js

```
const app = require("../index.js");
const supertest = require("supertest");
const request = supertest(app);

it("GET / endpoint with 200 status", async () => {
  const response = await request.get("/");
  expect(response.status).toBe(200);
});

it("Call an endpoint that doesn't exist with a 404 status", async () => {
  const response = await request.get("/not-an-endpoint");
  expect(response.status).toBe(404);
});
```

Running the above tests will ensure that the `/` most basic path is reachable and returns 200 and that a URL path that the app doesn't listen for doesn't work and returns a 404.

## Creating the CI Pipeline

Now we get to the best part, creating a CI pipeline that will provide an automated artifact process that you can use to deploy!

Create the following folders and file (`.github/workflows/ci-pipeline.yaml`):

```
.github/
    workflows/
        ci-pipeline.yaml
tests/
    app.test.js
Dockerfile
index.js
package.json
start.js
```

This is where you finally get to define your test, build and publish stages which will create our automated CI pipeline.

### .github/workflows/ci-pipeline.yaml

```
# This name shows up in the Github repository action page
name: CI Pipeline
# These define the CI pipeline triggers
on:                 
  # Provides a manual start option on the Github repository action page                
  workflow_dispatch: {}             
  push:
    branches:
      # Triggers when a new commit is pushed to the main branch
      - main
    pull_request:
      # Triggers when a PR is created that is merging into the main branch
      - main

jobs:
  build:
    # This defines that this will run on a Github managed ubuntu server
    runs-on: ubuntu-latest          
    steps:
      # Checks out our repo onto the ubuntu-latest machine
      uses: actions/checkout@v3     
  
      # Installs the node packages that the application uses
      name: Install deps            
      run: npm install
  
      # Runs our test suite, the return value will determine pipeline completion
      name: Run `npm test`          
      run: npm test

      # Builds and publishes the Docker image to Dockerhub
      name: Build image
      uses: bitovi/github-actions-docker-publish@main
      with:
        # This is a way of keeping your secrets safe by using injection instead of hardcoding
        docker_username: ${{ secrets.DOCKERHUB_USERNAME }}
        # Keep reading below to learn more
        docker_password: ${{ secrets.DOCKERHUB_PASSWORD }}
```

Let's quickly talk about Github action secrets. You'll have likely noticed the variable `${{ secrets.DOCKERHUB_USERNAME }}`, which is a way for GitHub to inject secrets that are stored at the GitHub repository or organizational levels. This pattern will keep your secrets… well, secret! During the pipeline execution, Github monitors the output and will parse out the secret if it is found.

Check out the [GitHub repository secret doc](https://docs.github.com/en/actions/security-guides/encrypted-secrets) to learn more information and how to create one (it's super easy).

With all that done the final step is to commit your work and head over to your repository page on `github.com` . On the top selection bar, navigate to the `actions` page. Since you just committed you should see a new pipeline execution for your CI pipeline.

On the left menu select `CI-pipeline` , this will allow you to manually trigger the CI pipeline on the right corner if you'd like to try that functionality.![ci-pipeline-1](https://www.bitovi.com/hs-fs/hubfs/ci-pipeline-1.gif?width=800&name=ci-pipeline-1.gif)

## Common Gotchas

If your pipeline is failing, navigate to your repo on [ github.com ](http://github.com) and select the actions page. Select the most recent failed run and click the cog found within the inner panel on the top right. In the menu select `view raw logs` . This will provide you with all of the logs. Check the bottom to see what the issue listed is.

Some common gotchas include;

- Missing install stage within the pipeline
- Mistyping the Docker account and password in your secrets
- Not having a repo created in the Docker account to push to (Should be the same name as on Github)

## Success!

![success](https://www.bitovi.com/hs-fs/hubfs/success.png?width=694&height=55&name=success.png)

Congrats! Seeing that little green check mark means you've successfully created a CI pipeline for your JavaScript/Node API!

From here you can do a lot. One option is to create more tests for your application to really ensure stability. Another could be to take your newly published artifact and deploy it... If you're interested in that, you'll want to keep an eye out for our next blog in the Cloud Ready Series - Setting up Infrastructure.

## Need Help?

Bitovi has consultants that can help. Drop into [Bitovi's Community Slack](https://join.slack.com/t/bitovi-community/shared_invite/zt-1epm5t72a-LJOpZp4KDg~zgIuaur1UgA), and talk to us in the #devops channel!

Need [DevOps](https://www.bitovi.com/blog/the-complete-guide-to-devops) Consulting Services? Head over to [DevOps Consulting - Bitovi](https://www.bitovi.com/devops-consulting), and book a free consultation.

 

[![Tag for cloud ready series](https://www.bitovi.com/hubfs/limbo/icons/tag.svg) cloud ready series ](https://www.bitovi.com/blog/topic/cloud-ready-series)

 Previous Post

![CSS-Only Type Grinding: Casting Tokens (sm|md|etc) into Useful Values](https://www.bitovi.com/hs-fs/hubfs/CSS-Only%20Type%20Grinding-%20Casting%20Tokens%20%28sm%7Cmd%7Cetc%29%20into%20Useful%20Values.png?height=117&name=CSS-Only%20Type%20Grinding-%20Casting%20Tokens%20%28sm%7Cmd%7Cetc%29%20into%20Useful%20Values.png) [ CSS-Only Type Grinding: Casting Tokens (sm|md|etc) into Useful Values ](https://www.bitovi.com/blog/css-only-type-grinding-casting-tokens-into-useful-values)

  

 Next Post

![How to Create a GraphQL Server with NestJS](https://www.bitovi.com/hs-fs/hubfs/How%20to%20Create%20a%20GraphQL%20Server%20with%20NestJS.png?height=117&name=How%20to%20Create%20a%20GraphQL%20Server%20with%20NestJS.png) [ How to Create a GraphQL Server with NestJS ](https://www.bitovi.com/blog/how-to-create-a-graphql-server-with-nestjs)

```json
{
  "@context" : "http://schema.org",
  "@type" : "Organization",
  "address" : {
    "@type" : "PostalAddress",
    "addressCountry" : "United States",
    "addressLocality" : "Libertyville",
    "addressRegion" : "IL",
    "postalCode" : "60048",
    "streetAddress" : "1134 Pine Tree Lane "
  },
  "alternateName" : "Bitovi",
  "areaServed" : {
    "@type" : "GeoCircle",
    "geoMidpoint" : {
      "@type" : "GeoCoordinates",
      "latitude" : "41.8781",
      "longitude" : "87.6298"
    },
    "geoRadius" : "5000 km"
  },
  "description" : "Bitovi is a UX, UI design and front-end JavaScript development consulting company",
  "email" : "contact@bitovi.com",
  "image" : "https://www.bitovi.com/hubfs/bitovi-logo-x2.png",
  "logo" : "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg",
  "mainEntityOfPage" : {
    "@id" : "https://www.bitovi.com/blog/cloud-ready-series-setting-up-a-ci-pipeline",
    "@type" : "WebPage",
    "description" : "Your JavaScript/Node API is containerized, but do you have a CI pipeline automating testing, building, & publishing images? Build one with GitHub workflows"
  },
  "naics" : "541511",
  "name" : "Bitovi Web App Consulting",
  "sameAs" : [ "https://www.facebook.com/BitoviLLC/", "https://twitter.com/bitovi", "https://www.linkedin.com/company/bitovi" ],
  "telephone" : "312-620-0386",
  "url" : "http://bitovi.com"
}
```

```json
{
  "@context" : "http://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Phil Henning"
  },
  "dateModified" : "October 6, 2023, 6:54:25 PM",
  "datePublished" : "2022-10-07 13:00:00",
  "description" : "Your JavaScript/Node API is containerized, but do you have a CI pipeline automating testing, building, & publishing images? Build one with GitHub workflows",
  "headline" : "Cloud Ready Series: Setting up a CI Pipeline",
  "image" : {
    "@type" : "ImageObject",
    "url" : "https://www.bitovi.com/hubfs/Cloud%20Ready%20Series-%20Setting%20up%20a%20CI%20Pipeline.png"
  },
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "url" : "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg"
    },
    "name" : "Bitovi"
  }
}
```