GitHub Actions – Deploying an Angular App

Recently I built an Angular demo application that showcases some of the features provided by Angular. I will deploy this application to GitHub pages using GitHub Actions, a newly released CI/CD platform that can be used by open source repositories for free.

Since I already have a completed Angular project pushed to GitHub, all I need to do is to create a GitHub workflow to build, test, and deploy the Angular application to GitHub Pages. Before I start, I need to create a folder named .github/workflows at the root of my repository.

To learn more about GitHub workflow, please read workflow syntax for GitHub Actions article.

Create a GitHub Actions Workflow File

In .github/workflows, I added a yaml file for the workflow. And inside the workflow file, you can choose to add the name of your workflow by adding:

name: workflow name

If you omit name inside the workflow file, GitHub will set workflow name to the workflow file path relative to the root of the repository.

GitHub is flexible with however you want to name your workflow file, but the file has to be a yaml file and it has to be in the .github/workflows folder.

Setup Workflow Trigger

A workflow trigger is required for a workflow. I configured the workflow to trigger on pushes to the master branch:

on:
  push:
    branches:
      - 'master'

If you want to use a different trigger for your workflow, please take a look at events that trigger workflows article and on section of workflow syntax for GitHub Actions.

Create the Angular Build And Test Job

In GitHub Actions, jobs are defined by a series of steps that are executed on a runner. Each job runs on a different workspace, meaning that files and job side effects are not kept between jobs. In order to reduce build time and build complexity, I will keep as much work inside one job as possible.

Thus, the job below is created to build and test the Angular application:

jobs:
  build:
    name: Build and Test
    runs-on: ubuntu-latest
    steps: ...

The latest version of Ubuntu GitHub-hosted runner is utilized for this job. But if you want to use a different Github-hosted runner, pease read virtual environments for GitHub-hosted runners article.

Checking out source code

Since jobs do not pull down the source code by default, you need to explicitly tell the job to do so. Therefore, I add the following to steps of build and test job:

- name: Checkout
  uses: actions/checkout@v1

Setup Node.js

To setup Node.js used by the job, add the following under steps of the job:

- name: Use Node 12.x
  uses: actions/setup-node@v1
  with:
    node-version: '12.x'

Build and test job is configured to use Node.js version 12.x. If you wish to use a different version, please take a look at using Node.js with GitHub Actions article.

Run build and test

To build and test the Angular application, I added some supporting scripts to the application’s package.json file:

"build:ci": "ng build --prod --sourceMap=false --base-href /YOUR_REPOSITORY_NAME_HERE/"
"test:ci": "ng test --watch=false --code-coverage --source-map true"

As you can see, the test:ci script will also generate code coverage results for us, which will be used later down the line.

Note: To avoid MIME type error due to invalid path, you need to set your base-href to your repository name

Then, I add the following to the job to build and test our application:

- name: Install dependencies
  run: npm ci
- name: Build
  run: npm run build:ci
- name: Test
  run: npm run test:ci

Upload artifacts

To expose the results of the current job to the next job, I need to configure build and test job to upload the build artifacts. I also configured the job to upload the code coverage results, so they can be reviewed.

- name: Archive build
  if: success()
  uses: actions/upload-artifact@v1
  with:
    name: deploy_dist
    path: dist
- name: Archive code coverage result
  if: success()
  uses: actions/upload-artifact@v1
  with:
    name: deploy_coverage
    path: coverage

if: success() is used to make sure upload artifact only runs if all the previous steps passed. For more information, read context and expression syntax for GitHub Actions article.

Create Deploy Job

With build and test job completed, I can create the job that will deploy the Angular application to GitHub Pages. I add the following yaml below build and test job:

deploy:
  runs-on: ubuntu-latest
  needs: build
  steps:
      - name: Checkout
        uses: actions/checkout@v1
      ...

needs: build is used to tell GitHub to only execute deploy job when build and test job completed successfully.

Download build artifact

I add the following under steps in the deploy job to download build artifact from build and test job:

- name: Download build
  uses: actions/download-artifact@v1
  with:
    name: deploy_dist

To learn more, take a look at persisting workflow data using artifacts article.

Deploy to GitHub Pages

I use GitHub Pages Deploy Action to deploy our Angular build to gh-pages branch of the project repository:

- name: Deploy to GitHub Pages
  uses: JamesIves/github-pages-deploy-action@releases/v3
  with:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    BRANCH: gh-pages
    FOLDER: deploy_dist/YOUR_PROJECT_NAME_HERE

GITHUB_TOKEN is used to avoid providing a personal access token, to learn more about GITHUB_TOKEN, read authenticating with the GITHUB_TOKEN article.

Conclusion

Once you check in your workflow file, which should look similar to the yaml below, to your master branch, you should see a GitHub workflow starting in the GitHub Actions page. When the workflow is complete, you will see the build output and test coverage results in the artifacts section and a branch called gh-pages will be created.

name: workflow name

on:
  push:
    branches:
      - 'master'

jobs:
  build:
    name: Build and Test
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Use Node 12.x
        uses: actions/setup-node@v1
        with:
          node-version: '12.x'
      - name: Install dependencies
        run: npm ci
      - name: Build
        run: npm run build:ci
      - name: Test
        run: npm run test:ci
      - name: Archive build
        if: success()
        uses: actions/upload-artifact@v1
        with:
          name: deploy_dist
          path: dist
      - name: Archive code coverage result
        if: success()
        uses: actions/upload-artifact@v1
        with:
          name: deploy_coverage
          path: coverage
  deploy:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Checkout
        uses: actions/checkout@v1
      - name: Download build
        uses: actions/download-artifact@v1
        with:
          name: deploy_dist
      - name: Deploy to GitHub Pages
        uses: JamesIves/github-pages-deploy-action@releases/v3
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          BRANCH: gh-pages
          FOLDER: deploy_dist/angular-demo

Ensure that your repository has GitHub Pages enabled and the deployment is based off gh-pages branch. If this is set up properly, your Angular application should be deployed!