Building Angular CLI Projects with Github Actions
Tags: angular, github
Published: 2020-01-02 06:06:55

---
published: true
title: Building Angular CLI Projects with Github Actions
description: Learn how to create an automated CI system for Angular CLI projects using Github Actions.
tags: angular, github
canonical_url: https://coryrylan.com/blog/building-angular-cli-projects-with-github-actions
---

The [Angular CLI](https://cli.angular.io) provides all the built tools out of the box to create, build, and test Angular applications. In this post, we will build a continuous integration (CI) build system using [Github Actions](https://github.com/features/actions).

Our CI process will run our build and unit tests anytime we push to our repository. Using the new Github Actions feature, we can easily integrate a CI system into our Github repositories. Let's get started!

## Running Angular Unit tests with Puppeteer

In our Angular CLI projects, we can build and test our entire project with just a few commands. To run these commands in our Github Actions environment, we need to add a new dependency called [Puppeteer](https://developers.google.com/web/tools/puppeteer).

Puppeteer is a headless version of Chrome. A "headless" browser is a browser that does not have a visual GUI. Using Puppeteer we can run Chrome in a CI environment, which allows us to run our unit tests. To install Puppeteer to our project, we can run the following command.

```bash
npm install Puppeteer --save-dev
```

Now that we have Puppeteer installed, we need to add a new configuration option to the `karma.conf.js` file. This new option config allows our Github Actions to run our tests with Puppeteer.

```javascript
// karma.conf.js
restartOnFileChange: true,
restartOnFileChange: true,
customLaunchers: {
  ChromeHeadlessCustom: {
    base: 'ChromeHeadless',
    flags: ['--no-sandbox', '--disable-gpu']
  }
},
```

In our `package.json` file we are going to add a few new commands that will make it easier to run our CLI build.

```json
// package.json
"scripts": {
  "ng": "ng",
  "clean": "rimraf ./dist",
  "start": "ng serve",
  "build": "ng build",
  "build:prod": "ng build --prod",
  "test": "ng test --watch=false --browsers=ChromeHeadlessCustom",
  "test:watch": "ng test",
  "lint": "ng lint",
  "e2e": "ng e2e",
  "build:ci": "npm run clean && npm run test && npm run build:prod"
},
```

With our new command `build:ci`, we can clean, run, and build our Angular CLI project with a single command. Our updated `test` script now runs our unit tests once and sets the appropriate browser configuration, `ChromeHeadlessCustom`, from our `karma.conf.js` file.

## Integrating the Angular CLI with Github Actions

Now that we can run our unit tests in Puppeteer we can integrate our project into Github Actions. We can run CI builds by creating build scripts or "Actions" in our project. To create actions, we need to create a new directory `.github/workflows/`.

In our directory, we can create many new build actions, but for now, we have a single `build.yml` file.

```yml
name: Build
on:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [12.x]

    steps:
      - uses: actions/checkout@v1

      - name: Node ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}

      - name: npm install and npm run build
        run: |
          npm ci
          npm run build:ci 
```

In our `build.yml` we define an action name as well as a trigger of when it should run. In this example, our action runs whenever we push to the `master` branch. You can configure this to run more complex scenarios like pull requests and branches. Once we define a trigger, we can define our jobs we want to run. We run our jobs using a Ubuntu Linux environment. We define our NodeJS we want to run.

Once we have our environment configured, we can define our build steps. In our example,  we log out the Node version that is running then install the NPM packages for our project. Once install has completed, we then run the `npm run build:ci` command to build and test our project.

While this config is functional, it is slow having to reinstall our
packages with each build. We can optimize our build speed by caching our
NPM `node_modules`.

```yml
{% raw %}
name: Build
on:
  push:
    branches:
      - master

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [12.x]

    steps:
      - uses: actions/checkout@v1

      - name: Cache node modules
        uses: actions/cache@v1
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

      - name: Node ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}

      - name: npm ci and npm run build
        run: |
          npm ci
          npm run build:ci 
{% endraw %}
```

We add a new step to our job that tracks our `package-lock.json` for any changes. If the job doesn't see any differences, then it can use the npm cache from a previous build, which speeds things up quite a bit.

Now if we push our project, we can go to the `Actions` tab in the Github Repo webpage to see the status of our build.

<img src="https://coryrylan.com/assets/images/posts/2019-11-17-building-angular-cli-projects-with-github-actions/angular-cli-in-github-actions.png" alt="Example of building a Angular CLI project with Github Actions" bp="full-width 8--max float-center" class="img-border" loading="lazy" />

We can also add a build status badge to our `README.md` project file to easily see a project build status.

<img src="https://coryrylan.com/assets/images/posts/2019-11-17-building-angular-cli-projects-with-github-actions/github-actions-build-status-badge.png" alt="Angular CLI build status badge with Github Actions" bp="full-width 8--max float-center" class="img-border" loading="lazy" />

To add a badge to your `README.md` use the following syntax:

```markdown
[![build status](https://github.com/coryrylan/angular-github-actions/workflows/Build/badge.svg)](https://github.com/coryrylan/angular-github-actions/actions)
```

Using the Angular CLI and Github Actions, it has never been easier to create and test frontend Web apps. Check out the fulling [working demo repo](https://github.com/coryrylan/angular-github-actions as well as the current [build status](https://github.com/coryrylan/angular-github-actions/actions) for the demo!