How to Automate Your GitHub Profile

How to Automate Your GitHub Profile Featured Image

GitHub profiles received a face lift in the last year, and now folks are coming with all kinds of cool ways to use them. If you’re not caught up in the hype, this article is a great place to start!

Table of Contents

The Special GitHub Repo

Every user of GitHub has a special GitHub repo that acts as their profile. To access it, you can use update the following link:

https://github.com/username/username

For example, here is my profile repoOpens in a new tab..

While this repo may seem special, there’s nothing really different from any other repo. You can store anything that you would store in a normal GitHub repo. The only difference is that the README file will be displayed on your profile page here:

 https://github.com/username

And again, here is my profileOpens in a new tab..

Learning Markdown

Because the README serves as the profile, you’ll probably want to learn some markdown. That way, you can properly format your profile to your needs. To help with that, I’ll lay out a brief cheat sheet here:

Headings

A heading of any level between 1 and 6 can be created using hashes:

# Heading 1

## Heading 2

### Heading 3

#### Heading 4

##### Heading 5

###### Heading 6

You can link any text using the following syntax:

[Text](https://some-link.com)

Lists

Ordered and unordered lists can be created as follows:

- This
- Is
- An
- Unordered
- List

1. This
2. Is
3. An
4. Ordered
5. List

Tables

Tables are probably one of the more complicated structures to replicate in markdown, but the general structure is as follows:

| Column Heading A | Column Heading B |
| ---------------- | ---------------- |
| Item 1A          | Item 1B          |
| Item 2A          | Item 1B          |

Miscellaneous

In addition to everything mentioned above, there are a few bonus features in markdown. For example, you can create a horizontal rule as follows:

---

Generating Markdown Programmatically

Now that you know some markdown, you can create a static profile. That said, we’re not here to create a static profile. We want something that builds itself. To do that, we’re going to lean on Python.

If you already know Python and markdown, this should be fairly straightforward. All you have to do is put your text into strings and dump it to a file. For example, here is a Python script that dumps “Hello, World!” to a README file:

with open("README.md", "w") as readme:
  readme.write("Hello, World!\n")

More than likely, of course, you probably want the Python script to do something more interesting. For example, maybe you have a blog, and you want to share a list of latest posts on your profile. It would be quite annoying to update that regularly, so why not automate it with Python? Here’s how you might collect your posts from your RSS feed:

import feedparser

def get_recent_posts() -> list:
    url = "https://therenegadecoder.com/feed/"
    feed = feedparser.parse(url).entries
    return feed

This code returns a list of posts from an RSS feed. We can then generate a list of them in markdown as follows:

import feedparser

def get_recent_posts() -> list:
    url = "https://therenegadecoder.com/feed/"
    feed = feedparser.parse(url).entries
    return feed

with open("README.md", "w") as readme:
  feed = get_recent_posts()
  for post in feed:
    readme.write(f"-[{post.title}]({post.link})\n")

See, that wasn’t so bad! But wait, there’s more.

Generating Markdown Using a Library

As much fun as you probably had learning markdown, it can be a nightmare. As a result, I made a markdown generation library called SnakeMD. Here’s how it works:

from snakemd import Document

readme = Document("README")
readme.add_paragraph("Hello, World!")
readme.output_page("")

Again, all this is going to do is dump “Hello, World!” to the README. And if you were particularly cynical, you might argue that it takes an extra line of code to do it. That said, look at how much cleaner it is to put together our list from earlier:

import feedparser
from snakemd import Document, MDList, InlineText

def get_recent_posts() -> list:
    url = "https://therenegadecoder.com/feed/"
    feed = feedparser.parse(url).entries
    return feed

readme = Document("README")
post_list = [InlineText(post.title, url=post.link) for post in get_recent_posts()]
readme.add_element(MDList(post_list))
readme.output_page("")

As always, I only mention SnakeMD as an alternative to writing the markdown by hand. You’re welcome to write your own Python script that manages all the markdown through strings.

Automating README Generation

Just because you have a Python script does not mean your README is automated. There’s one more step to go: continuous integration.

In general, there are many options for continuous integration. That said, the one we’ll be using is baked right into GitHub already: GitHub Actions. If you’re unfamiliar with GitHub Actions, it’s basically a tool for automation. Most folks use it for automated testing, but we’ll be using it for README automation.

Once you have a Python script ready to generate the README that you want, you can automate it as follows:

name: Deploy

on:
  push:
    branches: [ main ]
  schedule:
    - cron: '0 16 * * FRI'

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - name: Checkout repo 
      uses: actions/checkout@v2
        
    - name: Set up Python 3.9
      uses: actions/setup-python@v2
      with:
        python-version: 3.9
        
    - name: Download required libraries
      run: if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        
    - name: Generate README
      run: python readme.py

    - name: Commit wiki
      continue-on-error: true
      run: |
        git config --local user.email "action@github.com"
        git config --local user.name "GitHub Action"
        git add .
        git commit -m "Regenerated README"
        git push

This is an example of what a GitHub Action might look like for automating your Python script. Basically, I have this action scheduled for every Friday, which happens to line up with my publishing schedule. If you want something like this, feel free to copy the code into a file called “deploy.yml” at the following location: username/.github/workflows.

That said, even if you have a Python script called “readme.py,” there’s a chance that this action won’t work for you out of the box. You’re going to need a requirements.txt file with a list of all of your dependencies. Here’s what mine looks like:

snakemd
feedparser
subete

If you don’t have any dependencies, feel free to omit the requirements file.

Bringing It All Together

Once you have an actions file, a Python script, and a list of requirements, you can go ahead and dump all of them in your special repo. As a reminder, your special repo is located here:

https://github.com/username/username

Also, here’s an example of the appropriate repo layout:

/username
  /.github
    /workflows
      deploy.yml
  readme.py
  requirements.txt 

As soon as all the code is committed to main, the action should run for the first time. At that point, your initial README should be generated and committed to the repo. From there, it will be updated every Friday! To see what this looks like in practice, check out my profileOpens in a new tab. which is automated in exactly this way.

As you can probably tell, my profile does a little more than what we described here. If you’re interested in a follow up, let me know! Maybe I’ll make a template repo which you can use to generate a nice profile.

Regardless, that’s all I have for you today. As you can probably tell, I love Python, so here are some related posts:

Alternatively, here are some resources from the folks at Amazon (#ad):

Otherwise, take care!

Jeremy Grifski

Jeremy grew up in a small town where he enjoyed playing soccer and video games, practicing taekwondo, and trading Pokémon cards. Once out of the nest, he pursued a Bachelors in Computer Engineering with a minor in Game Design. After college, he spent about two years writing software for a major engineering company. Then, he earned a master's in Computer Science and Engineering. Today, he pursues a PhD in Engineering Education in order to ultimately land a teaching gig. In his spare time, Jeremy enjoys spending time with his wife and kid, playing Overwatch 2, Lethal Company, and Baldur's Gate 3, reading manga, watching Penguins hockey, and traveling the world.

Recent Code Posts