diff --git a/.forgejo/workflows/release.yml b/.forgejo/workflows/release.yml index 6895d74..3986ce4 100644 --- a/.forgejo/workflows/release.yml +++ b/.forgejo/workflows/release.yml @@ -57,3 +57,13 @@ jobs: env: FORGEJO_TOKEN: ${{ secrets.FORGEJO_RELEASE_TOKEN }} run: ./scripts/publish-release.sh "${GITHUB_REF_NAME}" + + - name: Refresh furtka.org download page + # The download page reads the latest release (ISO, size, date, + # checksum) from the Forgejo API at build time, so rebuild the site + # now that the release exists. Same runner + bind mounts as + # deploy-site.yml. A failure here doesn't touch the release. + continue-on-error: true + run: | + apk add --no-cache hugo rsync + ./website/deploy-ci.sh diff --git a/RELEASING.md b/RELEASING.md index db9070a..b830878 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -45,7 +45,7 @@ Tag per meaningful milestone, not on a calendar. A milestone is: ISO boots, a wi git push origin 26.1-alpha ``` -5. **The release workflow does the rest.** `.forgejo/workflows/release.yml` fires on the tag push and runs on the self-hosted runner: `scripts/build-release-tarball.sh` builds the self-update payload (tarball + sha256 + release.json under `dist/`), `iso/build.sh` builds the live-installer ISO, `scripts/publish-release.sh` uploads tarball + sha256 + release.json + ISO to the Forgejo release page. Pre-release is flagged automatically based on the suffix (`-alpha`/`-beta`/`-rc`). ISO build is `continue-on-error`: a flaky ISO step doesn't block the core tarball (the thing boxes need for self-update). +5. **The release workflow does the rest.** `.forgejo/workflows/release.yml` fires on the tag push and runs on the self-hosted runner: `scripts/build-release-tarball.sh` builds the self-update payload (tarball + sha256 + release.json under `dist/`), `iso/build.sh` builds the live-installer ISO, `scripts/publish-release.sh` uploads tarball + sha256 + release.json + ISO to the Forgejo release page. Pre-release is flagged automatically based on the suffix (`-alpha`/`-beta`/`-rc`). The ISO gets a `furtka-.iso.sha256` sidecar, and a last step rebuilds furtka.org so the download page (`/download/`) picks up the new ISO, size, date and checksum from the Forgejo API. ISO build is `continue-on-error`: a flaky ISO step doesn't block the core tarball (the thing boxes need for self-update). The release workflow needs one secret set at repo **Settings → Secrets → Actions**: - `FORGEJO_RELEASE_TOKEN` — a PAT with `write:repository` scope. diff --git a/scripts/publish-release.sh b/scripts/publish-release.sh index b784294..f092288 100755 --- a/scripts/publish-release.sh +++ b/scripts/publish-release.sh @@ -113,6 +113,15 @@ if [ -f "$ISO" ]; then if ! upload_asset "$ISO"; then echo "warning: ISO upload failed — release published without ISO asset" >&2 fi + # Checksum sidecar for the download page on furtka.org (and anyone + # verifying by hand). Uploaded even when the ISO upload reported a + # failure — a 504 there often still lands the file. Written from inside + # dist/ so the line carries the bare filename `sha256sum -c` expects. + ISO_SHA="$ISO.sha256" + (cd "$DIST_DIR" && sha256sum "$(basename "$ISO")" > "$(basename "$ISO_SHA")") + if ! upload_asset "$ISO_SHA"; then + echo "warning: ISO checksum upload failed" >&2 + fi fi echo "Release $VERSION published: https://$HOST/$REPO/releases/tag/$VERSION" diff --git a/website/assets/css/main.css b/website/assets/css/main.css index 52a7ad7..3b01b25 100644 --- a/website/assets/css/main.css +++ b/website/assets/css/main.css @@ -356,6 +356,214 @@ main.container { .cta--primary { animation: none; } } +.cta-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.9rem 1.1rem; +} +.cta--ghost { + color: var(--fg); + border: 1px solid var(--border); + background: var(--card-bg); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); +} +.cta--ghost:hover { + border-color: var(--accent); + color: var(--accent); + transform: translateY(-2px); +} + +/* ── How it works (home) ─────────────────────────────────── */ + +.how-steps { + list-style: none; + counter-reset: how; + margin: 0; + padding: 0; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); + gap: 1rem; +} +.how-step { + counter-increment: how; + position: relative; + background: var(--card-bg); + border: 1px solid var(--card-border); + border-radius: 1rem; + padding: 1.4rem 1.5rem 1.5rem; + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); +} +.how-step::before { + content: counter(how, decimal-leading-zero); + display: block; + font-family: var(--font-mono); + font-weight: 600; + font-size: 2.4rem; + line-height: 1; + letter-spacing: -0.04em; + margin-bottom: 0.9rem; + background-image: linear-gradient(135deg, var(--accent), var(--fg-muted)); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; +} +.how-step h3 { margin: 0 0 0.35rem; font-size: 1.15rem; letter-spacing: -0.01em; } +.how-step p { margin: 0; color: var(--fg-muted); font-size: 0.98rem; line-height: 1.5; } +.how-step strong { color: var(--fg); font-weight: 600; } + +/* ── Download band (home, before the closer) ─────────────── */ + +.dl-band { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 1.25rem 2rem; + margin-block: 4.5rem 0; + padding: 2rem; + border-radius: 1.25rem; + border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border)); + background: + radial-gradient(120% 140% at 0% 0%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 60%), + var(--card-bg); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); +} +.dl-band h2 { margin: 0 0 0.3rem; font-size: 1.5rem; letter-spacing: -0.02em; } +.dl-band p { margin: 0; color: var(--fg-muted); max-width: 26rem; } + +/* ── Download page ───────────────────────────────────────── */ + +.dl-hero { padding-block: 1rem 1rem; } +.dl-hero h1 { + font-size: clamp(2.4rem, 7vw, 4rem); + line-height: 1; + letter-spacing: -0.035em; + margin: 0 0 1rem; +} +.dl-hero .lede { + font-size: clamp(1.05rem, 1.6vw, 1.2rem); + color: var(--fg-muted); + max-width: 36rem; + margin: 0 0 2rem; +} +.dl-card { + padding: 1.75rem; + border-radius: 1.25rem; + border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border)); + background: + radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 60%), + var(--card-bg); +} +.dl-card .cta svg { flex: none; } +.dl-meta { + display: flex; + flex-wrap: wrap; + gap: 0.75rem 2rem; + margin: 1.5rem 0 0; +} +.dl-meta div { min-width: 0; } +.dl-meta dt { + font-size: 0.7rem; + font-weight: 500; + letter-spacing: 0.14em; + text-transform: uppercase; + color: var(--fg-muted); +} +.dl-meta dd { margin: 0.15rem 0 0; overflow-wrap: anywhere; } +.mono { font-family: var(--font-mono); font-size: 0.92em; } +.dl-host { margin: 1.25rem 0 0; font-size: 0.85rem; color: var(--fg-muted); } +.dl-alpha { + margin: 1.5rem 0 0; + padding: 0.9rem 1.1rem; + border-left: 3px solid var(--accent); + background: var(--bg-subtle); + border-radius: 0 0.6rem 0.6rem 0; + font-size: 0.95rem; + max-width: 40rem; +} +.dl-section { margin-top: 3.5rem; } +.dl-needs { margin: 0; padding-left: 1.2rem; max-width: 40rem; } +.dl-needs li { margin-bottom: 0.55rem; } +.dl-needs li::marker { color: var(--accent); } +.dl-steps { + list-style: none; + counter-reset: dl; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 1rem; +} +.step-card { + counter-increment: dl; + display: grid; + grid-template-columns: 2.6rem 1fr; + gap: 0 1rem; + padding: 1.3rem 1.4rem; + border: 1px solid var(--card-border); + border-radius: 1rem; + background: var(--card-bg); +} +.step-card::before { + content: counter(dl); + grid-row: span 2; + display: grid; + place-items: center; + width: 2.6rem; + height: 2.6rem; + border-radius: 999px; + background: linear-gradient(135deg, var(--accent), var(--accent-hover)); + color: #fff; + font-weight: 700; +} +.step-card h2 { margin: 0.35rem 0 0.4rem; font-size: 1.15rem; letter-spacing: -0.01em; } +.step-body { min-width: 0; color: var(--fg-muted); } +.step-body p { margin: 0 0 0.7rem; } +.step-body p:last-child { margin: 0; } +.step-body strong { color: var(--fg); font-weight: 600; } +.step-body a, .dl-older a, .dl-alpha a { color: var(--accent); } +kbd { + font-family: var(--font-mono); + font-size: 0.85em; + padding: 0.05rem 0.4rem; + border: 1px solid var(--border); + border-bottom-width: 2px; + border-radius: 0.3rem; + background: var(--bg); + color: var(--fg); +} +.download pre { + margin: 0.4rem 0 0; + padding: 0.85rem 1rem; + border-radius: 0.6rem; + background: var(--bg-subtle); + border: 1px solid var(--border); + overflow-x: auto; + font-size: 0.85rem; + line-height: 1.55; + color: var(--fg); +} +.download code { font-family: var(--font-mono); } +.download :not(pre) > code { + padding: 0.05rem 0.3rem; + border-radius: 0.3rem; + background: var(--bg-subtle); + font-size: 0.9em; +} +.dl-hash code { overflow-wrap: anywhere; white-space: pre-wrap; } +.dl-cmds .c { color: var(--fg-muted); } +.dl-muted { color: var(--fg-muted); } +.dl-older { margin-top: 3rem; } +@media (max-width: 30rem) { + .dl-card, .dl-band { padding: 1.35rem; } + .step-card { grid-template-columns: 1fr; } + .step-card::before { grid-row: auto; margin-bottom: 0.6rem; } +} + /* ── Intro paragraph (home, between hero and feature grids) ─ */ .intro { diff --git a/website/content/_index.de.md b/website/content/_index.de.md index 922180c..2d813cc 100644 --- a/website/content/_index.de.md +++ b/website/content/_index.de.md @@ -1,7 +1,9 @@ --- title: "Furtka" description: "Offenes Heimserver-Betriebssystem — einfach genug für alle." -status: "26.20-alpha — in Arbeit" +status_text: "in Arbeit" +cta_download: "ISO herunterladen" +cta_source: "Quellcode" poll_link: "/de/logo/" poll_text: "Wir suchen ein Logo — hilf uns beim Aussuchen" # features_today / features_next müssen index-parallel zu content/_index.md bleiben. @@ -12,6 +14,16 @@ intro: | Apps, eigenem Namen im Netz, eigenen Daten. Das Ziel ist einfach: **dein Vater soll das einrichten können.** +steps_label: "So funktioniert's" +steps: + - title: "Herunterladen" + body: "Installer holen und auf einen USB-Stick schreiben." + - title: "Installieren" + body: "Computer vom Stick starten und dem Assistenten folgen — im Browser auf Handy oder Laptop." + - title: "Loslegen" + body: "**http://furtka.local** öffnen und Apps mit einem Klick installieren." +band_title: "Lust, es auszuprobieren?" +band_text: "Kostenlos und quelloffen (AGPL-3.0). Läuft auf 64-Bit-PCs, auch auf alten." features_today_label: "Was heute schon geht" features_today: - "Vom USB-Stick booten und Furtka auf die Festplatte einrichten" diff --git a/website/content/_index.md b/website/content/_index.md index ffb814e..cc95e6f 100644 --- a/website/content/_index.md +++ b/website/content/_index.md @@ -1,7 +1,9 @@ --- title: "Furtka" description: "Open-source home server OS — simple enough for everyone." -status: "26.20-alpha — work in progress" +status_text: "work in progress" +cta_download: "Download ISO" +cta_source: "Source code" poll_link: "/logo/" poll_text: "We're picking a logo — help us choose" # Keep features_today / features_next index-aligned with content/_index.de.md. @@ -12,6 +14,16 @@ intro: | your own name on the network, your own data. The goal is simple: **your dad should be able to set this up.** +steps_label: "How it works" +steps: + - title: "Download" + body: "Get the installer and write it to a USB stick." + - title: "Install" + body: "Start the computer from the stick and follow the wizard — in the browser on your phone or laptop." + - title: "Use" + body: "Open **http://furtka.local** and install apps with one click." +band_title: "Ready to try it?" +band_text: "Free and open source (AGPL-3.0). Runs on 64-bit PCs, old ones included." features_today_label: "What works today" features_today: - "Boot from USB stick and install Furtka onto the hard drive" diff --git a/website/content/download.de.md b/website/content/download.de.md new file mode 100644 index 0000000..193a108 --- /dev/null +++ b/website/content/download.de.md @@ -0,0 +1,40 @@ +--- +title: "Furtka herunterladen" +description: "Der Furtka-Installer als ISO-Datei: auf einen USB-Stick schreiben, den Computer davon starten und den Heimserver im Browser einrichten." +translationKey: "download" +url: /de/download/ +type: download +button: "ISO herunterladen" +released: "Veröffentlicht" +size_label: "Größe" +alpha: "Furtka ist **Alpha-Software**: Dinge ändern sich und manches geht kaputt. Installiere es auf einem Computer, dessen Festplatte du nicht brauchst, und sichere alles Wichtige." +host_note: "Die Datei kommt von unserem Forgejo-Server (forgejo.sourcegate.online)." +need_label: "Was du brauchst" +needs: + - "Einen **64-Bit-PC** (x86-64) — ein alter Laptop oder Desktop reicht. UEFI- und ältere BIOS-Rechner funktionieren beide." + - "Eine Festplatte mit **mindestens 16 GB** für Furtka. **Sie wird komplett gelöscht.**" + - "Einen **USB-Stick** mit mindestens 2 GB (wird ebenfalls gelöscht)." + - "Ein **Netzwerkkabel** mit Internetzugang — der Installer lädt Pakete herunter, und WLAN wird nicht automatisch eingerichtet." + - "Ein **zweites Gerät mit Browser** (Handy oder Laptop) im selben Netzwerk." +steps_label: "So installierst du Furtka" +steps: + - title: "ISO auf einen USB-Stick schreiben" + body: | + Nimm [balenaEtcher](https://etcher.balena.io/) (Windows, macOS, Linux) oder [Rufus](https://rufus.ie/) unter Windows — wenn Rufus fragt, wähle den **DD-Abbild-Modus**. Unter Linux geht auch `dd` (ersetze `/dev/sdX` durch deinen Stick — lieber zweimal prüfen): + + ``` + sudo dd if={iso} of=/dev/sdX bs=4M status=progress oflag=sync + ``` + - title: "Computer vom Stick starten" + body: "Stick und Netzwerkkabel einstecken, Computer einschalten und die Taste fürs Bootmenü drücken (oft F11, F12 oder Esc — sie wird kurz am Bildschirm angezeigt). Den USB-Stick auswählen. Startet der Computer nicht davon, schalte **Secure Boot** in den Firmware-Einstellungen aus." + - title: "Installer von einem anderen Gerät öffnen" + body: "Nach kurzer Zeit zeigt der Bildschirm eine Adresse an — meist **http://proksi.local:5000**, dazu die IP-Adresse als Ausweichweg. Öffne sie im Browser auf Handy oder Laptop." + - title: "Durch den Assistenten klicken" + body: "Drei Seiten: ein Name für deinen Server mit Benutzername und Passwort, die Festplatte und eine letzte Kontrolle. Danach lädt der Installer alles herunter und richtet es ein." + - title: "Stick raus, neu starten, fertig" + body: "Wenn der Assistent es sagt, den USB-Stick abziehen und neu starten. Dein Server ist dann unter **http://<name>.local** erreichbar — zum Beispiel http://furtka.local." +verify_label: "Download prüfen (optional)" +verify_intro: "Vergleiche die Prüfsumme der heruntergeladenen Datei mit dieser:" +verify_missing: "Für die ISO dieses Releases ist noch keine Prüfsumme veröffentlicht — künftige Releases bringen eine mit." +older: "Alle Releases und Änderungen" +--- diff --git a/website/content/download.md b/website/content/download.md new file mode 100644 index 0000000..1d57bf3 --- /dev/null +++ b/website/content/download.md @@ -0,0 +1,40 @@ +--- +title: "Download Furtka" +description: "The Furtka installer as an ISO file: write it to a USB stick, start your computer from it, and set up your home server in the browser." +translationKey: "download" +url: /download/ +type: download +button: "Download ISO" +released: "Released" +size_label: "Size" +alpha: "Furtka is **alpha software**: things change and some will break. Install it on a computer whose disk you don't need, and keep a backup of anything important." +host_note: "The file is served from our Forgejo server (forgejo.sourcegate.online)." +need_label: "What you need" +needs: + - "A **64-bit PC** (x86-64) — an old laptop or desktop is fine. Both UEFI and older BIOS computers work." + - "A disk of **at least 16 GB** for Furtka. **It will be erased completely.**" + - "A **USB stick** with at least 2 GB (also erased)." + - "A **network cable** with internet access — the installer downloads packages, and Wi-Fi isn't set up automatically." + - "A **second device with a browser** (phone or laptop) on the same network." +steps_label: "How to install" +steps: + - title: "Write the ISO to a USB stick" + body: | + Use [balenaEtcher](https://etcher.balena.io/) (Windows, macOS, Linux) or [Rufus](https://rufus.ie/) on Windows — if Rufus asks, pick **DD image mode**. On Linux you can also use `dd` (replace `/dev/sdX` with your stick — double-check it): + + ``` + sudo dd if={iso} of=/dev/sdX bs=4M status=progress oflag=sync + ``` + - title: "Start the computer from the stick" + body: "Plug in the stick and the network cable, switch the computer on and press the one-time boot menu key (often F11, F12 or Esc — it flashes briefly on screen). Pick the USB stick. If the computer refuses to start from it, switch off **Secure Boot** in the firmware settings." + - title: "Open the installer from another device" + body: "After a short while the screen shows an address — usually **http://proksi.local:5000**, plus the IP address as a fallback. Open it in a browser on your phone or laptop." + - title: "Click through the wizard" + body: "Three pages: a name for your server with your username and password, the disk to install on, and a last check. Then the installer downloads and sets everything up." + - title: "Pull the stick, restart, done" + body: "When the wizard says so, remove the USB stick and restart. Your server comes up at **http://<name>.local** — for example http://furtka.local." +verify_label: "Check the download (optional)" +verify_intro: "Compare the checksum of the file you downloaded with this one:" +verify_missing: "This release has no published checksum for the ISO yet — future releases include one." +older: "All releases and changelogs" +--- diff --git a/website/hugo.toml b/website/hugo.toml index 056659a..c5113f8 100644 --- a/website/hugo.toml +++ b/website/hugo.toml @@ -8,6 +8,11 @@ enableRobotsTXT = true description = "Open-source home server OS — simple enough for everyone." version = "26.20-alpha" contactEmail = "hallo@furtka.org" + # Forgejo repo the download page reads its latest release (ISO asset, + # size, date, checksum) from at build time. `version` above is only the + # fallback when that lookup fails. + forgejoURL = "https://forgejo.sourcegate.online" + repoPath = "daniel/furtka" [markup.goldmark.renderer] unsafe = true @@ -32,5 +37,12 @@ enableRobotsTXT = true [build] writeStats = true +# The release lookup must be fresh on every build — Hugo's default keeps +# remote resources cached forever, which would pin the download page to +# whatever release existed on the first build. +[caches] + [caches.getresource] + maxAge = 0 + [minify] minifyOutput = true diff --git a/website/layouts/download/single.html b/website/layouts/download/single.html new file mode 100644 index 0000000..eecefa1 --- /dev/null +++ b/website/layouts/download/single.html @@ -0,0 +1,63 @@ +{{ define "main" }} +{{- $r := partialCached "release.html" . "release" -}} +{{- $file := path.Base $r.url -}} +
+
+

{{ $r.version }}

+

{{ .Title }}

+

{{ .Description }}

+ +
+ + + {{ .Params.button }} + +
+
ISO
{{ $file }}
+ {{ with $r.size }}
{{ $.Params.size_label }}
{{ lang.FormatNumber 1 (div (float .) 1e9) }} GB
{{ end }} + {{ with $r.date }}
{{ $.Params.released }}
{{ time.Format ":date_long" . }}
{{ end }} +
+

{{ .Params.host_note }}

+
+ +

{{ .Params.alpha | markdownify }}

+
+ +
+

{{ .Params.need_label }}

+
    + {{ range .Params.needs }}
  • {{ . | markdownify }}
  • {{ end }} +
+
+ +
+

{{ .Params.steps_label }}

+
    + {{ range .Params.steps }} +
  1. +

    {{ .title }}

    +
    {{ replace .body "{iso}" $file | markdownify }}
    +
  2. + {{ end }} +
+
+ +
+

{{ .Params.verify_label }}

+ {{ with $r.sha256 }} +

{{ $.Params.verify_intro }}

+
{{ . }}
+
# Linux
+sha256sum {{ $file }}
+# macOS
+shasum -a 256 {{ $file }}
+# Windows (PowerShell)
+Get-FileHash {{ $file }}
+ {{ else }} +

{{ $.Params.verify_missing }}

+ {{ end }} +
+ +

{{ .Params.older }} →

+
+{{ end }} diff --git a/website/layouts/index.html b/website/layouts/index.html index 5975241..7ee6db1 100644 --- a/website/layouts/index.html +++ b/website/layouts/index.html @@ -1,16 +1,17 @@ {{ define "main" }} +{{- $r := partialCached "release.html" . "release" -}} +{{- $dl := "download/" | relLangURL -}}
- {{ with .Params.status }} -

{{ . | safeHTML }}

- {{ end }} +

{{ $r.version }} — {{ .Params.status_text }}

{{ .Title }}

{{ with site.Params.description }}

{{ . }}

{{ end }}

- - {{ if eq site.Language.Lang "de" }}Neuestes Release{{ else }}Latest release{{ end }} + + {{ .Params.cta_download }} + {{ .Params.cta_source }}

{{ with .Params.poll_link }}

{{ partial "mark-m.html" (dict "class" "" "id" "hm") }}{{ partial "mark-r.html" (dict "class" "" "id" "hr") }}{{ $.Params.poll_text }} →

@@ -21,6 +22,20 @@
{{ . | markdownify }}
{{ end }} + {{ with .Params.steps }} +
+ {{ with $.Params.steps_label }}

{{ . }}

{{ end }} +
    + {{ range . }} +
  1. +

    {{ .title }}

    +

    {{ .body | markdownify }}

    +
  2. + {{ end }} +
+
+ {{ end }} + {{ if .Params.features_today }}
{{ with .Params.features_today_label }}

{{ . }}

{{ end }} @@ -43,6 +58,16 @@
{{ end }} + {{ with .Params.band_title }} +
+
+

{{ . }}

+

{{ $.Params.band_text }}

+
+ {{ $.Params.cta_download }} +
+ {{ end }} + {{ with .Content }}
{{ . }}
{{ end }} diff --git a/website/layouts/partials/release.html b/website/layouts/partials/release.html new file mode 100644 index 0000000..20f1479 --- /dev/null +++ b/website/layouts/partials/release.html @@ -0,0 +1,57 @@ +{{- /* + Latest Furtka release that has an ISO attached, looked up on Forgejo at + build time. Returns a dict: version, url (ISO), size (bytes, 0 = unknown), + date (time or ""), sha256 ("" when the release has no .iso.sha256), page + (release page URL), live (false when the lookup failed and we fell back + to site.Params.version). Use via partialCached "release.html" . "release". +*/ -}} +{{- $repo := printf "%s/%s" site.Params.forgejoURL site.Params.repoPath -}} +{{- $v := site.Params.version -}} +{{- $out := dict + "version" $v + "url" (printf "%s/releases/download/%s/furtka-%s.iso" $repo $v $v) + "size" 0 + "date" "" + "sha256" "" + "page" (printf "%s/releases/tag/%s" $repo $v) + "all" (printf "%s/releases" $repo) + "live" false +-}} +{{- $api := printf "%s/api/v1/repos/%s/releases?limit=10" site.Params.forgejoURL site.Params.repoPath -}} +{{- with try (resources.GetRemote $api) -}} + {{- with .Err -}} + {{- warnf "release.html: release lookup failed, using site.Params.version: %s" . -}} + {{- else with .Value -}} + {{- $done := false -}} + {{- range (. | transform.Unmarshal) -}} + {{- if and (not $done) (not .draft) -}} + {{- $rel := . -}} + {{- $iso := "" -}} + {{- $sum := "" -}} + {{- range .assets -}} + {{- if strings.HasSuffix .name ".iso" }}{{ $iso = . }}{{ end -}} + {{- if strings.HasSuffix .name ".iso.sha256" }}{{ $sum = . }}{{ end -}} + {{- end -}} + {{- with $iso -}} + {{- $done = true -}} + {{- $out = merge $out (dict + "version" $rel.tag_name + "url" .browser_download_url + "size" .size + "date" (time.AsTime $rel.published_at) + "page" $rel.html_url + "live" true) -}} + {{- with $sum -}} + {{- with try (resources.GetRemote .browser_download_url) -}} + {{- with .Value -}} + {{- $hash := index (split (trim .Content " \n") " ") 0 -}} + {{- if eq (len $hash) 64 }}{{ $out = merge $out (dict "sha256" $hash) }}{{ end -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{- return $out -}}