DEV Community

Cover image for Go automate your GitHub profile README
Victoria Drake
Victoria Drake

Posted on • Originally published at on

Go automate your GitHub profile README

GitHub’s new profile page README feature is having the wonderful effect of bringing some personality to the Myspace pages of the developer Internet. Though Markdown lends itself best to standard static text content, that’s not stopping creative folks from working to create a next-level README. You can include GIFs and images to add some motion and pizazz (they’re covered in GitHub Flavor Markdown), but I’m thinking of something a little more dynamic.

At front-and-center on your GitHub profile, your README is a great opportunity to let folks know what you’re about, what you find important, and to showcase some highlights of your work. You might like to show off your latest repositories, tweet, or blog post. Keeping it up to date doesn’t have to be a pain either, thanks to continuous delivery tools like GitHub Actions.

My current README refreshes itself daily with a link to my latest blog post. Here’s how I’m creating a self-updating with Go and GitHub actions.

Reading and writing files with Go

I’ve been writing a lot of Python lately, but for some things I really like using Go. You could say it’s my go-to language for just-for-func projects. Sorry. Couldn’t stop myself.

To create my, I’m going to get some static content from an existing file, mash it together with some new dynamic content that we’ll generate with Go, then bake the whole thing at 400 degrees until something awesome comes out.

Here’s how we read in a file called and put it in string form:

// Unwrap Markdown content
content, err := ioutil.ReadFile("")
if err != nil {
    log.Fatalf("cannot read file: %v", err)
    return err

// Make it a string
stringyContent := string(content)

Enter fullscreen mode Exit fullscreen mode

The possibilities for your dynamic content are only limited by your imagination! Here, I’ll use the package to read the RSS feed from my blog and get the newest post.

fp := gofeed.NewParser()
feed, err := fp.ParseURL("")
if err != nil {
    log.Fatalf("error getting feed: %v", err)
// Get the freshest item
rssItem := feed.Items[0]

Enter fullscreen mode Exit fullscreen mode

To join these bits together and produce stringy goodness, we use fmt.Sprintf() to create a formatted string.

// Whisk together static and dynamic content until stiff peaks form
blog := "Read my latest blog post: **[" + rssItem.Title + "](" + rssItem.Link + ")**"
data := fmt.Sprintf("%s\n%s\n", stringyContent, blog)

Enter fullscreen mode Exit fullscreen mode

Then to create a new file from this mix, we use os.Create(). There are more things to know about deferring file.Close(), but we don’t need to get into those details here. We’ll add file.Sync() to ensure our README gets written.

// Prepare file with a light coating of os
file, err := os.Create("")
if err != nil {
    return err
defer file.Close()

// Bake at n bytes per second until golden brown
_, err = io.WriteString(file, data)
if err != nil {
    return err
return file.Sync()

Enter fullscreen mode Exit fullscreen mode

View the full code here in my README repository.

Mmmm, doesn’t that smell good? 🍪 Let’s make this happen on the daily with a GitHub Action.

Running your Go program on a schedule with Actions

You can create a GitHub Action workflow that triggers both on a push to your master branch as well as on a daily schedule. Here’s a slice of the .github/workflows/update.yaml that defines this:

      - master
    - cron: '0 11 * * *'

Enter fullscreen mode Exit fullscreen mode

To run the Go program that rebuilds our README, we first need a copy of our files. We use actions/checkout for that:

    - name: 🍽️ Get working copy
      uses: actions/checkout@master
        fetch-depth: 1

Enter fullscreen mode Exit fullscreen mode

This step runs our Go program:

- name: 🍳 Shake & bake README
  run: |
    cd ${GITHUB_WORKSPACE}/update/
    go run main.go

Enter fullscreen mode Exit fullscreen mode

Finally, we push the updated files back to our repository. Learn more about the variables shown at Using variables and secrets in a workflow.

- name: 🚀 Deploy
  run: |
    git config "${GITHUB_ACTOR}"
    git config "${GITHUB_ACTOR}"
    git add .
    git commit -am "Update dynamic content"
    git push --all -f https://${{ secrets.GITHUB_TOKEN }}${GITHUB_REPOSITORY}.git

Enter fullscreen mode Exit fullscreen mode

View the full code for this Action workflow here in my README repository.

Go forth and auto-update your README

Congratulations and welcome to the cool kids’ club! You now know how to build an auto-updating GitHub profile README. You may now go forth and add all sorts of neat dynamic elements to your page – just go easy on the GIFs, okay?

Top comments (5)

mikeralphson profile image
Mike Ralphson • Edited

Thanks, this spurred me on to add automatic updating to my profile README using node.js and an ejs template. Your workflow was very helpful.

I found a little wrinkle, in that git was trying to avoid empty commits and was exiting with error code 1. To avoid this, there's a helpful little trick on this StackOverflow answer:

darrencearnaigh profile image
Darren Kearney (he/him) • Edited

Pretty inspiring! I was lucky enough to also catch it while it's still showing this blogpost!

screenshot of victoriadrake's github generated README link to the blogpost about the making it

bhupesh profile image
Bhupesh Varshney 👾 • Edited

Wait a sec, Is go available by default? We don't have to use setup-go ?
Update I just checked, python is also there 🤔

bdougieyo profile image
Brian Douglas

I love this use case for parsing RSS for READMEs, it makes me miss Google Reader. 🙂

vicradon profile image
Osinachi Chukwujama


More innovation