Building Middleman using GitHub Actions

My site now posts from anywhere thanks to GitHub actions!

I used this blog as a jumping off point, but there were a few things I had to modify:

  • there's an update to the action/checkout action, so version bump.
  • to handle the node and ruby dependencies, I'm using the provided actions.
  • my changelog relies on having access to the full git history. By default, actions/checkout only pulls the HEAD commit. I added fetch-depth to fix that.

The final file in .github/workflows/main.yml:

name: CI
      - master
    runs-on: ubuntu-latest
      - uses: actions/checkout@v2
          fetch-depth: 0
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
          aws-access-key-id: {{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: {{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - name: Setup node
        uses: actions/setup-node@v1
          node-version: '13.x'
      - name: Install node dependencies
        run: npm ci
      - name: Setup ruby
        uses: ruby/setup-ruby@v1
          bundler-cache: true
      - name: Install ruby dependencies
        run: bundle install
      - name: Build static site
        run: bundle exec middleman build
      - name: Deploy static site to S3 bucket
        run: aws s3 sync ./build/ s3://{{ secrets.BUCKET_NAME }} --delete

After some pushing and (shameful) git commit --amend, it's working!

As always, I write in Drafts. In the course of writing this post, I wound up hacking some quick actions in Drafts to make this process easier.


The first takes a typical Draft and write it to Working Copy in the format that Middleman expects.

// compute the date
let date = draft.createdAt;
// compute the filename
let title =
let filename_title =
    .replace(/[^a-zA-Z0-9\-]/g, "-")
let filename = `${strftime(date, "%F")}-${filename_title}.html.markdown`
let template =

title: ${draft.displayTitle}
date: ${strftime(date, "%F %R %Z")}


let cb = CallbackURL.create();
    cb.baseURL = "working-copy://x-callback-url/write/";
    cb.addParameter("key", "itsasecretdonttell");
    cb.addParameter("repo", "");
    cb.addParameter("path", `source/articles/${filename}`);
    cb.addParameter("text", template);
    cb.addParameter("x-success", "working-copy://");

// open in Working Copy
let success =;

// error handling
if (success) {
else {;

The next action is a convenience action for me… since my previous action bases the file name on the CreatedAt date of the Draft (which is stable) I can wind up in a position where I work on a post for a few days before I post it. Running "Update Date to Last Edit" does this:

draft.createdAt = draft.modifiedAt;

Very ugly. Works just fine.

The last action uses Shortcuts to select a photo, place it in Working Copy in the correct month folder, and write the path back to the Draft.


Honestly… this post will be the first attempt… so let's see if it even works!

  • 2022-06-08 11:31:29 -0500
    Rename articles

  • 2021-01-05 13:02:39 -0600
    Add details about `fetch-depth`

    Thanks to @tmiller for his insight.

  • 2021-01-01 08:51:30 -0600
    fix the yaml

    I think the drafts action does something weird to `{{` when it's sent
    over urlschemes… I'll look into it.

  • 2021-01-01 08:45:14 -0600
    update tags

  • 2021-01-01 08:41:57 -0600
    Update Date

  • 2021-01-01 08:41:24 -0600
    update date to today

  • 2021-01-01 08:39:23 -0600
    fix filename

    I forgot that middleman requires this weird `.html.markdown` filename.

  • 2021-01-01 08:34:12 -0600
    Post: Building middleman using github actions

    This is my first post 100% from an iOS device!