Forgejo workflows repository
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jan Kvíčala 6c278c2588 fix: přihlášení do registry bez docker login (proxy má AUTH=0)
`docker login` selhal na "403 Request forbidden by administrative rules" —
ověřuje údaje voláním POST /auth na daemonu a socket proxy má AUTH=0.

Zapisuje se proto přímo do ~/.docker/config.json. Na funkčnost to nemá vliv:
`docker push` i Registry v2 API (ověřovací krok) berou přihlášení z tohohle
souboru, `docker login` ho jen vyplňuje. Cena je, že se správnost údajů pozná
teprve při pushi (401 z registry) místo hned — proto zůstává kontrola na prázdné
hodnoty.

Zápis přes python3 (ne jq — v job image není), base64 s fallbackem pro BSD
variantu bez -w0. Otestováno end-to-end: zapíše správný base64, dekóduje se zpět
na user:pass.

Předchozí běh potvrdil, že Docker už funguje (`Docker API: zápis OK`), takže
tohle je poslední krok před samotným buildem.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-01 13:02:34 +02:00
.forgejo/workflows fix: přihlášení do registry bez docker login (proxy má AUTH=0) 2026-10-01 13:02:34 +02:00
.gitignore feat: sdílené build workflow pro Java monorepa 2026-09-25 11:00:36 +02:00
README.md docs: cache u @main, SHA pinning a java-docker-release 2026-10-01 08:57:10 +02:00

forgejo-workflows

Sdílená Forgejo Actions workflow pro gravela ekosystém — Java monorepa (java-*) a projekty v Rustu a Node (rust-check, node-check).

Vzniklo proto, že java-check-main.yaml existoval ve čtyřech různých verzích napříč pěti repozitáři — tři byly identické, jeden se lišil věcně (wardenero potřebuje JDK 8). Každá úprava CI se musela opakovat v každém repu zvlášť.


Workflow

java-build.yaml

Staví jen moduly, kterých se commit dotkl. Detekce běží z git diff a zúží Gradle na konkrétní cesty; testy běží s buildem.

Parametry:

vstup výchozí k čemu
roots . kořeny se změněnými moduly, oddělené čárkou; . = celé repo jako jeden modul
jdk8 false nainstalovat vedle JDK 21 i JDK 8 (wardenero / WebObjects)
jvmargs -Xmx3g -XX:MaxMetaspaceSize=512m … org.gradle.jvmargs pro CI

Runner label je natvrdo host. Parametrizovat ho nejde: Forgejo vyhodnocuje runs-on při plánování jobu, kdy inputs ještě neexistují — výraz by se přeložil na prázdno a job by čekal na runner bez labelu.

Potřebuje (nastavuje se v repu nebo organizaci):

  • secrets: GRADLE_ENCRYPTION_KEY, IVY_PASS
  • vars: IVY_USER, IVY_HOSTS, INIT_GRADLE_KTS

java-release.yaml

Volá release úlohy z kit.gradle.artifactory — posun verze, git tag, podpis a nahrání do Forgejo řeší plugin, workflow je jen obal.

vstup výchozí k čemu
modules — (povinné) Gradle cesty modulů, oddělené čárkou
app — (povinné) název aplikace z profile.yaml; úloha je <app>.release-<env>.<bump>
env test test nebo prod
bump patch patch, minor, nebo none (přebalení)
jdk8 false JDK 8 vedle 21
jvmargs -Xmx3g … org.gradle.jvmargs

java-docker-release.yaml

Staví a pushuje Docker image — backend přes Gradle (dockerPushAllImages nebo :modul:dockerPushImage), SPA přes spa/docker-image.sh. S java-release.yaml se nepřekrývá: ten vydává artefakty do Ivy/JFrog.

Spouští se jen z UI konzumenta (workflow_dispatch → workflow_call) — push image je vědomá akce, ne důsledek commitu.

vstup výchozí k čemu
tag pred Docker tag (dockerImageTag / SPA_TAG)
version — X.Y.Z → neměnný tag navíc + git tag vX.Y.Z (jen target: all)
additional-tags — další re-tagy po pushi, bez rebuildu
target all all, backend, nebo spa
modules — jen vybrané moduly, čárkou (cabinetry,hub-ui); backend vs. SPA se pozná příponou -ui
push true false = jen postavit, nepushovat
registry registry.maticon.cz registry pro ověřovací krok
jvmargs -Xmx3g … org.gradle.jvmargs

Navíc k běžným secrets potřebuje REGISTRY_USER (vars) + REGISTRY_PASS (secret) na docker login a MATICON_TOKEN na push git tagu.

Docker CLI a buildx si doinstaluje sám (apk, fallback apt-get) — runner image forgejo/runner je Alpine a Docker klienta neobsahuje, byť má DOCKER_HOST na socket proxy.

Git tag zakládá jen target: all bez modules, a teprve po úspěšném pushi i ověření registry. Tag je na celé repo, takže u částečného releasu by tvrdil, že vznikly i image, které se nepostavily.

java-promote.yaml

Přenese hotový release mezi prostředími — nestaví ani nepodepisuje, do produkce jde bajtově tentýž soubor.

vstup výchozí k čemu
modules, app — (povinné) jako výš
from / to TEST / PROD zdrojové a cílové prostředí
version (z gradle.properties) která verze se promuje

⚠️ eToken v CI nefunguje. Klientské JARy se podepisují hardwarovým tokenem v USB, takže repo se signing=etoken (dnes wardenero) vydává klienta lokálně; workflow zvládne jen server.

⚠️ Release potřebuje plnou historii (fetch-depth: 0 + tagy). Plugin kontroluje, jestli verze už nevyšla, a s mělkým klonem by tag nenašel.

rust-check.yaml

Formát, testy a clippy v jednom jobu.

Oddělit clippy by se hodilo (neblokoval by testy, při selhání by bylo hned vidět, co spadlo), ale u projektů s Tauri se za to platí instalací systémových knihoven nadvakrát — 266 balíčků, 163 MB a ~4,5 minuty na rozbalení a konfiguraci, protože každý job startuje v čerstvém kontejneru a stav systému se necachuje. Clippy se bez nich neobejde: gdk-sys build skript hledá GTK přes pkg-config už při kompilaci, takže padá i bez linkování.

Na našem runneru navíc joby běží sériově (jeden slot), takže oddělení dnes nezrychlí ani zpětnou vazbu. Až bude runner zvládat paralelizaci, rozdělení je otázka pár řádků.

vstup výchozí k čemu
exclude-packages (prázdné = všechny) balíčky VYNECHANÉ z fmt a clippy, jména oddělená mezerou
test-args --workspace argumenty pro cargo test
clippy false spustit clippy job
clippy-deny-warnings true -D warnings, tedy varování = chyba
tauri false doinstalovat GTK/WebKit pro Tauri

Vynechává se, nevyjmenovává. Seznam balíčků se odvozuje z cargo metadata; exclude-packages z něj jen ubírá. Cargo.toml s members = ["crates/*"] totiž přidá nový crate do workspace sám a ruční výčet by na něj zapomněl — crate by se tiše nekontroloval. Překlep v exclude-packages job zastaví s výpisem, co ve workspace není.

Vynechává se generovaný kód: formátovat ho nemá smysl a clippy na něm vyrábí stovky varování, která nikdo nečte. Testy ho naopak pokrývají, proto zůstává test-args: --workspace.

Toolchain se instaluje krokem (~15 s) — runner Rust mít nemusí. Verzi i komponenty bere rustup show z rust-toolchain.toml, takže se CI a lokální vývoj nerozejdou.

node-check.yaml

Install, testy, build. Jeden job — celá sada trvá jednotky sekund a zátěž je pnpm install, který by se v druhém jobu jen zopakoval.

vstup výchozí k čemu
node-version 22 drž shodné s .nvmrc a engines.node
pnpm-version — (povinné) MUSÍ odpovídat packageManager v package.json
test-command pnpm test z rootu; pnpm -r test v monorepu bez per-package skriptů neudělá nic
build-filter (prázdné = bez buildu) pnpm filtr, např. ./spa-apps/*
timezone UTC zóna pro celý job

build-filter musí začínat ./ — pak ho pnpm bere jako cestu. Bez tečky je to vzor na NÁZEV balíčku, takže spa-apps/* nematchne @scope/my-app a krok projde jako zelený, aniž by se cokoli postavilo.

timezone nastav tam, kde testy pracují s časem. Runner jede v UTC, takže testy s pevným časem (otevírací doba, formátování data) vycházejí posunuté — v kravify shodily build hláškou „expected '4:00–20:00' to match /6.*22/", přestože kód byl v pořádku. Totéž zafixuj i ve vitest konfiguraci, aby lokální běh dopadl stejně.


Použití

.forgejo/workflows/build.yaml v konzumentovi:

name: Build changed modules

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:

concurrency:
  group: build-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    uses: gradle/forgejo-workflows/.forgejo/workflows/java-build.yaml@main
    with:
      roots: 'client,libs,server'
      jdk8: true
    secrets: inherit

on: a concurrency: zůstávají v konzumentovi — reusable workflow je nedědí a každé repo je může chtít jinak.

Repozitáře na jiné Forgejo instanci (git.eiger.cz — springerize, eiger) odkazují plnou URL a musí si uvést runs-on samy:

jobs:
  build:
    runs-on: host          # ← nutné, viz níž
    uses: https://git.maticon.cz/gradle/forgejo-workflows/.forgejo/workflows/java-build.yaml@main

Důvod je v dokumentaci Forgejo: workflow z jiné instance nepodporuje „workflow expansion", která se tím automaticky vypne. Bez ní Forgejo nepřevezme runs-on z volaného workflow a job čeká na runner s prázdným labelem.

Na téže instanci se runs-on naopak vynechává — expansion funguje a zobrazí joby volaného workflow zvlášť, s vlastními runnery.

Vedlejší efekt vypnuté expansion: ve Forgejo UI se u cross-host volání objeví jen obalový job (Set up job / Complete job) místo jednotlivých kroků. Build běží správně, plný výstup je uvnitř Set up job — jen se hůř hledá. Zapnout to nejde, je to automatika.

Zkrácený tvar (gradle/forgejo-workflows/…) z jiné instance nefunguje: hledá organizaci lokálně a skončí na „user does not exist".

⚠️ Organizace nesmí mít v názvu tečku. Forgejo parsuje uses: jako <owner>/<repo>/<cesta>@<ref> a u tools.gradle/... nepozná, kde končí owner — skončí to na „expanding reusable workflow failed to access user tools.gradle: user does not exist". Proto gradle, ne tools.gradle.

⚠️ cancel-in-progress: true patří jen do build workflow. Release se rušit nesmí: zrušení uprostřed nahrávání assetů nechá release neúplný a kvůli skip-logice na velikosti a SHA by vypadal jako hotový.

Kdo to používá

repo roots jdk8
wardenero client,libs,server ✅
tornelix . ❌
bazaltis . ❌
springerize ¹ . ❌
eiger ¹ . ✅

¹ na git.eiger.cz — odkazuje plnou URL

java-docker-release:

repo co vydává ref
bazaltis 7 backend image + 9 SPA image SHA (viz Změny)

rust-check + node-check:

repo co
kravify Rust workspace (Tauri) + pnpm monorepo se SPA aplikacemi

Změny

⚠️ @main se neprojeví hned — Forgejo si stažené workflow cachuje. Zjištěno 2026-10-01 na bazaltis: po pushi opravy sem běžel konzument dál starou verzí (poznalo se to tak, že chybová hláška neodpovídala aktuálnímu kódu). „Rerun" nepomůže — přehrává tentýž běh s původním snapshotem definice. Nový běh cache obvykle obejde, spolehlivé to ale není.

Proto java-docker-release.yaml konzumuje bazaltis připíchnutý na commit SHA, ne @main: SHA je jiný ref, takže cache nemá co vrátit.

Push změny sem = úkol u konzumentů se SHA

Změna workflow, které konzument odkazuje přes SHA, se k němu sama nedostane — musí se v jeho .forgejo/workflows/*.yaml SHA bumpnout:

repo workflow ref
bazaltis java-docker-release.yaml SHA — bumpovat ručně
ostatní java-build.yaml, rust-check.yaml, … @main — propíše se samo (cache může zdržet)

Pořadí: nejdřív push sem, pak bump u konzumenta. Opačně odkazuje konzument commit, který na remote ještě není.

Volba refu

uses: .../java-build.yaml@main       # propíše se samo, cache může zdržet
uses: .../java-build.yaml@2b941f3    # reprodukovatelné, bump ručně

SHA stojí za to u workflow, které něco mění navenek (push image, git tag, release) — tam je nechtěná změna pod rukama drahá. U *-check workflow, kde nejhorší následek je falešně červený build, stačí @main.

Když by parametrů začalo přibývat nad rámec těch čtyř, je to signál, že se sdílení přepálilo — ne že je potřeba pátý.