HUGO

Deadly simple CMS with Trello for dummies

Hello,

Context / My goal

  • I needed a way to allow some people to manage/update some basic/important information on Hugo, but I do not want them to learn or install anything technical.
  • I also do not want to be attached to some forestry or similar visual CMS over hugo (and it’s still way too complicated for my public).
  • I read this brilliant blog post about using Trello to publish blog and trigger deploys on Netlify.
  • But it was not ready for Hugo, plus it was for a public Trello board, not a private one and it was still too technical to setup.

So here it is : A really simple way of using Trello to manage “some” Hugo content/data and deploy (on Netlify in my case), just by giving access to a simple private trello board.

And this works with the free plans. Many thanks to trello, slack and netlify for such great “free” tools. Not to forget gohugo.io, best thing ever since sliced bread invention.

The external tools

  1. Setup a trello account for managing the informations

    • Create a dedicated board, for example Hugo via trello
  2. Setup a slack account for triggering deploys

    • Create a workspace : myWorkspace for example
    • Create a dedicated channel, for example #web, in this workspace

3 - Go back to Trello, and use the butler.

  • Create a Board button butler with action = slack
  • First time you’ll need to link Trello/Slack giving autorisations.
  • For the slack action give those informations (will be for master) :
    • post message : publish-mysite-master for example
    • to Slack channel : #web
    • in workspace = myWorkspace
    • as Butler
  • Then do the same for the branch test
    • Create a Card button butler with action = slack
    • For the slack action give those informations:
      • post message : publish-mysite-branch for example
      • to Slack channel : #web
      • in workspace = myWorkspace
      • as Butler

Nota : we use 1 board and 1 card button because of the free account limitation.

4 - Go to your netlify site account linked to your gohugo/github site:

  • Find the Build & deploy / Build hooks section and add 2 hooks:
  • one hook for master : myNetlifyMasterHookUrl
  • one hook for your dev branch : myNetlifyBranchHookUrl

5 - Go back to Slack and add 2 'outgoing webhook` applications

  • chanel : #web
  • trigger word : publish-mysite-master
  • url : myNetlifyMasterHookUrl

and

  • chanel : #web
  • trigger word : publish-mysite-branch
  • url : myNetlifyBranchHookUrl

6 - Do not forget to add butler application to your #web chanel.

Now, you have the basic infrastructure for this :

 Trello => update informations (see below)
 => Button to deploy branch or master
 => Buttler send message to Slack
 => Slack get the message, find the Outgoing Hook
 => call the Netlify hook URL for deploy.
 => Netlify reprocess your hugo site, then get a fresh .json ...
 => ... and create a new version of the web site.

The Hugo part

1 - Identify in your hugo site what are variables/information you want to manage thru Trello
2 - Adapt your code to choose between variable from config.toml or from Trello (see below my example partials)

The dummy part

Then, people without any technical knowledge can:

  • Modify the trello
  • click on the publish button.

It just works.

Configure your Trello board

This is the trello made for the code below. Obviously you have to adapt it to your use case.
Look at the Hugo information below to see the link between trello cards and hugo code

1 - Create one list Manage Web from Trello for example

  • Two cards on this list :
    • Title : `Opening``
    • Due Date : the date you want for opening (instead of site.Params.global.dateopen)
      and
    • Title : `Close``
    • Due Date : the date you want for closing (instead of site.Params.global.dateclose)

2 - We will manage the eventually forced status season using a tag on the first card.

  • Create 2 tags CLOSE & OPEN
  • In my use case, If one of this tag is present on the opening card, this will allow us to eventually compute the real open status.

Detailed Hugo partials and setup

I’ll take a very simple example (3 variables for camping opening dates), but you’ll adapt easily to your use case. Basic same principle.

We request .json information from Trello, and use them instead of the site.Params ones.

Credential for accessing private Trello board

  • You need to get credential key and token
  • You need to put them in your system parameters or in Netlify parameters, but never on your git

Get credentials from Trello

Local system

export HUGO_PARAMS_TRELLO_KEY=mykeyabcdefg123456789
export HUGO_PARAMS_TRELLO_TOKEN=mytoken123456789abcdefg

On Netlify

  • Find the Build & deploy / Environnement section
  • Add your 2 HUGO_PARAMS_TRELLO_KEY and HUGO_PARAMS_TRELLO_TOKEN keys.

Actual config.toml

[params.global]
        statutsaison        = "close"       # open / close
        dateopen            = "2020-06-06"  # AAAA-MM-JJ
        dateclose           = "2020-09-14"  # AAAA-MM-JJ

Actual open.html partial

{{ $_dho := site.Params.global.dateopen | time }}
{{ $_dhc := site.Params.global.dateclose | time }}
{{ $_status_open = site.Params.global.statutsaison }}

Add a new section on config.toml

Look at the cards link in Trello and add them here.

[params.trello]
    # Use Trello as data source
    enable      = true
    board_url   = "https://trello.com/myTrelloBoardUrl"
    key = "" # DANGER : Only for local test. DO NOT PUT YOUR CREDENTIALS IN GIT. Use getenv
    token = "" # DANGER : Only for local test. DO NOT PUT YOUR CREDENTIALS IN GIT. Use getenv

    [params.trello.open]
        card_open_url    = "https://trello.com/c/myTrelloCardOpenUrl"
        card_close_url   = "https://trello.com/c/myTrelloCardCloseUrl"

    # Cache for Trello json trigering a fresh one
    [caches]
    [caches.getjson]
        dir = ":resourceDir/_gen"
        maxAge = "5m" # "24h" / 0 = désactivé / -1 = forever

Then you have to add this partial in your /partials.

partials/trello_json_card_info.html

<!-- Only infos from one card -->
{{ $card := .card | default "" }}
{{ $j_url_param := printf "trello.open.card_%s_url" $card }}
{{ $j_url := .context.Param $j_url_param }}

<!-- DEV ONLY do NOT put it in .git. Use getenv outside your computer
   site.Params.trello.key
   site.Params.trello.token -->
{{ $j_key   := getenv "HUGO_PARAMS_TRELLO_KEY" }}    
{{ $j_token := getenv "HUGO_PARAMS_TRELLO_TOKEN" }} 

<!-- Get le json from trello -->
{{ $url_card  := printf "%s.json?key=%s&token=%s" $j_url $j_key $j_token }}
{{ $json_card := getJSON $url_card }}

<!-- Initialisation des variables à retourner -->
{{ $date    := "" }}
{{ $name    := "" }}
{{ $forced  := "" }}

{{- range $key, $val := $json_card }}
   {{- if eq $key "due" }}
      <!-- Transforme la date en chaine caractères AU FORMAT pour partial open.html -->
      {{ $_fdate := "2006-01-02" }}
      {{ $date = dateFormat $_fdate $val}}
   {{- end }}
   {{- if eq $key "name" }}
      {{ $name = $val}}
   {{- end }}
   {{- if eq $key "labels" }}
      <!-- Itération pour obtenir si besoin le statut forcé  -->
      {{- range $k1, $v1 := $val }}
         <!-- On cherche le statut d'ouverture du label -->
         {{- range $k2, $v2 := $v1 }}
            {{- if eq $v2 "CLOSE"}}
               {{ $forced = "close" }}
            {{- else if eq $v2 "OPEN" }}
               {{ $forced = "open"}}
            {{- end }}
         {{- end }}
      {{- end }}
   {{- end }}
{{- end }}

<!-- Return a dict with card informations -->
{{- $infocard := dict "card" $card "name" $name "date" $date "forced" $forced }}
{{- return $infocard }}

And you can adapt your previous code like this for example :

New open.html partial

{{ $_dho        := "" }}
{{ $_dhc        := "" }}
{{ $card_open   := "" }}
{{ $card_close  := "" }}
{{ if site.Params.trello.enable }}
    {{ $card_open   = partial "trello_json_card_info.html" (dict "context" . "card" "open" ) }}
    {{ $_dho = $card_open.date | time }}
    {{ $card_close  = partial "trello_json_card_info.html" (dict "context" . "card" "close" ) }}
    {{ $_dhc = $card_close.date | time }}
{{ else }}
    {{ $_dho = site.Params.global.dateopen | time }}
    {{ $_dhc = site.Params.global.dateclose | time }}
{{ end }}

And

{{ $_forced := false }}
{{ $_forced_status := "close" }}
{{ if site.Params.trello.enable }}
    {{ if ne $card_open.forced "" }} <!-- Available because we already called trello_json_card_info.html -->
        {{ $_forced = true }}
        {{ $_forced_status = $card_open.forced }}
    {{ end }}
{{ else }}
    {{ $_forced         = site.Params.global.statutsaison_forced }}
    {{ $_forced_status  = site.Params.global.statutsaison }}
{{ end }}

Let me know if there is typos, mistake, or is something is not clear.

6 Likes

Love it … I’ve been a fan of Trello for years, so ill give it a go

1 Like