[ About · Archive ]

Hugo with markdown and asciidoc

All done!

Building on the previous post, here is a summary of what I had to do to collapse two sites (one a date-oriented blog, and the other an outline-based gitbook) into a single site.

I loathe maintaining dates inside of files. As a customization, hugo is configured to lift the date from the file name first, then git data, and only after those two have been tried will it fall back to dates in the file header:

    - ":filename"
    - ":git"
    - ":default"

The permalink structure for blog posts is also explicitly configured to match the URL pattern used by Jekyll:

  posts: /:year/:month/:day/:slug

To preserve previous links, I’m also using ugly URLs!

uglyURLs: true

I am also generally unbothered about having a .html extension on pages. These are static html files after all. This does require index files to fix top-level section behavior, as described below.

I almost never use pre-defined themes. Call me picky, or whatever, but I prefer defining resources that behave the way I want them to. For hugo, this means creating layouts and supporting files.

Blog posts / markdown

For the blog, I used a “posts” layout. Which means the header for blog entries minimally contains the following:

layout: post
title: ...
author: ...

Specifying the layout in this way tells hugo to look for files in layouts/posts. I have two files defined there, one for the list of blog entries (list.html), and one for each entry (post.html). The contents for these two templates are pretty standard fare, and take advantage of hugo’s support for sections to create navigation between posts. This allows the date-based URL space to remain distinct from the book pages.

The posts directory contains an _index.md file that assigns the list of blog posts to the /blog/ path:

title: "Blog: Events and other (mis-)adventures"
url: "/blog/"

GitBook / asciidoc

Managing book pages was a little more challenging. The book sprawled across multiple directories as a hierarchy of topics. The gitbook display format also included a TOC along the left side, which I was going to need to emulate one way or the other.

In this case, I opted to define a type:

title: ...
weight: 1
type: book

The default sorting mechanism in hugo uses the page weight first. By explicitly specifying the weight, I can control the order of the pages in the book, which is tiresome, but also exactly what I want.

This yaml metadata needs to be present at the top of all files, both section indexes and asciidoc content. The type similarly instructs hugo to look for layout pages in a book subdirectory, for either lists or individual pages.

Navigation was a real challenge, as links within a section weren’t going to be enough.

For list pages, I ended up with a layout that would either use a partial to recursively list all content (used by the /about/ section), or would list all the pages in the current section followed by a list of all top-level sections including subsections of the current section. Sounds complicated, and it kind of is, but it provides reasonable navigavtion between sections, and that’s important.

Navigation for pages was also laborious. I created another partial to navigate to the previous or next page in the current section. If there wasn’t a previous or next page in the section, it links to the previous or next section instead.

Both of the partials use .Scratch to propagate context between scopes. Somewhat annoyingly previous and next were inverted. I could have gone back and adjusted all the page weights so the pages sorted into reverse order, or just flipped the link. Numbering from 1 to whatever makes more sense, so I flipped the links. I am sure this will confused future me at some point.

Anyway, maybe someone will find all of that cleverness useful. I had to figure a lot of this out because it wasn’t quite what I found from anyone else.

From Jekyll and GitBook to Hugo and Asciidoc, care of Github Actions

This won’t be a super chatty post. We have two websites for Game On! (our microservices text adventure): a jekyll-based markdown blog and a legacy-gitbook-based asciidoc book. For various reason, I want to combine them,and I woukd rather not spend gobs of time converting between markdown and asciidoc.

To keep things quick: I knew I wanted a static site generator, and I’ve used hugo before and found it fast, straight-forward and unconfusing. So in my mind, I’d already picked hugo.

I found these two posts on hugo with asciidoc:

The second references the first. The first is also referenced in a git issue about some issues with how hugo invokes external helpers like asciidoc. The bottom line is that I can use hugo to do what I want, but there are some tricks required to influence how asciidoc is invoked to get better output.

Thinking about deployment

The existing two sites use Travis. They’ve existed so long (and have been running so well) that I forgot how to set them up. And, in the interim, the travis-ci.org vs. travis-ci.com shift has happened, and for one of the repos in particular, it feels like the settings have disappeared entirely. So. I can either figure out what happened with Travis and set that up again, or go fiddle with the new shiny thing, GitHub Actions.

The new shiny toy won because of these two actions:

These two actions (found easily in the marketplace) are well-documented and do exactly what I want. I will likely fork/clone/copy them over time, but it was nice to just see them already there.

At this point, I’m nowhere near ready for deployment, so I haven’t done much with the second. I used the first to start putting together a workflow that builds a new hugo-based site, with baby steps: First set-up hugo, then set up asciidoc with the tweaks noted above.

So far, this experiment looks like this:

name: publish

    - hugo

    runs-on: ubuntu-latest
    - name: check out
      uses: actions/checkout@v1

    - name: Setup ruby
      uses: actions/setup-ruby@v1
        ruby-version: '2.x'

    - name: Setup Asciidoctor
      run: |
        gem install asciidoctor
        gem install asciidoctor-html5s
        gem install asciidoctor-diagram
        . ./wrap_asciidoc.sh
        asciidoctor --version

    - name: Setup Hugo
      uses: peaceiris/actions-hugo@v2
        hugo-version: '0.62.2'

    - name: Build
      run: |
        export PATH=$PWD/bin:$PATH
        which asciidoctor
        hugo --minify

I defined one custom script (wrap_asciidoc.sh) used in the ‘Setup asciidoctor’ step to create a wrapper script to add required arguments when hugo makes the syscall to invoke asciidoctor. The path is updated in the ‘Build’ step to ensure the customized asciidoc script is used by hugo.

Take a look at the build output for these steps

I’ll stop here for now. The next bit of work is all about setting up the base set of templates I’ll need.

Scripts for the win! Updating git repositories for the lazy.

I love scripts! I treat them as my extended memory. Blog posts used to do this, but life and children have eaten up the capacity I used to have for writing.

But I thought I would share my latest script for the lazy (which I have now duplicated several times. I know, I know. WET, DRY. I can’t be bothered). This script iterates over all of the git repositories in a sub-directory (where I have several related ones), fetches everyting, fast-forwards if it can, and otherwise tries to rebase on the upstream branch if there is one that matches.

There is an extra case statement at the bottom as I inevitably extend this to do more things specific to this group of projects. This kind of approach grew out of the scripts written for Game On!, which still work well, and do their extra duty reminding me what on earth I was doing the last time I worked on it.


Monsters and Metrics at SpringOne 2019

Two things collided in my brain this year ahead of SpringOne: Preparing a new talk from scratch covering the Micrometer (and the related Spring implementation), and learning everything I needed to know to be a Dungeon Master for my 10-year-old son and his friends.

Thanks to a brilliant suggestion from a friend, these two things collided in the talk, too. Which lightened the mental load (or at least reduced the amount of full stack swapping going on).

Github repository: ebullient/monster-combat with Spring Boot 2, WebFlux, and Micrometer

Debug gulp

I had a gulp build unhelpfully finishing with:

(node:12030) UnhandledPromiseRejectionWarning: null
(node:12030) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:12030) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

So I added this to my gulpfile:

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at: Promise', p, ', reason:', reason);

which netted me this:

Unhandled Rejection at: Promise Promise {
  <rejected> null,
   Domain {
     domain: null,
     _events: { error: [Object] },
     _eventsCount: 1,
     _maxListeners: undefined,
     members: [] } } reason: null

Not much better.

Let’s try debugging gulp! How do I do that again?

In VS Code, let’s create a debug configuration that is brain-bashingly simple. Add this to launch.json:

        "type": "node",
        "request": "attach",
        "name": "Attach to Remote",
        "address": "",
        "port": 9229,
        "localRoot": "${workspaceFolder}/resources",
        "remoteRoot": "Absolute path to the remote directory containing the program"

Now launch gulp with some options. I’m using npx here because I detest npm install -g:

$ npx -n --inspect-brk gulp build

This process will now wait until VS Code attaches. At which time, do check the “Uncaught Exceptions” box in the breakpoint section of the debug panel.

Press play, and .. there it is. A much clearer picture of what tipped over. I feel so much better.

(Hope this helps, future self)

Doing the scary thing: Mainstage at SpringOne

I will absolutely confess that it was daunting to start with, but that once I was out on the stage, everything was fine.

I will also confess to ad nauseum rehearsal. To reciting what I had to cram into two segments (one only 2 minutes long, and the other 2 minutes and 30 seconds) to every inanimate object in my hotel room: lamps, laptops, mirrors, showerheads, and I’m pretty sure my pillow while I was sleeping.

I didn’t really wrap my head around what I wanted to say until the night before. Things just didn’t fall into place before then. But hey, I lived! It was quite the experience.

Git with edit on an iPad?

We shall see how this goes over time, but so far? Oh hell yes.

I am experimenting with a cute little app (I have, sad to say, fallen head over feet into the Apple ecosystem. Other devices might seem cool, but not worth the gymnastics. Ecosystem stickiness is a thing.) that allows me to edit. code. from. my. iPad.

Why would I want to do that?

  • Device junky that I am, I totes splurged and got an iPad Pro, with its little keyboard.
  • I would really really really like to make more entries to this blog, for example. This is a nice alternative to hauling laptop around.
  • I want to see how far I can push this über tiny device thing, that ALSO happens to have a stylus (yes, I am one of those people that thinks better long-hand).

So exciting!

The one challenge with this, in particular, is that I can’t get the Jekyll preview that I could if I were running locally. The iPad Pro is quite the workhorse… but it doesn’t (yet, ha!) run Docker containers.

Oh, right. The app: Working Copy. It also integrates with iOctocat.


Jekyll templates with Docker containers

It took me a few tries (divided attention, grr), but I realized that after messing with blogs for over 10 years, I’ve seen all the things! Way back in the beginning was Movable Type (which I didn’t realize was still a thing), followed by PHP-based CMS like Textpattern and Nucleus CMS, and then a brief flirtation with Blogger (someone made me do it). I have somehow avoided ever having to maintain templates for WordPress (?!). These systems all come back to some pretty basic concepts around templating.

The one snag was loathing having to do anything with ruby. I have never had anything but grief and pain installing ruby anywhere. But hey! We have docker now! Put it in a container and forget about it. WOOT!