Firebase Functions in CI/CD context

2022-03-24

Preface

In this blog post I'll share with you a way to have fine grained control over the Firebase functions and their automated deployment using the modern CI/CD platforms and tools.

Firebase Functions intro


"Cloud Functions for Firebase is a serverless framework that lets you automatically run backend code in response to events triggered by Firebase features and HTTPS requests. Your JavaScript or TypeScript code is stored in Google's cloud and runs in a managed environment. There's no need to manage and scale your own servers." (source)

Firebase Functions in CI/CD context


The firebase cli is a really powerfull tool, that everyone can use to control the Firebase Environment from his machine, for example controlling testing and deployments. But in order to move faster, and especially working in a team, it's better if we can integrate a CI/CD tool in our workflow.

Nowadays almost every CI/CD provider offers similar functionality:

  • describe your pipeline, workflow, steps using a .yaml format
  • we gonna build and deploy your stuff

So I'm not going to focus on any particular tools and platforms for CI/CD. I want to focus on one particular part of the deployment of the Firebase Functions - how we can deploy just the functions, that we have worked on, and not all of them, this way reducing the overall time for testing and deployment.

The usual cli command to deploy your Firebase Functions looks like:

$: firebase -p < your project > deploy --only functions

This will deploy all functions that you have. When they are few, it's not a big deal. But once their count grows, the deployment process becomes slower. Then, we can specify all the functions by hand:

$: firebase -p <your project> deploy --only functions:function1,function2,function3

which will give us more control and we can define what to deploy.

Now, this approach works pretty fine when we are dealing with Firebase Functions from our machine, but how can we control the process when we are using a CI/CD tool?

Let's say we have a pipeline that is executing the lines above:

... - run: working_directory: ~/project/functions command: | ./node_modules/.bin/firebase --token ${FIREBASE_TOKEN} --project="foo" deploy --only functions

Here, there's no easy way to pass which exact functions we want to deploy. Imagine our whole backend in our big fat complex project is running as Firebase Functions. Do we always want to deploy all the functions, or just the last few you had to add or modify in order to deliver your feature?

Now, one way to overcome this "limitation" is to detect which are the functions you want to deploy. A possible solution could be specifying the functions you want to deploy in a file, commit the file and read it when the CI/CD tool kicks in.

For example, let's say we have a config file that looks like the following:

enabled=yes functions=function1,function2

And, if I have a little script, that parse the content of the config file:

#!/usr/bin/env bash CONFIG_FILE=".deployonly" configExists() { if [ ! -f $DEPLOYONLY ]; then return 1 fi return 0 # file exists } configEnabled() { enabled=$(grep "enabled" ${CONFIG_FILE} | cut -d '=' -f 2) if [[ $enabled == 'yes' ]]; then return 0 fi return 1 } getFunctionsForDeployment() { echo $(cat $CONFIG_FILE | sed -n 2p | cut -d '=' -f 2) } main() { if configExists && configEnabled; then echo $(getFunctionsForDeployment) fi } # run the script main

We'd be able to modify the invocation of the Firebase cli in the pipeline, similar to:

... - run: working_directory: ~/project/functions command: | ./node_modules/.bin/firebase --token ${FIREBASE_TOKEN} \ --project="foo" \ deploy --only functions:$(./myscript.sh)

This way, we can deploy particular functions or all functions.

Summary


In this short post I've tried to present a generic way of extending the current CI/CD workflows in the context of Firebase Functions by giving more control of what's being deployed.

Let me know what you think or how do you deploy your Firebase functions!