DEV Community

Cover image for Automating Sketch with GitHub Actions
Antonio Feregrino
Antonio Feregrino

Posted on • Edited on

Automating Sketch with GitHub Actions

Sometimes I use Sketch to create graphics for my content; however, I have always found it challenging to keep track of my work. Saving files here and there, versioning them with what I thought were sensible name schemes, only to realise that following such schemes requires a lot of mental effort.

My dream was always to be able to store my Sketch files in a Git repo; for some reason, I always thought this would be impossible, that Sketch's files were binaries impossible to properly version.

In the following post, I'll explain why I was wrong and how is it that you can version your Sketch files as plain text documents.

So I start with a base document, nothing too complex as I don't want to overcomplicate things:

Simple image

I have named this document tcsg.sketch; then, the next thing to understand is how Sketch actually saves these documents as a single file. The most important thing is that a .sketch file is nothing more than a .zip file with a bunch of .json files inside.

De-sketchify

We know that Git does not play nice with binary files but plays very nicely with plain text files – and JSON is just that. Why not decompress the .sketch file and keep track of the .json files alone; after all, when we want to open our file in Sketch again, we can compress those files again.

Decompress

With this in mind, we can use:

unzip -d tcsg tcsg.sketch
Enter fullscreen mode Exit fullscreen mode

To unzip the files into the tcsg repository. A quick glance into the newly unzipped repository gives us the following repo structure:

tcsg
├── document.json
├── meta.json
├── pages
│   └── 4FB4BFA1-4E01-4EE8-9962-F07A85622B2F.json
├── previews
│   └── preview.png
└── user.json
Enter fullscreen mode Exit fullscreen mode

I will not discuss the details of the files, as they are well explained in Sketch's documentation.

We should note that for optimisation purposes, the JSON files are saved with no indentation, and all the contents are stored in a single line. As I want to embrace the full power of Git, I need to format these files to be able to view the diffs.

Indent files

There is a useful tool to work with JSON fines from the CLI, it is named jq, I will use it to format the files with indentation:

find ./tcsg -type f -name "*.json" \
    -exec sh -c "jq . {} | sponge {}"  \;
Enter fullscreen mode Exit fullscreen mode

An explanation of the above command:

  • find ./tcsg: Searches for objects in the ./tcsg folder
  • -type f: Specifies, with f that we are looking for a regular file
  • -name "*.json": Filters the files we will find to all those ending in .json
  • -exec [command]: Executes a command for each file; within this command we can use {} to refer to the file name. The command to execute should be followed by \;
  • sh -c "jq . {} | sponge {}": In this case, the command that will be executed for each file is jq . [filename] | sponge [filename].

Delete previews (optional)

There is a previews folder where the last page edited by the user is preserved to be used as a thumbnail (and a preview) for the document. Again, this is an image, and for the time being, I will delete it since it is not needed for the file format.

rm -rf ./tcsg/previews/preview.png
Enter fullscreen mode Exit fullscreen mode

And that is it! we now have a Sketch document as a series of plain text files.

Sketchify

Of course, I want this process to be reversible – I want to be able to open my documents in Sketch again.

Create a temporary folder

I rather not modify the original directory, so I will create a copy of the working directory:

cp -r ./tcsg ./tcsg_temp
Enter fullscreen mode Exit fullscreen mode

Un-indent files

When I decompressed the files, I realised that the JSON files contained all the information in a single line; to respect that format, let's apply the jq -c . {} | sponge {} command to all those files. It is pretty similar to the format command above, with the difference of the -c flat of jq, which "compresses" the output.

find ./tcsg_temp -type f -name "*.json" \
    -exec sh -c "jq -c . {} | sponge {}"  \;
Enter fullscreen mode Exit fullscreen mode

Remove previews (optional)

Again, let's delete any preview image, for consistency with the process above:

rm -rf ./tcsg_temp/previews/preview.png
Enter fullscreen mode Exit fullscreen mode

Putting everything together

I placed all the above code into a single file called desketchify.sh:

#!/usr/bin/env bash

unzip -o -d tcsg tcsg.sketch

find ./tcsg -type f -name "*.json" \
    -exec  sh -c "jq . {} | sponge {}" \;

rm -rf ./tcsg/previews/preview.png
Enter fullscreen mode Exit fullscreen mode

Compress

Finally, in the compression step, we need to change directory to the temporary folder I have been working on. Then apply the compression step using the zip utility:

cd ./tcsg_temp; zip -r -X ../tcsg.sketch *
Enter fullscreen mode Exit fullscreen mode

The flag -r specifies that zip should recursively compress the files; the -X flag specifies that the compression should not save any extra file attributes.

At the end of this command I should have a .sketch file that can be opened in the app.

Cleanup

Lastly, let's clean up what I just did:

cd ..; rm -rf ./tcsg_temp
Enter fullscreen mode Exit fullscreen mode

Putting everything together

I placed all the above code into a single file called sketchify.sh:

#!/usr/bin/env bash

cp -r ./tcsg ./tcsg_temp

find ./tcsg_temp -type f -name "*.json" \
    -exec  sh -c "jq -c . {} | sponge {}" \;

rm -rf ./tcsg_temp/previews/preview.png

cd ./tcsg_temp; zip -r -X ../tcsg.sketch *

cd ..; rm -rf ./tcsg_temp
Enter fullscreen mode Exit fullscreen mode

Exporting artboards

But why stop there? what if I want to export the contents of the file as images? This will make it easy to share the assets with people who do not have Sketch installed at all!

This is surprisingly easy using GitHub Actions; all I need to do is use a kind of hidden gem in the Sketch ecosystem: their sketchtool utility, read more about it here. It allows you to interact with Sketch documents without human interaction.

In particular, the command that I am interested in the most is the one that exports artboards: sketchtool export artboards [file].

The tool itself is free to use for my purposes, but we need to download Sketch, I wrote the following code to achieve that:

wget -O sketch.zip \
    https://download.sketch.com/sketch-88.1-145978.zip
unzip -qq sketch.zip
Sketch.app/Contents/MacOS/sketchtool -v
Enter fullscreen mode Exit fullscreen mode

Leaving the sketchtool accesible via the Sketch.app/Contents/MacOS/sketchtool command. Obviously, be mindful of the version you are working with.

Full automation

It is finally time to put everything together using GitHub actions, I want to run all these steps only when the source files of the Sketch document change:

name: Sketchify

on:
  workflow_dispatch:
  push:
    branches: [ "main" ]
    paths:
      - 'tcsg/**'
Enter fullscreen mode Exit fullscreen mode

The jobs are organised in steps, where each step performs one and only one action:

jobs:
  generate_assets:
    name: Generate assets
    runs-on: macos-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Install dependencies
        run: |
          brew install jq
          brew install moreutils
      - name: Create Sketchfile
        run: ./sketchify.sh
      - name: Install Sketch
        run: |
          wget -O sketch.zip https://download.sketch.com/sketch-88.1-145978.zip
          unzip -qq sketch.zip
          Sketch.app/Contents/MacOS/sketchtool -v
      - name: Export artboards
        run: Sketch.app/Contents/MacOS/sketchtool export artboards tcsg.sketch --output=export --formats=jpg --scales=1,2
      - name: Save exported images
        uses: actions/upload-artifact@v3
        with:
          name: images
          path: export/
      - name: Save generated Sketch file
        uses: actions/upload-artifact@v3
        with:
          name: sketch-file
          path: tcsg.sketch
Enter fullscreen mode Exit fullscreen mode

This will rebuild my Sketch file every time new changes are made to the repository and will export all the artboards in it. The best part? the artefacts will be available for download in the GitHub UI:

Artifact available to download

Conclusion

I consider this to be a pretty decent way to store Sketch files as assets in a Git repository; of course, depending on the changes you make, the diffs may still be monstrous; but at least they are more trackable than as a single zip file.

To use the code described in this post you will need to make some adjustments to it to refer to your own files.

So, tell me, do you use Sketch? I hope this post was useful for you as it was helpful for me, I discovered so many things about Sketch. If you have any doubts, let me know on Twitter at @feregri_no. As always, find the code for this post in GitHub. Happy Sketch-ing.

Top comments (0)