When I was looking for a solution for this blog, I had few demands, one of them was a integration with a git host, preferably a self-hosted one. I asked if someone knew of a solution like this, the few replies I got were negative. Alex over at the selfhosted.show Discord server found my idea intriguing, so my search continued.

I had given up on finding a platform with this integration, so I started looking for a general blogging platform. I already knew about Ghost, and it had to be good to be mentioned on the selfhosted podcast multiple times. However, I had not fully decided yet, I did even look at the (in)famous Wordpress setup. Ghost was still compelling, even after reading some posts from people migrating away from Ghost, my only takeaway from this was the lack of a native comment integration.

Now, fastforward a day and I have set up Ghost. I was learning the menus, as one should after getting something new and fancy and I noticed a middle-ground, Gist embeds! If you don't know what Gist is, it is GitHub’s solution for snippets that does not warrant a full repository.

I had ideas!


So there was some vital research which needed to be done.
* Could I use one gist with multiple files/snipptes?
* Could I make them look not terrible with my theme?
* Is there a easy API for Gists I could use?

A quick google search revealed that I could in fact embed a specific file, by just adding the parameter ?file=myFile.blah to the emded-url.
So, how do I stop the embed burning your eyes on my current theme on Ghost? There is always CSS, I know how it works, I just do not have any sense of making colours match and look good together. Turns out there are already stylesheets out there for Gist embeds, I choose one from this list that also matched one of the ones integrated in Prism.js.
It was time for getting technical. I was looking at GitHub’s documentation for the Gist API and found it, well, overkill. I just wanted to sync; I did not want to handle all the extra fuzz.

I was back to tinkering.

I wrote my first blogpost and experimented on how I wanted to attack this git-repo sync thingy. I looked at Ghosts API to see if I could easily grab a codeblock form the /content endpoint, it looked doable, but I already had done all this research and recon on the Gist approach that I continued looking into that idea.


While my initial though was going to be utilizing bash for this. I quickly realized that I either lacked the expertise, or that I had chosen the wrong tool for the job. There is this great book called “Automate the Boring Stuff with Python”, which I haven’t read, that came to mind. I started writing a python script which reads the content of a folder. I was still reading the Gist API but ended up on a tangent. I was not happy with how my Gist was “named” so I went looking for a way to rename it. While pressing a lot of different buttons, I found out that a Gist is actually a git repository. Which meant that I could probably use something to reference the gist in another repository. I spent a few minutes looking at sub-modules but discovered that the push flow was not the way I wanted to go. Shortly after I thought about referencing the Gist trough a file, which is the way I ended up with.

This script evolved drastically throughout the night, while it ended up on approximately a hundred lines, I went trough a lot of trial and error. The workflow I resulted in was temporarily cloning the gist repository to the disk, then copy all the files over to that directory before committing. I’m quite happy with the result, it’s not much, but it’s honest work. While you can run this script locally, I adapted it to run as a GitHub Action, meaning I can do edits on a computer without all the setup required for python.

There is definitely room for improvement, but it should work good enough for my use-case. I can see myself revisiting this script in the future while making better suited for use by others.


The code!

Now that's enough small talk, let's talk about the result.

This it the Python code I ended up with, it supports multiple directories, hence multiple Gists. The file connecting the folder to a gist is the .gist file, this has to to be formatted as user/gist-id where the ID is the string you see in your browsers address bar after creating the gist. The name of the folder doesn't really matter, but for making it easier for me to manage, I choose to call it the same as the blogpost.

As I mentioned earlier, I adapted it to work with GitHub actions. This change mostly consisted of handling the credential for the git push. I created a personal access token for my GitHub account with the scope of gist, and added it as a secret in my repository called GIST_TOKEN. In the action I set the environment variables for the password, email and username I wanted to attach to the commit.

Where is this magic stored?

I have put all my code in a GitHub repository for everyone to see!