Blog post publishing with GitHub Actions
For quite some time I have been regularly publishing new blog posts every Friday morning. I have the code for my blog in a GitHub repository. Each unpublished blog post that I have prepared in advance is in its own branch. To publish it, I just need to merge it with the main branch, which triggers the GitHub workflow I set up to deploy the blog.
I have a notification reminding me to do the merge on Friday morning. But while this does not take much time, I finally decided to look for ways to automate this last step. I quickly found the Merge Schedule GitHub Action, which seemed to do almost exactly what I needed: merge a pull request on a scheduled day. Creating pull requests for my post branches is not a huge effort.
To configure the action, I created a .github/workflows/merge-schedule.yml
file in my repository:
name: Merge Schedule
on:
pull_request:
types:
- opened
- edited
- synchronize
schedule:
- cron: 0 6 * * *
jobs:
merge_schedule:
runs-on: ubuntu-latest
steps:
- name: Obtain GitHub App Installation Access Token
id: githubAppAuth
run: |
TOKEN="$(npx obtain-github-app-installation-access-token ci ${{ secrets.GH_APP_CREDENTIALS_TOKEN }})"
echo "::add-mask::$TOKEN"
echo "::set-output name=token::$TOKEN"
- name: Run merge schedule action
uses: gr2m/merge-schedule-action@v1
env:
GITHUB_TOKEN: ${{ steps.githubAppAuth.outputs.token }}
I based the file on the file in the GitHub action documentation, but changed the schedule using cron syntax so that the action runs once a day in the morning instead of every hour. This allows me to specify only the publish date without time in the pull request description with the following syntax /schedule 2022-01-28
.
I also had to replace the automatically created secrets.GITHUB_TOKEN
token with the token I created myself. I learned the hard way that workflows do not trigger other workflows when they use the automatically created token. This meant that the post was not published, even though it was merged in the main branch, because the deployment workfklow was not triggered.
I initially tried to get it to work with a personal access token, but I could not find a way to give the action all the permissions it needed. The checks operations always failed with the following error message:
HttpError: You must authenticate via a GitHub App.
As the error message suggested, I ended up using a GitHub App. I could not find much documentation about it, but fortunately I stumbled across a very helpful blog post. It was enough to follow the steps in that post to get my workflow working:
I created a new GitHub App. I gave it a name and set its Homepage URL to the URL of my blog repository. I unchecked the Active option for the Webhook and added the following permissions:
- Actions: Read-only
- Checks: Read & write
- Contents: Read & write
- Metadata: Read-only (mandatory for apps and set by default)
- Pull requests: Read & write
After creating the app, I copied the App ID (six-digit value) from the top of the page and generated a private key using a button at the bottom of the page. I downloaded the private key locally.
Next, I clicked Install App from the sidebar at the top of the page and installed the app in my blog repository. After that, I was able to copy the installation ID from the URL of the page for that installation (seven-digit value).
I was now ready to generate a credentials token and a sample workflow script using a web page created by the author of the helpful blog post. I entered the three pieces of information I had gathered so far:
- the six-digit GitHub App ID
- the seven-digit installation ID
- the downloaded private key
I copied the generated credentials token value and used it to create a new actions secret in the Settings section of my blog repository called
GH_APP_CREDENTIALS_TOKEN
.I copied the first step of the generated sample workflow script into my final workflow script above and replaced the source for the
GITHUB_TOKEN
value with${{ steps.githubAppAuth.outputs.token }}
as seen in the second step of the sample workflow script.
That's it. When I now create a new pull request for a blog post with the schedule in the description, I can see that it is scheduled to publish on the selected day:
And in the Actions section of my blog repository, I can see that the Merge Schedule workflow runs every morning:
There is already a huge collection of GitHub actions. So even for someone like me who only knows the basics of GitHub actions, it's easy to create workflows to automate all sorts of tasks in a GitHub repository. Automating the publishing of my blog posts only took me a couple of hours, including testing.