Co-authored-by: moilanik <niko.moilanen@tietoevry.com> Reviewed-on: #12
10 KiB
Design Rationale — Gitea Actions CI -kirjasto
Miksi kirjasto on rakennettu näin. Arvot, periaatteet ja reunaehdot, joiden varaan arkkitehtuuri nojaa.
Tämä dokumentti on normatiivinen — arkkitehtuurin on noudatettava näitä periaatteita. Jos ehdotettu muutos on ristiriidassa rationalen kanssa, rationalen on muututtava ensin.
Miksi tämä projekti on olemassa
Mikropalveluarkkitehtuurissa jokainen palvelu tarvitsee CI-putken: testit,
laatutarkistukset, buildin, kontituksen ja julkaisun. Ilman jaettua
kirjastoa jokainen tiimi kopioi saman YAML-boilerplaten, tekee omat
virheensä ja ylläpitää omaa versiotaan. Ajan myötä putket ajautuvat erilleen
— toisessa on shell: bash, toisessa ei; toinen käyttää set -o pipefail,
toinen kadottaa exit-koodin tee:hen.
Tämä kirjasto on se mitä kopioidaan. Se tarjoaa valmiit, testatut,
dokumentoidut rakennuspalikat joista jokainen tiimi kokoaa oman putkensa.
Palikat ovat Gitea Actionsin uses:-direktiivillä kutsuttavia reusable
workflow'ta — ei asennusta, ei runtime-riippuvuutta, ei versiopäivityksiä
projekteihin.
Suunnitteluperiaatteet
1. Palikka-arkkitehtuuri: pieniä, vaihdettavia, yhden vastuun workflow'ta
Jokainen provider-workflow tekee yhden asian:
| Workflow | Vastuu |
|---|---|
config-provider.yml |
Lataa ja validoi konfiguraatio |
check-version.yml |
Tarkistaa onko commit buildattu, laskee version |
docker-build-push.yml |
Buildaa, puskea ja tagittaa kontin |
Mikään workflow ei kutsu toista provider-workflowta. Consumer — siis mikropalvelun oma pipeline-tiedosto — on ainoa paikka joka tietää mitä palikoita tarvitaan ja missä järjestyksessä.
Miksi: Tämä on sama periaate kuin Unix-putkissa tai mikropalveluissa: pieniä, itsenäisiä komponentteja jotka tekevät yhden asian hyvin. Consumer voi vaihtaa yhden palikan toiseen — esimerkiksi Docker-buildin tilalle Maven-paketoinnin — ilman että muut palikat muuttuvat. Ratkaisu ei ole se että kaikki ajetaan, vaan se että jokainen tiimi valitsee mitä tarvitsee. Monoliittinen "kaikki yhdessä" -workflow pakottaisi jokaisen tiimin ajamaan tarpeettomia vaiheita.
2. Gitea ensin — hyödynnä alustaa, älä taistele sitä vastaan
Gitea Actions tarjoaa kolme asiaa ilmaiseksi:
- Jobien visuaalinen status — jokainen jobi näkyy automaattisesti commit-näkymässä checkmarkilla, spinnerillä tai ristillä.
- Cross-job riippuvuudet —
needshoitaa virheiden propagointin: jos edeltävä jobi feilaa, riippuvat jobit skipataan. - Reusable workflow -jakelu —
uses: org/repo/.gitea/workflows/file.yml@v1on natiivisti versioitu, skopattu ja välimuistitettu.
Kirjasto käyttää näitä kaikkia. Ei omaa tilakonetta, ei custom action -runtimea, ei ulkoista orkestraattoria.
Esimerkki: Tool-jobit eivät kutsu commit-status API:a lainkaan.
Gitean oma job-status riittää — success/failure/running näkyy
automaattisesti. API:a käytetään vain kun tarvitaan custom-linkki
(testiraporttiin tai Docker registryyn), jota natiivistaatus ei tarjoa.
Tämä linjaus on dokumentoitu ADR 0004 ja 0007:ssä.
3. Status näkyy siellä missä työ tehdään — Git-commitissa
Kehittäjä työskentelee Gitissä. git log, git blame, PR-näkymä —
nämä ovat päivittäiset työkalut. CI-statuksen kuuluu näkyä siellä,
ei erillisessä dashboardissa.
Gitea Actionsin natiivi job-status tekee tämän automaattisesti:
jokainen commit näyttää välittömästi mitkä jobit on ajettu ja millä
tuloksella. Testiraportteihin pääsee yhdellä klikkauksella commitin
status-kuvakkeesta — koska report-status.sh asettaa target_url:n
osoittamaan suoraan HTML-raporttiin git-pagesissa.
Tämä ei ole kosmeettinen yksityiskohta. Se on devops-käytännön ydin: palautesilmukka on lyhin mahdollinen. Commit → build → status näkyy samassa näkymässä jossa kehittäjä jo on.
4. Exit-koodi on ainoa totuus
CI-putken jokaisen run-stepin onnistuminen määräytyy vain ja
ainoastaan exit-koodin perusteella. Ei tiedoston olemassaolon, ei
stdout-tulosteen, ei arvauksen. 0 = ok, kaikki muu = ei ok.
Tämä kuulostaa itsestään selvältä, mutta YAML-pipelineissa se rikkoutuu
helposti. Pipe (|) tee:hen syö exit-koodin. Tiedoston olemassaolon
tarkistus ([ -f results.xml ]) ei kerro testien läpimenosta.
Käytännössä: Jokainen run-steppi ottaa exit-koodin talteen
$?-muuttujaan ennen kuin mikään muu komento ehtii muuttaa sitä,
ja stepin viimeinen rivi on exit ${EXIT}. Pipeä ei käytetä
työvaiheen viimeisenä komentona. Ks. ADR 0008.
5. Pienin mahdollinen pinta-ala
Jokainen ylimääräinen riippuvuus on ylimääräinen vikaantumispiste. Kirjaston ainoat riippuvuudet:
- Gitea Actions (alusta)
bash,curl,jq(ubuntu-latest runnerissa valmiina)- Docker (runnerissa valmiina)
- git-pages (raporttien hostaus, erillinen palvelu)
Ei Pythonia, ei Node.js:ää ajonaikaisesti (testit omissa konteissaan). Ei tietokantaa. Ei ulkoista tilanhallintaa. Kirjasto on joukko YAML-tiedostoja ja shell-skriptejä — samat työkalut jotka jokainen devops-ihminen jo osaa.
6. Konfiguraatio repoon, salaisuudet Giteaan
Projektikohtainen konfiguraatio (.gitea/workflows/gitea-env.conf)
asuu mikropalvelun omassa repossa. Kehittäjä omistaa sen — hän tietää
mikä on Docker-imagen nimi, mihin registryyn puskea, mikä on
testiympäristön URL.
Salaisuudet (tokenit, salasanat) elävät Gitean secrets-mekanismissa,
eivät repon tiedostoissa. secrets: inherit välittää ne providerin
workflow'hun ilman että consumerin tarvitsee tietää mitä salaisuuksia
mikäkin provider tarvitsee.
Poikkeus: infra-tason asetukset (GIT_PAGES_URL, GITEA_API_URL)
ovat Gitean organization secrets/variables -mekanismissa. Ne eivät
ole repokohtaisia.
7. Consumer omistaa orkestroinnin, provider tarjoaa palikat
Tämä on kirjaston tärkein arkkitehtuurinen päätös (ADR 0005).
Provider (gitea-ci-library) ei tiedä mitä testejä ajetaan, missä
järjestyksessä, tai millä branchilla. Se tarjoaa kolme reusable
workflow'ta ja joukon skriptejä.
Consumer (mikropalvelun example-feature.yml / example-main.yml)
päättää:
- Mitkä palikat kutsutaan
- Missä järjestyksessä (
needs) - Millä branch-ehdoilla (
if) - Mitkä testikontit käytetään (input-parametrit)
Tämä on tarkoituksellinen vallanjako. Provider ei voi tietää jokaisen
tiimin tarpeita — eikä sen pidäkään. Consumer ei voi muuttaa providerin
sisäistä toteutusta — eikä sen pidäkään. Rajapinta on workflow_call ja
se on molemmille osapuolille selvä.
8. Branch-kohtainen reititys, ei yhtä kaikille
Eri brancheilla on eri tavoite:
- Feature-haara: Onko koodi laadukasta? → testit, validointi
- Main-haara: Onko tästä versiosta jo artifakti? Jos ei → testit + build + push + tag. Jos on → ei tehdä mitään (tai jatketaan klusteritesteihin).
Tämä logiikka elää consumerin pipeline-tiedostossa, ei providerissa.
Se on puhdasta if-ehtoa ja needs-ketjutusta — ei skriptausta,
ei monimutkaisia ehtoja providerin sisällä.
9. Raportit erillisellä palvelulla, linkit commitissa
Gitea Actionsin artifact-järjestelmä on binääriarkisto — ZIP-lataus, ei HTML-selailtavuutta. Testiraportit (Cucumber HTML, Bats-coverage) on voitava avata selaimessa yhdellä klikkauksella.
Ratkaisu: git-pages Helm-chartti, joka tarjoaa staattista
tiedostohostingia HTTP:llä. publish-git-pages.sh vie raportit
sinne; report-status.sh linkittää commit-statuksen suoraan
raporttiin. Retention hoitaa git-pagesin sidecar automaattisesti.
Tulevaisuudessa GITHUB_STEP_SUMMARY (Gitea 1.27+) tarjoaa
vaihtoehtoisen kanavan: jobin Summary-välilehdelle renderöityvä
Markdown-taulukko kaikista raporttilinkeistä.
10. Vain Gitea — ei monialustatukea ilman tarvetta
Yhden alustan tukeminen kunnolla on vaikeampaa kuin kolmen tukeminen
huonosti. Gitea Actionsin uses:-mekanismi, needs-semantiikka,
secrets: inherit, gitea-konteksti — nämä ovat alustakohtaisia
ominaisuuksia joita abstraktiokerros vain haittaisi.
Jos toinen alusta tulee ajankohtaiseksi, sille kirjoitetaan oma toteutus. Siihen asti yksi alusta riittää. Ennenaikainen yleistys on devopsissa yhtä haitallista kuin ohjelmistosuunnittelussa.
Arkkitehtuuriset rajoitteet
Mitä kirjasto EI tee
- Ei ulkoista orkestraattoria. Pipeline-ohjaus on Gitea Actionsin
needs-ketjuissa ja consumerinif-ehdoissa. - Ei custom actioneita. Reusable workflow on kevyempi, versioitu ja jaeltu Gitean oman mekanismin kautta.
- Ei asennusta projekteihin. Consumer viittaa
uses:-direktiivillä suoraan tämän repon workflow-tiedostoihin. Ei npm-pakettia, ei git-submodulea, ei kopioitavia tiedostoja. - Ei runtime-riippuvuuksia. Provider-skriptit käyttävät vain
työkaluja jotka ovat Gitea Actionsin
ubuntu-latestrunnerissa valmiina:bash,curl,jq. - Ei monorepo-konfiguraatiota. Jokainen mikropalvelu omistaa oman pipeline-tiedostonsa ja konfiguraationsa.
Mitä tietoisesti hylättiin
| Hylätty | Syy |
|---|---|
| Monoliittinen "kaikki yhdessä" -workflow | Pakottaa kaikille samat vaiheet. Palikka-arkkitehtuuri antaa jokaiselle tiimille vain mitä se tarvitsee |
| Oma orkestraattoripalvelin | Ylimääräinen ylläpidettävä. Gitean needs ja if riittävät |
| Docker-pohjaiset custom actionit | Tuovat riippuvuuden Docker-rekisteriin. Reusable workflow on natiivimpi |
| Commit-status API jokaiselle vaiheelle | Duplikointia — Gitea näyttää job-statuksen automaattisesti. API vain custom-linkeille |
tee-putki debug-näkyvyyteen |
Syö exit-koodin. stdout ohjataan tiedostoon > ilman pipeä |
| Multi-Git-platform-tuki | Ennenaikaista optimointia ilman tarvetta |
| Gitea Packages raporttien hostingiin | Ei HTML-selailtavuutta — vain binäärilataus |
| Gitea Pages + reports-branch | Race condition rinnakkaisten pushien kanssa |
repository_dispatch ketjutukseen |
Lisää konfiguraatiota vastaanottaviin repoihin. Suora API-kutsu eksplisiittisempi |