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
- Learning Markdown
- Generating Markdown Programmatically
- Generating Markdown Using a Library
- Automating README Generation
- Bringing It All Together
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 repo.
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 profile.
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
Links
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 profile 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:
- Introduction to Python Coding With Discord Bots
- Can You Actually Return Multiple Values From a Function in Python?
- Python 3.9 Features That Will Make Your Life Easier
Alternatively, here are some resources from the folks at Amazon (#ad):
- Effective Python: 90 Specific Ways to Write Better Python
- Python Tricks: A Buffet of Awesome Python Features
- Python Programming: An Introduction to Computer Science
Otherwise, take care!
Recent Code Posts
Unpacking the Jargon Around Compilers, Interpreters, and More
Today, we're going to get a little pedantic and try to define concepts like compiler and interpreter. Of course, I ultimately don't think it matters what the exact definitions are for practical...
Generally, people think of Python as a messy language because it lacks explicit typing and static type checking. But, that's not quite true in modern times. Surely, we can take advantage of type...