In this blog, we will see how to automate deploying a book created using rust-lang’s mdBook to Firebase using GitHub Actions. We will cover generating a deploy preview URL when a pull request (PR) is opened and updating the site when the PR is merged into the main branch.

Prerequisites Link to heading

This guide assumes that you have already installed the CLI tools mdBook and Firebase, and that you have created a Firebase project on its console which you will use to build and deploy to.

Sample GitHub repository Link to heading

I have created a sample GitHub repository based on the steps mentioned in this blog which can be found here. It has a sample PR for which a deploy preview URL was generated and, upon merging that PR, the book’s main site was updated. Look at the automatically triggered GitHub Actions here and the (empty) book here.

Let’s get started…

Initialize mdBook and Firebase Link to heading

Execute below command in the directory where you want your book’s data and configuration to be stored. I did it in the directory in which I had cloned my GitHub repository. This command initializes your book:

$ mdbook init .
Do you want a .gitignore to be created? (y/n)
y
What title would you like to give the book?
book
2023-02-02 20:41:59 [INFO] (mdbook::book::init): Creating a new book with stub content

All done, no errors...

$ ls
book  src  book.toml

Now let’s do Firebase related setup for the project. In the root of your GitHub repository:

  • Execute firebase init and choose the option Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys.
  • Next select your Firebase project for this mdBook project. This is the project you created on Firebase console.
  • When it asks What do you want to use as your public directory?, answer it with book. This is the directory containing your mdBook data.
  • Answer N to the question Configure as a single-page app (rewrite all urls to /index.html)?.
  • Answer Y to Set up automatic builds and deploys with GitHub?. This will open up GitHub in your default web browser and you’ll be asked to login to GitHub, if you haven’t already.
  • Mention your repository when it asks For which GitHub repository would you like to set up a GitHub workflow? (format: user/repository). If your current working directory is for your GitHub repository, Firebase will automatically detect and suggest that as the answer for this question.
  • Answer N to Set up the workflow to run a build script before every deploy?.
  • Answer Y to Set up automatic deployment to your site's live channel when a PR is merged?.
  • Mention the correct branch name when asked What is the name of the GitHub branch associated with your site's live channel?.

If all went well, firebase init will succeed and exit with:

$ firebase init
....
....
i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...

✔  Firebase initialization complete!

It will also create a .github directory that has the configuration for the GitHub Actions.

$ ls -a
.  ..  book  .git  .github  src  book.toml  firebase.json  .firebaserc  .gitignore

Configure GitHub Actions Link to heading

You should see two YAML files like below:

$ ls .github/workflows
firebase-hosting-merge.yml  firebase-hosting-pull-request.yml

As the names suggest, one is for the time a PR gets merged into the main branch, and another is for the time a PR is opened.

Modify the file firebase-hosting-merge.yml to look like below:

# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on merge
'on':
  push:
    branches:
      - main
jobs:
  build_and_deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Setup mdBook
        uses: peaceiris/actions-mdbook@v1
        with:
          mdbook-version: 'latest'

      - name: Build
        run: mdbook build

      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: '${{ secrets.GITHUB_TOKEN }}'
          firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_<firebase-project-id> }}'
          channelId: live
          projectId: <firebase-project-id>

It configures a GitHub Action that does the following when a PR is merged into the main branch:

  1. Clone the git repo
  2. Setup mdBook using the peaceiris/actions-mdbook GitHub Action
  3. Build the book/project.
  4. Deploy to Firebase

Modify the firebase-hosting-pull-request.yml file to look like below:

# This file was auto-generated by the Firebase CLI
# https://github.com/firebase/firebase-tools

name: Deploy to Firebase Hosting on PR
'on': pull_request
jobs:
  build_and_preview:
    if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Setup mdBook
        uses: peaceiris/actions-mdbook@v1
        with:
          mdbook-version: 'latest'

      - name: Build
        run: mdbook build

      - uses: FirebaseExtended/action-hosting-deploy@v0
        with:
          repoToken: '${{ secrets.GITHUB_TOKEN }}'
          firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_<firebase-project-id> }}'
          projectId: <firebase-project-id>

Above action does same things as the earlier one, but when a PR is opened.

Configuring GitHub secrets Link to heading

You will need a GitHub secret named FIREBASE_TOKEN for things to work. Generate this by doing:

$ firebase login:ci

It will open a web browser tab and authenticate you with Google. Upon successful authentication, it will print a token on the CLI:

$ firebase login:ci
⚠  Authenticating with a `login:ci` token is deprecated and will be removed in a future major version of `firebase-tools`. Instead, use a service account key with `GOOGLE_APPLICATION_CREDENTIALS`: https://cloud.google.com/docs/authentication/getting-started

Visit this URL on this device to log in:
https://accounts.google.com/o/oauth2/......

Waiting for authentication...

✔  Success! Use this token to login on a CI server:

<your-secret-token>

Example: firebase deploy --token "$FIREBASE_TOKEN"

This token needs to be stored in the Settings of your GitHub repository. Go to your GitHub repository; click on “Settings” tab of the repository; expand “Security and variables” and click on “Actions”; here click on “New repository secret”, create a secret named FIREBASE_TOKEN, and use the token printed on your CLI as its value.

Permissions for GitHub Actions Link to heading

While in the “Settings” of your GitHub repository, expand the section “Actions” and click on “General”; scroll to the section “Workflow permissions” and make sure to choose “Read and write permissions”. Click on “Save”.

Open and merge a PR Link to heading

You should be all set now. To test things, open a PR and see that GitHub Actions triggers a job that creates a deploy preview URL. When satisfied, merge the PR and see that GitHub Actions updates the book’s site to reflect what’s merged into the main branch.

That’s it! Link to heading

In case you have any suggestions/feedback, ping me on Twitter.