Lately, I’ve been a fan of blog posts that are short and sweet. So, let’s do that.
We needed a way to deploy arbitrary branches to different environments via GitHub actions. We use Google App Engine to host our app.
Assumptions
This assumes you have already set up CI/CD. I’m going to gloss over a lot of the setup (like where to get env vars and all of that). This also assumes you’re handling everything else around building your app & changing the DB the app is pointed to.
Deploy Actions Workflow
I created a dedicated deploy actions workflow, which looks something like this:
name: deploy-stage
on:
workflow_dispatch # Manually trigger these deploys via GitHub's UI
jobs:
deploy:
name: Deploy staging
runs-on: ubuntu-latest
environment: staging # Tie your secrets & vars to a new environment
permissions:
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
# Needed since GitHub does not provide a nice way to get the current branch name
- name: Extract branch name
id: get_branch
run: echo "branch=$(echo ${GITHUB_REF#refs/heads/} | tr / -)" >> $GITHUB_OUTPUT
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: $
service_account: $
- name: Set up Google Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Deploy to Google App Engine
id: 'deploy-staging'
uses: google-github-actions/deploy-appengine@v2
with:
flags: |
--no-promote
--quiet
--version stage-$
--service-account=$
- name: Deployed
run: echo "$" >> $GITHUB_STEP_SUMMARY
Basically, this will:
- Extract a nice branch name
- Authenticate with GCP
- Install the gcloud CLI
- Deploy the app to app engine with the
--version
&—no-promote
flags.
The —version
and --no-promote
flags are important. --version
allows us to name this app
version in App Engine after the branch. --no-promote
might be the most important. This prevents
the deployment from being promoted to getting primary traffic. Aka, do not send this to production.
Deleting the Preview
When the branch is deleted in GitHub, we want to also delete the preview in App Engine (and any other cleanup you might want to perform).
name: delete-stage
on:
delete
jobs:
delete:
name: Delete staging
if: github.event.ref_type == 'branch'
runs-on: ubuntu-latest
environment: staging
permissions:
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Extract branch name
id: get_branch
run: echo "branch=$(echo $ | sed 's#refs/heads/##' | tr / -)" >> $GITHUB_OUTPUT
- name: Authenticate to Google Cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: $
service_account: $
- name: Set up Google Cloud SDK
uses: google-github-actions/setup-gcloud@v2
- name: Delete deployment
run: |
gcloud app versions delete stage-$ |:
This will run each time a branch is deleted. So make sure whatever is put in this workflow can fail
safely if there wasn’t ever a deploy. That’s what |:
is doing for me at the end of the delete
command. We’re telling bash basically || true
, so it’ll always be a passing job.