Vodič za CI/CD u GitLabu za (skoro) apsolutne početnike
Ili kako da dobijete prelepe bedževe za svoj projekat u jednoj večeri jednostavnog kodiranja
Vjerovatno svaki programer koji u nekom trenutku ima barem jedan projekat za kućne ljubimce ima svrab oko lijepih bedževa sa statusima, pokrivenošću koda, verzijama paketa u nugetu... I ovaj svrab me je naveo da napišem ovaj članak. Pripremajući se za pisanje, dobio sam ovu ljepotu u jednom od svojih projekata:
Ovaj članak će vas provesti kroz osnovno podešavanje kontinuirane integracije i isporuke za projekat biblioteke klasa .Net Core u GitLabu, objavljivanje dokumentacije na GitLab stranicama i guranje izgrađenih paketa u privatni feed u Azure DevOps.
VS Code je korišten kao razvojno okruženje sa ekstenzijom GitLab Workflow (za validaciju datoteke postavki direktno iz razvojnog okruženja).
Kratki uvod
CD - da li je to kada ste samo gurnuli, a sve je već palo na klijenta?
Šta je CI/CD i zašto vam je potreban - lako možete proguglati. Pronađite kompletnu dokumentaciju o konfiguraciji cjevovoda u GitLabu takođe lako. Ovdje ću ukratko i, ako je moguće, bez nedostataka opisati proces rada sistema iz ptičje perspektive:
programer šalje urezivanje u spremište, kreira zahtjev za spajanje preko stranice, ili na neki drugi način, eksplicitno ili implicitno pokreće cevovod,
svi zadaci se biraju iz konfiguracije, čiji uslovi omogućavaju njihovo pokretanje u datom kontekstu,
zadaci su organizovani prema svojim fazama,
faze se izvode redom - tj. paralelno svi zadaci ove faze su završeni,
ako faza ne uspije (tj., barem jedan od zadataka faze ne uspije), cjevovod se zaustavlja (skoro uvijek),
ako su sve faze uspješno završene, cjevovod se smatra uspješnim.
Dakle, imamo:
pipeline - skup zadataka organiziranih u faze u kojima možete izgraditi, testirati, paketirati kod, implementirati gotovu verziju na uslugu u oblaku, itd.,
faza (faza) — organizaciona jedinica cjevovoda, sadrži 1+ zadatak,
zadatak (posao) je jedinica rada u procesu. Sastoji se od skripte (obavezno), uvjeta pokretanja, postavki za objavljivanje/keširanje artefakata i još mnogo toga.
Shodno tome, zadatak pri postavljanju CI/CD-a svodi se na kreiranje skupa zadataka koji implementiraju sve potrebne radnje za izgradnju, testiranje i objavljivanje koda i artefakata.
Prije početka: zašto?
Zašto Gitlab?
Jer kada je postalo neophodno kreirati privatne repozitorije za kućne projekte, oni su bili plaćeni na GitHubu, a ja sam bio pohlepan. Spremišta su postala besplatna, ali za sada to nije dovoljan razlog da pređem na GitHub.
Zašto ne Azure DevOps Pipelines?
Pošto je tamo postavka elementarna - poznavanje komandne linije nije ni potrebno. Integracija sa eksternim git provajderima - u par klikova, uvoz SSH ključeva za slanje urezivanja u spremište - takođe, cevovod se lako konfiguriše čak i ne iz šablona.
Početna pozicija: šta imate i šta želite
Imamo:
spremište u GitLabu.
Mi želimo:
automatsko sklapanje i testiranje za svaki zahtjev za spajanje,
pravljenje paketa za svaki zahtjev za spajanje i guranje do mastera, pod uvjetom da postoji određena linija u poruci urezivanja,
slanje izgrađenih paketa na privatni feed u Azure DevOps,
sastavljanje dokumentacije i objavljivanje u GitLab stranicama,
značke!11
Opisani zahtjevi organski spadaju u sljedeći model cjevovoda:
Faza 1 - Montaža
Prikupljamo kod, objavljujemo izlazne datoteke kao artefakte
Faza 2 - testiranje
Dobijamo artefakte iz faze izgradnje, pokrećemo testove, prikupljamo podatke o pokrivenosti koda
Faza 3 - Podnesite
Zadatak 1 - napravite nuget paket i pošaljite ga u Azure DevOps
Zadatak 2 - prikupljamo stranicu iz xmldoc u izvornom kodu i objavljujemo je na GitLab Pages
Kada kliknete na dugme Kreiraj, projekat će biti kreiran i bićete preusmjereni na njegovu stranicu. Na ovoj stranici možete onemogućiti nepotrebne funkcije tako što ćete otići na postavke projekta (donji link na listi s lijeve strane -> Pregled -> blok Azure DevOps Services)
Idite na Atrifacts, kliknite na Kreiraj feed
Unesite naziv izvora
Odaberite vidljivost
Poništite izbor Uključite pakete iz uobičajenih javnih izvora, tako da se izvor ne pretvori u dump nuget klon
Kliknite na Connect to feed, izaberite Visual Studio, kopirajte Source iz bloka za podešavanje mašine
Idite na postavke računa, odaberite Personal Access Token
Kreirajte novi pristupni token
Naziv - proizvoljan
Organizacija - trenutna
Vrijedi maksimalno 1 godinu
Opseg - pakovanje/čitanje i pisanje
Kopirajte kreirani token - nakon što se modalni prozor zatvori, vrijednost će biti nedostupna
Idite na postavke spremišta u GitLab-u, odaberite CI / CD postavke
Proširite blok Variables, dodajte novi
Ime - bilo koje bez razmaka (biće dostupno u komandnoj ljusci)
Vrijednost - pristupni token iz stava 9
Odaberite Varijablu maske
Ovim je završena predkonfiguracija.
Priprema konfiguracijskog okvira
Podrazumevano, CI/CD konfiguracija u GitLabu koristi datoteku .gitlab-ci.yml iz korijena spremišta. Možete postaviti proizvoljnu putanju do ove datoteke u postavkama spremišta, ali u ovom slučaju to nije neophodno.
Kao što možete vidjeti iz ekstenzije, datoteka sadrži konfiguraciju u formatu YAML. Dokumentacija opisuje koji ključevi mogu biti sadržani na najvišem nivou konfiguracije i na svakom od ugniježđenih nivoa.
Prvo, dodajmo vezu na docker sliku u konfiguracijskoj datoteci u kojoj će se izvršavati zadaci. Za ovo nalazimo Stranica slika .Net Core na Docker Hubu. The GitHub postoji detaljan vodič o tome koju sliku odabrati za različite zadatke. Slika sa .Net Core 3.1 je pogodna za nas da napravimo, pa slobodno dodajte prvi red u konfiguraciju
image: mcr.microsoft.com/dotnet/core/sdk:3.1
Sada, kada se cjevovod pokrene iz Microsoftovog spremišta slika, bit će preuzeta navedena slika u kojoj će se izvršavati svi zadaci iz konfiguracije.
Sljedeći korak je dodavanje faza's. GitLab podrazumevano definiše 5 faza:
.pre - izvodi se u svim fazama,
.post - izvodi se nakon svih faza,
build - prvo posle .pre pozornica,
test - druga faza,
deploy - treća faza.
Međutim, ništa vas ne sprječava da ih eksplicitno deklarirate. Redoslijed u kojem su navedeni koraci utječe na redoslijed kojim se oni izvode. Za kompletnost, dodajmo konfiguraciji:
stages:
- build
- test
- deploy
Za otklanjanje grešaka, ima smisla dobiti informacije o okruženju u kojem se zadaci izvršavaju. Dodajmo globalni skup naredbi koje će se izvršavati prije svakog zadatka sa before_script:
before_script:
- $PSVersionTable.PSVersion
- dotnet --version
- nuget help | select-string Version
Ostaje dodati barem jedan zadatak tako da kada se urezivanja pošalju, cjevovod će se pokrenuti. Za sada, dodajmo prazan zadatak da demonstriramo:
dummy job:
script:
- echo ok
Počinjemo validaciju, dobijamo poruku da je sve u redu, obavezujemo se, guramo, gledamo rezultate na sajtu... I dobijamo grešku u skripti - bash: .PSVersion: command not found. wtf?
Sve je logično - prema zadanim postavkama, trkači (odgovorni za izvršavanje skripti zadataka i koje obezbjeđuje GitLab) koriste bash za izvršavanje naredbi. Ovo možete popraviti eksplicitnim navođenjem u opisu zadatka koje oznake treba da ima izvršni cjevovod:
dummy job on windows:
script:
- echo ok
tags:
- windows
Odlično! Cjevovod sada radi.
Pažljiv čitalac, nakon što ponovi navedene korake, primijetit će da je zadatak završen u fazi test, iako nismo precizirali fazu. Kao što možete pretpostaviti test je podrazumevani korak.
Nastavimo kreirati kostur konfiguracije dodavanjem svih gore opisanih zadataka:
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
Dobili smo ne naročito funkcionalan, ali ipak ispravan cevovod.
Postavljanje okidača
Zbog činjenice da filteri okidača nisu specificirani ni za jedan od zadataka, cevovod će potpuno izvršiti svaki put kada se urezivanje gurne u spremište. Budući da ovo općenito nije željeno ponašanje, postavit ćemo filtere okidača za zadatke.
Filteri se mogu konfigurirati u dva formata: samo/osim и pravila. ukratko, only/except omogućava vam da konfigurirate filtere po okidačima (merge_request, na primjer - postavlja zadatak da se izvršava svaki put kada se kreira zahtjev za povlačenjem i svaki put kada se urezivanja šalju grani koja je izvor u zahtjevu za stapanje) i imena grana (uključujući korištenje regularnih izraza); rules omogućava vam da prilagodite skup uslova i, opciono, promenite uslov izvršenja zadatka u zavisnosti od uspeha prethodnih zadataka (when u GitLab CI/CD).
Prisjetite se skupa zahtjeva - sastavljanje i testiranje samo za zahtjev za spajanjem, pakovanje i slanje u Azure DevOps - za zahtjev za spajanje i push-ove na master, generiranje dokumentacije - za push-ove na master.
Prvo, postavimo zadatak izgradnje koda dodavanjem pravila koje se pokreće samo na zahtjev za spajanje:
build job:
# snip
only:
- merge_request
Sada podesimo zadatak pakiranja da se aktivira na zahtjev za spajanje i dodamo urezivanje na master:
Pod uslovima, možete koristiti varijable navedene ovdje; pravila rules nespojivo sa pravilima only/except.
Konfiguriranje čuvanja artefakata
Tokom zadatka build job imaćemo izgrađene artefakte koji se mogu ponovo koristiti u narednim zadacima. Da biste to učinili, morate dodati staze u konfiguraciju zadatka, datoteke duž kojih ćete morati spremiti i ponovo ih koristiti u sljedećim zadacima, u ključ artifacts:
Putanja podržavaju zamjenske znakove, što ih definitivno čini lakšim za postavljanje.
Ako zadatak kreira artefakte, tada će svaki sljedeći zadatak moći da im pristupi - oni će biti locirani duž istih putanja u odnosu na korijen spremišta koji su prikupljeni iz originalnog zadatka. Artefakti su također dostupni za preuzimanje na stranici.
Sada kada imamo spreman (i testiran) konfiguracijski okvir, možemo nastaviti s pisanjem skripti za zadatke.
Pišemo skripte
Možda je nekada davno, u dalekoj, dalekoj galaksiji, izgradnja projekata (uključujući i one na .net) sa komandne linije bila muka. Sada možete izgraditi, testirati i objaviti projekat u 3 tima:
dotnet build
dotnet test
dotnet pack
Naravno, postoje neke nijanse zbog kojih ćemo donekle zakomplicirati naredbe.
Želimo izdanje, a ne debug build, pa dodajemo svakoj komandi -c Release
Prilikom testiranja želimo prikupiti podatke o pokrivenosti koda, tako da moramo uključiti analizator pokrivenosti u test biblioteke:
Dodajte paket u sve testne biblioteke coverlet.msbuild: dotnet add package coverlet.msbuild iz fascikle projekta
Dodajte naredbi za probno pokretanje /p:CollectCoverage=true
Dodajte ključ u konfiguraciju testnog zadatka da dobijete rezultate pokrivenosti (pogledajte dolje)
Kada pakujete kod u nuget pakete, postavite izlazni direktorij za pakete: -o .
Prikupljanje podataka o pokrivenosti koda
Nakon pokretanja testova, Coverlet ispisuje statistiku pokretanja na konzolu:
GitLab vam omogućava da navedete regularni izraz da biste dobili statistiku, koja se zatim može dobiti u obliku značke. Regularni izraz je specificiran u postavkama zadatka pomoću ključa coverage; izraz mora sadržavati grupu hvatanja, čija će vrijednost biti proslijeđena znački:
test and cover job:
# snip
coverage: /|s*Totals*|s*(d+[,.]d+%)/
Ovdje dobijamo statistiku iz linije sa ukupnom pokrivenošću linije.
Objavite pakete i dokumentaciju
Obe akcije su predviđene za poslednju fazu gasovoda - pošto su montaža i testovi prošli, možemo da podelimo svoja dostignuća sa svetom.
Prvo razmislite o objavljivanju u izvornom paketu:
Ako projekat nema nuget konfiguracioni fajl (nuget.config), kreirajte novu: dotnet new nugetconfig
Za što: slika možda nema pristup za pisanje globalnim (korisničkim i mašinskim) konfiguracijama. Da ne bismo uhvatili greške, jednostavno kreiramo novu lokalnu konfiguraciju i radimo s njom.
Sve pakete šaljemo iz trenutnog direktorija, dakle *.nupkg.
name - sa koraka iznad.
key - bilo koju liniju. U Azure DevOps-u, u prozoru Poveži se na feed, primjer je uvijek linija az.
-skipduplicate - kada pokušate poslati već postojeći paket bez ovog ključa, izvor će vratiti grešku 409 Conflict; sa ključem, slanje će biti preskočeno.
Sada postavimo kreiranje dokumentacije:
Prvo, u spremištu, u glavnoj grani, inicijaliziramo docfx projekat. Da biste to učinili, pokrenite naredbu iz korijena docfx init i interaktivno postaviti ključne parametre za građevinsku dokumentaciju. Detaljan opis minimalne postavke projekta ovdje.
Prilikom konfiguriranja važno je navesti izlazni direktorij ..public - GitLab podrazumevano uzima sadržaj javne fascikle u korenu spremišta kao izvor za stranice. Jer projekat će se nalaziti u folderu ugniježđenom u spremištu - dodajte izlaz na nivo gore u putanji.
Ubacimo promjene u GitLab.
Dodajte zadatak u konfiguraciju cjevovoda pages (rezervisana reč za zadatke objavljivanja sajta u GitLab stranicama):
Skripta:
nuget install docfx.console -version 2.51.0 - instalirati docfx; verzija je navedena kako bi se osiguralo da su staze instalacije paketa ispravne.
Ranije sam, prilikom postavljanja projekta, naveo izvor koda za dokumentaciju kao datoteku rješenja. Glavni nedostatak je što se dokumentacija kreira i za testne projekte. U slučaju da to nije potrebno, možete postaviti ovu vrijednost na čvor metadata.src:
metadata.src.src: "../" - idemo jedan nivo više u odnosu na lokaciju docfx.json, jer u obrascima, pretraživanje stabla direktorija ne radi.
metadata.src.files: ["**/*.csproj"] - globalni obrazac, prikupljamo sve C # projekte iz svih direktorija.
metadata.src.exclude: ["*.tests*/**"] - globalni obrazac, isključite sve iz foldera sa .tests U naslovu
Međuzbir
Ovako jednostavnu konfiguraciju možete kreirati za samo pola sata i par šoljica kafe, što će vam omogućiti da proverite da li je kod izgrađen i da su testovi prošli, napravite novi paket, ažurirate dokumentaciju i ugodite oku prelepim značke u README projekta sa svakim zahtjevom za spajanje i slanjem masteru.
Finalni .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
Kad smo već kod bedževa
Zbog njih je, ipak, sve počelo!
Bedževi sa statusima cjevovoda i pokrivenošću koda dostupni su u GitLabu u CI/CD postavkama u bloku Gtntral cjevovoda:
Napravio sam bedž sa vezom do dokumentacije na platformi shields.io - tamo je sve prilično jednostavno, možete kreirati vlastiti bedž i dobiti ga pomoću zahtjeva.
![Пример с Shields.io](https://img.shields.io/badge/custom-badge-blue)
Azure DevOps Artifacts vam također omogućava da kreirate značke za pakete s najnovijom verzijom. Da biste to učinili, u izvoru na Azure DevOps web-mjestu morate kliknuti na Kreiraj značku za odabrani paket i kopirati markdown:
Dodavanje ljepote
Isticanje zajedničkih fragmenata konfiguracije
Dok sam pisao konfiguraciju i pretraživao dokumentaciju, naišao sam na zanimljivu karakteristiku YAML-a - ponovno korištenje fragmenata.
Kao što možete vidjeti iz postavki zadatka, svi oni zahtijevaju oznaku windows na pokretaču, a pokreću se kada se zahtjev za stapanjem pošalje master/kreiranom (osim dokumentacije). Dodajmo ovo fragmentu koji ćemo ponovo koristiti:
I sada možemo umetnuti ranije deklarirani fragment u opis zadatka:
build job:
<<: *common_tags
<<: *common_only
Nazivi fragmenata moraju početi s tačkom, kako se ne bi tumačili kao zadatak.
Verzija paketa
Prilikom kreiranja paketa, kompajler provjerava prekidače komandne linije, a u nedostatku i projektne datoteke; kada pronađe Version čvor, uzima njegovu vrijednost kao verzija paketa koji se gradi. Ispostavilo se da da biste napravili paket s novom verzijom, morate ga ili ažurirati u datoteci projekta ili ga proslediti kao argument komandne linije.
Hajde da dodamo još jednu listu želja - neka dva sporedna broja u verziji budu godina i datum izrade paketa, i dodajmo prelease verzije. Naravno, možete dodati ove podatke u projektnu datoteku i provjeriti prije svakog podnošenja – ali to možete učiniti i u procesu prikupljanja verzije paketa iz konteksta i prošavanja kroz argument komandne linije.
Složimo se da ako poruka urezivanja sadrži liniju kao release (v./ver./version) <version number> (rev./revision <revision>)?, tada ćemo preuzeti verziju paketa iz ove linije, dopuniti je trenutnim datumom i proslijediti je kao argument naredbi dotnet pack. U nedostatku linije, jednostavno nećemo preuzeti paket.
Sljedeća skripta rješava ovaj 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
Dodavanje skripte zadatku pack and deploy job i posmatrajte sastavljanje paketa striktno u prisustvu datog niza u poruci urezivanja.
Ukupno
Nakon što smo potrošili oko pola sata ili sat vremena na pisanje konfiguracije, otklanjanje grešaka u lokalnom powershell-u i, eventualno, nekoliko neuspješnih pokretanja, dobili smo jednostavnu konfiguraciju za automatizaciju rutinskih zadataka.
Naravno, GitLab CI/CD je mnogo opsežniji i višestruki nego što se može činiti nakon čitanja ovog vodiča - to uopšte nije istina. Čak i tamo Auto DevOps jedopuštajući
automatski otkriti, izgraditi, testirati, implementirati i nadgledati vaše aplikacije
Sada su planovi da se konfiguriše cevovod za postavljanje aplikacija na Azure, koristeći Pulumi i automatsko određivanje ciljnog okruženja, što će biti pokriveno u sledećem članku.