Alebo ako za jednu večernú nenáročnú kódovanie získať krásne odznaky pre svoj projekt
Asi každý vývojár, ktorý má aspoň jeden pet projekt, pocíti v určitom momente túžbu po krásnych odznakoch so statusmi, pokrytím kódu, verziami balíkov v nuget... A mňa táto túžba priviedla k napísaniu tohoto článku. Počas prípravy na jeho napísanie som sa obohatil o takúto krásu v jednom z mojich projektov:

V článku sa bude zaoberať základným nastavením kontinuálnej integrácie a dodávky pre projekt knižnice tried na .Net Core v GitLab, s publikovaním dokumentácie v GitLab Pages a odosielaním zostavených balíkov do súkromného feedu v Azure DevOps.
Ako vývojové prostredie sa používal VS Code s rozšírením (na validáciu súboru nastavení priamo z vývojového prostredia).
Krátke úvodné slovo
CD — je to, keď si práve zatlačil a u klienta už všetko spadlo?
Čo je CI/CD a na čo je potrebné — dá sa ľahko vyhľadať. Kompletnú dokumentáciu k nastaveniu pipeliningov v GitLab nájsť . Tu stručne a podľa možností bez chýb opíšem proces fungovania systému z vtáčej perspektívy:
- vývojár odošle commit do repozitára, vytvorí merge request cez web alebo iným spôsobom jasne alebo nejasne spustí pipeline,
- z konfigurácie sa vyberú všetky úlohy, ktorých podmienky umožňujú ich spustenie v tomto kontexte,
- úlohy sa organizujú podľa svojich etáp,
- etapy sa postupne vykonávajú — t.j. paralelne sa vykonávajú všetky úlohy tejto etapy,
- ak etapa skončí neúspešne (t.j. ak aspoň jedna z úloh etapy skončí neúspešne) — pipeline sa zastaví (takmer vždy),
- ak sa všetky etapy skončia úspešne, pipeline sa považuje za úspešne prebehnuté.
Takže máme:
- pipeline — súbor úloh, organizovaných v etapách, v ktorom je možné zostaviť, otestovať, zabaliť kód, nasadiť hotové zostavenie do cloudovej služby, atď.,
- etapa (stage) — jednotka organizácie pipeline, obsahuje 1+ úlohu,
- úloha (job) — jednotka práce v pipeline. Skladá sa zo skriptu (povinne), podmienok spustenia, nastavení publikovania/kešovania artefaktov a mnoho iného.
Teda úlohou pri nastavení CI/CD je vytvoriť súbor úloh, ktoré realizujú všetky potrebné činnosti na zostavenie, testovanie a publikovanie kódu a artefaktov.
Pred začiatkom: prečo?
- Prečo GitLab?
Pretože keď vznikla potreba vytvoriť súkromné repozitáre pre pet projekty, na GitHub-e boli platené, a ja som bol zhanobený. Repozitáre sa stali bezplatnými, ale zatiaľ to nie je dostatočný dôvod na presťahovanie na GitHub.
- Prečo nie Azure DevOps Pipelines?
Pretože tam je nastavenie elementárne — ani nie sú potrebné znalosti príkazového riadku. Integrácia s externými poskytovateľmi git — na pár kliknutí, import SSH kľúčov na odosielanie commitov do repozitára — tiež, pipeline sa dá ľahko nastaviť aj bez šablóny.
Počiatočná pozícia: čo máme a čo chceme
Máme:
- repozitár v GitLab.
Chceme:
- automatickú zostavu a testovanie pre každý merge request,
- zostavenie balíkov pre každý merge request a push do master pri splnení určitej podmienky v správe commitu,
- odoslanie zostavených balíkov do súkromného feedu v Azure DevOps,
- zostavenie dokumentácie a publikovanie v GitLab Pages,
- badge-y!11
Popísané požiadavky prirodzene zapadajú do nasledujúceho modelu pipeline:
- Fáza 1 — zostava
- Zostavíme kód, výstupné súbory publikujeme ako artefakty
- Fáza 2 — testovanie
- Získavame artefakty z fázy zostavovania, spúšťame testy, zhromažďujeme údaje o pokrytí kódom
- Fáza 3 — odoslanie
- Úloha 1 — zostavujeme nuget balík a odosielame do Azure DevOps
- Úloha 2 — zostavujeme web z xmldoc v zdrojovom kóde a publikujeme v GitLab Pages
Poďme na to!
Zostavujeme konfiguráciu
Pripravujeme účty
Vytvárame účet v
Prechádzame do
Vytvárame nový projekt
- Názov — ľubovoľný
- Viditeľnosť — ľubovoľná

Po kliknutí na tlačidlo Create bude projekt vytvorený a bude sa realizovať prechod na jeho stránku. Na tejto stránke je možné vypnúť zbytočné možnosti, prechodom do nastavení projektu (dolný odkaz v zozname vľavo -> Overview -> blok Azure DevOps Services)

Prechádzame do Atrifacts, klikneme na Create feed
- Zadávame názov zdroja
- Vyberáme viditeľnosť
- Zrušíme zaškrtnutie Include packages from common public sources, aby sa zdroj nestal smetiskom klonov nuget

Klikáme na Connect to feed, vyberáme Visual Studio, z bloku Machine Setup kopírujeme Source

Ideme do nastavení účtu, vyberáme Personal Access Token

Vytvárame nový prístupový token
- Názov — ľubovoľný
- Organizácia — aktuálna
- Doba platnosti — max 1 rok
- Rozsah (scope) — Packaging/Read & Write

Kopírujeme vytvorený token — po zatvorení modálneho okna nebude hodnota dostupná
Prejdeme do nastavení repozitára v GitLabe, vyberieme nastavenia CI/CD

Rozbalíme blok Variables, pridáme nový
- Názov — akýkoľvek bez medzier (bude dostupný v príkazovom riadku)
- Hodnota — prístupový token z bodu 9
- Vyberieme Mask variable

Na tomto predbežné nastavenie sa skončilo.
Pripravujeme rámec konfigurácie
Predvolene sa na nastavenie CI/CD v GitLabe používa súbor .gitlab-ci.yml z koreňa repozitára. Môžete nastaviť ľubovoľnú cestu k tomuto súboru v nastaveniach repozitára, ale v tomto prípade to nie je potrebné.
Ako je vidieť z príponu, súbor obsahuje konfiguráciu vo formáte YAML. V dokumentácii je podrobne opísané, aké kľúče môžu byť na vrchole konfigurácie a v každej z vnorených úrovní.
Najprv prídame do konfiguračného súboru odkaz na docker-obráz, v ktorom sa budú vykonávať úlohy. Na tento účel nájdeme . V existuje podrobné vedenie, ktorý obrázok si vybrať pre rôzne úlohy. Pre náš build vyhovuje obrázok s .Net Core 3.1, preto smelo pridáme ako prvý riadok do konfigurácie
image: mcr.microsoft.com/dotnet/core/sdk:3.1Teraz pri spustení pipeline so zdrojom obrázkov Microsoft sa stiahne uvedený obrázok, v ktorom sa budú vykonávať všetky úlohy z konfigurácie.
Ďalší krok — pridať stageetapy. Predvolene GitLab určuje 5 etáp:
.pre— vykonáva sa pred všetkými etapami,.post— vykonáva sa po všetkých etapách,build— prvý po.preetape,test— druhá etapa,deploy— tretia etapa.
Nič nebráni výslovne ich vyhlásiť. Poradie, v ktorom sú etapy uvedené, ovplyvňuje poradie, v ktorom sa vykonávajú. Pre úplnosť vyhlásenia pridáme do konfigurácie:
stages:
- build
- test
- deployPre ladenie má zmysel získať informácie o prostredí, v ktorom sa úlohy vykonávajú. Pridáme globálnu sadu príkazov, ktoré sa vykonajú pred každou úlohou, pomocou before_script:
before_script:
- $PSVersionTable.PSVersion
- dotnet --version
- nuget help | select-string VersionZostáva pridať aspoň jednu úlohu, aby sa pipeline spustila pri odosielaní commitov. Zatiaľ pridáme prázdnu úlohu na demonštráciu:
dummy job:
script:
- echo okSpúšťame validáciu, dostávame správu, že všetko je v poriadku, commitujeme, pushujeme, sledujeme výsledky na stránke... A dostávame chybu skriptu — bash: .PSVersion: príkaz nenájdený. Čo?
Všetko dáva zmysel — predvolene runner'y (zodpovedajúce za vykonávanie skriptov úloh, a poskytované GitLabom) používajú bash na vykonávanie príkazov. Môžeme to opraviť tak, že jasne uvedieme v popise úlohy, aké tagy by mali mať spúšťajúce pipelinové runnery:
dummy job na windows:
script:
- echo ok
tags:
- windowsVýborne! Teraz pipeline prebieha.
Pozorný čitateľ, ktorý zopakuje uvedené kroky, si všimne, že úloha sa vykonala v etape test, hoci sme etapu neuviedli. Ako sa dá predpokladať, test je predvolenou etapou.
Pokračujme v vytváraní kostry konfigurácie pridaním všetkých úloh, ktoré sme uviedli vyššie:
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: deployDostali sme nie veľmi funkčný, ale napriek tomu správny pipeline.
Nastavenie spúšťačov
Keďže pre žiadnu z úloh nie sú uvedené filtre spúšťania, pipeline sa bude úplne vykonávať pri každom odoslaní commitov do repozitára. Pretože to nie je želané správanie v obvyklých prípadoch, nastavíme filtre spúšťania pre úlohy.
Filtre môžu byť nastavené v dvoch formátoch: a . Stručne povedané, only/except umožňuje nastavovať filtre podľa spúšťačov (merge_request, napríklad — nastavuje úlohu na vykonávanie pri každom vytvorení požiadavky na zlúčenie a pri každom odoslaní commitov do vetvy, ktorá je pôvodná v požiadavke na zlúčenie) a mená vetiev (vrátane použitia regulárnych výrazov); rules umožňuje nastavovať súbor podmienok a voliteľne meniť podmienku vykonávania úlohy v závislosti od úspechu predchádzajúcich úloh ().
Pripomeňme si súbor požiadaviek — zostavenie a testovanie iba pre merge request, balenie a odosielanie do Azure DevOps — pre merge request a pushy do master, generovanie dokumentácie — pre pushy do master.
Najprv nastavíme úlohu na zostavenie kódu, pridaním pravidla spúšťania iba pri merge request:
build job:
# snip
only:
- merge_requestTeraz nastavíme úlohu balenia na spúšťanie po merge requeste a pridávaní commitov do master:
úloha balenia a nasadenia:
# snip
iba:
- merge_request
- masterAko vidno, všetko je jednoduché a priamočiare.
Rovnako môžeme nastaviť úlohu na spúšťanie iba v prípade, že bol vytvorený merge request s určitou cieľovou alebo zdrojovou vetvou:
pravidlá:
- ak: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"V podmienkach môžeme používať ; pravidlá rules nie sú kompatibilné s pravidlami only/except.
Nastavenie uchovania artefaktov
Počas vykonávania úlohy úloha build nám budú vytvorené artefakty zostavenia, ktoré je možné znovu použiť v nasledujúcich úlohách. Na to je potrebné do konfigurácie úlohy pridať cesty, súbory, ktoré sa musia uložiť a znovu použiť v nasledujúcich úlohách, v kľúči :
úloha build:
# snip
artefakty:
cesty:
- path/to/build/artifacts
- another/path
- MyCoolLib.*/bin/Release/*Cesty podporujú zástupné znaky, čo určite zjednodušuje ich definovanie.
Ak úloha vytvára artefakty, tak každá nasledujúca úloha k nim získa prístup — budú sa nachádzať na tých istých cestách relatívne ku koreňu repozitára, po ktorých boli vytvorené zo zdrojovej úlohy. Taktiež sú artefakty dostupné na stiahnutie na stránke.
Teraz, keď máme pripravený (a overený) rámec konfigurácie, môžeme prejsť priamo k písaniu skriptov pre úlohy.
Píšeme skripty
Možno, že kedysi dávno, v ďalekej-ďalekej galaxii, bolo budovanie projektov (vrátane .net) z príkazového riadku bolesti. Teraz sa však projekt dá zostaviť, otestovať a publikovať v 3 príkazoch:
dotnet build
dotnet test
dotnet packSamozrejme, existujú určité nuansy, kvôli ktorým príkazy trochu skomplikujeme.
- Chceme vydanie, nie ladenú zostavu, preto ku každému príkazu pridáme
-c Release - Pri testovaní chceme zhromaždiť údaje o pokrytí kódu, preto bude potrebné pripojiť analyzátor pokrytia do testovacích knižníc:
- Do všetkých testovacích knižníc je potrebné pridať balík
coverlet.msbuild:dotnet add package coverlet.msbuildz adresára projektu - Do príkazu spustenia testov pridáme
/p:CollectCoverage=true - Do konfigurácie úlohy testovania pridáme kľúč na získanie výsledkov pokrytia (pozri nižšie)
- Do všetkých testovacích knižníc je potrebné pridať balík
- Pri balení kódu do nuget balíkov nastavíme výstupný adresár pre balíky:
-o .
Zhromažďujeme údaje o pokrytí kódu
Coverlet po spustení testov vypisuje do konzoly štatistiku o spustení:
Prebieha výpočet výsledku pokrytia...
Generovanie správy 'C:Usersxxxsourcereposmy-projectmyProject.testscoverage.json'
+-------------+--------+--------+--------+
| Modul | Riadok | Vetva | Metóda |
+-------------+--------+--------+--------+
| projekt 1 | 83,24% | 66,66% | 92,1% |
+-------------+--------+--------+--------+
| projekt 2 | 87,5% | 50% | 100% |
+-------------+--------+--------+--------+
| projekt 3 | 100% | 83,33% | 100% |
+-------------+--------+--------+--------+
+---------+--------+--------+--------+
| | Riadok | Vetva | Metóda |
+---------+--------+--------+--------+
| Celkom | 84,27% | 65,76% | 92,94% |
+---------+--------+--------+--------+
| Priemer | 90,24% | 66,66% | 97,36% |
+---------+--------+--------+--------+GitLab umožňuje zadať regulárny výraz pre získavanie štatistík, ktoré potom môžete získať vo forme odznaku. Regulárny výraz sa uvádza v nastaveniach úlohy s kľúčom coverage; v výraze musí byť prítomná capture-skupina, ktorej hodnota bude odovzdaná do odznaku:
test and cover job:
# snip
coverage: /|\s*Totals*|\s*(\d+[,.]\d+%)Tu získavame štatistiku z riadku s celkovým pokrytím podľa riadkov.
Zverejňujeme balíky a dokumentáciu
Obe činnosti sú u nás naplánované na posledný krok pipeline — keď už prebehla kompilácia a testy, môžeme sa podeliť so svetom o naše výsledky.
Najprv sa pozrime na publikovanie do zdroja balíkov:
Ak v projekte nie je prítomný konfiguračný súbor nuget (
nuget.config), vytvoríme nový:dotnet new nugetconfigPrečo: v obraze môže byť zakázaný zápis do globálnych (používateľských a systémových) konfigurácií. Aby sme sa vyhli chybám, jednoducho vytvoríme novú lokálnu konfiguráciu a budeme s ňou pracovať.
- Pridáme do lokálnej konfigurácie nový zdroj balíkov:
nuget sources add -name -source -username -password -configfile nuget.config -StorePasswordInClearTextname— lokálne meno zdroja, nie je podstatnéurl— URL zdroja z kroku "Pripravujeme účty", p. 6organization— názov organizácie v Azure DevOpsgitlab variable— názov premennej s prístupovým tokenom, pridaného v GitLab ("Pripravujeme účty", p. 11). Samozrejme, vo formáte$variableName-StorePasswordInClearText— hack na obídenie chyby odmietnutia prístupu ()- Na prípade chýb môže byť užitočné pridať
-verbosity detailed
- Odosielame balík do zdroja:
nuget push -source -skipduplicate -apikey *.nupkg- Odosielame všetky balíky z aktuálneho adresára, preto
*.nupkg. name— z predchádzajúceho kroku.kľúč— akýkoľvek reťazec. V Azure DevOps v okne Pripojiť k feedu vždy uvádzajú ako príklad reťazecaz.-skipduplicate— pri pokuse o odoslanie už existujúceho balíka bez tohto kľúča zdroj vráti chybu409 Konflikt; s kľúčom bude odoslanie preskočené.
- Odosielame všetky balíky z aktuálneho adresára, preto
Teraz si nastavíme tvorbu dokumentácie:
- Na začiatok, v repozitári, v branche master, inicializujeme projekt docfx. Na to je potrebné v koreňovom adresári vykonať príkaz
docfx inita v interaktívnom režime zadáme kľúčové parametre pre zostavenie dokumentácie. Podrobné popisovanie minimálneho nastavenia projektu .- Pri nastavovaní je dôležité uviesť výstupný adresár
..public— GitLab predvolene berie obsah priečinka public v koreňovom repozitári ako zdroj pre Pages. Keďže projekt bude umiestnený vo vnorenej priečinke v repozitári — pridáme do cesty výstup na úroveň vyššie.
- Pri nastavovaní je dôležité uviesť výstupný adresár
- Odosielame zmeny do GitLab.
- Do konfigurácie pipeline pridáme úlohu
pages(zabrané slovo pre úlohy publikovania webových stránok v GitLab Pages):- Skript:
nuget install docfx.console -version 2.51.0— nainštaluje docfx; verzia je uvedená pre záruku správnosti ciest inštalácie balíka..docfx.console.2.51.0toolsdocfx.exe .docfx_projectdocfx.json— zostavujeme dokumentáciu
- Uzol artifacts:
- Skript:
pages:
# snip
artifacts:
paths:
- publicLyrické odbočenie o docfx
Skôr pri nastavovaní projektu som uvádzal zdroj kódu pre dokumentáciu ako súbor riešenia. Hlavná nevýhoda — dokumentácia sa vytvára aj pre testovacie projekty. V prípade, že to nie je potrebné, môžeme zadať takéto hodnotenie uzlu metadata.src:
{
"metadata": [
{
"src": [
{
"src": "..\/",
"files": [
"**\/*.csproj"
],
"exclude":[
"*.tests*\/**"
]
}
],
\/\/ --- snip ---
},
\/\/ --- snip ---
],
\/\/ --- snip ---
}metadata.src.src: "..\/"— vychádzame na úroveň vyššie vo vzťahu k umiestneniudocfx.json, pretože v vzorcoch nefunguje vyhľadávanie vyššie po strome adresárov.metadata.src.files: ["**\/*.csproj"]— globálny vzor, zhromažďujeme všetky projekty C# zo všetkých adresárov.metadata.src.exclude: ["*.tests*\/**"]— globálny vzor, vylučujeme všetko z priečinkov s.testsv názve
Medzi výsledkami
Takúto jednoduchú konfiguráciu môžeme zostaviť doslova za pol hodiny a pár šálok kávy, ktorá umožní pri každom požiadavku na zlúčenie a odosielanie do master kontrolovať, že kód sa zostavuje a testy prechádzajú, zhromažďovať nový balík, aktualizovať dokumentáciu a potešiť oko peknými odznakmi v README projektu.
Konečný .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:
- masterBy the way about badges
After all, that was the whole point!
Badges with pipeline statuses and code coverage are available in GitLab under CI/CD settings in the Gtntral pipelines block:

I created a badge with a link to the documentation on the platform — where everything is quite straightforward, you can create your own badge and retrieve it via a request.

Azure DevOps Artifacts also allows creating badges for packages indicating the current version. To do this, on the Azure DevOps website, click on Create badge for the selected package and copy the markdown markup:


Let's add some flair
Highlighting common configuration fragments
While writing the configuration and searching through the documentation, I stumbled upon an interesting YAML feature — reusing fragments.
As can be seen from the job settings, all of them require the presence of a tag windows on the runner, and trigger when pushed to master/creating a merge request (except for documentation). Let's add this to the fragment that we will reuse:
.common_tags: &common_tags
tags:
- windows
.common_only: &common_only
only:
- merge_requests
- masterAnd now we can insert the previously declared fragment in the job description:
build job:
<<: *common_tags
<<: *common_onlyThe names of the fragments should start with a dot to avoid being interpreted as a job.
Versioning of packages
Pri vytváraní balíka kompilátor skontroluje príkazové riadky a v prípade ich neprítomnosti súbory projektov; po nájdení uzla Version prevezme jeho hodnotu ako verziu zostavovaného balíka. Takže, aby sme zostavili balík s novou verziou, musíme buď aktualizovať ju v súbore projektu, alebo ju odovzdať ako argument príkazového riadku.
Pridáme ešte jednu požiadavku – nech sú dva posledné čísla vo verzii rokom a dňom zostavenia balíka a pridáme predverzové verzie. Tieto údaje môžeme samozrejme pridávať do súboru projektu a kontrolovať pred každým odoslaním – ale môžeme to robiť aj v pipeline, pozostávajúcej z kontextu a odovzdávať cez argument príkazového riadku.
Dohodneme sa, že ak v správe commit-u existuje riadok v tvare release (v. /ver. /version) (rev. /revision )?, budeme z tohto riadku brať verziu balíka, doplníme ju o aktuálny dátum a odovzdáme ako argument príkazu dotnet pack. V prípade neprítomnosti riadku – jednoducho nebudeme balík zostavovať.
Túto úlohu rieši nasledujúci skript:
# регулярное выражение для поиска строки с версией
$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=$versionPridáme skript do úlohy pack and deploy job a sledujeme zostavenie balíkov iba pri prítomnosti zadaného riadku v správe commit-u.
Spolu
Strávili sme asi pol hodiny až hodinu časom na písanie konfigurácie, ladenie v lokálnom PowerShell a možno niekoľko neúspešných spustení, dostali sme jednoduchú konfiguráciu na automatizáciu rutinných úloh.
Samozrejme, GitLab CI/CD je oveľa rozsiahlejší a viacvrstvový, než sa môže zdať po prečítaní tohoto sprievodcu – Navyše, , čo umožňuje
automaticky detekovať, zostavovať, testovať, nasadiť a monitorovať vaše aplikácie.
Teraz v plánoch – nakonfigurovať pipeline na nasadenie aplikácií v Azure, s použitím Pulumi a automatickým určovaním cieľového prostredia, čo bude podrobne opísané v ďalšom článku.
Zdroj: habr.com








