Releases and downloads
OINK keeps release facts in two local places: a release_url in a page’s
front matter names the GitHub release this page is about, and
data/download/<key>.yaml says how to install it. Release cards, asset tables, download blocks and index pages all
derive from those two. Nothing contacts GitHub at build time, and nothing claims
a tag or an asset already exists.
Its front matter holds a release_url (OINK v0.4.0), and the card, asset
table and download block below are really rendered. The checksums and asset
filenames are fabricated: the URLs are derived locally from the repository and
the tag, the files they point at do not exist in any real release, and the
hashes here must not be used to verify anything.
Components and where the facts come from
| What you want | What renders it | Facts come from |
|---|---|---|
| A version summary card (tag, date, archives, repo) | release-card |
The page’s release_url |
| A checksum asset table | The checksums fence / release-assets |
sha*sum lines in the body |
| A multi-channel download block | download |
data/download/<key>.yaml |
| A chronological release index | layout: releases |
Each page’s release_url, or its title |
The page owns the release facts
One key in the release page’s front matter is the whole record — the exact-tag GitHub release URL:
The owner, the project, and the tag come out of the URL, and the date is the
page’s own date. A value that is not an exact-tag GitHub release URL warns
and skips the release block — and fails a --panicOnWarning build. The 0.5
release map (product / version / repo / tag / date / prev / checksums) and
its string shorthand are gone; a page still carrying one gets a warning that
names release_url.
Put a parameterless shortcode wherever the summary belongs; the call itself accepts no facts:
The card carries the four links the URL alone can name — the release, both source archives, and the repository — all derived locally. Checksum files belong in the asset table below a note, and comparisons live on GitHub.
The release index page
A section can switch to the release index layout. It lists every regular page of the section, newest first — the page date, with the tag’s version as the tiebreaker inside one day (SemVer precedence, with a deterministic fallback for non-SemVer tags):
An entry whose release_url parses reads as project tag — oink v0.4.0 —
over the page’s description; a page without one keeps its own title, so a
plain note between releases is a plain entry, not a warning. The 0.5
release_products filter and release_group_by_product grouping are gone;
naming either warns.
This site’s Releases currently uses the ordinary blog list.
Switch to layout: releases when a strict chronology is wanted.
Checksum assets
The checksums fence is the native form of a checksum table, holding the
verbatim output of a sha*sum command:
| File | Checksum | |
|---|---|---|
| oink-0.4.0-linux-amd64.tar.gz Linuxamd64SHA-256 | 1e2f4c8a…e7c4 |
|
| oink-0.4.0-darwin-arm64.tar.gz macOSarm64SHA-256 | 7b3d9e0c…8250 |
Only two line shapes are accepted: <hex><two spaces><filename> and
<hex><space>*<filename>. Blank lines and lines starting with # are ignored.
The hash length decides the algorithm (MD5 / SHA-1 / SHA-256 / SHA-512), and one
block holds one algorithm. A malformed line fails the build with its line
number. A filename must be a single path segment. The type, operating system and
architecture badges are inferred from the filename; they are decoration, and
nothing shows when the inference fails.
The base for asset links: with release_url front matter on the page it is derived
as https://github.com/<repo>/releases/download/<tag>/; a page without release
facts must write base= explicitly. Having both is an error.
release-assets is the shortcode form of the same parser and renderer. It adds
one thing the fence lacks, src=, so the checksum file itself can be committed
as a page resource or a global asset (src and inner content are mutually
exclusive); group="auto" groups by platform and architecture:
.rpm
| File | Checksum | |
|---|---|---|
| oink-0.4.0-1.el9.x86_64.rpm Linuxamd64SHA-256 | 5a0c7d1e…7db6 |
|
| oink-0.4.0-1.el9.aarch64.rpm Linuxarm64SHA-256 | c93f16a8…0ea8 |
In HTML the hash is shown truncated while the full value stays in the accessible name and in what the copy button copies, and that button comes from a local runtime loaded on demand. With JavaScript disabled it is still a complete linked table. Print expands the full hash without controls, and Markdown and RSS emit a pipe table of full hashes.
Download channel data
How to install belongs to the product rather than to one release, so it lives in
data/download/<key>.yaml. This site’s real record is
data/download/prd5.yaml:
The record has exactly five top-level fields — version, repo, tag,
published, channels — and one extra key fails the build. version may be
omitted here and supplied by the site’s params.version instead.
Each channel:
Two rules:
- Localization resolves by suffix:
<field>_<exact language>→<field>_<base language>→<field>. A Chinese site resolvestitle_zh_cn, thentitle_zh, thentitle. camelCase aliases are not accepted. - Only a pinned channel’s
urlandsteps[].codeinterpolate${version}and${tag}. A rolling channel refuses interpolation, so a stable install command is never bound to one version. Titles and notes never interpolate.
Rendering the download block
download takes exactly one positional parameter, the data key:
Install script
The rolling channel deliberately contains no version interpolation.
Source archive
Release assets
| File | Checksum | |
|---|---|---|
| oink-0.4.0.tar.gz SHA-256 | aaaaaaaa…aaaa |
In HTML it renders a row of anchor chips plus one section per channel; code steps reuse the enhanced code block and its on-demand copy runtime, and a checksum channel reuses the asset table above. Print statically expands the same content, Markdown emits the titles, source fences and full hashes, and RSS omits the component.
Before the tag is cut and the assets are uploaded, mark the record unpublished:
Rolling channels keep working. Pinned channels become an unclickable “pending release” state, omit the pinned commands, and disable asset links and copy controls. Flip the switch once the tag and the assets resolve, rather than writing a guessed link into the prose first.
The same record can also feed a landing page’s download section, with no
second version model — see
Home and landing pages.
How this relates to blog release notes
The two have different jobs:
- A release note in the blog (this site keeps them in
content/blog/release/) is the narrative: what changed, how to upgrade, what breaks. Its front matter carriesrelease_url, and arelease-cardcan sit at the top. How to write one is in Blog posts. - The download data is the operation: which channel, which command, which hash. It is decoupled from the version number, so an upgrade edits one place.
The order for a release: update version in data/download/<key>.yaml → write a
new content/blog/release/<version>.md with its release_url → flip
published to true once the tag and assets are in place.
Verify
- The build is warning-free:
hugo --printPathWarnings --panicOnWarning. A malformed hash line, mixed algorithms, a missingbaseand a misspelled channel field all fail here. - On the page: the card’s tag and date match the repository, and every asset row opens a real download URL.
- Check the hashes against the actual artifacts by hand: the component only lays them out and verifies nothing.
- Confirm the hashes are complete in non-HTML output:
- Rehearse with
published: falsefirst and switch totrueonly once the tag and assets really exist; test each language and a subpath deployment.
Related
- Blog posts — where release notes live and how they are ordered
- Code Blocks — code rendering and copying inside download steps
- Home and landing pages — the landing
downloadsection - Configuration —
params.versionand the related site parameters - Upgrade — how a consuming site tracks theme versions