CI/CD for Angular projects with Firebase and Github

Source of image

In a previous post, we managed to set up different environments for development and production, with the same crucial settings for both projects, but there is one concern left. At this point, we need to manually deploy to the development or production project. Firstly, we can easily forget to deploy. Secondly, we might accidentally deploy to the wrong project. If for some reason, the concept of Continous Integration and Continous Delivery is new, it is perfectly summed up by Jeff Delaney in under 2 minutes.

We can utilize GitHub Actions to automatically deploy on every push. We want to have an automatic build and deployment for production every time we push something.

In our repository's /.github/workflows folder, create a file called deploy@master.yml. The script below does exactly what we want to do on the master:

  • Creates a Ubuntu VM
  • Sets up Node on it
  • Retrieves dependencies from the cache, if it is possible
  • Install the project's dependencies
  • Runs unit tests
  • Builds the project
  • Deploys it to Firebase, both to my master and dev environment
name: deploy@master
on:
    push:
        branches:
            - master
jobs:
    main:
        name: Test, Build and Deploy
        runs-on: ubuntu-latest
        steps:
            - name: Check out code
              uses: actions/checkout@v2

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

            - name: Cache node modules
              uses: actions/cache@v2.1.1
              env:
                  cache-name: cache-node-modules
              with:
                  # npm cache files are stored in `~/.npm` on Linux/macOS
                  path: ~/.npm
                  key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
                  restore-keys: |
                      ${{ runner.os }}-build-${{ env.cache-name }}-
                      ${{ runner.os }}-build-
                      ${{ runner.os }}-

            - name: Install npm dependencies
              run: |
                  cd functions
                  npm install
                  cd ..
                  npm install

            - name: Run tests
              run: npm run test

            - name: Build production
              run: npm run build:prod

            - name: Deploy to Firebase@master
              uses: w9jds/firebase-action@v1.5.0
              with:
                  args: deploy --only storage,firestore,functions
              env:
                  FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
                  PROJECT_ID: todo

            - name: Deploy to Firebase@dev
              uses: w9jds/firebase-action@v1.5.0
              with:
                  args: deploy
              env:
                  FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
                  PROJECT_ID: todo-dev
deploy.yml

The first steps are best explained by the official GitHub Docs. Caching and installing npm dependencies are also well explained there. To make that work, we must set up a secret in the repo named FIREBASE_TOKEN, where the value is the token we get when we sign in from the CLI using firebase login:ci. The PROJECT_ID must match the project name in Firebase.

A successful run using already cached npm dependencies

Summary

We have implemented CD support for our Angular&Firebase project. We enhanced CI by failing as soon as possible using automated tests. To further improve, it might be a good idea to run tests on pull requests too. To do that, we only need to change the trigger at the beginning of the file from push to pull_request, remove the last three steps, and put this into a separate YAML file.