Dynamic github readme with jbang and quarkus

6 mentions
Max Rydahl Andersen

Today Red Hat has its quarterly learning day and I’m using it to finish up loose
ends in some JBang experiments I had laying around.

First of is my attempt to make a JBang version of Frankels kscript based github readme updater. He writes about it here and here.

Idea is to have your github README repo automatically update with things like latest blogs, video post, talks, etc.

Then that becomes part of your github profile landing page.

Try it out

You can fork or copy https://github.com/maxandersen/maxandersen into your own personal repository and get hacking!

Just update the script and template to have the content you want!

If you add some other additional fetching of data online I would love to get a PR or issue with link to see :)

Below the script and workflow are described in a bit more detail if interested.

The script

The jbang script is using Quarkus - mainly just because it can but I actually saved some code and time as it comes pre-configured to use Qute for templating.

Full script is here it is just ~70 lines, but I’ll just call out the important bits below:

Dependencies

The start is setting up bootstrap and dependencies that JBang will handle:

///usr/bin/env jbang "$0" "$@" ; exit $?  (1)
//DEPS io.quarkus:quarkus-bom:${quarkus.version:2.2.0.CR1}@pom (2)
//DEPS io.quarkus:quarkus-qute (3)
//DEPS https://github.com/w3stling/rssreader/tree/v2.5.0 (4)
1 bash/zsh "shebang" line that also works as java comment. Lets you run the script directly
2 Quarkus 2.2 platform bom to manage versions - only use one currently so strictly not necessary
3 The script uses Qute - don’t need to specify versions as managed by the Quarkus bom
4 rssreader is a library giving a fluent api to read rss feeds. They only publish to jcenter which is no longer thus here using jbangs support to build a github repo using jitpack. Just need to provide the URL for the specific branch and everything is taken care of.

Quarkus command mode

To use Quarkus we need to tell Quarkus to run in command mode as we are not serving any content here just a cli - with that we can get injection working.

@QuarkusMain (1)
public class update implements QuarkusApplication { (2)

    @Inject
    Engine qute; (3)

    public int run(String... args) throws Exception { (4)
1 Define Quarkus main thus we will get called on start
2 Injecting of Qute for rendering from templates
3 The run method that will get passed any arguments. Which we don’t use in this example.

Fetching blog posts

In the core of the update I fetch my latest blogs using the rss reader. Could also fetch content from youtube, github commits, etc. but for now just adding blogs.

That code is as below:

Collection<Item> sorted = new PriorityQueue<>(Collections.reverseOrder()); (1)
RssReader reader = new RssReader();
Stream<Item> rssFeed = reader.read("https://xam.dk/blog/feed.atom");
sorted.addAll(rssFeed.limit(3).collect(Collectors.toList())); (1)

sorted.addAll(reader.read("https://quarkus.io/feed.xml").filter(p->p.getAuthor().get().contains("/maxandersen")).limit(3).collect(Collectors.toList())); (2)
1 Set up a list that is sorted in reverse date order
2 Read my personal rss feed using the RssReader, limiting to last 3 posts
3 Same from quarkus.io but this time add additional filter to have it only include the ones I authored.

Rendering README.adoc

Finally the rendering - here using Qute to generate a Asciidoc page.

Files.writeString(Path.of("readme.adoc"), qute.parse(Files.readString(Path.of("template.adoc.qute")))
        .data("bio", bio)
        .data("posts", sorted)
        .render());

The template is here and is a straightforward Qute template iterating over the posts and inserting the bio strings setup in the update script.

The workflow action

The github workflow is fairly trivial, add a .github/workflows/build.yml like this:

name: Update README

on:
  workflow_dispatch:
  schedule:
    - cron:  '47 1 * * *' (1)
  push:
    branches:
      - master

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository
        uses: actions/checkout@v2
      - name: jbang
        uses: jbangdev/jbang-action@v0.78.0
        with:
          script: update.java (2)
          scriptargs: "my world"
        env:
          JBANG_REPO: /root/.jbang/repository
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} (3)
      - name: Commit README and push
        uses: EndBug/add-and-commit@v7 (4)
        with:
          add: readme.adoc
          default_author: github_actions
          message: Automatically update README.adoc
1 Setup cron schedule to build every day
2 Run jbang script to generate readme file
3 Setup a GITHUB_TOKEN in repository to use from script
4 Commit and push readme

Hope that was useful showing the power and simplicity of Java when used with tools like JBang and Quarkus :)

Have fun!