Una guia de CI/CD a GitLab per al principiant (gairebé) absolut
O com obtenir insígnies precioses per al vostre projecte en una tarda de codificació fàcil
Probablement, cada desenvolupador que tingui almenys un projecte per a mascotes en algun moment té una picor per les belles insígnies amb estats, cobertura de codi, versions de paquets a nuget... I aquesta picor em va portar a escriure aquest article. En preparació per escriure'l, vaig aconseguir aquesta bellesa en un dels meus projectes:
Aquest article us guiarà a través de la configuració bàsica d'integració i lliurament contínua per a un projecte de biblioteca de classes .Net Core a GitLab, publicació de documentació a GitLab Pages i enviant paquets creats a un canal privat a Azure DevOps.
VS Code es va utilitzar com a entorn de desenvolupament amb l'extensió Flux de treball de GitLab (per validar el fitxer de configuració directament des de l'entorn de desenvolupament).
Breu introducció
CD - és quan acabes d'empènyer i ja ha caigut tot sobre el client?
Què és CI/CD i per què el necessiteu: podeu cercar-lo fàcilment a Google. Trobeu la documentació completa sobre la configuració de canalitzacions a GitLab també fàcil. Aquí descriuré breument i, si és possible, sense defectes, el procés del sistema des d'una vista d'ocell:
el desenvolupador envia una confirmació al dipòsit, crea una sol·licitud de combinació a través del lloc, o d'alguna altra manera, inicia explícitament o implícitament el pipeline,
totes les tasques es seleccionen de la configuració, les condicions de la qual permeten llançar-les en el context donat,
les tasques s'organitzen segons les seves etapes,
les etapes s'executen al seu torn, és a dir. paral·lel s'han completat totes les tasques d'aquesta etapa,
si l'etapa falla (és a dir, almenys una de les tasques de l'etapa falla), el gasoducte s'atura (quasi sempre),
si totes les etapes es completen amb èxit, el gasoducte es considera reeixit.
Així, tenim:
pipeline: un conjunt de tasques organitzades en etapes en què podeu crear, provar, empaquetar codi, desplegar una compilació acabada en un servei al núvol, etc.,
etapa (etapa) — unitat organitzativa de pipeline, conté 1+ tasca,
tasca (treball) és una unitat de treball en procés. Consisteix en un script (obligatori), condicions de llançament, paràmetres per a la publicació/emmagatzematge en memòria cau d'artefactes i molt més.
En conseqüència, la tasca a l'hora de configurar CI / CD es limita a crear un conjunt de tasques que implementin totes les accions necessàries per construir, provar i publicar codi i artefactes.
Abans de començar: per què?
Per què Gitlab?
Perquè quan es va fer necessari crear dipòsits privats per a projectes de mascotes, es pagaven a GitHub i jo era cobdiciós. Els dipòsits s'han convertit en gratuïts, però fins ara aquest no és motiu suficient per moure'm a GitHub.
Per què no Azure DevOps Pipelines?
Com que allà la configuració és elemental, ni tan sols es requereix el coneixement de la línia d'ordres. Integració amb proveïdors externs de git (en un parell de clics, importació de claus SSH per enviar commits al dipòsit) també, el pipeline es configura fàcilment fins i tot no des d'una plantilla.
Posició inicial: què tens i què vols
Tenim:
repositori a GitLab.
Volem:
muntatge i prova automàtics per a cada sol·licitud de fusió,
crear paquets per a cada sol·licitud de combinació i enviant-los al mestre, sempre que hi hagi una línia determinada al missatge de confirmació,
enviant paquets creats a un canal privat a Azure DevOps,
muntatge de documentació i publicació a GitLab Pages,
insígnies!11
Els requisits descrits es troben orgànicament en el model de canalització següent:
Etapa 1 - Muntatge
Recopilem el codi, publiquem els fitxers de sortida com a artefactes
Fase 2: proves
Obtenim artefactes de l'etapa de construcció, fem proves, recopilem dades de cobertura de codi
Fase 3 - Presentació
Tasca 1: creeu el paquet nuget i envieu-lo a Azure DevOps
Tasca 2: recollim el lloc de xmldoc al codi font i el publiquem a les pàgines de GitLab
Quan feu clic al botó Crear, el projecte es crearà i se us redirigirà a la seva pàgina. En aquesta pàgina, podeu desactivar funcions innecessàries si aneu a la configuració del projecte (enllaç inferior a la llista de l'esquerra -> Visió general -> Bloqueig Azure DevOps Services)
Aneu a Atrifacts, feu clic a Crea feed
Introduïu el nom de la font
Trieu visibilitat
Desmarqueu Inclou paquets de fonts públiques comunes, de manera que la font no es converteixi en un clon de nuget dump
Feu clic a Connecta per alimentar, seleccioneu Visual Studio, copieu la font des del bloc Configuració de la màquina
Aneu a la configuració del compte, seleccioneu Fitxa d'accés personal
Creeu un testimoni d'accés nou
Nom - arbitrari
Organització - actual
Vàlid màxim d'1 any
Àmbit: embalatge/lectura i escriptura
Copia el testimoni creat - després de tancar la finestra modal, el valor no estarà disponible
Aneu a la configuració del dipòsit a GitLab, seleccioneu la configuració de CI / CD
Amplieu el bloc Variables, afegiu-ne un de nou
Nom: qualsevol sense espais (estarà disponible a l'intèrpret d'ordres)
Valor: testimoni d'accés del paràgraf 9
Seleccioneu la variable Màscara
Això completa la preconfiguració.
Preparació del marc de configuració
Per defecte, la configuració CI/CD a GitLab utilitza el fitxer .gitlab-ci.yml des de l'arrel del dipòsit. Podeu establir un camí arbitrari a aquest fitxer a la configuració del dipòsit, però en aquest cas no és necessari.
Com podeu veure a l'extensió, el fitxer conté una configuració en el format YAML. La documentació detalla quines claus es poden contenir al nivell superior de la configuració i a cadascun dels nivells imbricats.
Primer, afegim un enllaç a la imatge de Docker al fitxer de configuració, en el qual es realitzaran les tasques. Per això trobem Pàgina d'imatges .Net Core a Docker Hub. En GitHub hi ha una guia detallada sobre quina imatge escollir per a diferents tasques. Una imatge amb .Net Core 3.1 és adequada perquè puguem construir, així que no dubteu a afegir la primera línia a la configuració
image: mcr.microsoft.com/dotnet/core/sdk:3.1
Ara, quan s'iniciï el pipeline des del dipòsit d'imatges de Microsoft, es baixarà la imatge especificada, en la qual s'executaran totes les tasques de la configuració.
El següent pas és afegir etapa's. Per defecte, GitLab defineix 5 etapes:
.pre - realitzat fins a totes les etapes,
.post - realitzat després de totes les etapes,
build - primer després .pre etapa,
test - segona fase,
deploy - la tercera etapa.
Res no impedeix declarar-los explícitament, però. L'ordre en què s'enumeren els passos afecta l'ordre en què es realitzen. Per completar la configuració, afegim a la configuració:
stages:
- build
- test
- deploy
Per a la depuració, té sentit obtenir informació sobre l'entorn en què s'executen les tasques. Afegim un conjunt global d'ordres que s'executaran abans de cada tasca amb before_script:
before_script:
- $PSVersionTable.PSVersion
- dotnet --version
- nuget help | select-string Version
Queda per afegir almenys una tasca perquè quan s'enviïn els commits, s'iniciï el pipeline. De moment, afegim una tasca buida per demostrar:
dummy job:
script:
- echo ok
Comencem la validació, rebem un missatge que tot està bé, ens comprometem, empenyem, mirem els resultats al lloc... I obtenim un error d'script - bash: .PSVersion: command not found. wtf?
Tot és lògic: per defecte, els corredors (responsables d'executar scripts de tasques i proporcionats per GitLab) utilitzen bash per executar ordres. Podeu solucionar-ho especificant explícitament a la descripció de la tasca quines etiquetes hauria de tenir l'executor de pipeline:
dummy job on windows:
script:
- echo ok
tags:
- windows
Genial! El gasoducte està en marxa.
Un lector atent, després d'haver repetit els passos indicats, notarà que la tasca s'ha completat a l'etapa test, tot i que no hem concretat l'etapa. Com podeu endevinar test és el pas predeterminat.
Continuem creant l'esquelet de configuració afegint totes les tasques descrites anteriorment:
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
Tenim una canalització no especialment funcional, però tanmateix correcta.
Configuració de disparadors
A causa del fet que no s'especifiquen filtres activadors per a cap de les tasques, el pipeline ho farà completament s'executarà cada vegada que s'envia una confirmació al repositori. Com que aquest no és el comportament desitjat en general, configurarem filtres activadors per a les tasques.
Els filtres es poden configurar en dos formats: només/excepte и normes. Breument, only/except permet configurar filtres per activadors (merge_request, per exemple: estableix la tasca que s'executa cada vegada que es crea una sol·licitud d'extracció i cada vegada que s'envien confirmacions a la branca que és l'origen de la sol·licitud de combinació) i els noms de les branques (incloent l'ús d'expressions regulars); rules permet personalitzar un conjunt de condicions i, opcionalment, canviar la condició d'execució de la tasca en funció de l'èxit de les tasques anteriors (when a GitLab CI/CD).
Recordem un conjunt de requisits: muntatge i prova només per a la sol·licitud de combinació, empaquetat i enviament a Azure DevOps, per a sol·licituds de combinació i enviaments al mestre, generació de documentació, per a enviaments al mestre.
Primer, configurem la tasca de creació de codi afegint una regla que s'activa només a la sol·licitud de combinació:
build job:
# snip
only:
- merge_request
Ara configurem la tasca d'embalatge per activar la sol·licitud de combinació i afegir commits al mestre:
En condicions, podeu utilitzar variables enumerades aquí; regles rules incompatible amb les normes only/except.
Configuració de l'estalvi d'artefactes
Durant una tasca build job haurem de construir artefactes que es poden reutilitzar en tasques posteriors. Per fer-ho, heu d'afegir els camins a la configuració de la tasca, els fitxers pels quals haureu de desar i reutilitzar en les tasques següents, a la clau artifacts:
Els camins admeten comodins, cosa que sens dubte els fa més fàcils d'establir.
Si una tasca crea artefactes, cada tasca posterior podrà accedir-hi: es trobaran pels mateixos camins en relació a l'arrel del dipòsit que es van recollir de la tasca original. Els artefactes també es poden descarregar al lloc.
Ara que tenim un marc de configuració preparat (i provat), podem procedir a escriure scripts per a les tasques.
Escrivim guions
Potser, hi havia una vegada, en una galàxia molt, molt llunyana, construir projectes (inclosos els de .net) des de la línia d'ordres era un dolor. Ara podeu construir, provar i publicar el projecte en 3 equips:
dotnet build
dotnet test
dotnet pack
Naturalment, hi ha alguns matisos pels quals complicarem una mica les ordres.
Volem una compilació de llançament, no una compilació de depuració, així que afegim a cada comanda -c Release
Quan fem les proves, volem recollir dades de cobertura de codi, de manera que hem d'incloure un analitzador de cobertura a les biblioteques de proves:
Afegiu el paquet a totes les biblioteques de prova coverlet.msbuild: dotnet add package coverlet.msbuild de la carpeta del projecte
Afegiu a l'ordre d'execució de prova /p:CollectCoverage=true
Afegiu una clau a la configuració de la tasca de prova per obtenir resultats de cobertura (vegeu a continuació)
Quan empaqueteu el codi en paquets nuget, configureu el directori de sortida dels paquets: -o .
Recollida de dades de cobertura del codi
Després d'executar les proves, les impressions de Coverlet executen estadístiques a la consola:
GitLab us permet especificar una expressió regular per obtenir estadístiques, que després es poden obtenir en forma de distintiu. L'expressió regular s'especifica a la configuració de la tasca amb la clau coverage; l'expressió ha de contenir un grup de captura, el valor del qual es passarà a la insígnia:
test and cover job:
# snip
coverage: /|s*Totals*|s*(d+[,.]d+%)/
Aquí obtenim estadístiques d'una línia amb cobertura total de línia.
Publicar paquets i documentació
Ambdues accions estan programades per a l'última etapa del gasoducte: ja que el muntatge i les proves han passat, podem compartir els nostres desenvolupaments amb el món.
Primer, considereu la possibilitat de publicar a la font del paquet:
Si el projecte no té un fitxer de configuració nuget (nuget.config), creeu-ne un de nou: dotnet new nugetconfig
Per a què: és possible que la imatge no tingui accés d'escriptura a configuracions globals (usuari i màquina). Per no detectar errors, simplement creem una nova configuració local i treballem amb ella.
Afegim una nova font de paquets a la configuració local: nuget sources add -name <name> -source <url> -username <organization> -password <gitlab variable> -configfile nuget.config -StorePasswordInClearText
name - nom de la font local, no crític
url - URL de la font de l'etapa "Preparació de comptes", pàg. 6
organization - nom de l'organització a Azure DevOps
gitlab variable - el nom de la variable amb el testimoni d'accés afegit a GitLab ("Preparació de comptes", p. 11). Naturalment, en el format $variableName
En cas d'error, pot ser útil afegir -verbosity detailed
Enviament del paquet a la font: nuget push -source <name> -skipduplicate -apikey <key> *.nupkg
Enviem tots els paquets des del directori actual, per tant *.nupkg.
name - del pas anterior.
key - qualsevol línia. A Azure DevOps, a la finestra Connect to feed, l'exemple sempre és la línia az.
-skipduplicate - quan s'intenta enviar un paquet ja existent sense aquesta clau, la font retornarà un error 409 Conflict; amb la clau, l'enviament es saltarà.
Ara configurem la creació de la documentació:
Primer, al repositori, a la branca mestra, inicialitzem el projecte docfx. Per fer-ho, executeu l'ordre des de l'arrel docfx init i establir de manera interactiva els paràmetres clau per a la documentació de l'edifici. Descripció detallada de la configuració mínima del projecte aquí.
Quan es configura, és important especificar el directori de sortida ..public - GitLab pren per defecte el contingut de la carpeta pública a l'arrel del dipòsit com a font per a Pages. Perquè el projecte s'ubicarà en una carpeta imbricada al repositori: afegiu una sortida al nivell superior del camí.
Anem a impulsar els canvis a GitLab.
Afegiu una tasca a la configuració de la canalització pages (paraula reservada per a les tasques de publicació del lloc a les pàgines de GitLab):
Guió:
nuget install docfx.console -version 2.51.0 - instal·lar docfx; la versió s'especifica per assegurar-se que les rutes d'instal·lació del paquet són correctes.
.docfx.console.2.51.0toolsdocfx.exe .docfx_projectdocfx.json - Recollida de documentació
Artefactes de nodes:
pages:
# snip
artifacts:
paths:
- public
Digressió lírica sobre docfx
Anteriorment, en configurar un projecte, vaig especificar la font del codi per a la documentació com a fitxer de solució. El principal desavantatge és que també es crea documentació per a projectes de prova. En cas que això no sigui necessari, podeu establir aquest valor al node metadata.src:
metadata.src.src: "../" - Pugem un nivell en relació a la ubicació docfx.json, perquè en patrons, la cerca a l'arbre de directoris no funciona.
metadata.src.files: ["**/*.csproj"] - un patró global, recollim tots els projectes C # de tots els directoris.
metadata.src.exclude: ["*.tests*/**"] - patró global, exclou-ho tot de les carpetes amb .tests Al títol
Subtotal
Es pot crear una configuració tan senzilla en només mitja hora i un parell de tasses de cafè, la qual cosa us permetrà comprovar que el codi està construït i que les proves passen, crear un nou paquet, actualitzar la documentació i complaure la vista amb una bella insígnies al README del projecte amb cada sol·licitud de fusió i enviament al mestre.
.gitlab-ci.yml final
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
Parlant de distintius
Per culpa d'ells, al cap i a la fi, tot va començar!
Les insígnies amb estats de canalització i cobertura de codi estan disponibles a GitLab a la configuració de CI/CD al bloc de canalitzacions Gtntral:
Vaig crear un distintiu amb un enllaç a la documentació de la plataforma escuts.io - Allà tot és molt senzill, podeu crear la vostra pròpia insígnia i rebre-la mitjançant una sol·licitud.
![Пример с Shields.io](https://img.shields.io/badge/custom-badge-blue)
Azure DevOps Artifacts també us permet crear insígnies per a paquets amb la darrera versió. Per fer-ho, a la font del lloc d'Azure DevOps, heu de fer clic a Crea una insígnia per al paquet seleccionat i copiar el marcatge de reducció:
Afegint bellesa
Ressaltant fragments de configuració comuns
Mentre escrivia la configuració i cercava a través de la documentació, em vaig trobar amb una característica interessant de YAML: la reutilització de fragments.
Com podeu veure a la configuració de la tasca, totes requereixen l'etiqueta windows al corredor, i es desencadenen quan s'envia una sol·licitud de combinació al mestre/creat (excepte la documentació). Afegim això al fragment que reutilitzarem:
I ara podem inserir el fragment declarat anteriorment a la descripció de la tasca:
build job:
<<: *common_tags
<<: *common_only
Els noms dels fragments han de començar amb un punt, per no ser interpretats com una tasca.
Versions de paquets
Quan es crea un paquet, el compilador comprova els interruptors de la línia d'ordres i, en absència, els fitxers del projecte; quan troba un node Versió, pren el seu valor com a versió del paquet que s'està construint. Resulta que per crear un paquet amb una versió nova, cal actualitzar-lo al fitxer del projecte o passar-lo com a argument de línia d'ordres.
Afegim una llista de desitjos més: deixeu que els dos números menors de la versió siguin l'any i la data de creació del paquet i afegiu versions prèvies. Per descomptat, podeu afegir aquestes dades al fitxer del projecte i comprovar-les abans de cada enviament, però també podeu fer-ho en el pipeline, recopilant la versió del paquet del context i passant-la per l'argument de la línia d'ordres.
Estem d'acord que si el missatge de confirmació conté una línia com release (v./ver./version) <version number> (rev./revision <revision>)?, llavors agafarem la versió del paquet d'aquesta línia, la complementarem amb la data actual i la passarem com a argument a l'ordre dotnet pack. En absència de línia, simplement no recollirem el paquet.
El següent script resol aquest problema:
# регулярное выражение для поиска строки с версией
$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
Afegir un script a una tasca pack and deploy job i observeu el muntatge de paquets estrictament en presència d'una cadena determinada al missatge de confirmació.
En total
Després de passar aproximadament mitja hora o una hora escrivint la configuració, depurant al powershell local i, possiblement, un parell de llançaments sense èxit, vam obtenir una configuració senzilla per automatitzar les tasques rutinàries.
Per descomptat, GitLab CI / CD és molt més extens i polifacètic del que podria semblar després de llegir aquesta guia: això no és cert. Fins i tot allà Auto DevOps éspermetent
detectar, crear, provar, desplegar i supervisar automàticament les vostres aplicacions
Ara els plans són configurar un pipeline per desplegar aplicacions a Azure, utilitzant Pulumi i determinant automàticament l'entorn objectiu, que es tractarà al següent article.