Files
gitea-ci-library/docs/ci-pipeline-practices.md
T
moilanik 0da16af045
CI / Load gitea-env.conf to pipeline env (push) Successful in 13s
CI / Quality Gate (push) Failing after 0s
CI / Build & Push Artifact (push) Has been skipped
masteria varten haarat kuntoon
2026-06-14 08:42:47 +03:00

9.5 KiB

**⚠️ STATUS: ALERT DRAFT** — Ei ole validoitu. Voi sisältää virheellisiä tai puutteellisia käytäntöjä.

CI Pipeline Practices

1. Error Taxonomy

Taso Esimerkki Status URL Job status
Tool failure npx ei löydy, python3 puuttuu Gitea Actions logi fail
Test failure assertio feilaa, testi palauttaa nollasta poikkeavan Raportti git-pagesissa fail
Suite failure Build ei päässyt ajoon Raportti git-pagesissa fail
  • Tool ja test erotetaan omiin steppeihin
  • Tool check: --help ei riitä, lataa --dry-run moduulit
  • Tool fail → linkki Gitea logiin; test fail → linkki raporttiin
  • Jobin status tulee exit-koodista (exit $?), ei raporttitiedostojen olemassaolosta

2. Job Reporting

  • Jokainen suite julkaisee raporttinsa omaan alihakemistoonsa: reports/{SHA8}/{suite}/
  • Commit status URL osoittaa suoraan suitelinkkiin
  • Raportit tuotetaan ja julkaistaan aina (if: always()) — testin lopputuloksesta riippumatta
  • Linkkejä summary-sivuille ei tarvita — kukaan ei sinne pääse ilman suoraa URLia
  • Index.html suitetason raporttiin generoidaan aina, linkittää kaikkiin suiten tiedostoihin

3. Docker-in-Docker Volume Mount

Runner-kontti ja Docker daemon näkevät eri polut. -v "$PWD":/path ei toimi — runner-näkökulman polku ei ole daemonin näkökulman polku.

Kolme toimivaa vaihtoehtoa:

  • container: keyword — runner hoitaa mountin oikein
  • docker volume create -- docker run -v volume:/data -- docker run -v volume:/data
  • tar c . | docker run --rm -i -v volume:/data alpine tar x -C /data

4. Env variable scope (validated 2026-06-13)

env: — oli se workflow- tai job-tasolla — toimii vain natiiveissa shell-stepeissä ja docker run -e VAR -komennoissa. docker run ilman -e-lippua ei peri env:-muuttujia.

Tämä on validioitu POC-ajolla: tmp/poc-env-scope.yml

Sijainti Native shell docker run ilman -e docker run -e VAR
workflow env: perii tyhjä perii
job env: perii tyhjä perii
GITHUB_ENV perii tyhjä perii

Käytäntö:

  • Workflow-tason env: sopii arvoille, joita tarvitaan natiivistepeissä (publish, status, reportointi)
  • Jos docker run tarvitsee env-arvoja, välitä ne eksplisiittisesti -e VAR-lipulla
  • GITHUB_ENV on validi tapa välittää arvoja stepien välille samassa jobissa, mutta ei leviä docker run-kontteihin ilman -e-lippua

Cross-job config propagation (validated 2026-06-13)

Config-arvojen vienti kaikkiin jobeihin ilman toistoa vaatii kahden mekanismin ketjuttamista:

  1. needs + with:jobs.<job_id>.with.<with_id> tukee needs-kontekstia. Tämä mahdollistaa sen, että yhden jobin outputit voidaan välittää toiselle reusable workflowille inputeina.
  2. Workflow env: — ainoa natiivi mekanismi, joka tekee arvoista näkyviä kaikissa jobeissa automaattisesti (POC validioitu).

Ketju toimii näin:

gitea-env.conf  →  config-provider.yml  →  env_json (yksi JSON-string)
       (1)                                    (2)
                                                 ↓
                                        ci.yml with: env_json
                                        ${{ needs.load-config.outputs.env_json }}
                                          (3)
                                                 ↓
                                        build-feature.yml workflow env:
                                        GITEA_API_URL: ${{ fromJson(inputs.env_json).GITEA_API_URL }}
                                          (4)
                                                 ↓
                                         kaikki jobit → $GITEA_API_URL, $GIT_PAGES_URL jne.
                                          (5)

Vaiheet:

  1. Consumer määrittelee arvot gitea-env.conf:ssä (KEY=VALUE)
  2. config-provider.yml lukee confin ja tuottaa yhden JSON-stringin outputina
  3. ci.yml välittää JSONin needs + with: -ketjulla
  4. build-feature.yml purkaa arvot workflow env:-tasolle fromJson():lla
  5. Kaikki jobit käyttävät valmiita env-muuttujia ($GIT_PAGES_URL jne.)

Avainkomponentit:

  • config-provider.yml — reusable workflow, joka muuntaa conf-tiedoston yhdeksi JSON-outputiksi. Yksi output riittää, ei per-key outputteja.
  • jobs.<job_id>.with — tukee needs-kontekstia (Gitea Actions, kuten GitHub Actions). Tämä on kriittinen yksityiskohta: ilman tätä config-arvoja ei voi välittää reusable workflowille dynaamisesti.
  • workflow env: — ainoa tapa jakaa arvot kaikkiin jobeihin. fromJson(inputs.env_json).KEY purkaa yksittäiset arvot ilman toistoa.
  • Per-job env: — sisältää vain secretit (GITEA_TOKEN, GIT_PAGES_PUBLISH_TOKEN), ei config-arvoja.

5. Pipeline Provides All Dependencies

  • Ei luottamusta runnerin esiasennettuihin työkaluihin
  • apk add, npm install, apt-get install — kaikki pipelinesta
  • Erityisesti: curl, lsof, jq, python3 unohtuvat helposti
  • Node-version päivitettävä jos paketti vaatii uudempaa (node:20node:22)
  • Jos kontin entrypoint on sh (Alpine ash), käytä --entrypoint bash

6. Rakenne

  • Rinnakkaiset jobit (bats + cucumber) — tuloksia saa heti kun valmistuu
  • Jokainen testisetti omassa jobissaan
  • Finalize/build voi kerätä yhteenvedon (ei julkaista summarya jos kenelläkään ei ole linkkiä)

7. Commit Status Before Exit

Commit status (ci-bats, ci-cucumber) on asetettava ennen stepin exit-komentoa, samassa shell-prosessissa. Ei GITHUB_ENV-propagointiin luottamista stepien välillä — Gitea Actions ei välttämättä prosessoi GITHUB_ENV-tiedostoa epäonnistuneen stepin jälkeen.

Käytäntö testi-stepissä:

testit_ajoon
EXIT=$?

STATE="success"
[ "${EXIT}" != "0" ] && STATE="failure"

# Jos raportti on kirjoitettu levylle → linkki git-pagesiin
if [ -f "reports/${SHA8}/sute/index.html" ]; then
  bash .ci/scripts/report-status.sh "${STATE}" "Kuvaus" ci-{suite} {suite}
else
  # Muuten linkki Gitea Actions logiin
  bash .ci/scripts/report-status.sh "${STATE}" "Kuvaus" ci-{suite}
fi

exit ${EXIT}

Tämä takaa:

  • Aina commit status riippumatta siitä, onko kyseessä tool- vai test error
  • Oikea URL: raportti git-pagesissa (jos tiedosto on kirjoitettu) tai Gitea Actions logeissa
  • PR merge-esto toimii luotettavasti: branch protection näkee statuksen aina, koska se kirjoitetaan ennen stepin failaamista

Julkaisu (publish-git-pages.sh) jää edelleen omaksi stepikseen if: always():lla.

8. Pipeline Exit Code Safety (validated 2026-06-14)

Pipeline (cmd1 | cmd2 | cmd3) asettaa $?:ksi viimeisen komennon exit-koodin. Jos tee tai muu aina-onnistuva komento on viimeisenä, testin todellinen exit-koodi katoaa.

Dangerous patterns

Pattern $? captures Result
docker run … | tee file tee:n exit (0) test error kadotettu
tar | docker | tee tee:n exit (0) test error kadotettu
docker run … 2>&1 | tee file tee:n exit (0) stderr-ohjaus ei auta
set -o pipefail + pipeline viimeisen epäonnistuneen exit ⚠️ pipefail riippuu bash-versiosta ja PIPESTATUS resetoituu helposti

Safe patterns

Pattern $? captures Verified
docker run … > file 2>&1 suoraan kontin exit lokaali + CI
docker volume + tar | alpine tar x (data transfer) + docker run > file suoraan kontin exit lokaali + CI

Why volume-based approach works

Kolmen erillisen komennon ketju ilman testiä putkittavaa pipeä:

docker volume create ws           # 1. volyymi
tar c . | docker run … alpine …   # 2. data volyymiin (tämä on pipe, mutta data transfer)
docker run -v ws:/data … > file   # 3. testit → exit koodi $?:iin puhtaana

Vaihe 2 on pipe, mutta se on data transfer — sen exit-koodilla ei ole väliä. Vaihe 3 on suora docker run > file ilman pipeä, joten $? on aina kontin exit.

Debug-näkyvyys ilman tee:tä

tee antaa real-time logit, mutta tappaa exit-koodin. Ratkaisu: jaa kahteen steppiin:

- name: Run tests
  run: |
    docker run … > results.txt 2>&1
    EXIT=$?
    echo "EXIT=${EXIT}" >> "${GITHUB_ENV}"
    exit ${EXIT}

- name: Publish reports
  if: always()
  run: publish.sh

- name: Set commit status
  if: always()
  run: |
    [ "${EXIT}" = "0" ] && report-status.sh success … || report-status.sh failure …

if: always() julkaisee raportit ja asettaa commit statuksen riippumatta testin lopputuloksesta. GITHUB_ENV:iin talletettu exit-koodi on luettavissa myöhemmissä stepeissä.

Oppitunti

Pienikin muutos — kuten | tee lisääminen debug-näkyvyyttä varten — voi murtaa error propagationin huomaamatta. Ainoa tapa varmistua on testata lokaalisti kontissa:

docker run … > results.txt 2>&1
EXIT=$?
echo $EXIT   # pitää olla 1 jos testit failaa

9. Inline Logic Threshold

Logiikka workflow YAML:ssa on hauras: YAML:n sisennys, heredocit ja kenoviivat tuottavat helposti toimimattomia steppejä.

Kynnys siirtää scriptiksi: heti kun steppiin tulee ehtoja, silmukoita, tai yli 3 riviä inline-koodia, siirrä omaksi scriptikseen .gitea/scripts/- kansioon.

Esimerkki: coverage-datan purku ja navigointi-indexin luonti oli aluksi inline-heredocina workflow YAML:ssa. Siirto omaan bats-coverage.sh-scriptiin teki siitä luettavan, testattavan ja muokattavan ilman YAML-muotoiluriskejä.