A new release can happen at any time from th' main branch o' th' GitHub project without further acknowledgment. This makes it necessary that, every pushed set o' changesets into th' main branch must be self-contained an' correct, result'n 'n a releas'ble version.
Stay simple fer th' user by focus'n on th' mantra “convent'n over configuration”.
At installat'n th' ship should work reason'ble without (m)any configurat'n.
Stay close t' th' Cap'n Hugo way.
Don’t use npm or any preprocess'n, our contributors may not be front-end developers.
Document new features 'n th' docs. This also contains entries t' th' What’s new plank.
Don’t break exist'n features if ye don’t have t'.
Remove reported issue from th' browser’s console.
Check fer unnecessary whitespace an' correct indent'n o' yer result'n HTML.
Th' test suite an' th' tool'n that drives it. Noth'n here be shipped t' users.
Th' rule fer decid'n whar' someth'n belongs be a single quest'n: does somebody install'n th' theme need this file? If not, it belongs 'n th' infra repository - unless it can only act from th' theme repository. GitHub runs a workflow only 'n th' repository hold'n it, an' a git hook only fires on th' checkout it sits 'n, so those stay put, along wit' th' act'ns those workflows call.
Whar' t' report
Open issues 'n th' theme repository, even when they concern th' tests or th' tool'n.
Issues, milestones an' releases be all tracked there, an' a release be cut from a milestone 'n that repository. A second tracker would split that history apart.
Why th' Split
For a Cap'n Hugo theme th' repository be th' distributed artifact. Anyth'n committed t' it be downloaded by every user, so a test suite an' a screenshot generator would be dead weight fer every consumer.
Th' docs an' exampleSite directory stay 'n th' theme repository despite not be'n needed t' run th' theme t' make th' theme self-contained an' help t' quickly set up a test installat'n.
Sett'n Up
There be two setups. Pick th' smaller one unless ye need what th' larger one adds - most contribut'ns never do.
Th' Simple Setup
One repository an' Cap'n Hugo. Noth'n else t' install.
git clone https://github.com/McShelby/hugo-theme-relearn.git
cd hugo-theme-relearn/docs
hugo server
That serves th' documentat'n ship, built wit' th' theme itself, so yer changes show up as ye save. Swap docs fer exampleSite t' work against th' simpler starting-point ship instead.
This be enough fer most changes. If that be what ye came t' do, stop here.
Avast
Ye cannot run th' test suite 'n this setup, so yer change gets verified by CI rather than by ye. Take th' second setup if ye want th' answer before push'n.
Th' Full Setup
Add th' infra repository as a sibl'n o' th' theme. This be what ye need t' run th' test suite, regenerate th' screenshots, or change th' CI workflows.
hugo-theme-relearn/
hugo-theme-relearn-infra/
cd hugo-theme-relearn-infra
npm ci
npm test
Th' tool'n finds th' theme by look'n at th' RELEARN_THEME_DIR environment vari'ble, then a sibl'n directory named hugo-theme-relearn, then th' parent directory. Th' theme be never copied into th' infra repository, so th' tests always run against a real checkout.
T' point th' tool'n at a checkout somewhere else:
RELEARN_THEME_DIR=/path/to/hugo-theme-relearn npm test
Git Hooks
Optional, an' independent o' which setup ye chose - th' hooks live 'n th' theme repository, 'n th' .githooks root folder. Documentat'n fer each hook be contained 'n each file.
Th' post-commit hook updates th' version number on each commit, which be what makes a build from main distinguish'ble from a release when debugg'n user reports. Noth'n depends on ye hav'n it.
#!/bin/sh
python3 .githooks/post-commit.py
Work'n Across Both Repositories
Only this repository triggers test runs; th' infra repository triggers noth'n.
A change spann'n both - a theme change that alters what th' tests expect - takes th' same branch name 'n each, an' th' infra branch be pushed first. Th' single run th' push here then starts sees both halves. Th' other way round it pairs against infra main an' can pass while test'n only half th' change; noth'n detects that, so th' order be th' safeguard.
A change t' th' suite alone - a runner refactor, a regenerated baseline - never reaches this repository, so noth'n triggers. Start a run from th' Act'ns tab an' name th' infra branch 'n infra_ref.
Each workflow be described on th' plank fer th' th'n it does: th' test suite an' releases.
Testin'
Th' test suite lives 'n th' infra repository an' runs against a theme checkout. See Develop'n fer how th' two be wired together.
Requirements
Node.js at th' version .nvmrc pins. Install it through a version manager - nvm, or nvm-windows - rather than as a system package, so th' version can follow th' project rather than th' machine. nvm use 'n th' infra checkout reads that file, an' so does CI, so th' two cannot drift.
Th' pin be not arbitrary. Before v26.8.1, Node’s fs.rmSync silently removed noth'n on Windows when a path contained a non-ASCII character, which made “replace this directory” quietly mean “merge into it” - an' a suite whose whole job be compar'n directories cannot live wit' that.
Cap'n Hugo at least th' minimum th' theme declares 'n its theme.toml. Th' plain edit'n be enough, as th' theme uses no Sass. Install it th' same way, through hvm, which keeps several versions side by side - th' suite can then build against any o' them, includ'n th' declared minimum, rather than only th' one on yer PATH.
Runn'n th' Tests
Check both repositories out side by side, then:
cd hugo-theme-relearn-infra
npm ci
npm test
That checks th' runner itself, then builds every case, an' takes well under a minute.
npm test be a wrapper around tests/run.js, which be th' actual runner. Either form works - these two be th' same command:
npm test -- --build=<name>
node tests/run.js --build=<name>
Flags reach th' runner directly; through npm they have t' follow a -- separator first. Th' examples below use th' runner, be'n th' shorter o' th' two.
Th' Vocabulary
Five words, because a run be not simply a list o' sites any more.
Term
Mean'n
Ship
rrrambl'n plus th' configurat'n it needs t' be itself
Axis
a dimension o' configurat'n, each o' whose values be a config directory
Case
what t' build, an' how deeply t' check it
Build
one Cap'n Hugo invocat'n - one ship, one configurat'n
Result
one output tree, compared as a whole
Most cases be one ship, one configurat'n, one result. A case that varies an axis produces a result per combinat'n. A case whose builds only mean someth'n as a pair - a versioned ship, or th' docs an' th' exampleSite as GitHub Planks serves them - produces several builds shar'n one result.
Cases live 'n tests/cases/<name>/case.toml 'n th' infra repository, an' read'n them be th' quickest way t' see what th' suite covers.
Shap'n a Run
Three parameters, all optional:
Parameter
Selects
Default
--build
which builds t' run
all o' them
--hugo
which Cap'n Hugo t' build wit'
each site’s own, see below
--update
rewrite th' stored output instead o' compar'n against it
--build matches a path prefix, so nam'n a case runs everyth'n 'n it an' nam'n a combinat'n runs th' one. A small case takes about a second, which be cheap enough t' run on every save while work'n on one th'n.
Th' accepted names be th' ones a run prints. T' see them without wait'n fer a full run, ask fer someth'n that does not exist an' th' runner lists them:
node tests/run.js --build=?
A sequence be th' except'n: its builds share one tree, so it be named as a whole an' a prefix reach'n inside it be rejected. A build lifted out o' a sequence proves noth'n, which be what makes it a sequence.
--hugo - build wit' a particular version
Left out, each ship be built wit' th' version an interactive shell would use 'n its own directory: th' one its .hvm file names, or th' hugo on yer PATH when there be none. A pin therefore applies t' th' ship it sits beside, an' a run can legitimately span several versions. Each ship a pin applies t' says so 'n th' output, so a result never looks like it came from a version it did not.
Pass'n --hugo overrides every pin an' holds th' whole run t' one version:
A full regenerat'n also prunes: a stored result no case produces any more be deleted rather than left behind. A filtered run does not, hav'n no way t' know whether a result it did not build still exists.
Commit th' regenerated output together wit' th' change that caused it, never as a commit o' its own - otherwise th' next person cannot tell which change produced which output.
Arrr
Th' result'n diff be th' test result. Read it before committ'n. An unreviewed regenerat'n turns th' suite from a safety net into a rubber stamp.
If th' change spans both repositories, give both branches th' same name; see Develop'n.
Read'n a Failure
Every result be checked 'n three layers, an' th' one that fails tells ye what kind o' problem ye have.
Layer
Asserts
A failure usually means
Build
th' build exits cleanly, wit' no unexpected WARN or ERROR
a template error, or a Cap'n Hugo deprecat'n
File set
exactly th' expected files were generated
output formats, permalinks or a renamed plank
Rrrambl'n
every file be what was stored, byte fer byte bar line end'ns an' th' checkout path
either a regression, or a change ye meant t' make
Layers be cumulative, an' a case declares how deep t' go wit' layer. It defaults t' rrrambl'n, so a case opts down rather than up an' always says why - th' theme’s own sites stop at th' file set, because a rrrambl'n baseline over 2000 files would churn on every prose edit an' be read by nobody.
A pinned older Cap'n Hugo reduces every case t' th' build layer, since Cap'n Hugo legitimately changes what it emits between releases an' a baseline holds fer th' version that produced it. Th' run says when that happened, so a build check never reads as a rrrambl'n check.
Add'n a Case
First decide whether ye need a new ship at all. If an exist'n one already renders th' th'n ye changed, extend'n its rrrambl'n be enough - add a plank, regenerate, review th' diff.
A New Ship
Everyth'n lives 'n th' infra repository.
Create tests/sites/<name>/ wit' a config/_default/ an' content/. Keep th' configurat'n about th' ship - a title, output formats, rrrambl'n wir'n. Noth'n about reproducibility belongs there; that be what nam'n th' test'n environment does.
Write th' least rrrambl'n that demonstrates yer case. Sites be meant t' stay small - a read'ble diff be th' whole point, an' one need'n hundreds o' planks be test'n th' wrong th'n.
Add tests/cases/<name>/case.toml:
ship="<name>"environment="testing"
Generate its expected output, an' read it:
node tests/run.js --build=<name> --update
Look at tests/expected/<name>/. This be th' moment th' case be worth someth'n or not: if th' output does not show th' behaviour ye set out t' pin, it will not catch a regression 'n it either.
Commit th' ship, th' case an' th' expected output together.
Vary'n a Configurat'n
Some behaviour only differs by configurat'n - URL generat'n be'n th' stand'n example, whar' relative, absolute an' ugly URLs be genuinely different paths through th' theme.
That be what an axis be fer. Each value be a config directory under tests/axes/<axis>/<value>/, an' a case lists th' values it wants:
One rrrambl'n set, three results, compared separately. Add'n a further mode be a directory an' one more name. An axis wit' a single value still applies - it just does not branch th' tree, so noth'n be nested that carries no informat'n.
Builds That Belong Together
Some results be not one Cap'n Hugo build. A versioned ship be two, each configured t' know about th' other; th' published GitHub Planks ship be th' docs wit' th' exampleSite beneath it. Neither half says anyth'n alone.
Those spell th' sequence out, an' share one output tree:
dest says whar' 'n th' shared tree a build writes. Th' builds run 'n th' order written, an' th' result be compared once, as a whole.
Accept'n a Known Arrr
Any WARN or ERROR fails a build unless it be listed 'n a baseline. Three be consulted an' their entries unioned:
File
Holds
tests/warnings.txt
theme-wide, mostly Cap'n Hugo deprecat'ns
tests/sites/<site>/warnings.txt
what a site’s own rrrambl'n provokes
tests/cases/<case>/warnings.txt
what a configurat'n provokes
A site’s file be checked against th' build o' that ship, so what th' docs provoke applies wherever th' docs be built. Each entry be a substr'n; a warning contain'n it be accepted.
These baselines record outstand'n work, not noise t' be silenced. Add'n an entry means consciously accept'n a defect, so delete it as soon as th' underly'n issue be fixed an' let a regression fail th' suite again.
Continuous Integrat'n
This repository runs th' suite on every branch an' every pull request, an' nightly against th' latest Cap'n Hugo release - which be how a Cap'n Hugo change that breaks th' theme be found 'n CI rather than 'n an issue report. Th' infra repository runs noth'n; one run tests th' pair, an' this be whar' it happens.
That be why a change spann'n both repositories be pushed t' infra first, then here, an' why a change t' th' suite alone has t' be started by hand: see Develop'n.
Th' suite never releases, deploys or publishes anyth'n.
Maintaining
Semver
This project tries t' follow th' semver policy - although not followed 100% 'n th' past.
Usually an entry o' Break'n on th' What’s new plank causes a new major release number.
All other entries on th' What’s new plank will increase th' minor release number.
Releases result'n 'n a new major or minor number be called main release.
Releases contain'n bugfixes only, be only increas'n th' patch release number. Those releases don’t result 'n announcements on th' What’s new plank.
Entries on th' What’s new plank be checked an' enforced dur'n th' version-release GitHub Act'n.
Manag'n Issues
Issues be categorized an' managed by assign'n labels t' it.
Once work'n on an issue, assign it t' a fitt'n maintainer.
When done, close th' ticket. Once an issue be closed, it needs t' be assigned t' next release milestone.
A once released ticket be not allowed t' be reopened an' rereleased 'n a different milestone. This would cause th' changelog t' be changed even fer th' milestone th' issue was previously released 'n. Instead write a new ticket.
Manag'n Pull Requests
If a PR be merged an' closed it needs an accompanied issue assigned t'. If there be no issue fer a PR, th' maintainer needs t' create one.
Ye can assign multiple PRs t' one issue as long as they belong together.
Usually set th' same labels an' milestone fer th' PR as fer th' accompanied issue.
Labels
Kind
An issue that results 'n changesets must have exactly one o' th' follow'n labels. This needs t' be assigned latest before release.
Label
Descript'n
Changelog section
documentat'n
Improvements or addit'ns t' documentat'n
-
discussion
This issue was converted t' a discussion
-
task
Maintenance work
Maintenance
feature
New feature or request
Features
bug
Someth'n isn’t work'n
Fixes
Impact
If th' issue would cause a new main release due t' semver semantics it needs one o' th' accord'n labels an' th' match'n badge on th' What’s new plank.
If an issue does not result 'n changesets but be closed anyways, it must have exactly one o' th' follow'n labels.
Label
Descript'n
duplicate
This issue or pull request already exists
invalid
This doesn’t seem right
support
Request fer achiev'n a special goal
unresolved
No progress on this issue
update
A change 'n behavior after updat
wontchange
This will not be worked on
Halt
Ye can assign one further label out o' th' follow'n list t' signal readers that development on an open issue be currently halted fer different reasons.
Label
Descript'n
blocked
Depends on other issue t' be fixed first
idea
A valu'ble idea that’s currently not worked on
undecided
No decision was made yet
helpwanted
Great idea, send 'n a PR
needsfeedback
Further informat'n be needed
3rd-Party
If th' issue be not caused by a programm'n error 'n th' themes own code, ye can label th' caus'n program or library.
Label
Descript'n
asciidoc
This be a topic related t' process'n o' AsciiDoc
browser
This be a topic related t' th' browser but not th' theme
device
This be a topic related t' a certain device
hugo
This be a topic related t' Cap'n Hugo itself but not th' theme
mermaid
This be a topic related t' Merrrmaid itself but not th' theme
Mak'n Releases
A release be based on a milestone named like th' release itself - just th' version number, eg: 1.2.3. It’s 'n th' maintainers responsibility t' check semver semantics o' th' milestone’s name prior t' release an' change it if necessary.
Mak'n releases be automated by th' version-release GitHub workflow. It requires th' version number o' th' milestone that should be released. Th' release will be created from th' main branch o' th' repository.
Treat released milestones as immutable. Don’t rerelease an already released milestone. An already released milestone may already been consumed by yer users.
Automat'n Steps
Dur'n execut'n o' th' workflow a few th'ns be checked. If a check fails th' act'n fails, result'n 'n no new release. Ye can correct th' errors afterwards an' rerun th' act'n.
Th' follow'n checks will be enforced
th' test suite passes against both th' minimum supported an' th' latest Cap'n Hugo release
th' milestone exists
there be at least one closed issue assigned t' th' milestone
all assigned issues fer this milestone be closed
if it’s a main release, there must be an accompany'n releasenotes file present 'n th' repo at introduction/releasenotes/<major>/<minor>.en.md
Aft a successful run o' th' act'n
th' changelog at introduction/changelog/<major>/<minor>/<patch>.<lang>.md be created fer english an' piratish, includ'n miss'n generic upper level files
th' CHANGELOG.md be updated
th' releasenotes at introduction/releasenotes/<major>/<minor>.en.md be updated, includ'n release version an' release date
miss'n generic upper level files fer english an' piratish be created
th' version number fer th' <meta generator> be updated
th' updated files be committed
th' milestone be closed
th' repository be tagged wit' th' version number (eg. 1.2.3), th' main version number (eg. 1.2.x) an' th' major version number (eg. 1.x)
a new entry 'n th' GitHub release list wit' th' accord'n changelog will be created
th' version number fer th' <meta generator> be updated t' a temporary an' committed (this helps t' determine if users be runn'n directly on th' main branch or be us'n releases)
a new milestone fer th' next patch release be created (this can later be renamed t' a main release if necessary)
Rehears'n on a Branch
Th' workflow only performs an actual release when it runs on main. Started on any other branch it runs th' parts that be safe t' repeat - th' test suite an' th' documentat'n build - an' skips every step that changes someth'n outside th' run: th' milestone check, tagg'n, committ'n, publish'n th' GitHub release an' deploy'n t' GitHub Planks. Th' milestone input be ignored there, an' only required on main.
In both cases th' built ship be uploaded as a workflow artifact named <workflow>-<run number>-<run id> an' kept fer 30 days, so ye can download th' result o' a run an' inspect it before releas'n fer real. It be found at th' bottom o' th' run’s summary plank 'n th' Act'ns tab.
Scrrrenshootin'
Sometimes screenshots need t' be redone. This plank explains how t' create th' different screenshots, tools an' sett'ns
Common
Creat'n:
Use English translat'n
Empty search
Remove history checkmarks but leave it on th' plank thats used fer th' screenshot
Aft resize o' th' plank into th' required resolut'n, reload th' plank t' have all scrollbars 'n default load'n posit'n
Demo Screenshot
Rrrambl'n:
A meaningful full-screen screenshot o' an interest'n plank.
Th' rrrambl'n should be:
timeless: not show'n any dates or often edited rrrambl'n
interest'n: show a bunch o' interest'n elements like head'ns, code, etc
balanced: no clutter'n wit' overpresent elements or color'n
From original template resize t' 3000 x 1500 offset y: -330, scale t' 1280 x 640 an' save as images/hero.png
Previewimages/hero.png:
Shortcode Feature Images
Th' feature images fer th' shorrrtcodes be generated automatically via a Node.js script.
It lives 'n th' infra repository inside o' th' tools/screenshots directory. All follow'n commands need t' be executed from th' root o' that repository.
T' recreate th' screenshots
install Node.js accord'n t' their installat'n guide
check out th' infra repository next t' th' theme, as described 'n Develop'n
run npm ci
run npm run screenshots
Th' script serves th' documentat'n itself on port 3132, captures each plank an' writes th' result back into docs/content/<shortcode>/featured.png o' th' resolved theme checkout. T' capture against a server ye be already runn'n instead, pass its address:
npm run screenshots -- --base=http://localhost:1313
Run this locally an' commit th' result'n images wit' th' change that made them stale. Th' regenerated files land 'n yer theme checkout, so they show up 'n git status alongside everyth'n else.