Migrating from CircleCI to GitHub Actions
Since the introduction of GitHub Actions there's often no need any more to use an external CI/CD service. After I moved my blog repository from BitBucket to GitHub it was time to move my continuous deployment configuration from CircleCI to GitHub Actions as well.
Despite extensive documentation it took me a while to get started. However, once I figured out the basics, tranforming most of the CircleCI configuration to GitHub Actions format was pretty straightforward.
I started by following the workflow configuration instructions pretty closely. I created a build.yml
configuration file in the .github/workflows
folder of my repository:
name: Build
on: [push]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 10.x
This part is just the intialization and doesn't map directly to the CircleCI configuration. It specifies the following:
- The workflow will be triggered on every push.
- It will use a GitHub-hosted Ubuntu runner.
- It will check out the code.
- It will install 10.x LTS version of Node.js.
The process of installing NPM modules and caching them didn't directly align with the CircleCI approach although it was conceptually identical. I based my configuration on the example in the documentation:
- name: Cache NPM modules
uses: actions/cache@v1
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm
The cache key depends on the runner and the package-lock.json
file. If the latter changes, the prefix with runner information only is used as a fallback to find the best match.
From here on, the steps mostly differ from the ones in CircleCI only because of the differences in YAML syntax:
- name: Install dependencies
run: npm install
- name: Generate site
run: npm start
- name: Run tests
run: npm test
- name: Create ZIP archive
run: bash ./.scripts/archive.sh
- name: Deploy
env:
DEPLOY_USERNAME: ${{ secrets.DEPLOY_USERNAME }}
DEPLOY_PASSWORD: ${{ secrets.DEPLOY_PASSWORD }}
DEPLOY_APPNAME: ${{ secrets.DEPLOY_APPNAME }}
run: |
if [ "${GITHUB_REF}" == "refs/heads/master" ]; then
curl --fail -X POST --data-binary @out.zip https://${DEPLOY_USERNAME}:${DEPLOY_PASSWORD}@${DEPLOY_APPNAME}.scm.azurewebsites.net/api/zipdeploy
fi
The only exception is the final step:
- In GitHub Actions, all secrets aren't automatically injected as environment variables. The mapping needs to be specified explicitly for each secret in the step that uses it.
- Also, the information about the current branch is available in a different environment variable and in a different format.
To get everything working, there was one last change I had to make in the Bash script invoked from the Create ZIP archive
step. Since I couldn't find a way to control the working directory for the job in GitHub Actions, I couldn't rely on it in the script any more and had to make all paths relative. This change resulted in a more generic script any way:
#!/bin/bash
cd ./out
zip -r ../out.zip ./*
After I committed the changes to the repository (and entered the secret values in the repository settings), the workflow was automatically triggered on every commit as specified in the configuration file. It was time to remove the project from CircleCI to avoid duplicate deployments.