firebase-ci
Simplified Firebase interaction for continuous integration
Features
- Deploy to different Firebase projects based on Git Branch
- Automatically use commit message as deploy message
- Expose CI environment variables based on branch name
- Mapping of CI environment variables to Firebase Functions Config
- Optional Deploying of targets Functions, Hosting, Database (rules) and Storage (rules)
- Skip For Pull Requests
Getting Started
-
Generate a CI token through
firebase-tools
by runningfirebase login:ci
-
Place this token within your CI environment under the variable
FIREBASE_TOKEN
-
Install
firebase-ci
into your project (so it is available on your CI):npm install --save-dev firebase-ci firebase-tools
. If you don't wantfirebase-tools
as a dev dependency, it can be left out as it is installed automatically if it doesn't exist. -
Set different Firebase project names in
projects
parameter of.firebaserc
. The project aliases should match branch names like so:{ "projects": { "prod": "prod-firebase", "master": "dev-firebase", "default": "dev-firebase" } }
-
Add calls to the scripts within to your CI stages, here are a few example snippets:
Github Actions (.github/workflows/*.yml)
jobs: deploy: name: ${{ matrix.app }} Deploy runs-on: ubuntu-18.04 steps: - name: Checkout Code uses: actions/checkout@v2 ## Place other steps for installing deps, building, etc. here ## See the github-actions example for a full workflow # Deploy to Firebase project matching branch name in projects parameter of .firebaserc - name: Deploy To Firebase run: | $(npm bin)/firebase-ci deploy
Travis (travis.yml)
script: # Deploy to Firebase project matching branch name in projects parameter of .firebaserc - $(npm bin)/firebase-ci deploy
NOTES:
-
firebase-ci
can be used through the nodejsbin
OR installed globally (npm bin is used here since instructions include adding firebase-ci as a dev dependency) -
firebase-tools
will be installed (from@latest
) if it is not already installed locally or globally
-
Setting Project
There are a number of ways to set which Firebase project within .firebaserc
is being used when running actions. Below is the order of for how the project is determined (default at bottom):
-
FIREBASE_CI_PROJECT
environment variable (overrides all) - branch name (dependent on CI provider):
- Github Actions -
GITHUB_HEAD_REF
orGITHUB_REF
(refs/heads/
prefix is removed) - Travis-CI -
TRAVIS_BRANCH
- Gitlab -
CI_COMMIT_REF_SLUG
- Circle-CI -
CIRCLE_BRANCH
- wercker -
WERCKER_GIT_BRANCH
- drone-ci -
DRONE_BRANCH
- codeship -
CI_BRANCH
- bitbucket -
BITBUCKET_BRANCH
- Github Actions -
- fallback name (dependent on CI provider)
- Gitlab -
CI_ENVIRONMENT_SLUG
- Gitlab -
master
-
default
(must be set within.firebaserc
)
Examples
Examples are the same basic html file upload to Firebase hosting of different projects (or "environments") for different CI providers:
Why?
Advanced configuration of Firebase deployment is often necessary when deploying through continuous integration environment. Instead of having to write and invoke your own scripts, firebase-ci
provides an easy way to create/modify advanced configurations.
FAQ
-
What about Travis's
firebase
deploy option?Using the built in travis firebase deploy tool is actually a perfect solution if you want to do general deployment. You can even include the following to install stuff functions dependencies on Travis:
after_success: - npm install --prefix ./functions deploy: provider: firebase project: $TRAVIS_BRANCH skip_cleanup: true token: secure: $FIREBASE_TOKEN
This lets you deploy to whatever instance you want based on your branch (and config in
.firebaserc
).firebase-ci
is for more advanced implementations including only deploying functions, hosting
Commands
-
copyVersion
- Copy version frompackage.json
tofunctions/package.json
-
createConfig
- Create a config file based on CI environment variables (defaults tosrc/config.js
) -
deploy
- Deploy to Firebase project matching branch name in.firebaserc
(runs otherfirebase-ci
actions by default unless-s
is passed) -
serve
- Serve a the Firebase project matching branch name in.firebaserc
usingfirebase serve
-
mapEnv
- Map environment variables from CI Environment to Firebase functions environment -
project
- Output project name associated with CI environment (useful for commands that should be run for each environment)
copyVersion
It can be convenient for the version within the functions/package.json
file to match the top level package.json
. Enabling the copyVersion
option, automatically copies the version number when calling deploy
if the following config is provided:
"ci": {
"copyVersion": true
}
setEnv
Expose environment variables to CI based on current branch.
With a .firebaserc
that looks like so:
"ci": {
"setEnv": {
"master": {
"SOME_VAR": "some value"
"REACT_APP_ENV_VARIABLE": "val passed to react app"
},
"prod": {
"SOME_VAR": "some other value"
"REACT_APP_ENV_VARIABLE": "val passed to react app"
}
}
}
SOME_VAR
and REACT_APP_ENV_VARIABLE
will be exposed to environment variables of your CI based on branch. Meaning that on the master branch SOME_VAR
will be set to "some value"
createConfig
DEPRECATED
Create a config file based on CI environment variables (defaults to src/config.js
). Allows for creating files of different types based on the extension passed.
With the following environment variables:
GA_TRACKINGID
- Your google analytics tracking id
INT_FIREBASE_WEBAPIKEY
- API key of your integration/main Firebase instance (this can also be hard coded if you prefer since it doesn't)
PROD_FIREBASE_WEBAPIKEY
- API key of your production Firebase instance
And a .firebaserc
that looks like so:
"ci": {
"createConfig": {
"master": {
"version": "${npm_package_version}",
"gaTrackingId": "${GA_TRACKINGID}",
"firebase": {
"apiKey": "${INT_FIREBASE_WEBAPIKEY}",
"authDomain": "firebase-ci-int.firebaseapp.com",
"databaseURL": "https://firebase-ci-int.firebaseio.com",
"projectId": "firebase-ci-int",
"storageBucket": "firebase-ci-int.appspot.com"
}
},
"prod": {
"version": "${npm_package_version}",
"gaTrackingId": "${GA_TRACKINGID}",
"firebase": {
"apiKey": "${PROD_FIREBASE_WEBAPIKEY}",
"authDomain": "firebase-ci.firebaseapp.com",
"databaseURL": "https://firebase-ci.firebaseio.com",
"projectId": "firebase-ci",
"storageBucket": "firebase-ci.appspot.com"
}
}
}
}
building on master branch, produces a file in src/config.js
that looks like so:
export const version = "0.0.1" // or whatever version your package is
export const gaTrackingId = "123GA" // your google analytics tracking ID
export const firebase = {
apiKey: "<- your app API key ->",
authDomain: "<- your app name ->.firebaseapp.com",
databaseURL: "https://<- your app name ->.firebaseio.com",
projectId: "<- your app name ->",
storageBucket: "<- your app name ->.appspot.com"
}
export default { version, gaTrackingId, firebase }
Options
Options can be passed as flags or within an options object if calling action as a function
--project
- Project within .firebaserc to use when creating config file. Defaults to "default"
then to "master"
--path
- Path to save the config file. Defaults to src/config.js
deploy
firebase-ci deploy
Options:
Deploy to Firebase. Following the API of firebase-tools
, specific targets (i.e. functions, hosting
) can be specified for deployment.
Default
- Everything skipped on Pull Requests
- Deployment goes to default project
- If you have a
functions
folder,npm install
will be run for you within yourfunctions
folder -
copyVersion
is called before deployment based on settings in.firebaserc
, if you don't want this to happen, use simple mode. -
mapEnv
is called before deployment based on settings in.firebaserc
, if you don't want this to happen, use simple mode.
Simple Mode
Option: --simple
Flag: -s
Skip all firebase-ci
actions and only run Firebase deployment
Info Option
Option : --info
Flag: -i
Provide extra information from internal actions (including npm install of firebase-tools
).
Only Option
Option : --only
Flag: -o
Firebase targets to include (passed directly to firebase-tools)
Except Option
Option : --except
Deploy to all targets except specified (e.g. "database")
Force Option
Option : --force
Flag: -f
Delete Cloud Functions missing from the current working directory without confirmation
Skipping Deploying Functions
If you have a functions folder, your functions will automatically deploy as part of using firebase-ci
. For skipping this functionality, you may use the only flag, similar to the API of firebase-tools
.
script:
- $(npm bin)/firebase-ci deploy --only hosting
serve
firebase-ci serve
Options:
Serve using to firebase serve
. Following the API of firebase-tools
, specific targets (i.e. functions, hosting
) can be specified for serving.
Default
- Project alias matching branch name is served
- If there is no matching alias,
default
project is used
Only Option
Option : --only
Flag: -o
Firebase targets to include (passed directly to firebase-tools)
mapEnv
firebase-ci mapEnv
Set Firebase Functions variables based on CI variables. Does not require writing any secure variables within config files.
NOTE: Called automatically during firebase-ci deploy
Set the mapEnv
parameter with an object containing the variables you would like to map in the following pattern:
TRAVIS_VAR: "firebase.var"
Example
CI variable is SOME_TOKEN="asdf" and you would like to set it to some.token
on Firebase Functions you would provide the following config:
"ci": {
"mapEnv": {
"SOME_TOKEN": "some.token"
}
}
Internally calls firebase functions:config:set some.token="asdf"
. This will happen for every variable you provide within mapEnv.
skipDependenciesInstall
Skip installing of dependencies including firebase-tools
and node_modules
within functions
folder
skipToolsInstall
Skip installing of firebase-tools
(installed by default when calling firebase-ci deploy
without simple mode)
skipFunctionsInstall
Skip running npm install
within functions
folder (npm install
is called within functions
folder by default when calling firebase-ci deploy
).
project
Get name of project associated with the CI environment
Example
echo "Project to deploy to $(firebase-ci project)"
projectID
Get the projectId associated with the CI environment. Initially loaded from ci.createConfig.${branchName}.firebase.projectId
and falls back to project from project
command
Example
echo "Project ID from config $(firebase-ci projectId)"
branch
Get the branch associated with the CI environment (loaded from environment variables)
Example
echo "Branch name from ci env $(firebase-ci branch)"
Roadmap
-
setCORS
option for copying CORS config file to Cloud Storage Bucket - only setting non existent env vars with
mapEnv
- Support for Continuous Integration Tools other than Travis-CI