Co-authored-by: moilanik <niko.moilanen@tietoevry.com> Reviewed-on: #22
21 KiB
name, description, activation-gate, category, impact
| name | description | activation-gate | category | impact |
|---|---|---|---|---|
| consumer-pipelines | Creating or modifying consumer CI pipelines, .gitea/workflows/ files, reusable test workflows, monorepo CI configuration, or CI routing files (ci-feature.yml, ci-main.yml, ci-*.yml). Activates when the user asks to build, fix, or change consumer-side Gitea Actions pipelines that use gitea-ci-library providers. | User mentions consumer pipelines, ci-feature.yml, ci-main.yml, test workflows, .gitea/workflows/ files, monorepo CI, routing files, or asks to create/modify CI pipelines on top of gitea-ci-library. | ci | high |
Consumer Pipelines — Pipeline Standards
Säännöt joilla consumer-projektit rakentavat CI-pipelinejä gitea-ci-library-kirjaston päälle.
Nämä eivät ole provider-kirjaston sääntöjä — ne kuvaavat miten consumerin kuuluu käyttää kirjastoa oikein.
1. Reitittimen puhtaus
Reitittimet (ci-feature.yml, ci-main.yml) eivät sisällä run:-steppejä. Ne koostuvat vain:
uses:
needs:
if:
secrets: inherit
with:
env_json:
<parametrit>:
Jokainen job vastaa yhtä loogista testiä tai operaatiota. Reititin on orkestraattori — kaikki suorittava
logiikka on omassa workflow_call-tiedostossaan.
Esimerkki:
jobs:
load-config:
uses: <owner>/gitea-ci-library/.gitea/workflows/config-provider.yml@v1
secrets: inherit
<test-1>:
needs: [load-config]
uses: ./.gitea/workflows/<component>.<test-1>.yml
secrets: inherit
with:
env_json: ${{ needs.load-config.outputs.env_json }}
<test-2>:
needs: [load-config]
uses: ./.gitea/workflows/<component>.<test-2>.yml
secrets: inherit
with:
env_json: ${{ needs.load-config.outputs.env_json }}
report-summary:
needs: [load-config, <test-1>, <test-2>]
if: always()
uses: <owner>/gitea-ci-library/.gitea/workflows/report-summary.yml@v1
with:
env_json: ${{ needs.load-config.outputs.env_json }}
suites: <suite-1> <suite-2>
2. Yksi asia per tiedosto
Ei monoliittista ci-tests.yml. Jokainen testityyppi tai operaatio on oma workflow_call-tiedostonsa.
Miksi:
- Testit ajetaan rinnakkain (ei keinotekoisia riippuvuuksia)
- Yhden testin fail ei estä muita
- Testattavissa itsenäisesti
workflow_dispatch:llä - Diff näyttää heti mitä testiä muutettiin
3. Exit-koodin käsittely
set -e on oletuksena käytössä Gitea Actions -stepeissä — ensimmäinen feilaava komento pysäyttää stepin
ja exit-koodi välittyy natiivisti. Ylimääräistä EXIT=$? + echo >> GITHUB_ENV -käärettä ei tarvita.
- name: Run tests
shell: bash
run: |
<testikomento> > results.txt 2>&1
Miksi ei pipeä (| tee):
# VÄÄRIN — pipe syö exit-koodin
<komento> | tee results.txt
# OIKEIN — redirect tiedostoon
<komento> > results.txt 2>&1
set -e ei pelasta pipe-tilanteessa — | syö exit-koodin kuten ennenkin. Redirectillä exit-koodi
välittyy luonnollisesti.
Yksi asia per step: Älä koskaan niputa useaa post-process-komentoa samaan run:-blockiin.
bash -e pysäyttää koko stepin jos yksi komento epäonnistuu — seuraavat jäävät ajamatta.
Käytä erillisiä steppejä if: always():lla, jotta jokainen vaihe ajetaan itsenäisesti:
# VÄÄRIN — jos coverage epäonnistuu, report jää generoimatta
- name: Post-process reports
run: |
bash .ci/.gitea/scripts/bats-coverage.sh reports/bats
bash .ci/.gitea/scripts/bats-report.sh reports/bats
# OIKEIN — erilliset stepit if: always()
- name: Post-process coverage
if: always()
run: bash .ci/.gitea/scripts/bats-coverage.sh reports/bats
- name: Post-process test report
if: always()
run: bash .ci/.gitea/scripts/bats-report.sh reports/bats
4. Konttipolitiikka
- Julkiset registry-kontit kiinteällä versiolla —
alpine/helm:3.19.0,node:22,maven:3.9-eclipse-temurin-21. Toistettavuus ja turvallisuus eivät saa riippua ulkoisestalatest:sta - Projektin omat CI-kontit
latest-tägillä — buildattuci-container-build-<kontti>.yml:llä. Kontin build-pipeline päivittäälatest:n automaattisesti. Rebuild = käyttöönotto kaikissa pipelineissa ilman versioviittauksien päivittelyä.lateston näille paras käytäntö, ei kompromissi - Ei koskaan
curl-latauksia CI-ajon sisällä — työkalujen asennus CI-stepeissä hidastaa, epäluotettavaa, ja vaikeuttaa toistettavuutta - Konttikuva hallitaan workflow'ssa, ei kutsujassa — jos workflow vaatii tietyn
konttikuvan, se määritellään oletuksena (
default:) workflow'n inputissa. Kutsujan ei tarvitse tietää eikä välittää image-nimeä ellei halua ylikirjoittaa.
CI-kontin build-workflow'n template: skills/ci-container-build/SKILL.md — sisältää
valmiin ci-container-build-<kontti>.yml-pohjan jossa workflow_dispatch-tuki manuaaliajoon.
4.1 CI-kontin ajaminen jobissa
Ainoa sallittu tapa on container:-direktiivi. docker run komennolla kontin
käynnistäminen stepin sisällä on anti-pattern.
Miksi: docker run erilliskonttina aiheuttaa:
- Tiedostojen jako vaatii erillisen volyyminhallinnan (
docker volume create) - Coverage-data jää volyymiin, ei filesystemille → post-process-skriptit eivät löydä sitä
- Ylimääräisiä siirtoja (
tar,docker cp), jotka voivat epäonnistua hiljaa - Vaikeampi debugata (data on kontissa, ei CWD:ssä)
container:-direktiivillä kaikki ajetaan samassa kontissa — tiedostot ovat suoraan
filesystemillä, post-process-skriptit näkevät ne ilman erillistä siirtoa.
jobs:
<työkalu>:
runs-on: ubuntu-latest
container:
image: ${{ inputs.<image-name> }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v4
with:
repository: <owner>/gitea-ci-library
path: .ci
- name: Run <työkalu>
shell: bash
run: |
mkdir -p "reports/<suite>"
<komento> > "reports/<suite>/results.txt" 2>&1
- name: Post-process reports
if: always()
run: |
<mahdollinen_raporttien_jälkikäsittely>
- name: Report
if: always()
run: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite>
Jos testi tuottaa raportteja suoraan ilman jälkikäsittelyä, Post-process-steppiä ei tarvita.
Jos jälkikäsittely on tarpeen (coverage-siirto, HTML-generointi raa'asta outputista),
se tehdään omassa stepissä if: always() — katso tarkemmin Raporttitasot.
Mallit:
example-cucumber-tests.yml— ei post-processiaexample-bats-tests.yml— post-process coverage + report
5. Raporttitasot
Testi tuottaa raportin reports/<suite>/-hakemistoon. Yksi ci-report.sh-kutsu hoitaa sekä
julkaisun että commit-statuksen — erillistä Publish + Report Status -kaksivaiheisuutta ei tarvita.
Taso 1: Ei jälkikäsittelyä
Kun testi tuottaa raportit suoraan (kuten pytest --html tai cucumber-js --format html):
- name: Run tests
shell: bash
run: |
mkdir -p "reports/<suite>"
<testikomento>
- name: Report
if: always()
run: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite>
Taso 2: Jälkikäsittely tarvitaan
Kun testi tuottaa raakadataa (stdout, coverage-tiedostot) joka pitää muuntaa tai siirtää
reports/<suite>/-hakemistoon, käytetään Post-process-steppejä. Jokainen operaatio
omassa stepissään — älä koskaan niputa useaa post-process-komentoa samaan run:-blockiin:
- name: Run tests
shell: bash
run: |
mkdir -p "reports/<suite>"
<testikomento> > "reports/<suite>/results.txt" 2>&1
- name: Post-process coverage
if: always()
run: <siirrä coverage-data reports/<suite>/coverage/-hakemistoon>
- name: Post-process test report
if: always()
run: <HTML-generointi raa'asta outputista>
- name: Report
if: always()
run: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite>
Huomio subdir-sisällöstä: Jos testi tuottaa dataa alihakemistoon (esim.
coverage ./coverage/-kansioon), se pitää erikseen SIIRTÄÄ
reports/<suite>/<subdir>/-hakemistoon ennen ci-report.sh:n ajoa.
Ilman siirtoa sisältö ei näy index-sivulla, vaikka työkalu tuottaisi sen oikein.
Subdir vaatii lisäksi index.html:n, jotta ci-report.sh löytää sen.
Miksi: Gitea Actions käyttää bash -e-oletusta. Jos yksi post-process-komento
epäonnistuu (esim. set -euo pipefail-skripti), koko stepi pysähtyy eivätkä seuraavat
komennot käynnisty — raportti jää julkaisematta. Erilliset stepit if: always() takaavat
että jokainen post-process-vaihe ajetaan itsenäisesti.
Monta raportoitavaa tiedostoa
Kun reports/<suite>/-hakemistossa on useita tiedostoja tai alihakemistoja,
ci-report.sh generoi automaattisesti reports/<suite>/index.html jos hakemistossa
on enemmän kuin yksi raportoitava item.
reports/<suite>/
├── results.txt ← testin stdout (skannataan FILES)
├── test-report.html ← generoitu HTML (skannataan FILES)
└── <mikä tahansa>/ ← alihakemisto (skannataan SUBDIRS)
└── index.html ← VAIN jos tämä on olemassa
Subdir-sääntö: Alihakemisto näkyy indexissä VAIN jos se sisältää index.html:n.
Pelkkä tyhjä subdir ilman index.html:ää ei näy — tämä on yleisin syy miksi
jokin raportin osa (kuten coverage) puuttuu indexistä.
6. Raportin julkaisukelpoisuus
ci-report.sh päättää onko raportti julkaisukelpoinen skannaamalla
reports/<suite>/-hakemistoa.
Mitä skannataan
| Mitä | Sääntö |
|---|---|
| Tiedostot (FILES) | Kaikki reports/<suite>/-juuressa olevat tiedostot paitsi index.html |
| Alihakemistot (SUBDIRS) | Vain ne, joissa on index.html |
Julkaisukelpoisuus
| Tila | Seuraus |
|---|---|
FILES + SUBDIRS = 0 |
Failure — ci-report.sh palauttaa virheen, raporttia ei julkaista |
FILES + SUBDIRS = 1 |
Suora linkki itemiin — ei generoi index-sivua |
FILES + SUBDIRS > 1 |
Generoi reports/<suite>/index.html-sivun, linkit kaikkiin itemeihin |
Esimerkki: coverage-näkymä
reports/<suite>/coverage/index.html ← on olemassa
Coverage-dataa ei siirretä automaattisesti. Testin tai post-process-stepin pitää
siirtää coverage reports/<suite>/coverage/-hakemistoon ja varmistaa että
index.html on mukana. Sama periaate pätee mihin tahansa subdir-sisältöön.
7. Debug-ohje: raportti ei näy
1. Aja lokaalisti samalla komennolla kuin CI
Näet mitä tiedostoja syntyy, mihin ne tulevat ja mikä on työkalun exit-koodi.
# Esimerkki
mkdir -p reports/bats
bashcov -- bats tests/ > reports/bats/results.txt 2>&1
echo "exit: $?"
ls -la reports/bats/
2. Lisää echo "DEBUG: ..." >&2 ennen ja jälkeen kriittisen operaation
Debuggaus stderriin (>&2) näkyy CI-logissa eikä häiritse skriptin normaalia outputia.
echo "DEBUG: coverage exists? $([ -d coverage ] && echo YES || echo NO)" >&2
echo "DEBUG: target/index.html exists? $([ -f reports/suite/coverage/index.html ] && echo YES || echo NO)" >&2
3. Tarkista kutsuparametrit
Yleisin virhe: skripti odottaa $1 = X, mutta kutsuja antaa $1 = Y ja $2 = X.
Skripti lukee väärän parametrin ja etsii dataa väärästä paikasta.
4. Tarkista tiedostopolut
- Onko lähdetiedosto olemassa ennen kopiointia?
- Onko kohde olemassa kopioinnin jälkeen?
- Onko
index.htmlsubdirissä (vaaditaanci-report.sh:lle)?
Jos vastaus johonkin on "ei" — tiedät mikä pitää korjata.
5. Poista debug-echot kun ongelma on korjattu
Debug-rivit eivät kuulu tuotantoon.
6. Älä kokeile — debuggaa
Kokeilu = arvaus. Debuggaus = lisää echo, aja, lue logi, eristä ongelma. Vasta sitten korjaa. Tämä on nopeampi tie oikeaan ratkaisuun.
8. Nimeäminen
Tiedostonimet .gitea/workflows/-kansiossa noudattavat yhtenäistä rakennetta, jotta
tiedostot löytyvät nopeasti ja niiden rooli on selvillä:
<komponentti>.ci-feature.yml ← feature-haaran reititin
<komponentti>.ci-main.yml ← main-haaran reititin
<komponentti>.<testityyppi>.yml ← yksittäinen testi tai operaatio
<komponentti>.ci-container-build-<kontti>.yml ← CI-kontin build-workflow
<komponentti>.gitea-env.conf ← komponenttikohtainen konfiguraatio
Single repossa <komponentti> jätetään pois — tiedostot ovat suoraan ci-feature.yml,
ci-main.yml, <testityyppi>.yml, ci-container-build-<kontti>.yml.
Monorepossa prefiksi pitää komponentin tiedostot yhdessä: ls <komponentti>.* löytää kaikki
kerralla.
9. Artifact-kuri
Gitea Actionsin upload-artifact jättää pysyvän tiedoston. Artifakteja ei käytetä
workflow_call:ien väliseen datan siirtoon ellei se ole teknisesti välttämätöntä.
Ensisijainen ratkaisu: jokainen testi tuottaa tarvitsemansa datan itse. Ei
upload-artifact + download-artifact -riippuvuuksia.
# OIKEIN — molemmat testit tuottavat oman datansa
- name: Prepare data
run: <komento> > /tmp/data
- name: Validate data
run: <validointikomento> /tmp/data
Miksi:
- Testit pysyvät itsenäisinä — yhden testin fail ei estä muita
- Ei "artifact expired" -virheitä myöhemmin
- Ei pysyviä artifakteja siivoamatta
Konfiguraatiotiedosto (.gitea-env.conf)
Tiedosto on key=value-muotoinen (kuten .env). Kommentit ja tyhjät rivit sallittuja.
Single repo
# .gitea/workflows/gitea-env.conf
GITEA_API_URL=https://gitea.example.com
GIT_PAGES_URL=https://reports.example.com
Docker-artifaktin buildaavat projektit
DOCKER_REGISTRY=gitea.example.com/myorg
DOCKER_IMAGE_NAME=my-service
DOCKER_UI_URL=https://gitea.example.com/myorg/-/packages/container
#DOCKERFILE=Dockerfile.platform # valinnainen, oletus Dockerfile
DOCKER_UI_URL ei sisällä image-nimeä — se on puhdas container-registryn osoite.
Image-nimi lisätään automaattisesti URL:iin docker-build-push.yml:ssä.
Salaisuudet (Gitea Settings → Secrets)
| Secret | Pakollinen |
|---|---|
GITEA_TOKEN |
Aina (Gitean sisäinen, automaattisesti saatavilla) |
GIT_PAGES_PUBLISH_TOKEN |
Aina |
DOCKER_USERNAME |
Vain jos buildaat kontteja |
DOCKER_PASSWORD |
Vain jos buildaat kontteja |
Monorepo
Monorepossa yhdessä repossa asuu useampi julkaistava komponentti. Jokaiselle komponentille
oma conf-tiedosto .gitea/workflows/<komponentti>.gitea-env.conf, jossa on kaikki
komponenttikohtainen tieto.
Suositus: komponentit omiin juurihakemistoihin
On suositeltavaa sijoittaa jokaisen komponentin koko lähdekoodi omaan juuritason
hakemistoonsa (api/, frontend/, shared/). Tämä helpottaa paths:-filtteröintiä,
pitää komponentit selkeästi erillään, ja tekee repossa navigoinnista suoraviivaista.
Tämä on kuitenkin vain suositus — ei pakottava sääntö.
Ongelmat ja ratkaisut
| Ongelma | Ratkaisu |
|---|---|
| Monta komponenttia, yksi repo — mikä triggeröi? | paths:-filtteri: push: { paths: ['<komponentti>/**'] } |
| Jokaisella komponentilla oma versio | VERSION_FILE=<komponentti>/package.json confissa |
| Git-tägit sekaisin ellei nimiavaruutta | GIT_TAG_PREFIX=<komponentti>/ confissa → tägi <komponentti>/1.2.3 |
| Eri julkaisutahdit | Riippumattomat CI-triggerit, omat versiopolut |
Komponenttikohtainen conf
# .gitea/workflows/<komponentti>.gitea-env.conf
GITEA_API_URL=https://gitea.example.com
GIT_PAGES_URL=https://reports.example.com
DOCKER_REGISTRY=gitea.example.com/myorg
DOCKER_IMAGE_NAME=<image-nimi>
DOCKER_UI_URL=https://gitea.example.com/myorg/-/packages/container
GIT_TAG_PREFIX=<komponentti>/
# Jompikumpi — JSON (.version-kenttä) tai plain text:
VERSION_FILE=<komponentti>/package.json
#VERSION_FILE=<komponentti>/VERSION
Monorepo reititin
name: CI <Komponentti> Main
on:
push:
branches:
- main
paths:
- '<komponentti>/**'
jobs:
load-config:
uses: <owner>/gitea-ci-library/.gitea/workflows/config-provider.yml@v1
secrets: inherit
with:
config_path: .gitea/workflows/<komponentti>.gitea-env.conf
check-version:
needs: [load-config]
uses: <owner>/gitea-ci-library/.gitea/workflows/check-version.yml@v1
secrets: inherit
with:
env_json: ${{ needs.load-config.outputs.env_json }}
<testit>:
needs: [load-config, check-version]
if: needs.check-version.outputs.artifact_exists != 'true'
uses: ./.gitea/workflows/<komponentti>.<testi>.yml
secrets: inherit
with:
env_json: ${{ needs.load-config.outputs.env_json }}
build-push:
needs: [load-config, check-version, <testit>]
if: needs.check-version.outputs.artifact_exists != 'true'
uses: <owner>/gitea-ci-library/.gitea/workflows/docker-build-push.yml@v1
secrets: inherit
with:
env_json: ${{ needs.load-config.outputs.env_json }}
version: ${{ needs.check-version.outputs.version }}
Version elinkaari per komponentti
GIT_TAG_PREFIX takaa että eri komponenttien versiohistoria pysyy erillään.
Git-tägi <komponentti>/0.2.3 ei sekoitu toisen komponentin tägeihin.
check-version.yml suodattaa ja laskee seuraavan patchin vain kyseisen
komponentin etuliitteellä. Idempotenttius toimii komponenttikohtaisesti:
jos commitilla on jo tägi, pipeline skipataan if: artifact_exists != 'true'.
Mitä EI kannata tehdä monorepossa
- Älä aja kaikkia komponentteja samasta triggeristä —
paths:pitää CI:t erillisinä - Älä käytä samaa versionhallintatiedostoa usealle komponentille
- Älä anna monorepo-parametreja pipeline-overrideina — kaikki kuuluu conf-tiedostoon
Versionhallinta
check-version.yml lukee version automaattisesti prioriteettijärjestyksessä:
| # | Lähde | Formaatti |
|---|---|---|
| 1 | VERSION_FILE confissa |
Määritelty polku |
| 2 | VERSION-tiedosto (root) |
Plain text |
| 3 | package.json (root) |
.version-kenttä |
| 4 | pom.xml (root) |
<version>-elementti |
major.minor otetaan tästä. Patch lasketaan automaattisesti git-tageista.
Esim. VERSION = 0.2, tagit = 0.2.0, 0.2.1 → seuraava 0.2.2.
Branch protection (PR-gate)
Gitean Settings → Branches → Add Rule:
- Branch:
main - Enable Require Status Checks: päälle
- Status checks: valitse testijobien nimet
Provider-rajapinnat — referenssi
Workflowt
| Workflow | Käyttötarkoitus |
|---|---|
config-provider.yml |
Lataa + validoi .conf, tuottaa env_json |
check-version.yml |
Tarkistaa onko commit buildattu, laskee version |
docker-build-push.yml |
Buildaa + puskea Docker-imagen, tagittaa commitin |
report-summary.yml |
GITHUB_STEP_SUMMARY-taulukko raporttilinkeillä (Gitea 1.27+) |
Skriptit (kutsutaan .ci/scripts/-polun kautta)
| Skripti | Käyttötarkoitus |
|---|---|
ci-report.sh |
Yhdistetty raportointi: julkaisee git-pagesiin ja asettaa commit-statuksen. Korvaa erilliset publish-git-pages.sh + report-status.sh -kutsut. Käyttö: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite> |
report-status.sh |
POSTaa commit-statuksen linkillä (kutsutaan ci-report.sh:n sisältä) |
publish-git-pages.sh |
Julkaisee raporttihakemiston git-pagesiin (kutsutaan ci-report.sh:n sisältä) |
ci-validate.sh |
Validoi .conf-tiedoston (kutsutaan config-provider.yml:stä) |
ADR-yhteenveto — consumerin kannalta oleelliset säännöt
Reititin ei sisällä suorittavaa koodia (ADR 0010)
ci-feature.yml ja ci-main.yml koostuvat vain uses:, needs: ja if:-avainsanoista.
Ei run:-komentoja, ei inline-skriptejä, ei actions/checkout.
Yksi steppi = yksi workflow_call-tiedosto
Jokainen job reitittimessä on oma workflow_call-tiedostonsa.
Ei kahta eri komentoa samassa workflow'ssa.
Provider-versio on @v1 (ADR 0009)
Kaikki provider-viittaukset käyttävät @v1-tagia. @main on vain providerin oman repon
sisäiseen dogfood-käyttöön. Breaking changet kielletty — v1-rajapinta on pysyvä.
Paikalliset uses: eivät käytä refiä
Gitea act runner v1.0.8 muodostaa paikallisista uses: ./.gitea/workflows/*.yml@main-viittauksista
epävalidin git-refin main@<sha>, joka aiheuttaa virheen Revision invalid : reference must be defined once at the beginning.
Paikallisista uses:-direktiiveistä EI koskaan käytetä @main- tai muuta ref-päätettä:
uses: ./.gitea/workflows/chart.helm-lint.yml← oikeinuses: ./.gitea/workflows/chart.helm-lint.yml@main← väärin
Ilman refiä runner käyttää workflow'ta triggeröivästä commitista. Ulkoisten repojen
viittauksissa (niko/...@v1) pääte pysyy. Nämä resolvoidaan eri reittiä ja toimivat oikein.
Exit-koodi on ainoa onnistumisen mittari (ADR 0008)
Ei pipeä (|) komennon perässä — se syö exit-koodin. Käytä redirectiä (> file 2>&1).
Commit-status vain raporttilinkille (ADR 0007)
ci-report.sh-skriptiä käytetään VAIN kun on raportti linkitettäväksi.
Tool-jobit (build, deploy) luottavat Gitean natiiviin job-statukseen.
Providerin checkout ei kuulu consumerille
Providerin scriptit haetaan actions/checkout-stepillä .ci/-polkuun.
Consumer ei kopioi eikä muokkaa providerin tiedostoja.