En guide til CI/CD i GitLab for den (næsten) absolutte nybegynder
Eller hvordan du får smukke badges til dit projekt på en aften med nem kodning
Sandsynligvis har enhver udvikler, der har mindst ét kæledyrsprojekt på et tidspunkt, kløen over smukke badges med statusser, kodedækning, pakkeversioner i nuget ... Og denne kløe fik mig til at skrive denne artikel. Som forberedelse til at skrive den fik jeg denne skønhed i et af mine projekter:
Denne artikel vil lede dig gennem den grundlæggende opsætning af kontinuerlig integration og levering for et .Net Core-klassebiblioteksprojekt i GitLab, udgivelse af dokumentation til GitLab-sider og skubbe indbyggede pakker til et privat feed i Azure DevOps.
VS Code blev brugt som udviklingsmiljø med udvidelsen GitLab arbejdsgang (til validering af indstillingsfilen direkte fra udviklingsmiljøet).
Kort introduktion
CD - er det, når du lige har skubbet, og alt allerede er faldet på klienten?
Hvad er CI/CD og hvorfor har du brug for det – du kan nemt google det. Find komplet dokumentation om konfiguration af pipelines i GitLab også nemt. Her vil jeg kort og om muligt uden fejl beskrive systemets proces ud fra et fugleperspektiv:
udvikleren sender en commit til depotet, opretter en fletteanmodning gennem webstedet, eller på anden måde eksplicit eller implicit starter pipelinen,
alle opgaver er valgt fra konfigurationen, hvis betingelser tillader dem at blive lanceret i den givne kontekst,
opgaverne er organiseret efter deres stadier,
stadier udføres på skift - dvs. parallel alle opgaver i denne fase er afsluttet,
hvis etapen fejler (dvs. mindst én af fasernes opgaver fejler), stopper pipelinen (næsten altid),
hvis alle faser er gennemført med succes, anses pipelinen for at være vellykket.
Således har vi:
pipeline - et sæt opgaver organiseret i faser, hvor du kan bygge, teste, pakke kode, implementere en færdig build til en skytjeneste osv.
scene (etape) — pipeline organisationsenhed, indeholder 1+ opgave,
opgave (arbejde) er en arbejdsenhed i pipelinen. Det består af et script (obligatorisk), startbetingelser, indstillinger for publicering/caching af artefakter og meget mere.
Følgelig kommer opgaven ved opsætning af CI / CD ned til at skabe et sæt opgaver, der implementerer alle de nødvendige handlinger til at bygge, teste og udgive kode og artefakter.
Før du starter: hvorfor?
Hvorfor Gitlab?
For da det blev nødvendigt at oprette private repositories til kæledyrsprojekter, blev de betalt på GitHub, og jeg var grådig. Lagrene er blevet gratis, men indtil videre er dette ikke grund nok til, at jeg flytter til GitHub.
Hvorfor ikke Azure DevOps Pipelines?
Fordi der er indstillingen elementær - kendskab til kommandolinjen er ikke engang påkrævet. Integration med eksterne git-udbydere - med et par klik, import af SSH-nøgler for at sende commits til repository - også, pipelinen konfigureres nemt, selv ikke fra en skabelon.
Udgangsposition: hvad du har, og hvad du ønsker
Vi har:
repository i GitLab.
Vi vil have:
automatisk samling og test for hver fletteanmodning,
bygge pakker for hver fletteanmodning og push til masteren, forudsat at der er en bestemt linje i commit-meddelelsen,
at sende indbyggede pakker til et privat feed i Azure DevOps,
samling af dokumentation og publicering i GitLab-sider,
badges!11
De beskrevne krav falder organisk på følgende pipelinemodel:
Trin 1 - Montering
Vi indsamler koden, udgiver outputfilerne som artefakter
Fase 2 - test
Vi får artefakter fra byggefasen, kører tests, indsamler kodedækningsdata
Trin 3 - Indsend
Opgave 1 - byg nuget-pakken og send den til Azure DevOps
Opgave 2 - vi samler webstedet fra xmldoc i kildekoden og udgiver det i GitLab Pages
Når du klikker på knappen Opret, oprettes projektet, og du vil blive omdirigeret til dets side. På denne side kan du deaktivere unødvendige funktioner ved at gå til projektindstillingerne (nederste link i listen til venstre -> Oversigt -> Azure DevOps Services-blok)
Gå til Atrifacter, klik på Opret feed
Indtast navnet på kilden
Vælg synlighed
Fjern markeringen Inkluder pakker fra almindelige offentlige kilder, så kilden ikke bliver til en dump nuget klon
Klik på Opret forbindelse til feed, vælg Visual Studio, kopier kilde fra maskinens opsætningsblok
Gå til kontoindstillinger, vælg Personal Access Token
Opret et nyt adgangstoken
Navn - vilkårlig
Organisation - aktuel
Gælder højst 1 år
Omfang - Emballering/Læs & Skriv
Kopiér det oprettede token - efter at det modale vindue er lukket, vil værdien være utilgængelig
Gå til lagerindstillingerne i GitLab, vælg CI / CD-indstillingerne
Udvid blokken Variabler, tilføj en ny
Navn - enhver uden mellemrum (vil være tilgængelig i kommandoskallen)
Værdi - adgangstoken fra afsnit 9
Vælg Mask variabel
Dette fuldender præ-konfigurationen.
Forberedelse af konfigurationsrammerne
Som standard bruger CI/CD-konfiguration i GitLab filen .gitlab-ci.yml fra roden af depotet. Du kan indstille en vilkårlig sti til denne fil i lagerindstillingerne, men i dette tilfælde er det ikke nødvendigt.
Som du kan se af udvidelsen, indeholder filen en konfiguration i formatet YAML. Dokumentationen beskriver, hvilke nøgler der kan være indeholdt på det øverste niveau af konfigurationen og på hvert af de indlejrede niveauer.
Lad os først tilføje et link til docker-billedet i konfigurationsfilen, hvor opgaverne vil blive udført. Til dette finder vi .Net Core-billedside på Docker Hub. I GitHub der er en detaljeret guide til, hvilket billede du skal vælge til forskellige opgaver. Et billede med .Net Core 3.1 er velegnet til os at bygge, så du er velkommen til at tilføje den første linje til konfigurationen
image: mcr.microsoft.com/dotnet/core/sdk:3.1
Nu, når pipelinen startes fra Microsofts billedlager, vil det angivne billede blive downloadet, hvor alle opgaver fra konfigurationen vil blive udført.
Det næste trin er at tilføje etape's. Som standard definerer GitLab 5 trin:
.pre - opført op til alle stadier,
.post - opført efter alle stadier,
build - først efter .pre scene,
test - anden fase,
deploy - tredje fase.
Intet forhindrer dig dog i at erklære dem eksplicit. Den rækkefølge, som trinene er angivet i, påvirker den rækkefølge, de udføres i. For fuldstændighedens skyld, lad os tilføje til konfigurationen:
stages:
- build
- test
- deploy
Til debugging giver det mening at få information om det miljø, hvori opgaverne udføres. Lad os tilføje et globalt sæt kommandoer, der vil blive udført før hver opgave med before_script:
before_script:
- $PSVersionTable.PSVersion
- dotnet --version
- nuget help | select-string Version
Det er tilbage at tilføje mindst én opgave, så når commits er sendt, starter pipelinen. Indtil videre, lad os tilføje en tom opgave for at demonstrere:
dummy job:
script:
- echo ok
Vi starter validering, vi får en besked om, at alt er i orden, vi forpligter, vi presser, vi ser på resultaterne på siden ... Og vi får en scriptfejl - bash: .PSVersion: command not found. wtf?
Alt er logisk - som standard bruger løbere (ansvarlige for at udføre opgavescripts og leveres af GitLab) bash at udføre kommandoer. Du kan rette op på dette ved eksplicit at angive i opgavebeskrivelsen, hvilke tags den udførende pipeline runner skal have:
dummy job on windows:
script:
- echo ok
tags:
- windows
Store! Rørledningen kører nu.
En opmærksom læser, efter at have gentaget de angivne trin, vil bemærke, at opgaven blev fuldført i fasen test, selvom vi ikke specificerede scenen. Som du måske kan gætte test er standardtrinnet.
Lad os fortsætte med at skabe konfigurationsskelettet ved at tilføje alle de opgaver, der er beskrevet ovenfor:
build job:
script:
- echo "building..."
tags:
- windows
stage: build
test and cover job:
script:
- echo "running tests and coverage analysis..."
tags:
- windows
stage: test
pack and deploy job:
script:
- echo "packing and pushing to nuget..."
tags:
- windows
stage: deploy
pages:
script:
- echo "creating docs..."
tags:
- windows
stage: deploy
Vi fik en ikke særlig funktionel, men ikke desto mindre korrekt pipeline.
Opsætning af triggere
På grund af at der ikke er angivet triggerfiltre for nogen af opgaverne, vil pipelinen fuldt udføres hver gang en commit skubbes til depotet. Da dette generelt ikke er den ønskede adfærd, opsætter vi triggerfiltre for opgaver.
Filtre kan konfigureres i to formater: kun/undtagen и regler. Kort, only/except giver dig mulighed for at konfigurere filtre efter triggere (merge_request, for eksempel - indstiller opgaven, der skal udføres, hver gang en pull-anmodning oprettes, og hver gang der sendes commits til grenen, der er kilden i fletteanmodningen) og filialnavne (inklusive brug af regulære udtryk); rules giver dig mulighed for at tilpasse et sæt betingelser og eventuelt ændre opgaveudførelsesbetingelserne afhængigt af succesen med tidligere opgaver (when i GitLab CI/CD).
Lad os huske et sæt krav - samling og test kun for fletteanmodning, pakning og afsendelse til Azure DevOps - for fletteanmodning og push til master, dokumentationsgenerering - for push til master.
Lad os først konfigurere kodeopbygningsopgaven ved at tilføje en regel, der kun udløses ved fletningsanmodning:
build job:
# snip
only:
- merge_request
Lad os nu konfigurere pakkeopgaven til at aktivere fletteanmodningen og tilføje commits til masteren:
Under betingelser kan du bruge variabler anført her; regler rules uforenelig med reglerne only/except.
Konfiguration af artefaktlagring
Under en opgave build job vi skal bygge artefakter, der kan genbruges i efterfølgende opgaver. For at gøre dette skal du tilføje stierne til opgavekonfigurationen, filerne, som du skal gemme og genbruge i følgende opgaver, til nøglen artifacts:
Stier understøtter jokertegn, hvilket helt sikkert gør dem nemmere at indstille.
Hvis en opgave opretter artefakter, så vil hver efterfølgende opgave være i stand til at få adgang til dem - de vil være placeret langs de samme stier i forhold til lagerroden, som blev indsamlet fra den oprindelige opgave. Artefakter er også tilgængelige til download på webstedet.
Nu hvor vi har en konfigurationsramme klar (og testet), kan vi fortsætte med faktisk at skrive scripts til opgaver.
Vi skriver manuskripter
Måske engang, i en galakse langt, langt væk, var det en smerte at bygge projekter (inklusive dem på .net) fra kommandolinjen. Nu kan du bygge, teste og publicere projektet i 3 teams:
dotnet build
dotnet test
dotnet pack
Naturligvis er der nogle nuancer, på grund af hvilke vi vil komplicere kommandoerne noget.
Vi vil have en release build, ikke en debug build, så vi tilføjer til hver kommando -c Release
Når vi tester, ønsker vi at indsamle kodedækningsdata, så vi skal inkludere en dækningsanalysator i testbibliotekerne:
Tilføj pakken til alle testbiblioteker coverlet.msbuild: dotnet add package coverlet.msbuild fra projektmappe
Tilføj til testkørselskommandoen /p:CollectCoverage=true
Tilføj en nøgle til testopgavekonfigurationen for at få dækningsresultater (se nedenfor)
Når du pakker koden i nuget-pakker, skal du indstille output-mappen for pakkerne: -o .
Indsamling af kodedækningsdata
Efter at have kørt testene, udskriver Coverlet kørestatistikker til konsollen:
GitLab giver dig mulighed for at angive et regulært udtryk for at få statistik, som så kan fås i form af et badge. Det regulære udtryk er angivet i opgaveindstillingerne med tasten coverage; udtrykket skal indeholde en optagelsesgruppe, hvis værdi vil blive videregivet til badgen:
test and cover job:
# snip
coverage: /|s*Totals*|s*(d+[,.]d+%)/
Her får vi statistik fra en linje med samlet linjedækning.
Udgiv pakker og dokumentation
Begge handlinger er planlagt til den sidste fase af pipelinen - da montagen og testene er bestået, kan vi dele vores udvikling med verden.
Overvej først at udgive til pakkekilden:
Hvis projektet ikke har en nuget-konfigurationsfil (nuget.config), opret en ny: dotnet new nugetconfig
For hvad: billedet har muligvis ikke skriveadgang til globale (bruger og maskine) konfigurationer. For ikke at fange fejl opretter vi blot en ny lokal konfiguration og arbejder med den.
Lad os tilføje en ny pakkekilde til den lokale konfiguration: nuget sources add -name <name> -source <url> -username <organization> -password <gitlab variable> -configfile nuget.config -StorePasswordInClearText
name - lokalt kildenavn, ikke kritisk
url - URL til kilden fra stadiet "Forberedelse af regnskaber", s. 6
organization - organisationsnavn i Azure DevOps
gitlab variable - navnet på variablen med adgangstoken tilføjet til GitLab ("Forberedelse af konti", s. 11). Naturligvis i formatet $variableName
Vi sender alle pakker fra den aktuelle mappe, så *.nupkg.
name - fra trin ovenfor.
key - enhver linje. I Azure DevOps, i vinduet Opret forbindelse til feed, er eksemplet altid linjen az.
-skipduplicate - når du forsøger at sende en allerede eksisterende pakke uden denne nøgle, vil kilden returnere en fejl 409 Conflict; med tasten springes afsendelsen over.
Lad os nu konfigurere oprettelsen af dokumentation:
Først initialiserer vi docfx-projektet i depotet, i mastergrenen. For at gøre dette skal du køre kommandoen fra roden docfx init og interaktivt indstille nøgleparametrene for bygningsdokumentation. Detaljeret beskrivelse af minimum projektopsætning her.
Når du konfigurerer, er det vigtigt at angive output-biblioteket ..public - GitLab tager som standard indholdet af den offentlige mappe i roden af depotet som en kilde til Pages. Fordi projektet vil være placeret i en mappe indlejret i depotet - tilføj et output til niveauet op i stien.
Lad os skubbe ændringerne til GitLab.
Tilføj en opgave til pipeline-konfigurationen pages (reserveret ord til webstedsudgivelsesopgaver i GitLab-sider):
Manuskript:
nuget install docfx.console -version 2.51.0 - installer docfx; versionen er specificeret for at sikre, at pakkeinstallationsstierne er korrekte.
.docfx.console.2.51.0toolsdocfx.exe .docfx_projectdocfx.json - indsamling af dokumentation
Node artefakter:
pages:
# snip
artifacts:
paths:
- public
Lyrisk digression om docfx
Tidligere, ved opsætning af et projekt, specificerede jeg kodekilden til dokumentationen som en løsningsfil. Den største ulempe er, at der også skabes dokumentation for testprojekter. Hvis dette ikke er nødvendigt, kan du indstille denne værdi til noden metadata.src:
metadata.src.src: "../" - vi går et niveau op i forhold til beliggenheden docfx.json, fordi i mønstre virker det ikke at søge i mappetræet.
metadata.src.files: ["**/*.csproj"] - et globalt mønster, vi samler alle C #-projekter fra alle mapper.
metadata.src.exclude: ["*.tests*/**"] - globalt mønster, udelad alt fra mapper med .tests I titlen
Subtotal
En sådan simpel konfiguration kan oprettes på bare en halv time og et par kopper kaffe, som giver dig mulighed for at kontrollere, at koden er bygget og testene bestå, bygge en ny pakke, opdatere dokumentationen og glæde øjet med smukke badges i README af projektet med hver fletteanmodning og afsendelse til masteren.
Endelig .gitlab-ci.yml
image: mcr.microsoft.com/dotnet/core/sdk:3.1
before_script:
- $PSVersionTable.PSVersion
- dotnet --version
- nuget help | select-string Version
stages:
- build
- test
- deploy
build job:
stage: build
script:
- dotnet build -c Release
tags:
- windows
only:
- merge_requests
- master
artifacts:
paths:
- your/path/to/binaries
test and cover job:
stage: test
tags:
- windows
script:
- dotnet test -c Release /p:CollectCoverage=true
coverage: /|s*Totals*|s*(d+[,.]d+%)/
only:
- merge_requests
- master
pack and deploy job:
stage: deploy
tags:
- windows
script:
- dotnet pack -c Release -o .
- dotnet new nugetconfig
- nuget sources add -name feedName -source https://pkgs.dev.azure.com/your-organization/_packaging/your-feed/nuget/v3/index.json -username your-organization -password $nugetFeedToken -configfile nuget.config -StorePasswordInClearText
- nuget push -source feedName -skipduplicate -apikey az *.nupkg
only:
- master
pages:
tags:
- windows
stage: deploy
script:
- nuget install docfx.console -version 2.51.0
- $env:path = "$env:path;$($(get-location).Path)"
- .docfx.console.2.51.0toolsdocfx.exe .docfxdocfx.json
artifacts:
paths:
- public
only:
- master
Apropos badges
På grund af dem blev alting jo sat i gang!
Badges med pipeline-statusser og kodedækning er tilgængelige i GitLab i CI/CD-indstillingerne i Gtntral-pipelines-blokken:
Jeg oprettede et badge med et link til dokumentationen på platformen shields.io - alt er ret ligetil der, du kan oprette dit eget badge og modtage det ved hjælp af en anmodning.
![Пример с Shields.io](https://img.shields.io/badge/custom-badge-blue)
Azure DevOps Artifacts giver dig også mulighed for at oprette badges til pakker med den nyeste version. For at gøre dette skal du i kilden på Azure DevOps-webstedet klikke på Opret badge for den valgte pakke og kopiere markdown-markeringen:
Tilføjelse af skønhed
Fremhævelse af almindelige konfigurationsfragmenter
Mens jeg skrev konfigurationen og søgte gennem dokumentationen, stødte jeg på et interessant træk ved YAML - genbrug af fragmenter.
Som du kan se fra opgaveindstillingerne, kræver de alle tagget windows hos løberen, og udløses, når en fletteanmodning sendes til masteren/oprettes (undtagen dokumentation). Lad os tilføje dette til fragmentet, som vi vil genbruge:
Og nu kan vi indsætte det tidligere erklærede fragment i opgavebeskrivelsen:
build job:
<<: *common_tags
<<: *common_only
Fragmentnavne skal begynde med en prik, for ikke at blive fortolket som en opgave.
Pakkeversionering
Når du opretter en pakke, kontrollerer compileren kommandolinje-omskifterne, og i deres fravær projektfilerne; når den finder en versionsknude, tager den sin værdi som den version af pakken, der bygges. Det viser sig, at for at bygge en pakke med en ny version, skal du enten opdatere den i projektfilen eller sende den som et kommandolinjeargument.
Lad os tilføje endnu en ønskeliste - lad de to underordnede tal i versionen være pakkens årstal og byggedato, og tilføj prerelease-versioner. Selvfølgelig kan du tilføje disse data til projektfilen og tjekke før hver indsendelse - men du kan også gøre det i pipelinen, samle pakkeversionen fra konteksten og sende den gennem kommandolinjeargumentet.
Lad os blive enige om, at hvis commit-meddelelsen indeholder en linje som release (v./ver./version) <version number> (rev./revision <revision>)?, så tager vi versionen af pakken fra denne linje, supplerer den med den aktuelle dato og sender den som et argument til kommandoen dotnet pack. Hvis der ikke er en linje, afhenter vi simpelthen ikke pakken.
Følgende script løser dette problem:
# регулярное выражение для поиска строки с версией
$rx = "releases+(v.?|ver.?|version)s*(?<maj>d+)(?<min>.d+)?(?<rel>.d+)?s*((rev.?|revision)?s+(?<rev>[a-zA-Z0-9-_]+))?"
# ищем строку в сообщении коммита, передаваемом в одной из предопределяемых GitLab'ом переменных
$found = $env:CI_COMMIT_MESSAGE -match $rx
# совпадений нет - выходим
if (!$found) { Write-Output "no release info found, aborting"; exit }
# извлекаем мажорную и минорную версии
$maj = $matches['maj']
$min = $matches['min']
# если строка содержит номер релиза - используем его, иначе - текущий год
if ($matches.ContainsKey('rel')) { $rel = $matches['rel'] } else { $rel = ".$(get-date -format "yyyy")" }
# в качестве номера сборки - текущие месяц и день
$bld = $(get-date -format "MMdd")
# если есть данные по пререлизной версии - включаем их в версию
if ($matches.ContainsKey('rev')) { $rev = "-$($matches['rev'])" } else { $rev = '' }
# собираем единую строку версии
$version = "$maj$min$rel.$bld$rev"
# собираем пакеты
dotnet pack -c Release -o . /p:Version=$version
Tilføjelse af et script til en opgave pack and deploy job og observer samlingen af pakker strengt i nærværelse af en given streng i commit-meddelelsen.
I alt
Efter at have brugt omkring en halv time eller en time på at skrive konfigurationen, fejlfinde i den lokale powershell og muligvis et par mislykkede lanceringer, fik vi en simpel konfiguration til at automatisere rutineopgaver.
Selvfølgelig er GitLab CI / CD meget mere omfattende og mangefacetteret, end det kan se ud efter at have læst denne guide - det er slet ikke sandt. Der endda Auto DevOps ertillader
automatisk opdage, bygge, teste, implementere og overvåge dine applikationer
Nu er planerne at konfigurere en pipeline til implementering af applikationer til Azure, ved hjælp af Pulumi og automatisk bestemmelse af målmiljøet, hvilket vil blive dækket i den næste artikel.