Auto Committing with Github Actions

May 23, 2020

We usually have tools that can automatically format or lint code for us, running on file save or as a precommit hook.

However, if the tool takes a long time to run, it can be disruptive to your flow. Github Actions can be used to run commands on your behalf and commit the fixes back to your branch. Here’s how to configure an action that does that. In this example, I will use Scalafix as an example of a tool that can take a significant amount of time to run (on the order of minutes for larger projects), but any other tool can be substituted (e.g. eslint --fix).

Create a file in <project root>/.github/workflows, and put the following:

name: "Scalafix"
on: [pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
      with:
        ref: ${{ github.event.pull_request.head.ref }}
    - name: Set up JDK 1.8
      uses: actions/setup-java@v1
      with:
        java-version: 1.8
    - name: Run Scalafix
      # JVM settings as recommended by Scalafix
      env:
        JAVA_OPTS: -Xmx8G -Xms1G -Xss8M
      run: sbt all compile:scalafix test:scalafix
    - name: Commit files and push
      # We run git diff first to check if there are any files changed
      # before committing, since git commit will throw exit code 1 if there
      # are no files to commit
      run: |
        git config --local user.email "action@github.com"
        git config --local user.name "GitHub Action"
        git diff --quiet HEAD || git commit -am "Github Action: Scalafix"
        git push

This is a workflow that is triggered on the pull_request event. Feel free to tweak it trigger on other events.

By default, actions/checkout will checkout to a detached HEAD, since pull request refs (stored in refs/pulls/12/merge) are not regular branches (e.g. refs/heads/update-readme). In order to be able to able to commit back to the branch itself, checkout the branch corresponding to the pull request, using the ${{ github.event.pull_request.head.ref }} Github context variable.

Next, do Scalafix things, or insert the tool of your choice. Giving Scalafix enough memory is important to prevent the Github Actions runner from crashing from OOM errors. Github Actions runners are all standardized with a 2-core CPU and 7GB of memory, which seems to be sufficient for Scalafix.

Once the tool(s) is done running, there may be some changed files in the working directory. git commit returns an exit code of 1 if there are no files to commit, so check for the presence of changed files with git diff --quiet HEAD before committing all changed files, otherwise the workflow will appear to fail. Finally, push the commit to the branch.