Automating README Updates with Hashnode Articles Using GitHub Actions
Why Automate README Updates?
I was trying to spice up my github profile page by adding an automated list of my latest posts on hashnode to showcase. This is how I did it.
Tools Used
GitHub Actions: A powerful automation tool that integrates directly into GitHub repositories.
Hashnode API: A GraphQL API that allows you to fetch the latest articles from your Hashnode blog.
Python: To interact with the Hashnode API and manipulate the README.md file.
Step1: get your hashnode ID
This might not be necessary, but it looked tidier and more pythonical.
You can head over to https://gql.hashnode.com/?source=legacy-api-page playground and get your pub id by querying the api
query Publication($host: String = "surestride.hashnode.dev") {
publication(host: $host) {
id
}
}
{
"data": {
"publication": {
"id": "6714bcb54bcdc5c7d9980730"
}
}
}
You will need to change the url for your own url in the snippet
Step 2: Set Up the Hashnode API Request
The first step is to fetch the latest articles from your Hashnode blog. Hashnode provides a GraphQL API that allows you to query your blog posts. Here’s the Python code I used to retrieve the latest posts:
I used Postman to verify contents and then hacked them into a python script
import requests
# Hashnode API endpoint
url = "https://gql.hashnode.com"
# GraphQL query
query = """
query Publication(
$id: ObjectId="6714bcb54bcdc5c7d9980730"
) {
publication(
id: $id
) {
posts(first:3) {
edges {
node {
title,
brief,
slug,
url
}
}
}
}
}
"""
response = requests.post(url, json={"query": query})
data = response.json()
posts = data['data']['publication']['posts']['edges']
# Format posts for markdown
md_content = ""
for idx, post in enumerate(posts, start=1):
md_content += (f"{idx}. [{post['node']['title']}]({post['node']['url']})\n")
This script queries the latest three posts from my Hashnode blog and formats them into a markdown-friendly list.
Step 3: Update the README.md File
Now just update the readme file.
As I have other stuff in there, i only wanted to replace the relevant contents. To help with this I added comment before and after the text I wanted to replace in the README.md
<!-- BEGIN HASHNODE ARTICLES -->
1. [Why Python Decorators Are Essential for Clean and Readable Code](https://surestride.hashnode.dev/why-python-decorators-are-essential-for-clean-and-readable-code)
2. [Why you should user Gherkin in your user stories...](https://surestride.hashnode.dev/why-you-should-user-gherkin-in-your-user-stories)
3. [Best Practices for Python Type Annotations](https://surestride.hashnode.dev/best-practices-for-python-type-annotations)
<!-- END HASHNODE ARTICLES -->
Here is the script for your entertainment
start_marker = "<!-- BEGIN HASHNODE ARTICLES -->"
end_marker = "<!-- END HASHNODE ARTICLES -->"
# Read the current content of README.md
with open("README.md", "r") as readme:
content = readme.read()
# Find the markers
start_idx = content.find(start_marker)
end_idx = content.find(end_marker)
# Update content between markers or append new section
if start_idx != -1 and end_idx != -1:
updated_content = (
content[:start_idx + len(start_marker)] # Content before the start marker
+ "\n" + md_content.strip() + "\n" # New content
+ content[end_idx:] # Content after the end marker
)
else:
updated_content = content + f"\n{start_marker}\n{md_content.strip()}\n{end_marker}\n"
# Write the updated content back to README.md
with open("README.md", "w") as readme:
readme.write(updated_content)
print("README.md has been updated.")
Step 4: Automate with GitHub Actions
Using GitHub Actions you can automate script execution, theres a few workflows available and I jsut adapted one to my own use
name: Update README with Hashnode Articles
on:
schedule:
- cron: "0 0 * * *" # Run daily at midnight
workflow_dispatch: # Allow manual triggering
jobs:
update-readme:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.12" # Specify the Python version you're using
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install requests # Install requests if you don't have a requirements.txt
- name: Run Update Script
run: |
python automate_profile_hashnode_article_population.py
- name: Check if README.md is modified
run: |
git diff README.md
if git diff --quiet README.md; then
echo "No changes to commit"
exit 0
else
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git add README.md
git commit -m "Update README with latest Hashnode articles"
git push
fi
Key Points of the Workflow:
Schedule: The workflow is set to run daily at midnight using a cron expression (0 0 *), but you can also trigger it manually.
Python Setup: The workflow sets up Python 3.12 using actions/setup-python@v4. I had to explicitly define python version here (3.x gave me errors)
Dependencies: It installs the requests library, which is required for interacting with the Hashnode API.
Run Script: The script is executed to fetch the latest Hashnode articles and update the README.md file.
Git Commit: After the script runs, it checks if the README.md file has been modified. If changes are detected, it commits and pushes the updates to the repository.