Eller hvordan du får vakre merker for prosjektet ditt på en kveld med enkel koding
Sannsynligvis har alle utviklere som har minst ett kjæledyrprosjekt på et tidspunkt en kløe på vakre merker med statuser, kodedekning, pakkeversjoner i nuget ... Og denne kløen førte til at jeg skrev denne artikkelen. Som forberedelse til å skrive den, fikk jeg denne skjønnheten i et av prosjektene mine:

Denne artikkelen vil lede deg gjennom det grunnleggende oppsettet av kontinuerlig integrasjon og levering for et .Net Core-klassebibliotekprosjekt i GitLab, publisere dokumentasjon til GitLab-sider og skyve innebygde pakker til en privat feed i Azure DevOps.
VS-kode ble brukt som utviklingsmiljø med utvidelsen (for å validere innstillingsfilen direkte fra utviklingsmiljøet).
Kort introduksjon
CD - er det når du bare presset, og alt har allerede falt på klienten?
Hva er CI / CD og hvorfor du trenger det - du kan enkelt google det. Finn fullstendig dokumentasjon om konfigurering av rørledninger i GitLab . Her vil jeg kort og om mulig uten feil beskrive prosessen med systemet fra et fugleperspektiv:
- utvikleren sender en forpliktelse til depotet, oppretter en sammenslåingsforespørsel gjennom nettstedet, eller på annen måte, eksplisitt eller implisitt starter rørledningen,
- alle oppgaver velges fra konfigurasjonen, hvis betingelser gjør at de kan startes i den gitte konteksten,
- oppgavene er organisert etter stadier,
- trinn utføres etter tur - dvs. parallell alle oppgavene på dette stadiet er fullført,
- hvis etappen mislykkes (dvs. minst én av oppgavene til etappen mislykkes), stopper rørledningen (nesten alltid),
- hvis alle stadier er fullført, anses rørledningen som vellykket.
Dermed har vi:
- pipeline - et sett med oppgaver organisert i stadier der du kan bygge, teste, pakke kode, distribuere en ferdig build til en skytjeneste, etc.,
- scene (scene) — rørledningsorganisasjonsenhet, inneholder 1+ oppgave,
- oppgave (jobb) er en arbeidsenhet i rørledningen. Den består av et skript (obligatorisk), lanseringsbetingelser, innstillinger for publisering/bufring av artefakter og mye mer.
Følgelig kommer oppgaven når du setter opp CI / CD ned til å lage et sett med oppgaver som implementerer alle nødvendige handlinger for å bygge, teste og publisere kode og artefakter.
Før du starter: hvorfor?
- Hvorfor Gitlab?
For da det ble nødvendig å lage private depoter for kjæledyrprosjekter, ble de betalt på GitHub, og jeg var grådig. Lagrene har blitt gratis, men så langt er ikke dette nok grunn for meg til å flytte til GitHub.
- Hvorfor ikke Azure DevOps Pipelines?
Fordi der er innstillingen elementær - kunnskap om kommandolinjen er ikke engang nødvendig. Integrasjon med eksterne git-leverandører - med et par klikk, import av SSH-nøkler for å sende commits til depotet - også, pipelinen konfigureres enkelt selv ikke fra en mal.
Utgangsposisjon: hva du har og hva du vil ha
Vi har:
- repository i GitLab.
Vi vil:
- automatisk montering og testing for hver sammenslåingsforespørsel,
- bygge pakker for hver sammenslåingsforespørsel og skyve til masteren, forutsatt at det er en bestemt linje i commit-meldingen,
- sende innebygde pakker til en privat feed i Azure DevOps,
- sammenstilling av dokumentasjon og publisering i GitLab-sider,
- merker!11
De beskrevne kravene faller organisk på følgende rørledningsmodell:
- Trinn 1 - montering
- Vi samler inn koden, publiserer utdatafilene som artefakter
- Trinn 2 - testing
- Vi henter artefakter fra byggestadiet, kjører tester, samler inn kodedekningsdata
- Trinn 3 - Send inn
- Oppgave 1 – bygg nuget-pakken og send den til Azure DevOps
- Oppgave 2 - vi samler nettstedet fra xmldoc i kildekoden og publiserer det i GitLab Pages
La oss komme i gang!
Samler inn konfigurasjonen
Utarbeidelse av regnskap
Opprett en konto i
Gå til
Vi lager et nytt prosjekt
- Navn - hvilken som helst
- Synlighet - evt

Når du klikker på Opprett-knappen, opprettes prosjektet og du blir omdirigert til siden. På denne siden kan du deaktivere unødvendige funksjoner ved å gå til prosjektinnstillingene (nedre lenke i listen til venstre -> Oversikt -> Azure DevOps Services-blokk)

Gå til Atrifacter, klikk på Opprett feed
- Skriv inn navnet på kilden
- Velg synlighet
- Fjern merket Inkluder pakker fra vanlige offentlige kilder, slik at kilden ikke blir til en dump nuget-klon

Klikk på Koble til feed, velg Visual Studio, kopier kilde fra maskinoppsettblokken

Gå til kontoinnstillinger, velg Personlig tilgangstoken

Opprett et nytt tilgangstoken
- Navn - vilkårlig
- Organisasjon - aktuell
- Gyldig i maks 1 år
- Omfang - Pakking/Les & Skriv

Kopier det opprettede tokenet - etter at det modale vinduet er lukket, vil verdien være utilgjengelig
Gå til depotinnstillingene i GitLab, velg CI / CD-innstillingene

Utvid Variables-blokken, legg til en ny
- Navn - alle uten mellomrom (vil være tilgjengelig i kommandoskallet)
- Verdi - tilgangstoken fra avsnitt 9
- Velg Mask-variabel

Dette fullfører forhåndskonfigurasjonen.
Forbereder konfigurasjonsrammeverket
Som standard bruker CI/CD-konfigurasjon i GitLab filen .gitlab-ci.yml fra roten til depotet. Du kan angi en vilkårlig bane til denne filen i depotinnstillingene, men i dette tilfellet er det ikke nødvendig.
Som du kan se av utvidelsen, inneholder filen en konfigurasjon i formatet YAML. Dokumentasjonen beskriver hvilke nøkler som kan inneholde på toppnivået i konfigurasjonen, og på hvert av de nestede nivåene.
La oss først legge til en lenke til docker-bildet i konfigurasjonsfilen, der oppgavene skal utføres. For dette finner vi . I det er en detaljert veiledning om hvilket bilde du skal velge for ulike oppgaver. Et bilde med .Net Core 3.1 er egnet for oss å bygge, så legg gjerne til den første linjen i konfigurasjonen
image: mcr.microsoft.com/dotnet/core/sdk:3.1Nå, når rørledningen er lansert fra Microsofts bildelager, vil det angitte bildet bli lastet ned, der alle oppgavene fra konfigurasjonen vil bli utført.
Neste trinn er å legge til scene's. Som standard definerer GitLab 5 stadier:
.pre- fremført opp til alle stadier,.post- fremført etter alle stadier,build- først etter.prescene,test- andre fase,deploy- den tredje fasen.
Ingenting hindrer deg imidlertid i å deklarere dem eksplisitt. Rekkefølgen som trinnene er oppført i, påvirker rekkefølgen de utføres i. For fullstendighetens skyld, la oss legge til konfigurasjonen:
stages:
- build
- test
- deployFor feilsøking er det fornuftig å få informasjon om miljøet der oppgavene utføres. La oss legge til et globalt sett med kommandoer som vil bli utført før hver oppgave med before_script:
before_script:
- $PSVersionTable.PSVersion
- dotnet --version
- nuget help | select-string VersionDet gjenstår å legge til minst én oppgave slik at rørledningen starter når forpliktelsene er sendt. For nå, la oss legge til en tom oppgave for å demonstrere:
dummy job:
script:
- echo okVi starter validering, vi får en melding om at alt er i orden, vi forplikter oss, vi presser, vi ser på resultatene på nettstedet ... Og vi får en skriptfeil - bash: .PSVersion: command not found. wtf?
Alt er logisk - som standard bruker løpere (ansvarlig for å utføre oppgaveskript og levert av GitLab) bash å utføre kommandoer. Du kan fikse dette ved å spesifisere eksplisitt i oppgavebeskrivelsen hvilke tagger den utførende pipeline-løperen skal ha:
dummy job on windows:
script:
- echo ok
tags:
- windowsFlott! Rørledningen er nå i gang.
En oppmerksom leser, etter å ha gjentatt de angitte trinnene, vil legge merke til at oppgaven ble fullført på scenen test, selv om vi ikke spesifiserte scenen. Som du kanskje gjetter test er standardtrinn.
La oss fortsette å lage konfigurasjonsskjelettet ved å legge til alle oppgavene 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: deployVi fikk en ikke spesielt funksjonell, men likevel riktig rørledning.
Sette opp triggere
På grunn av at det ikke er spesifisert triggerfiltre for noen av oppgavene, vil rørledningen fullt utføres hver gang en commit skyves til depotet. Siden dette ikke er ønsket oppførsel generelt sett, vil vi sette opp triggerfiltre for oppgaver.
Filtre kan konfigureres i to formater: и . Kort, only/except lar deg konfigurere filtre etter utløsere (merge_request, for eksempel - setter oppgaven som skal utføres hver gang en pull-forespørsel opprettes og hver gang commits sendes til grenen som er kilden i sammenslåingsforespørselen) og grennavn (inkludert bruk av regulære uttrykk); rules lar deg tilpasse et sett med betingelser og eventuelt endre betingelsen for oppgaveutførelse avhengig av suksessen til tidligere oppgaver ().
La oss huske et sett med krav – montering og testing kun for sammenslåingsforespørsel, pakking og sending til Azure DevOps – for sammenslåingsforespørsel og push til master, dokumentasjonsgenerering – for push til master.
Først, la oss sette opp kodebyggingsoppgaven ved å legge til en regel som bare utløses ved sammenslåingsforespørsel:
build job:
# snip
only:
- merge_requestLa oss nå sette opp pakkeoppgaven til å sende på sammenslåingsforespørselen og legge til forpliktelser til masteren:
pack and deploy job:
# snip
only:
- merge_request
- masterSom du kan se, er alt enkelt og greit.
Du kan også angi at oppgaven skal utløses bare hvis en sammenslåingsforespørsel er opprettet med et spesifikt mål eller kildegren:
rules:
- if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"Under forhold kan du bruke ; regler rules uforenlig med reglene only/except.
Konfigurere Artefaktlagring
Under en oppgave build job vi vil ha byggeartefakter som kan gjenbrukes i påfølgende oppgaver. For å gjøre dette må du legge til banene til oppgavekonfigurasjonen, filene som du må lagre og gjenbruke i følgende oppgaver, til nøkkelen :
build job:
# snip
artifacts:
paths:
- path/to/build/artifacts
- another/path
- MyCoolLib.*/bin/Release/*Baner støtter jokertegn, noe som definitivt gjør dem enklere å sette.
Hvis en oppgave lager artefakter, vil hver påfølgende oppgave kunne få tilgang til dem - de vil være plassert langs de samme banene i forhold til depotroten som ble samlet inn fra den opprinnelige oppgaven. Artefakter er også tilgjengelig for nedlasting på nettstedet.
Nå som vi har konfigurasjonsrammeverket klart (og testet), kan vi fortsette å faktisk skrive skript for oppgaver.
Vi skriver manus
Kanskje, en gang i tiden, i en galakse langt, langt unna, var det vanskelig å bygge prosjekter (inkludert de på .net) fra kommandolinjen. Nå kan du bygge, teste og publisere prosjektet i 3 team:
dotnet build
dotnet test
dotnet packNaturligvis er det noen nyanser som gjør at vi kompliserer kommandoene noe.
- Vi vil ha et utgivelsesbygg, ikke et feilsøkingsbygg, så vi legger til hver kommando
-c Release - Når vi tester, ønsker vi å samle kodedekningsdata, så vi må inkludere en dekningsanalysator i testbibliotekene:
- Legg pakken til alle testbibliotekene
coverlet.msbuild:dotnet add package coverlet.msbuildfra prosjektmappe - Legg til i testkjøringskommandoen
/p:CollectCoverage=true - Legg til en nøkkel til testoppgavekonfigurasjonen for å få dekningsresultater (se nedenfor)
- Legg pakken til alle testbibliotekene
- Når du pakker koden inn i nuget-pakker, setter du utdatakatalogen for pakkene:
-o .
Samler inn kodedekningsdata
Etter å ha kjørt testene, skriver Coverlet ut kjørestatistikk til konsollen:
Calculating coverage result...
Generating report 'C:Usersxxxsourcereposmy-projectmyProject.testscoverage.json'
+-------------+--------+--------+--------+
| Module | Line | Branch | Method |
+-------------+--------+--------+--------+
| project 1 | 83,24% | 66,66% | 92,1% |
+-------------+--------+--------+--------+
| project 2 | 87,5% | 50% | 100% |
+-------------+--------+--------+--------+
| project 3 | 100% | 83,33% | 100% |
+-------------+--------+--------+--------+
+---------+--------+--------+--------+
| | Line | Branch | Method |
+---------+--------+--------+--------+
| Total | 84,27% | 65,76% | 92,94% |
+---------+--------+--------+--------+
| Average | 90,24% | 66,66% | 97,36% |
+---------+--------+--------+--------+GitLab lar deg spesifisere et regulært uttrykk for å få statistikk, som deretter kan fås i form av et merke. Det regulære uttrykket er spesifisert i oppgaveinnstillingene med nøkkelen coverage; uttrykket må inneholde en fangstgruppe, hvis verdi vil bli sendt til merket:
test and cover job:
# snip
coverage: /|s*Totals*|s*(d+[,.]d+%)/Her får vi statistikk fra en linje med total linjedekning.
Publiser pakker og dokumentasjon
Begge handlingene er planlagt for siste fase av rørledningen - siden monteringen og testene har bestått, kan vi dele utviklingen vår med verden.
Vurder først å publisere til pakkekilden:
Hvis prosjektet ikke har en nuget-konfigurasjonsfil (
nuget.config), lag en ny:dotnet new nugetconfigFor hva: bildet kan ikke ha skrivetilgang til globale (bruker og maskin) konfigurasjoner. For ikke å fange opp feil, oppretter vi ganske enkelt en ny lokal konfigurasjon og jobber med den.
- La oss legge til en ny pakkekilde til den lokale konfigurasjonen:
nuget sources add -name <name> -source <url> -username <organization> -password <gitlab variable> -configfile nuget.config -StorePasswordInClearTextname- lokalt kildenavn, ikke kritiskurl- URL til kilden fra stadiet "Forberede kontoer", s. 6organization- organisasjonsnavn i Azure DevOpsgitlab variable- navnet på variabelen med tilgangstoken lagt til GitLab ("Forberede kontoer", s. 11). Naturligvis i formatet$variableName-StorePasswordInClearText- et hack for å omgå feilen tilgang nektet ()- Ved feil kan det være nyttig å legge til
-verbosity detailed
- Sende pakken til kilden:
nuget push -source <name> -skipduplicate -apikey <key> *.nupkg- Vi sender alle pakker fra gjeldende katalog, så
*.nupkg. name- fra trinnet ovenfor.key- hvilken som helst linje. I Azure DevOps, i Koble til feed-vinduet, er eksemplet alltid linjenaz.-skipduplicate- når du prøver å sende en allerede eksisterende pakke uten denne nøkkelen, vil kilden returnere en feil409 Conflict; med nøkkelen vil sendingen hoppes over.
- Vi sender alle pakker fra gjeldende katalog, så
La oss nå sette opp opprettelsen av dokumentasjon:
- Først, i depotet, i mastergrenen, initialiserer vi docfx-prosjektet. For å gjøre dette, kjør kommandoen fra roten
docfx initog interaktivt angi nøkkelparametere for bygningsdokumentasjon. Detaljert beskrivelse av minimum prosjektoppsett .- Ved konfigurering er det viktig å spesifisere utdatakatalogen
..public- GitLab tar som standard innholdet i den offentlige mappen i roten av depotet som en kilde for Pages. Fordi prosjektet vil være plassert i en mappe nestet i depotet - legg til en utgang til nivået opp i banen.
- Ved konfigurering er det viktig å spesifisere utdatakatalogen
- La oss presse endringene til GitLab.
- Legg til en oppgave i rørledningskonfigurasjonen
pages(reservert ord for nettstedspubliseringsoppgaver i GitLab-sider):- Manus:
nuget install docfx.console -version 2.51.0- installer docfx; versjonen er spesifisert for å sikre at pakkeinstallasjonsbanene er riktige..docfx.console.2.51.0toolsdocfx.exe .docfx_projectdocfx.json- innhenting av dokumentasjon
- Node-artefakter:
- Manus:
pages:
# snip
artifacts:
paths:
- publicLyrisk digresjon om docfx
Tidligere, når jeg satte opp et prosjekt, spesifiserte jeg kodekilden for dokumentasjonen som en løsningsfil. Den største ulempen er at det også lages dokumentasjon for testprosjekter. I tilfelle dette ikke er nødvendig, kan du sette en slik verdi til noden metadata.src:
{
"metadata": [
{
"src": [
{
"src": "../",
"files": [
"**/*.csproj"
],
"exclude":[
"*.tests*/**"
]
}
],
// --- snip ---
},
// --- snip ---
],
// --- snip ---
}metadata.src.src: "../"– vi går ett nivå opp i forhold til beliggenhetendocfx.json, fordi i mønstre fungerer det ikke å søke opp katalogtreet.metadata.src.files: ["**/*.csproj"]- et globalt mønster, vi samler alle C #-prosjekter fra alle kataloger.metadata.src.exclude: ["*.tests*/**"]- globalt mønster, ekskluder alt fra mapper med.testsI tittelen
Delsum
En slik enkel konfigurasjon kan lages på bare en halv time og et par kopper kaffe, som lar deg sjekke at koden er bygget og testene passerer, bygge en ny pakke, oppdatere dokumentasjonen og glede øyet med vakre merker i README for prosjektet med hver sammenslåingsforespørsel og sending 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:
- masterApropos merker
På grunn av dem ble tross alt alt startet!
Merker med rørledningsstatuser og kodedekning er tilgjengelig i GitLab i CI/CD-innstillingene i Gtntral-rørledningsblokken:

Jeg laget et merke med en lenke til dokumentasjonen på plattformen - alt er ganske enkelt der, du kan lage ditt eget merke og motta det ved å bruke en forespørsel.

Azure DevOps Artifacts lar deg også lage merker for pakker med den nyeste versjonen. For å gjøre dette, i kilden på Azure DevOps-nettstedet, må du klikke på Opprett merke for den valgte pakken og kopiere markeringen:


Legger til skjønnhet
Utheving av vanlige konfigurasjonsfragmenter
Mens jeg skrev konfigurasjonen og søkte gjennom dokumentasjonen, kom jeg over en interessant funksjon ved YAML – gjenbruk av fragmenter.
Som du kan se fra oppgaveinnstillingene, krever de alle taggen windows hos løperen, og utløses når en sammenslåingsforespørsel sendes til master/opprettes (unntatt dokumentasjon). La oss legge dette til fragmentet som vi skal gjenbruke:
.common_tags: &common_tags
tags:
- windows
.common_only: &common_only
only:
- merge_requests
- masterOg nå kan vi sette inn fragmentet som er erklært tidligere i oppgavebeskrivelsen:
build job:
<<: *common_tags
<<: *common_onlyFragmentnavn må begynne med en prikk, for ikke å bli tolket som en oppgave.
Pakkeversjon
Når du oppretter en pakke, sjekker kompilatoren kommandolinjebryterne, og i deres fravær prosjektfilene; når den finner en versjonsnode, tar den verdien som versjonen av pakken som bygges. Det viser seg at for å bygge en pakke med en ny versjon, må du enten oppdatere den i prosjektfilen eller sende den som et kommandolinjeargument.
La oss legge til en ønskeliste til - la de to mindre tallene i versjonen være år og byggedato for pakken, og legg til forhåndsversjoner. Selvfølgelig kan du legge til disse dataene i prosjektfilen og sjekke før hver innsending - men du kan også gjøre det i pipelinen, samle pakkeversjonen fra konteksten og sende den gjennom kommandolinjeargumentet.
La oss bli enige om at hvis commit-meldingen inneholder en linje som release (v./ver./version) <version number> (rev./revision <revision>)?, så tar vi versjonen av pakken fra denne linjen, supplerer den med gjeldende dato og sender den som et argument til kommandoen dotnet pack. I mangel av linje vil vi rett og slett ikke hente pakken.
Følgende skript løser dette problemet:
# регулярное выражение для поиска строки с версией
$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=$versionLegge til et skript til en oppgave pack and deploy job og observer sammenstillingen av pakker strengt i nærvær av en gitt streng i commit-meldingen.
Totalt
Etter å ha brukt omtrent en halvtime eller en time på å skrive konfigurasjonen, feilsøke i det lokale powershell og muligens et par mislykkede lanseringer, fikk vi en enkel konfigurasjon for å automatisere rutineoppgaver.
Selvfølgelig er GitLab CI / CD mye mer omfattende og mangefasettert enn det kan virke etter å ha lest denne veiledningen - . Der til og med tillater
automatisk oppdage, bygge, teste, distribuere og overvåke applikasjonene dine
Nå er planene å konfigurere en pipeline for distribusjon av applikasjoner til Azure, ved å bruke Pulumi og automatisk bestemme målmiljøet, som vil bli dekket i neste artikkel.
Kilde: www.habr.com








