CI/CD with Angular 6 & Firebase & Bitbucket Pipelines

Automate build, test and deployment using Bitbucket Pipelines

Kai Niklas
Quick Code
7 min readDec 13, 2018

--

Motivation to invest in CI/CD

Modern development practices are reducing batch sizes of work significantly to, e.g., speed up time to market or get customer feedback earlier. Classic release cadences of once or twice a year are not applicable anymore to keep pace with the market in more and more industries. Instead releases are done in extrem cases every 11.6 seconds at amazon (status as of 2011). Building releases by hand, executing manual tests and handing over code to operations via ticket systems who then try to deploy by hand, are obviously not working any more.

Continuous Integration (CI) is a development practice which requires developers to integrate their code into a shared repository frequently, usually several times a day. Every check-in is verified by building the code and executing tests to detect problems early. [Compare: ThoughtWorks]

Continuous Deplyoment (CD) is a strategy to automatically deploy the code to production after all automated tests were passed during the CI phase. [Compare: Techtarget]

The 2017 State of DevOps Report motivates why CI/CD is beneficial to apply in comparison to classic approaches:

  • Quality: 5x lower change failure rate
  • Delivery: 440x faster lead time from commit to deploy
  • Delivery: 46x more frequent code deployments
  • Happy teams: 44% more time spent on new features and code
Excerpt of 2017 State of DevOps Report Infograph

The automation of build, test and deployment are the most typical steps which can be automated. In this article we will automatically build, test and deploy an Angular 6 application to Firebase hosting on every commit to the master branch. To automate the process we use Bitbucket Pipelines.

In earlier articles I already demonstrated CI/CD using Bitbucket Pipelines for 1) CakePHP via FTP to shared hosting server and 2) CakePHP to Heroku.

Outline

  1. Create Bitbucket Repository
  2. Create Angular 6 demo application
  3. Create Firebase project
  4. Configure Bitbucket Pipeline

Prerequisites

(1) Create a Bitbucket repository

First we create a new Bitbucket repository. You can find my demo repository here: https://bitbucket.org/kainiklas/angular-firebase-ci-demo

Create new Bitbucket repository

(2) Initialize Angular application

For this demonstration we create our Angular application with the Angular CLI. If you have not installed the CLI yet, use the following command to do so:

If you have already installed an older version of the angular CLI, use the following command to upgrade to the latest version as described here:

Then we can create our Angular skeleton application:

If you are interested in what you just created start it with the build in server:

The command should automatically start your browser and navigate to http://localhost:4200/.

Configure Test with Puppeteer

The default test behavior is to start Chrome and execute the tests. On our CI environment we do not have Chrome installed and we do not want to start an GUI based application anyway. Therefore, we utilize the puppeteer package which includes chrome and which we can then start in a headless mode which means without GUI.

First, we include a dev-dependency to puppeteer:

Then we configure our karma.conf.js to use ChromeHeadless instead of Chrome. Additionally, we need to use the — no-sandbox option, to make it work on our CI environment. Further, we only want to let the test cases run once which we can configure with the flag singleRun.

Commit to Bitbucket

Now we can share our local code with the remote repository in Bitbucket. You can find the git URL in the Bitbucket repository overview. For me the commands look like this:

The code should be visible in our Bitbucket repository now.

(3) Create Firebase Application

Create a new project on https://console.firebase.google.com/.

New Firebase Project

Install Firebase Tools

As we want to deploy to firebase we need the firebase tools. Let’s add them to our dev-dependencies and also install them globally on our machine:

Add build and deployment command

In our package.json we add the following two commands for production build and deployment. We will use them later in our pipeline.

Add configuration for Firebase

General Firebase project configuration:

Firebase hosting configuration. Let’s only deploy what is inside the dist folder which is created during the production build.

Commit Firebase Configuration

We need to push all changes now to our master branch.

(4) Setup Bitbucket Pipeline

Configure Pipeline

We navigate to our repository on Bitbucket and navigate to Pipelines in the left navigation menu. The first time we click on it, it may take some time until we see something (~ 5–10 seconds). We scroll down the page and choose JavaScript. Replace the content of the auto-generated bitbucket-pipelines.yml file with the following content and commit the file:

Note: We will get some errors as we have not configured the environment variables yet.

Explanation of the configured pipeline

Withimage: node:10 we tell our pipeline which docker container should be used for the build. For Angular 6 we require Node 10.x.

Using branches: master: we define, that the pipeline should run as soon as we check in code to the master branch.

With caches: -node we cache all node_modules which are downloaded during the installation of dependencies. This will speed up the subsequent runs.

To track deployment we use the command deployment: production which tells Bitbucket to consider this Pipeline as a production deployment. Find more information here on Bitbucket Deployments.

The last part are the scripts in the script: section.

  1. Install all required modules which are described in package.json
  2. Install required libraries to run chrome on the docker image as discussed in puppeteer’s troubleshooting documentation
  3. Execute test cases
  4. Build production ready artifacts
  5. Deploy artifacts to Firebase

If any command fails, the whole pipeline fails. That means, a failed test will prevent from deploying to the server (which is good as we do not want to break the production).

Set environment variables in Bitbucket

In our pipeline script we have defined the environment variable FIREBASE_TOKEN which is used to auth ourselves against Firebase. We get the token by typing on our command line the following:

The token we put into out pipeline in Settings > Pipeline > Repository variables.

Important: Never store passwords or other confidential information in git. Instead make use of, e.g., securely stored environment variables for passwords.

Now commit to master or rerun the pipeline, and you will see a deployment to Firebase.

Alternative Docker Image

The pipeline is currently “poisoned” with a statement to install required libraries for chrome. Without these libraries chrome is not working and quits with the following error:

A cleaner approach is to use a custom docker container, which includes these libraries. This is more friendly to maintain and speeds up the pipeline. How this could look like is described in puppeteer’s troubleshooting documentation.

Final thoughts

Additionally, we could define test or staging environments to which we deploy after code has been merged to a specific branch.

Want to read more?

Subscribe to my newsletter on modern software architecture. Grow your skills and become a better software architect.

Support my work and check out my book “Become a Better Software Architect — Actions and insights from practical experience”.

Become a Better Software Architect — Actions and insights from practical experience

Originally published at kai-niklas.de on December 14, 2018.

--

--

Kai Niklas
Quick Code

Software Architect | Software Engineer | Open-Minded | Paraglider | PhD | Innovation Principal Consultant | https://bettersoftwarearchitect.com