How to Create a GitHub Action to Upload Posts From Hugo to Medium
Directly upload your latest post to Medium while uploading it to your Hugo blog

Motivation
Every time I added a blog on my personal website (which is very rare), I had to go to my Medium profile and import it manually. Once I got to know about GitHub Actions, my first idea was to automate this process. Also, this project was an attempt to better understand GitHub Actions.
Description
Whenever I push my code to the GitHub repo with a special commit message, our action takes the new post, uses the Medium API, and creates a new draft on my Medium account.
Here’s an example of a commit message:
added: blog PUBLISH post.md
OK, so let’s get into it.
Development
First of all, let me clear some things up. As this was my first GitHub action, I had no idea of how this all integrates. It took me time before it all started making sense, so what I will suggest for newcomers is creating two repositories: one for your action and another for testing that action.
The official setup guide is good, but it was still a bit confusing for me, as the Docker container example is very simple and covers just a Hello World
type.
Before we start, please read how to set up the environment variables in GitHub and also generate your APP_ID
, APP_SECRET
, and ACCESS_TOKEN
from Medium applications and Medium settings.
Create action.yml
First, let’s see the code:
So it’s pretty simple:
name
: The name of our action.description
: The normal description of our action.runs
: This is where it starts. Basically, it uses our Dockerfile and spawns it.branding
: This is just a normal branding that will be used in the marketplace.
Create Dockerfile
OK, so our Dockerfile will be using a Python Alpine image. Then, it will install the required modules. After that, we will be installing the Medium library that will be used later to provide an interface between Medium and our project.
Then it will copy our entrypoint.sh
as well as post.py
and then finally the Entrypoint defines the script that will run first.
Create entrypoint.sh
This is simple too. Basically, it finds our latest GitHub commit message and sends it to our post.py
script. We can easily do this by using Python (as we will be needing Python later), but for some reason, I wanted to use bash to traverse a JSON file. And to be honest, it was good. For those curious, take a look at the documentation for it.
The $GITHUB_EVENT_PATH
stores the path for the JSON file, which stores the information about our repo (commits, owners, etc.).
Create post.py
So let’s see the code for posting it to Medium. We will be using environment variables, as we mentioned at the start. BLOG_DIR
is the directory where your blogs are posted.
For example, content\blog
:
The code takes all the environment variables and also takes the commit message that is passed from entrypoint.sh
.
It checks whether the commit message contains PUBLISH
. If yes, then we go on matching it from all the files in the blog directory. Once it finds the blog name given in the commit message, it takes the file and sends it to our function, which will handle the Medium part.
The Medium part is simple. It’s taken from Medium’s official documentation. It takes APP_ID
and APP_SECRET
from the environment variables to create our client. Then it takes ACCESS_TOKEN
from the environment. Next, we get the user details and use the user id
to create the post.
The title for our post is the file name right now. We are sending the code in Markdown format, as our Hugo blog is in Markdown. And that’s it! Our post is uploaded to our Medium profile.
But wait a minute! What about those join split strips
? OK, so everything I said above is how things should go. Honestly, at one point, my GitHub action log was showing something like Post.MD == Post.MD => False
. After 30 minutes of testing and modifications, I discovered that the length of both strings was different because there were empty spaces. So that's why we need to strip them.
Other than that, join
is just to convert the list of strings to a string and split
is to get the content after the tag in our commit message PUBLISH
.
Sample main.yml
Let’s see a sample main.yml
for setting up in our personal projects.
We are using the checkout action because we will be requiring our repo content in the Dockerfile. Then I will call my action from the master branch.
Paste this into .github/workflows/
and you’re done.
You can find the full source code at @pr4k/Hugo-To-Medium. Thanks for reading.