Lär dig bygga effektiva och tillförlitliga GitLab CI-pipelines för monorepon med villkorliga includes, rules:changes och beprövade metoder för pipelines.
Joonas Jauhiainen
DevOps Lead
Joonas is a DevOps lead with experience in telecom, banking, insurance, and manufacturing, among other industries. His hobbies include investigation of IT devices, developing games and other SW projects not to mention underwater rugby!
GitLab monorepo CI – vad du bör och inte bör göra
Det här inlägget fokuserar på hur du effektivt hanterar monorepo-pipelines med GitLab CI, särskilt genom att använda modern villkorslogik för att hålla konfigurationerna enkla och robusta.
I GitLab 16.4 introducerades nya regler som underlättar hanteringen av monorepo-pipelines med GitLab CI. Det är viktigt att känna till för läsare som kanske använder äldre versioner.
Efter att ha byggt och förstört dessa pipelines flera gånger har jag lärt mig exakt vad som fungerar och, ännu viktigare, vad som inte fungerar.
GitLab monorepo-pipeline förklarad
Till det här blogginlägget har jag förberett en teknisk demo i mitt offentliga GitLab-konto, Atihinen/monorepo-demo, som jag kommer att hänvisa till genom hela inlägget.
En av de största utmaningarna i tidiga versioner av arbetet med monorepos var att hantera komplexiteten i CI/CD. Tidigare behövde du alltid inkludera konfigurationen för varje enskild underpipeline eller varje jobb och sedan omsorgsfullt definiera regler i varje enskilt jobb för att avgöra om det skulle köras. Resultatet blev stora filer som var svåra att underhålla och röriga pipeline-utvärderingar.
Tack vare uppdateringar i GitLab, som gör att nyckelordet changes kan utvärderas direkt i villkorliga include-satser, kan vi nu skriva en enkel och robust pipeline på toppnivå som från början endast hämtar de underpipelines som behövs.
I min monorepo-demo har jag en huvudkonfiguration för pipeline som hanterar två separata CLI-verktyg som utvecklas parallellt: ett skrivet i Go (cligo) och ett i Python (clipy), samt en dokumentationsmapp.
Så här orkestrerar pipelinen på toppnivå dessa delprojekt villkorligt:
Nu går vi vidare till mina lärdomar från de senaste två åren.
Gör så här: Definiera din .gitlab-ci.yml noggrant
När du skapar root-pipelinen för en monorepo i GitLab CI bör du definiera och utforma de steg som behövs noggrant. Säkerställ också att pipelinen på root-nivå innehåller jobb om underpipelines inte åsidosätter eller skapar jobb för stegen, eftersom det kan orsaka fel vid körning. Det är lätt att tänka att ett ”platshållarjobb” i huvudfilen yml bara kan vara ett jobb som till exempel kör echo, men jag rekommenderar i stället att du kör något som redan skapar värde i utvecklingsarbetet.
I mitt demo-repo har jag definierat följande steg (https://gitlab.com/Atihinen/monorepo-demo/-/blob/main/.gitlab-ci.yml?ref_type=heads#L2):
statisk_analys
build
Jag har definierat följande jobb i huvudpipelinen:
I stället för att låta alla jobb bara echo:a ”något fantastiskt” har jag redan lagt till standard-linters på huvudnivån, eftersom de går snabbt att köra även vid varje commit. För build-steget kunde jag tyvärr inte definiera en gemensam nämnare, eftersom det är mycket produktspecifikt.
Gör inte så här: Räkna med att kunna anpassa underpipelines
I föregående kapitel uppmanade jag dig att verkligen lägga tid på att bestämma vilka steg som ska finnas i pipelinen. Här är anledningen: GitLab stöder inte nya steg i underpipelines. Titta på denna commit (https://gitlab.com/Atihinen/monorepo-demo/-/commit/e838b935e9e9ee6577e1ef9404339bca05418acc):
Detta leder till ett fel i GitLab CI (https://gitlab.com/Atihinen/monorepo-demo/-/pipelines/1645391400):
deploy-go job: chosen stage deploy does not exist; available stages are .pre, static-analysis, build, .post
Gör så här: Använd 'needs' i stället för nya steg
Nya steg bör bara införas om alla underpipelines faktiskt kommer att använda dem. För säkerhets skull behöver toppnivån då också implementera ytterligare ett jobb.
I exemplet från föregående kapitel skulle GoLang-underpipelinen behöva ett nytt steg, ”deploy”, för att genomföra en driftsättning som Python-pipelinen inte behöver. Det kan lösas med GitLab-nyckelordet needs (https://docs.gitlab.com/ci/yaml/#needs). Då kan vi definiera ett nytt jobb i exempelvis build-steget, men deploy-jobbet körs först när exempelvis jobbet build-go är klart.
Gör inte: Utgå från att * är ett jokertecken
Min första uppfattning var att det skulle räcka med path/to/some/src/* (https://gitlab.com/Atihinen/monorepo-demo/-/blob/main/.gitlab-ci.yml?ref_type=heads#L38):
GitLab tolkar jokertecknet * endast på den översta nivån i den angivna sökvägen. Det söker inte rekursivt i underkataloger.
Du kan se hur det fungerar i praktiken (https://gitlab.com/Atihinen/monorepo-demo/-/pipelines/1643388739)
Detta triggade inte det förväntade mdlint-jobbet (https://gitlab.com/Atihinen/monorepo-demo/-/pipelines/1643389164).
Gör så här: Använd */** i stället för *
I föregående kapitel förklarade jag varför path/to/something/in/repo/* inte är en bra idé. Använd i stället path/to/something/in/repo/*/** för att matcha alla ändringar under den sökvägen.
Exempel:
Detta matchar varje filändring under katalogen cligo/.
Slutsats
GitLab CI:s nya rules-nyckelord changes är ett kraftfullt verktyg för monorepon, men det finns några fallgropar som du behöver känna till. Förhoppningsvis hjälper de här exemplen dig att undvika samma fallgropar och lägga för mycket tid på att felsöka varför det inte fungerar som du förväntar dig.
- GitLab
- CI/CD
Subscribe to our newsletter
Related blogs