Adding Recent Blog Posts to Your GitHub Readme
Tags: github, tutorial
Published: 2022-04-04 00:13:53

> This is my first post here. I am still learning, so If you see any issues with this post please let me know so that I can fix them.


GitHub is one of the most popular git repository websites, hosting a countless number of open source projects. Over the years, GitHub has grown into a diverse community, full of great code created by both solo web development hobbyists like myself and professional teams working for big companies like Facebook.

# Hi there. 👋

I'm ErrorGamer2000 (I may reveal my real name in the future, but for now I'll remain hidden behind this pseudonym). I am a solo web developer working my way through my junior year in high school, and I spent the majority of my "virtual school" year during the COVID-19 pandemic pretty much ignoring my classes, using the time to instead teach myself web development. For my first blog post, I want to share my first REAL JavaScript (well, really, it's TypeScript) project with you.

# Okay, we get it, back to the post already!

If you have used GitHub before, which I'm sure you have, you have most undoubtedly come across a profile readme before. While GitHub allows some level of profile personalization out-of-the-box, the profile readme feature allows you to add any content you want to your profile. Take [my profile](https://github.com/ErrorGamer2000) for example. As you can see, I have many different elements that are not a part of the normal GitHub profile.

Since these readme files provide your potential followers, customers, or even potential employers with a quick overview of both your activity and your ability, you want to put as much relevant content as you can on your readme. Just don't make it too long, or nobody will take the time to read it 😉.

Now, since you want your customers or employers to see the full extent of your skills, there are many tidbits of information that would be perfect to put on your profile, including any blog posts that you have made. If you are a blogger as well as a developer, then this is the perfect article for you (Even if you aren't feel free to keep reading, I don't mind).

As I planned to start blogging, I stumbled across this idea as I myself was looking to start a blogging presence of my own. As I looked around, I was able to only find [one easy-to-use GitHub action](https://github.com/marketplace/actions/blog-post-workflow) that would allow me to add a list of my posts to my readme. Sadly, I was disappointed to discover that this action had little formatting, only setting up the posts as a bulleted list of links, which was less than appealing to the eye.

# Alright, I'm lost. What is this post really about?

Okay, okay. I get it. A little much background, right? So, to the point. Unable to find a suitable solution, I began making one myself.

## The Action itself
I figure I've kept you long enough by now. This action is extremely simple to use, all you need to do is give it a simple URL, and it does the rest.

If you want to go ahead and see what it looks like, go ahead and [look at it on the GitHub Actions Marketplace](https://github.com/marketplace/actions/github-readme-blog-post-action).

## Setup

As I said, this action is very easy to use, and there is minimal setup. Let's go ahead and start with a basic workflow file:

```yml
name: Generate Blog List

on:
  push:
  schedule:
    - cron: "0 */1 * * *"
jobs:
  blog:
    runs-on: ubuntu-latest
    name: Fetch and Generate Blog Posts
    steps:
```

This workflow, as you may be able to see, runs every time you push new code to the repository (so, if you update the readme it will automatically replace the old blog posts in case you changed the configuration of the action) as well as on a set schedule of every hour.

Now, in order for this action to be able to work, the action needs to have the ability to read your readme, so let's go ahead and add a checkout step to start with. Add a new step that consists simply of a `uses` property:

```yml
    steps:
      - uses: actions/checkout@v3
```

This will ensure that the repository is fully loaded for the action to run in. Now that we are about ready to actually add the step to load our posts, there is one last thing that we need: our [RSS feed](https://rss.com/blog/how-do-rss-feeds-work/). Now the URL to your RSS feed will depend on the site that you are blogging on. For dev.to, it is `https://dev.to/feed/{username}`, where you replace `{username}` with your username. For example, my RSS feed URL here would be `https://dev.to/feed/errorgamer2000`.

## Configuring the Action

Now we are finally ready to set up the action. Let's add another step to our workflow, but we will give this one a name.

```yml
    steps:
      - uses: actions/checkout@v3
      - name: GitHub Readme Blog Post Action
        uses: ErrorGamer2000/github-readme-blog-post-action@v1
        with:
          feed_urls: "{rss_feed}"
```

Now, just replace the `{rss_feed}` with the URL to your RSS feed. You may have noticed that the option we are using is called `feed_urls` rather than `feed_url`. Plural, not singular. That's right: you can give multiple URLs for different feeds, each of them separated by a comma.

## Final configuration

Almost done, hang in there!

Now that we have added this action to our workflow, the action will automatically create all of the images it needs and save them to the folder `blog-post-list-output`. Go ahead. Save the file, commit it, and (if you are running a locally cloned repo) push your changes. Head over to the GitHub website for your repository and open the actions tab. You should see your brand new `Generate Blog List` action showing up there, with a little orange circle next to it. Wait until the action has finished (the circle will become a green checkmark) and open up the readme.md file.

*Uhhh, nothing happened. There isn't even the `blog-post-list-output` folder...*

Well, of course nothing happened. The action **did** make the changes to the repo, but we have not set up anything to actually save those changes. To do that, we need one final step: a `git commit` step. If you are handy with the `git` CLI, go ahead and do this yourself. I, however, prefer to use `stefanzweifel/git-auto-commit-action`. So, let's add another step to the workflow:

```yml
    steps:
      - uses: actions/checkout@v3
      - name: GitHub Readme Blog Post Action
        uses: ErrorGamer2000/github-readme-blog-post-action@v1
        with:
          feed_urls: "{rss_feed}"
      - name: Commit changed files
        uses: stefanzweifel/git-auto-commit-action@v4
        with:
          commit_message: Save Generated Blog Posts
          skip_checkout: true
```

This will save the changed files. Go ahead and try this out again, committing the changed workflow file and head over to the Actions tab again. Once your workflow has finished running, head back over to the readme.

*Ugh, not again. Still no posts on the readme. But we are making progress: the new folder is there and everything.*

Well, yes, there is nothing in the readme yet. But our workflow is complete and running smoothly, we simply have not told it where to put the list of posts.

## Telling the Action Where to Put the Posts

Now that our workflow is *work*ing 😏, all that is left is to actually make it put stuff into the readme. to do that, just slap a couple of comments in it somewhere, like so:

```md
<!-- blog-post-list:start -->
<!-- blog-post-list:end -->
```

Commit the changes again, wait for the workflow to finish, and then check the readme.

*OMG IT WORKED!!!!!!!*

Yes, congrats, you did it! you now have a working, automatically updated, list of posts on your readme! Have fun!🤗

# Customizing the Action

There are a number of different options that you can use with the action:

> Note: This table will most likely become out of date as I update the action. Head over to the [GitHub Repository](https://github.com/ErrorGamer2000/github-readme-blog-post-action) to see an up-to-date table.

<table>
  <thead>
    <tr>
      <th>Option Name</th>
      <th>Type</th>
      <th>Default Value</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code>feed_urls</code></td>
      <td><code>string</code></td>
      <td><code>""</code></td>
      <td>A (comma-seperated) list of RSS feed URLs to load posts from. This is the only required input.</td>
    </tr>
    <tr>
      <td><code>max_posts_per_url</code></td>
      <td><code>number</code></td>
      <td><code>5</code></td>
      <td>The maximum number of posts to show for each feed. If the number of posts is less than this, then all of the posts will be shown.</td>
    </tr>
    <tr>
      <td><code>position_indicator</code></td>
      <td><code>string</code></td>
      <td><code>blog-post-list</code></td>
      <td>The text of the comments that the action uses to inject the images into the README file. Everything between the two comments in the form <code>&lt;!-- position_indicator:start --&gt;</code> and <code>&lt;!-- position_indicator:end --&gt;</code> is replaced. Changing this can allow you to use multiple configurations for different feeds by using different markers for each.</td>
    </tr>
    <tr>
      <td><code>show_feed_data</code></td>
      <td><code>boolean</code></td>
      <td><code>true</code></td>
      <td>Whether or not to show the generated markdown describing the feed, which includes the title of the feed, the description of the feed, the <code>Read More</code> link, the last updated date, and the post count. Each of these can also be individually toggled with the following options. This will override any of the specific options, so it is better to disable/enable them specifically if you want to remove some elements.</td>
    </tr>
    <tr>
      <td><code>show_feed_title</code></td>
      <td><code>boolean</code></td>
      <td><code>true</code></td>
      <td>Whether or not to show the header containing the title of the feed. This will be formatted as an <code>h2</code> header. An option to customize this header will be in a future update.</td>
    </tr>
    <tr>
      <td><code>show_feed_description</code></td>
      <td><code>boolean</code></td>
      <td><code>true</code></td>
      <td>Whether or not to show the title of the feed that is provided by the RSS feed.</td>
    </tr>
    <tr>
      <td><code>show_read_more</code></td>
      <td><code>boolean</code></td>
      <td><code>true</code></td>
      <td>Whether or not to show the <code>Read More</code> link under the feed description.</td>
    </tr>
    <tr>
      <td><code>show_last_updated_date</code></td>
      <td><code>boolean</code></td>
      <td><code>true</code></td>
      <td>Whether or not to show the date and time of the last update of the list.</td>
    </tr>
    <tr>
      <td><code>show_post_count</code></td>
      <td><code>boolean</code></td>
      <td><code>true</code></td>
      <td>Whether or not to show the number of posts shown and the total number of posts provided by the RSS feed.</td>
    </tr>
    <tr>
      <td><code>show_post_date</code></td>
      <td><code>boolean</code></td>
      <td><code>true</code></td>
      <td>Whether or not to show the date of each post on the card.</td>
    </tr>
    <tr>
      <td><code>locale</code></td>
      <td><code>string</code></td>
      <td><code>"en"</code></td>
      <td>The locale of the project. This is used <strong>purely</strong> for formatting the dates of the cards and last update.</td>
    </tr>
    <tr>
      <td><code>time_zone</code></td>
      <td><code>string</code></td>
      <td><code>"UTC"</code></td>
      <td>A valid time zone to use for the last updated date.</td>
    </tr>
    <tr>
      <td><code>output_dir</code></td>
      <td><code>string</code></td>
      <td><code>"blog-post-list-output"</code></td>
      <td>The directory to store the post card images in. Must be in the root directory (i.e. no path separators <code>/</code> or <code>\</code>) and cannot include the characters <code>/\?%*:|"&lt;&gt;</code>.</td>
    </tr>
  </tbody>
</table>

# How It Works

This action does a little more than just parsing a simple RSS feed. It does start with this, however, and it uses this data as a backup for missing information. What it **does** do is use the link that it receives from the feed to fetch the HTML for the webpage of the blog, and then uses [The Open Graph protocol](https://ogp.me/) to find the preview image for the post as well as the title and description. Any of this missing information is taken from the RSS feed, if it is there. If an image is not found for the post, then it is removed from the card.

Happy coding! Please let me know how you feel about this post, and anything else you think I should add in the future!