Sitemap

CICD with firebase hosting

3 min readApr 19, 2022

--

Press enter or click to view image in full size

Technology used

  • CICD Pipeline: Azure DevOps Pipeline
  • Hosting Service: Firebase Hosting
  • Source Code: Github
  • Secret Management: Azure KeyVault

Step1: Create an App in Firebase

From Firebase Console, you want to create an “App”. For exact steps, you can refer to the document here, https://support.google.com/firebase/answer/9326094?hl=en

or

you can also run following command

firebase hosting:sites:create SITE_ID

Make sure to tick “Also set up Firebase Hosting for this app.”

Press enter or click to view image in full size

For our use case, we created three projects (dev, stage, and prod) and each contains one web app.

Tip: you can label the project to be Prod. This helps engineers to visually differentiate between different projects.

Press enter or click to view image in full size

Step2: Get the required secrets

we need the project id and firebase deploy token.

project id can be fetched from

firebase console > project settings > general 

firebase deploy token needs to be generated

firebase login:ci

Step3: Set up secrets in Azure KeyVault

You need secrets to deploy frontend projects to firebase hosting. Since we are using Azure DevOps for the cicd pipeline, KeyVault was the de facto standard to share secrets.

Step3.1: Manually add secrets in Azure KeyVault

Step3.2: Link it with the library from Azure DevOps

Press enter or click to view image in full size

Step4: Prep YAML for the pipeline

I just added dev env in the sample below but you can extend YAML by just adding more env as you need. (Spacing might be wrong as copy&paste directly from vscode did not help with the correct spacing)

# webhosting.yaml
stages:
- stage: dev
jobs:
- template: templates/cicd.yaml
parameters:
env: dev
# templates/cicd.yaml
parameters:
- name: env
type: string
default: 'dev'
jobs:
- job: CI${{ parameters.env }}
displayName: CI ${{ parameters.env }}
variables:
- group: kv-${{ parameters.env }}
steps:
- task: NodeTool@0
inputs:
versionSpec: '16.x'
displayName: 'Install Node.js'
- task: Bash@3
inputs:
targetType: 'inline'
script: |
yarn install
yarn run build
- task: CopyFiles@2
inputs:
sourceFolder: '$(System.DefaultWorkingDirectory)/dist'
targetFolder: $(Build.ArtifactStagingDirectory)
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop${{ parameters.env }}/dist'
- task: CopyFiles@2
inputs:
sourceFolder: $(System.DefaultWorkingDirectory)
contents: 'firebase.json'
targetFolder: '$(Build.ArtifactStagingDirectory)'
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop${{ parameters.env }}
- deployment:
condition: in(variables['Build.SourceBranch'], 'refs/heads/main')
variables:
- group: kv-${{ parameters.env }}
strategy:
runOnce:
deploy:
steps:
- task: DownloadBuildArtifacts@1
inputs:
buildType: 'current'
artifactName: drop${{ parameters.env }}
- script: |
npm install -g firebase-tools
- script: |
cd drop${{ parameters.env }}
firebase deploy --token $(token) --project $(projectId) --force -m $(Build.BuildNumber)

ref:

--

--