Skip to main content

Display RSS feed on your GitHub profile

· 3 min read
Stephan Hochdörfer
Head of IT Business Operations

Can our latest blog posts be rendered on our bitExpert GitHub organization page? This was the challenge I tried to solve. Apparently, yes. In this blog post, I cover all the steps needed to achieve that in this blog post.

First, we need a script to download a feed from our blog and extract the latest blog posts. Those will then be used to update a Markdown file. I decided to go with a simple PHP script as this was the quickest & easiest way for me.

Since Docusaurus does not only generate an RSS Atom feed but also a JSON representation, I decided to use the JSON feed as an input. Since JSON is easy to parse and process in PHP, I decided to use the JSON feed as the input for the script:

$jsonFeedUrl = 'https://blog.bitexpert.de/blog/feed.json';
$jsonFeed = file_get_contents($jsonFeedUrl);
$blogposts = json_decode($jsonFeed, true, 512, JSON_THROW_ON_ERROR);

Now that all blog posts are available, we can iterate over the list and collect the latest elements. Since the list contains the blog posts ordered by the publication date, it was enough to extract the first few items from that list:

$maxBlogpostsToRender = 4;
$latestBlogposts = [];
if(isset($blogposts['items']) and is_array($blogposts['items'])) {
foreach($blogposts['items'] as $post) {
$latestBlogposts[] = $post;

if (count($latestBlogposts) > $maxBlogpostsToRender) {
break;
}
}
}

In the next step, we can build the Markdown content that gets injected (or replaced) in the Readme.md file. Iterating over the array of $latestBlogposts and using the title and url information to render Markdown links is all we need to do:

$markdownBlogpostCollection = '';
foreach($latestBlogposts as $post) {
if(!isset($post['title']) || !isset($post['url'])) {
continue;
}

$markdownBlogpostCollection .= ' - ['.$post['title'].']('.$post['url'].')'."\n";
}

Finally, we can replace the "old" content in the Markdown file with the newly generated content. To replace the existing content, the Markdown file needs a start & end tag to help us identify where the blog posts are placed. I decided to use <!--- blog_start ---> and <!--- blog_end ---> as respective start and end tags. Since the "tags" are actually HTML comments, GitHub's Markdown rendering engine will strip them out when rendering the Markdown file, which is another bonus:

$readmeFile = dirname(__FILE__).'/../profile/README.md';
$markdownBlogpostCollection = "<!--- blog_start --->\n".$markdownBlogpostCollection."<!--- blog_end --->";
$readmeFileContents = file_get_contents($readmeFile);
$readmeFileContents = preg_replace('#<!--- blog_start --->([^{]+)<!--- blog_end --->#m', $markdownBlogpostCollection, $readmeFileContents);
file_put_contents($readmeFile, $readmeFileContents);

Now that we have the script ready, how to invoke it? GitHub Actions to the rescue. GitHub Actions can be run on schedule to act like a cron job. Also, GitHub Actions can access the repository itself and push changes. That's all we need.

In the GitHub repository, add a file .github/workflows/deploy.yml with the following content:

name: Deploy

on:
schedule:
- cron: '0 4 * * *'

jobs:
run:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v2

- name: Configure PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'

- name: Fetch RSS feed
run: php ./build/feed_update.php

- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Update Blog posts feed

The deploy job consists of 4 steps. First, we check out the latest version of the repository via the actions/checkout@v2 GitHub action. Next, the shivammathur/setup-php@v2 action configures the job to have PHP 8.2 installed. That allows us to execute the feed_update.php script, which also needs to be part of the repository. Finally, the stefanzweifel/git-auto-commit-action@v4 action allows to commit the changes back to the repository. No commit will be made if the file does not change because no new blog posts have been published.