# 8. Exit code — ainoa onnistumisen mittari ## Päätös Jokaisen `run`-stepin on nostettava virheellinen exit-koodi ylös sellaisenaan. Exit-koodia ei saa "syödä" missään tilanteessa. Onnistumisen ja epäonnistumisen päättely tapahtuu **ainoastaan** exit-koodin perusteella — ei tiedostojen olemassaolon, stdout-tulosteen tai minkään muun heuristiikan perusteella. ## Periaatteet 1. Exit-koodi on ainoa totuus. `0` = onnistui, kaikki muut = epäonnistui. 2. Exit-koodia ei saa syödä. Pipe (`|`) viimeisenä komentona `tee`:hen syö exit-koodin — `docker run … | tee file` palauttaa aina 0. 3. Data transfer -pipet ovat sallittuja (`tar c . | docker run … tar x`), koska niiden exit-koodilla ei ole semanttista merkitystä. 4. Testien tai työkalujen ajaminen ei saa päättyä pipeen. 5. `set -o pipefail` ei ole riittävä suojaus — PIPESTATUS resetoituu herkästi. ## Sallitut patternit ```yaml # Oikein: suora ajo, exit koodi $?:iin - name: Do work run: | some-command EXIT=$? echo "EXIT=${EXIT}" >> "${GITHUB_ENV}" exit ${EXIT} # Oikein: stdout talteen ilman pipeä - name: Do work run: | some-command > results.txt 2>&1 EXIT=$? echo "EXIT=${EXIT}" >> "${GITHUB_ENV}" exit ${EXIT} # Oikein: docker run ilman pipeä - name: Run in container run: | docker run --rm image command > output.txt 2>&1 EXIT=$? exit ${EXIT} ``` ## Kielletyt patternit ```yaml # Väärin: pipe syö exit-koodin - run: docker run … | tee results.txt # Väärin: pipe syö exit-koodin - run: tar … | docker … | tee file # Väärin: onnistumisen päättely tiedoston olemassaolosta - run: | some-command || true [ -f success.txt ] && exit 0 || exit 1 ``` ## Tausta Gitea Actionsissa `run`-stepin tila määräytyy viimeisen komennon exit-koodista. Pipe (`|`) asettaa `$?`:ksi viimeisen komennon tuloksen — jos viimeinen komento on `tee`, tulos on aina 0 riippumatta siitä mitä aiemmat komennot palauttivat. Tämä on aiheuttanut tuotannossa tilanteita, joissa testit feilasivat mutta jobi näytti vihreää, koska `tee` söi exit-koodin. Virhe havaittiin vasta kun raportteja alettiin lukea manuaalisesti — commit-status valehteli. Ratkaisu on yksiselitteinen: exit-koodi talteen `$?`-muuttujaan ennen kuin mikään muu komento ehtii muuttaa sitä, ja stepin viimeinen komento on aina `exit ${EXIT}`.