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
-
Setup a trello account for managing the informations
- Create a dedicated board, for example
Hugo via trello
- Create a dedicated board, for example
-
Setup a slack account for triggering deploys
- Create a workspace :
myWorkspace
for example - Create a dedicated channel, for example
#web
, in this workspace
- Create a 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
- post message :
- 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
- post message :
- Create a Card button butler with
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
andtoken
- You need to put them in your system parameters or in Netlify parameters, but never on your git
Get credentials from Trello
- Generate a Trello key for dev :
-
https://trello.com/1/appKey/generate
. - You get a result like
mykeyabcdefg123456789
-
- Generate a token for the board
- https://trello.com/1/authorize?key=mykeyabcdefg123456789&name=Hugo&expiration=never&response_type=token
- You get a result like
mytoken123456789abcdefg
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
andHUGO_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.