Github introduce new feature for repository that have special name as your nickname on Github. If you add README.md
there they display content in profile header.
I see first on twitter where my friend mention this. I like it and make similar version. Later I see this tweet about automate content of readme.
I’m not big friend with python and I need something else there that I make my own version in Golang using Github Actions.
First I created template for readme and use go to proceed template. I read RSS/Atom from my blog to update readme and I used just Golang standard library. Output is just printed to stdout.
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"text/template"
)
// Item type for RSS
type Item struct {
Title string `xml:"title"`
Link string `xml:"link"`
Desc string `xml:"description"`
GUID string `xml:"guid"`
PubDate string `xml:"pubDate"`
}
// Channel type for RSS
type Channel struct {
Title string `xml:"title"`
Link string `xml:"link"`
Desc string `xml:"description"`
Items []Item `xml:"item"`
}
// Rss type for RSS as root
type Rss struct {
Channel Channel `xml:"channel"`
}
func readFeed(url string) []string {
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
rss := Rss{}
decoder := xml.NewDecoder(resp.Body)
err = decoder.Decode(&rss)
if err != nil {
log.Fatal(err)
}
output := []string{}
for _, item := range rss.Channel.Items {
output = append(output, fmt.Sprintf("[%s](%s)\n", item.Title, item.Link))
}
return output
}
func main() {
content, err := ioutil.ReadFile("README.md.template")
if err != nil {
log.Fatal(err)
}
text := string(content)
blogURL := os.Getenv("BLOG_URL")
rssItems := readFeed(blogURL)
data := struct {
Title string
Items []string
}{
Title: "Last blog posts",
Items: rssItems,
}
t, err := template.New("readme").Parse(text)
if err != nil {
log.Fatal(err)
}
err = t.Execute(os.Stdout, data)
if err != nil {
log.Fatal(err)
}
}
For automating this I created workflow file .github/workflows/build.yml
.
name: Build README
on:
push:
workflow_dispatch:
schedule:
- cron: "0 4 * * *"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: "^1.14.3"
- run: go version
- name: Update README
env:
BLOG_URL: ${{ secrets.BLOG_URL }}
run: |-
go run main.go > README.md
cat README.md
- name: Commit and push if README changed
run: |-
git diff
git config --global user.email "readme-bot@github.com"
git config --global user.name "README-bot"
git diff --quiet || (git add README.md && git commit -m "Updated README")
git push
I run cron daily, you can change as you need it. I run my program go run main.go
and stdout is forward into file and commit into repository if diff exists. Github Actions manage access into repository and you don’t need add ssh key or something else. The blog URL is defined in repository <repo>/settings/secrets
with name BLOG_URL
, but can be directly set in this yaml file too as normal environment variable.