Angular DevOps Series (Part 1)

Are you searching for a solution for automating the Angular application development process? In this series, I’m taking you along with me in my journey towards a fully automated process for my Angular application. The series includes 4 parts:

Part 1: Establish Workflows from Source Code to Staging Environment Using GitHub, CircleCI, Docker, and Firebase.

Part 2: First Quality Gate: Static Testing.

Part 3: Second Quality Gate: Unit Testing.

Part 4: Third Quality Gate: E2E Testing.


Angular DevOps – Part 1: Establish Workflows from Source Code to Staging Environment Using GitHub, CircleCI, Docker, and Firebase

Overview

This is the first post in Angular DevOps Series. In this post, I’m going to establish workflows from Source Code to staging environment by setting up Auto Build and Auto Deploy pipelines with supports from GitHub, CircleCI, Docker, and Firebase. Now, let’s start to define our pipelines.

Auto Build Pipeline

The auto build aims to compile the Angular application into an output directory. It could be executed to build the whole application or a specific library. If there are any errors, auto build will provide as much as detail regarding the error to developers so they can fix the error.
With auto build, we will handle familiar user cases while developing an application feature:

  • Trigger auto build when making a pull request to merge a developer feature.
  • Trigger auto build when updating the pull request with new commit (or “revision”).
  • Trigger auto build to prepare AUT build for QA Testing.

Summary of Auto Build pipeline goals:

  1. Build the application when a pull request is created
  2. Build the application when pushing a new commit to a pull request
  3. Provide build result to the Pull Request on GitHub
  4. Notify build errors to developer
  5. Notify build status to team members

Auto Deploy Pipeline

The auto deploy aims to deploy the application to a staging or production environment. Because of the continuous nature of the pipeline, auto deploy can help you get application changes faster, identify potential build issues as they arise, and release more easily to your users. We also try to handle familiar cases with auto deploy. By doing this, we are able to apply our knowledge to real projects.

  • Trigger auto deploy to prepare AUT build for QA Testing.
  • Trigger auto deploy to prepare production build.

Summary of Auto Deploy pipeline goals:

  1. Trigger auto deploy when a pull request to staging branch is merged.
  2. Provide deploying status to pull request on GitHub.
  3. Notify deploying errors to developer.
  4. Notify new build to team members.

How to Create the Pipelines

Prepare application source code on GitHub and Git branch strategy

In this section, we are going to create a Git repository to manage source code using GitHub, as well as create branches following our Git branch strategy.
To create your repository, follow the article Create GitHub Repo.

As you can see in the above image, branching can get complicated. It seems that we need an orderly, controlled way of organising and dealing with them. So, we need a set of rules and conventions. We call it a Branching Strategy. In this Angular DevOps series, we are going to follow the Feature Branch Workflow.

  • The master branch should contain only the most stable and fully tested code. The master branch will never contain broken code. All end user deployments should be based on this branch.
  • The staging (release candidate) branch is for QA purposes. The code could be less stable than the code inside the master branch. After the code passes the QA process, it can be pulled back to the master branch.
  • Thedevelop branch is the main branch for developers. Each new feature should be developed inside a separate branch based on the develop branch.

You don’t have to follow the Feature Branch Workflow; there are other Git options out there, such as:

Establish Auto Build Pipeline

To establish the Auto Build pipeline, we have multiple choices for a CI system, such as CircleCI, Travis CI, Jenkins, and so on and so forth. However, for an easy and quick start, I chose CircleCI as my cloud CI system.
GitHub and Slack are integrated to CircleCI: GitHub is used for as the source code repository and Slack provides CI notifications.
To establish the Auto Build pipeline, there are 5 steps. They are as follows:

  1. Pull source code from a GitHub branch.
  2. Gathering all dependencies to install use NPM.
  3. Compile source code with Angular CLI.
  4. Save compiled source code to CircleCI work-space.
  5. Notify build status to Slack channel for developer and team member.

Now for the step-by-step process, open your browser and sign into CircleCI via your GitHub account to get started.

CircleCI will fetch entire GitHub repositories. Let’s choose a repository and setup a project.

Select a suitable Operating System and Language. Here, we chose Linux OS for your Operating System and Node as our Language for Angular source code. Next, follow the directions in the Next Steps section. After that, you can start building.

Go to the JOBS tab and make sure that the CircleCI build is running.

Open the config.yml file and define a step to pull source code from a GitHub branch.

version: 2.1
executors:
  my-executor:
    docker:
      - image: circleci/node:8.9.4-browsers
    working_directory: ~/mwd-angular-zerotohero-v7
jobs:
  setup-environment:
    executor: my-executor
    steps:
      - checkout
      - run:
          name: Show current branch
          command: echo ${CIRCLE_BRANCH}
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package.json" }}
            - v1-dependencies-

Then, gather all dependencies and install those using NPM (Node Package Manager) commands.

version: 2.1
executors:
  my-executor:
    docker:
      - image: circleci/node:8.9.4-browsers
    working_directory: ~/mwd-angular-zerotohero-v7
jobs:
  setup-environment:
    executor: my-executor
    steps:
      ...
      - run:
          name: Install local dependencies
          command: |
            sudo npm i npm@6.9.0 -g
            npm install
      - run:
          name: Build Node Sass
          command: npm install --unsafe-perm node-sass
      - save_cache:
          key: v1-dependencies-{{ checksum "package.json" }}
          paths:
            - node_modules
      - persist_to_workspace:
          root: .
          paths:
            - src
            - package.json
            - angular.json
            - Dockerfile
            - tslint.json
            - tsconfig.json
            - .firebaserc
            - firebase.json

Compile the source code and save the results to CircleCI workspace. Angular CLI converts Typescript to plain JavaScript and takes additional steps to further optimize resources.

build:
    executor: my-executor
    steps:
      - attach_workspace:
          at: ~/mwd-angular-zerotohero-v7
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package.json" }}
            - v1-dependencies-
      - run:
          name: Building
          command: |
            if [[ "${CIRCLE_BRANCH}" == "staging-"* ]]; then
              npm run build-staging
            elif [ "${CIRCLE_BRANCH}" == "master" ]; then
              npm run build-production
            else
              npm run build
            fi
      # Cache the dist folder for the deploy job
      - save_cache:
          key: v1-dist-{{ .Environment.CIRCLE_BRANCH }}-{{ .Environment.CIRCLE_SHA1 }}
          paths:
            - dist
      - persist_to_workspace:
          root: .
          paths:
            - dist

Now, to notify the developers and team members of the build status via a Slack channel, you are able to configure this manually on CircleCI; to do so, follow the guideline Enable Chat Notification. Another way you can do this is with Slack Orb, as shown below:

orbs:
  slack: circleci/slack@3.2.0
version: 2.1
executors:
  my-executor:
    docker:
      - image: circleci/node:11.8.0-stretch-browsers
    working_directory: ~/mwd-angular-zerotohero
jobs:
  ...
  build:
      ...
      - slack/notify:
          message: 'Building source code is completed.'
          webhook: $DEV_SLACK_WEBHOOK
      - slack/status:
          webhook: $DEV_SLACK_WEBHOOK

So far, you’ve been through the tutorial to get familiar with CircleCI, GitHub and Slack as well as establishing an Auto Build pipeline. In next section, we are going to establish Auto Deploy pipeline.

Establish Auto Deploy Pipeline

Docker is a software platform that allows you build, test, and deploy your application faster. A Docker image is a good option for releasing the AUT build to QA Testing as well as for management on the Docker Hub. With some simple commands, you are able to start running your application on a local Docker container for testing or review.

Another solution is using Firebase to deploy your application on a fast, secure, static, and production-grade hosting platform. You will receive an URL address to access to the application after the compiled source code is deployed to Firebase Hosting.

In this section, I’m going to use a Docker image to release AUT build to QA Testing and Firebase Hosting to release production.

Publish AUT Build to Docker Hub

  1. You need a Docker Hub account and a Docker Hub repo for AUT builds.
  2. Install Docker client on CircleCI container
  3. Build a Docker image and publish it to Docker Hub repo

You can create a Docker Hub account at here

First, let’s create a repository. Take a note to save the repository name and Docker Hub account, as we’ll need these pieces of information in the next steps of our Docker image build.

Next, publish Angular app as a Docker image from the build folder. You need to define a build-docker job. Docker client is required to authenticate and connect to the Docker Hub. The docker_layer_caching flag should be enabled to avoid rebuilding without any changes and speed up CI performance.

build-docker:
    docker:
      - image: circleci/cci-demo-docker-primary:0.0.2
    working_directory: ~/mwd-angular-zerotohero-v7
    steps:
      - attach_workspace:
          at: ~/mwd-angular-zerotohero-v7
      - run:
          name: Install Docker client
          command: |
            set -x
            VER="17.03.0-ce"
            curl -L -o /tmp/docker-$VER.tgz https://get.docker.com/builds/Linux/x86_64/docker-$VER.tgz
            tar -xz -C /tmp -f /tmp/docker-$VER.tgz
            mv /tmp/docker/* /usr/bin
      - setup_remote_docker:
          docker_layer_caching: true
      - deploy:
          name: Build and push Docker image
          command: |
            TAG="0.1.${CIRCLE_BUILD_NUM}"
            docker build -t $DOCKER_HUB_REPO:$TAG .
            docker login -u $DOCKER_LOGIN -p $DOCKER_PASSWORD
            docker push $DOCKER_HUB_REPO:$TAG
      - slack/notify:
          message: 'Building AUT Docker image is completed.'
          webhook: $DEV_SLACK_WEBHOOK
      - slack/status:
          webhook: $DEV_SLACK_WEBHOOK
      - slack/notify:
          message: 'Building AUT Docker image is completed.'
          webhook: $QA_SLACK_WEBHOOK
      - slack/status:
          webhook: $QA_SLACK_WEBHOOK

Publish Angular App to Firebase Hosting

  1. You need a Firebase account and to setup a Firebase project.
  2. Generate a Firebase Token CI.
  3. Install a Firebase tool on CircleCI container.
  4. Deploy a Firebase app use Firebase Token CI.

To setup an Angular project with Firebase, follow the guide line Firebase Hosting Quickstart.

Next, generate a Firebase Token CI using the command firebase login:ci and create an Environment Variable FIREBASE_TOKEN for the firebase token.

Open the config.yml file and define deploy job. You are able to ignore the Switch environment step, as it will automatically use the default Firebase environment. However, I suggest separating the deployment environment into developing and production. Please refer to the topic Firebase Multiple Environments for more details.

deploy:
    executor: my-executor
    steps:
      - attach_workspace:
          at: ~/mwd-angular-zerotohero-v7
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "package.json" }}
            - v1-dependencies-
      - run:
          name: Install Firebase Tool
          command: sudo npm install -g firebase-tools
      - run:
          name: Switch environment
          command: firebase use production
      - run:
          name: Firebase deploy
          command: firebase deploy --token "$FIREBASE_TOKEN"
      - slack/notify:
          message: 'Deploy Firebase application is completed.'
          webhook: $DEV_SLACK_WEBHOOK
      - slack/status:
          webhook: $DEV_SLACK_WEBHOOK
      - slack/notify:
          message: 'Deploy Firebase application is completed.'
          webhook: $QA_SLACK_WEBHOOK
      - slack/status:
          webhook: $QA_SLACK_WEBHOOK

And there we have it: the Auto Deploy pipeline is finished. I hope that we built CI jobs inside the pipeline to publish an AUT build as a Docker image and Production build as a Firebase application. Now, everything is ready for us to establish workflows for pipelines in next section.

Establish Workflows for Our Pipelines

To make a pipeline triggered by a specified scenario, we need to define a workflow in the config.yml file.

Example: When source code is merged to staging or master branch, a workflow will be triggered to run the pipelines Auto Build and Auto Deploy. By doing it this way, the source code will be pulled down from staging or master branch, dependency packages will be installed before compiling the source code, and an AUT or Production build will be automatically deployed.

Below are our workflows:

workflows:
  version: 2
  nightly:
    triggers:
      - schedule:
          cron: '0 0 * * *'
          filters:
            branches:
              only:
                - master
    jobs:
      - build
  commit:
    jobs:
      - setup-environment
      - build:
          requires:
            - setup-environment
      - build-docker:
          requires:
            - build
          filters:
            branches:
              only:
                - /staging-.*/
                - master
      - deploy:
          requires:
            - build
          filters:
            branches:
              only:
                - master

Verify Auto Build and Auto Deploy Pipelines

In this section, I’m going to trigger pipelines to react to changes from GitHub repository. This way, we start to verify established pipelines.

Trigger Auto Build Pipeline

I created a feature branch zth-001 from develop-1.0.0 branch to implement authentication for our application. Now, let’s make a pull request to merge zth-001 to develop-1.0.0 branch.

Because GitHub is integrated to CircleCI, the Auto Build pipeline is triggered when the feature pull request is submitted, and it will update the status (PASSED or FAILED) on the pull request.

Click on Details link to view the CI build details.

The Auto Build pipeline will also send a notification to the Slack channel about the build status.

The Auto Build pipeline is also triggered when new commit is pushed on the pull request.

Trigger Auto Deploy Pipeline

As a developer team, I want to publish an AUT build to QA Testing. A developer makes a pull request to merge develop-1.0.0 branch to staging-1.0.0 branch.

Once this pull request is merged, a CI build is triggered with Auto Build and Auto Deploy pipelines.

Notifications about new AUT build or any errors will be sent to the Slack channel. You are able to customize notification content to provide more or less build information.

To publish new version of production, make a pull request to merge staging-1.0.0 to master branch.

Once this pull request is merged, a CI build is triggered with Auto Build and Auto Deploy pipelines.

Notifications of a new Production build or any errors will be reported to the Slack channel. You are able to customise notification content to provide more or less build information.

Our Results


Summary

I hope you are enjoying the fruits of your efforts for completing the first article in the series Angular DevOps: Establish Workflows from Source Code to Staging Environment Using GitHub, CircleCI, Docker, and Firebase. Below are established workflows.

From here we are ready to start adding more steps to the workflow. Next thing, we are going to add some quality gates such as static analysis tool, and establishing Unit Testing and End-to-End testing to improve the quality at every step. Stay tuned for part 2!

Luong Mai
Luong Mai joined LogiGear in 2012 as an Automation Engineer. Currently, he works as a Software Developer for MOWEDE. He is responsible for developing front end applications (mobile, web) and DevOps in web development. Mai loves to automate everything in software development in order to maximize the productivity of development teams and is actively involved in developing software framework in MOWEDE
Luong Mai
Luong Mai joined LogiGear in 2012 as an Automation Engineer. Currently, he works as a Software Developer for MOWEDE. He is responsible for developing front end applications (mobile, web) and DevOps in web development. Mai loves to automate everything in software development in order to maximize the productivity of development teams and is actively involved in developing software framework in MOWEDE