Albo jak zdobyć ładne odznaki dla swojego projektu w jeden wieczór odprężającego kodowania
Pewnie każdy programista mający przynajmniej jeden projekt pet, w pewnym momencie odczuwa potrzebę posiadania ładnych odznak ze statusami, pokryciem kodu, wersjami pakietów w nuget… I ta potrzeba skłoniła mnie do napisania tego artykułu. W trakcie przygotowań do jego napisania zyskałem taką piękność w jednym ze swoich projektów:

Artykuł ten omówi podstawową konfigurację ciągłej integracji i dostarczania dla projektu biblioteki klas w .Net Core w GitLab, z publikacją dokumentacji w GitLab Pages i wysyłką zbudowanych pakietów do prywatnego feedu w Azure DevOps.
Jako środowisko deweloperskie używano VS Code z rozszerzeniem (do walidacji pliku konfiguracyjnego bezpośrednio z środowiska deweloperskiego).
Krótkie wprowadzenie
CD — to kiedy właśnie wypchnąłeś, a u klienta już wszystko się posypało?
Czym jest CI/CD i po co jest — można łatwo wygooglować. Pełną dokumentację na temat konfiguracji pipeline'ów w GitLab znaleźć . Tutaj w skrócie i, o ile to możliwe, bez błędów opiszę proces działania systemu z wysokości ptasiego lotu:
- programista wysyła commit do repozytorium, tworzy merge request przez stronę lub w inny sposób jawnie lub niejawnie uruchamia pipeline,
- z konfiguracji wybierane są wszystkie zadania, których warunki pozwalają je uruchomić w danym kontekście,
- zadania są organizowane zgodnie z ich etapami,
- etapy są wykonywane kolejno — tzn. równolegle wszystkie zadania tego etapu są wykonywane,
- jeśli etap kończy się niepowodzeniem (tzn. kończy się niepowodzeniem przynajmniej jedno z zadań etapu) — pipeline zatrzymuje się (niemal zawsze),
- jeśli wszystkie etapy zakończą się pomyślnie, pipeline uważa się za zakończony z sukcesem.
W ten sposób otrzymujemy:
- pipeline — zestaw zadań zorganizowanych w etapy, w którym można kompilować, testować, pakować kod, wdrażać gotową wersję w chmurze, itd.,
- etap (stage) — jednostka organizacji pipeline'u, zawiera 1+ zadanie,
- zadanie (job) — jednostka pracy w pipeline'ie. Składa się ze skryptu (obowiązkowo), warunków uruchamiania, ustawień publikacji/cache'owania artefaktów i wielu innych elementów.
W związku z tym, zadanie podczas konfigurowania CI/CD polega na stworzeniu zestawu zadań realizujących wszystkie niezbędne działania do kompilacji, testowania i publikacji kodu oraz artefaktów.
Przed rozpoczęciem: dlaczego?
- Dlaczego GitLab?
Ponieważ gdy pojawiła się potrzeba stworzenia prywatnych repozytoriów dla projektów pobocznych, na GitHubie były płatne, a ja jestem oszczędny. Repozytoria stały się darmowe, ale do tej pory nie jest to dla mnie wystarczający powód, by przenosić się na GitHub.
- Dlaczego nie Azure DevOps Pipelines?
Ponieważ tam konfiguracja jest bardzo prosta — nie wymaga nawet znajomości wiersza poleceń. Integracja z zewnętrznymi dostawcami git — w kilka kliknięć, import kluczy SSH do wysyłania commitów do repozytorium — również, pipeline jest łatwy do skonfigurowania nawet bez szablonu.
Punkt startowy: co mamy i czego chcemy
Mamy:
- repozytorium w GitLab.
Chcemy:
- automatyczną kompilację i testowanie dla każdego merge request,
- kompilację paczek dla każdego merge request i pushu do mastera pod warunkiem, że w wiadomości commit znajduje się określony ciąg znaków,
- wysyłkę zbudowanych paczek do prywatnego feedu w Azure DevOps,
- kompilację dokumentacji i publikację w GitLab Pages,
- odznak!11
Opisane wymagania organicznie pasują do następującego modelu pipeline'u:
- Etap 1 — kompilacja
- Kompilujemy kod, publikujemy pliki wyjściowe jako artefakty
- Etap 2 — testowanie
- Pobieramy artefakty z etapu kompilacji, uruchamiamy testy, zbieramy dane z pokrycia kodu
- Etap 3 — wysyłka
- Zadanie 1 — tworzymy pakiet nuget i wysyłamy do Azure DevOps
- Zadanie 2 — tworzymy stronę z xmldoc w kodzie źródłowym i publikujemy w GitLab Pages
Zaczynamy!
Zbieramy konfigurację
Przygotowujemy konta
Tworzymy konto w
Przechodzimy do
Tworzymy nowy projekt
- Nazwa — dowolna
- Widoczność — dowolna

Po naciśnięciu przycisku Create projekt zostanie utworzony, a my przejdziemy do jego strony. Na tej stronie można wyłączyć niepotrzebne możliwości, przechodząc do ustawień projektu (dolny link w lewym menu -> Overview -> blok Azure DevOps Services)

Przechodzimy do Atrifacts, klikamy Create feed
- Wprowadzamy nazwę źródła
- Wybieramy widoczność
- Usuwamy zaznaczenie Include packages from common public sources, aby źródło nie stało się śmietnikiem klonów nuget

Klikamy Connect to feed, wybieramy Visual Studio, z bloku Machine Setup kopiujemy Source

Idziemy do ustawień konta, wybieramy Personal Access Token

Tworzymy nowy token dostępu
- Nazwa — dowolna
- Organizacja — bieżąca
- Okres ważności — maksymalnie 1 rok
- Zakres działania (scope) — Packaging/Read & Write

Kopiujemy utworzony token — po zamknięciu okna modalnego wartość będzie niedostępna
Wchodzimy w ustawienia repozytorium w GitLab, wybieramy ustawienia CI/CD

Rozwijamy blok Variables, dodajemy nową
- Nazwa — dowolna bez spacji (będzie dostępna w powłoce komend)
- Wartość — token dostępu z p. 9
- Wybieramy Mask variable

Na tym wstępna konfiguracja została zakończona.
Przygotowujemy szkielet konfiguracji
Domyślnie, do konfiguracji CI/CD w GitLab używany jest plik .gitlab-ci.yml z katalogu głównego repozytorium. Można skonfigurować dowolną ścieżkę do tego pliku w ustawieniach repozytorium, ale w tym przypadku nie jest to potrzebne.
Jak widać z rozszerzenia, plik zawiera konfigurację w formacie YAML. W dokumentacji szczegółowo opisano, jakie klucze mogą być zawarte na najwyższym poziomie konfiguracji oraz w każdych z poziomów zagnieżdżonych.
Najpierw dodamy w pliku konfiguracji link do obrazu docker, w którym będą wykonywane zadania. W tym celu znajdujemy . W jest szczegółowa instrukcja, który obraz wybrać do różnych zadań. Nam do budowy pasuje obraz z .Net Core 3.1, dlatego śmiało dodajemy jako pierwszą linię w konfiguracji
image: mcr.microsoft.com/dotnet/core/sdk:3.1Teraz przy uruchomieniu pipeline'u z repozytoriów obrazów Microsoft zostanie pobrany wskazany obraz, w którym będą wykonywane wszystkie zadania z konfiguracji.
Następny etap — dodać stageetapy. Domyślnie GitLab definiuje 5 etapów:
.pre— wykonywane przed wszystkimi etapami,.post— wykonywane po wszystkich etapach,build— pierwszy po.preetapie,test— drugi etap,deploy— trzeci etap.
Nic nie stoi na przeszkodzie, aby zadeklarować je wyraźnie. Kolejność, w jakiej są wskazane etapy, wpływa na kolejność ich wykonania. Dla pełności wywodu dodamy do konfiguracji:
stages:
- build
- test
- deployDla debuggowania ma sens uzyskanie informacji o środowisku, w którym wykonywane są zadania. Dodamy globalny zestaw komend, który będzie wykonywany przed każdą zadań, z pomocą before_script:
before_script:
- $PSVersionTable.PSVersion
- dotnet --version
- nuget help | select-string VersionPozostało dodać przynajmniej jedną zadań, aby podczas przesyłania commitów pipeline uruchomił się. Na razie dodajemy pustą zadanie dla demonstracji:
dummy job:
script:
- echo okRozpoczynamy walidację, otrzymujemy komunikat, że wszystko jest w porządku, zatwierdzamy, wypychamy i sprawdzamy wyniki na stronie… A otrzymujemy błąd skryptu — bash: .PSVersion: command not found. WTF?
Wszystko logiczne — domyślnie runner’y (odpowiedzialne za wykonanie skryptów zadań, dostarczane przez GitLab) używają bash do wykonywania poleceń. Możemy to naprawić, wyraźnie wskazując w opisie zadania, jakie tagi powinny mieć uruchamiające runner'y potoku:
dummy job on windows:
script:
- echo ok
tags:
- windowsŚwietnie! Teraz potok wykonuje się.
Uważny czytelnik, powtarzając wskazane kroki, zauważy, że zadanie wykonało się w etapie test, chociaż nie wskazywaliśmy etapu. Jak można się domyślić, test jest etapem domyślnym.
Kontynuujemy tworzenie szkieletu konfiguracji, dodając wszystkie zadania opisane wcześniej:
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: deployUzyskaliśmy niezbyt funkcjonalny, ale mimo to poprawny potok.
Konfiguracja wyzwalaczy
Z powodu braku filtrów uruchamiania dla żadnego z zadań, potok będzie w pełni wykonywany za każdym razem, gdy komitujemy w repozytorium. Ponieważ nie jest to pożądane zachowanie w ogólnym przypadku, skonfigurujemy filtry uruchamiania dla zadań.
Filtry mogą być konfigurowane w dwóch formatach: i . W skrócie, only/except pozwala na ustawienie filtrów dla wyzwalaczy (merge_request, na przykład — ustawia zadanie do wykonania przy każdym utworzeniu żądania o scalenie i przy każdym przesłaniu commitów do gałęzi, będącej źródłem w żądaniu o scalenie) oraz nazw gałęzi (w tym z wykorzystaniem wyrażeń regularnych); rules pozwala na ustawienie zestawu warunków i, opcjonalnie, zmianę warunku wykonania zadania w zależności od sukcesu wcześniejszych zadań ().
Przypomnijmy zestaw wymagań — budowa i testowanie tylko dla merge request, pakowanie i przesyłanie do Azure DevOps — dla merge request i pushów do mastera, generowanie dokumentacji — dla pushów do mastera.
Na początek skonfigurujmy zadanie budowy kodu, dodając regułę wyzwalania tylko przy merge request:
build job:
# snip
only:
- merge_requestTeraz skonfigurujmy zadanie pakowania, aby uruchamiało się przy merge request i dodaniu commitów do mastera:
pakiet i wdrożenie zadania:
# snip
tylko:
- merge_request
- masterJak widać, wszystko jest proste i bezpośrednie.
Można również skonfigurować zadanie, aby uruchamiało się tylko wtedy, gdy utworzono merge request z określoną gałęzią docelową lub źródłową:
reguły:
- jeśli: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"W warunkach można używać ; reguły rules nie są zgodne z regułami only/except.
Konfiguracja przechowywania artefaktów
Podczas wykonywania zadania zadania budowania tworzymy artefakty budowania, które można ponownie wykorzystać w następnych zadaniach. W tym celu należy dodać do konfiguracji zadania ścieżki i pliki, które należy zachować i ponownie wykorzystać w następnych zadaniach, w kluczu :
zadanie budowania:
# snip
artefakty:
ścieżki:
- path/to/build/artifacts
- another/path
- MyCoolLib.*/bin/Release/*Ścieżki obsługują znaki wieloznaczne, co zdecydowanie ułatwia ich określenie.
Jeśli zadanie tworzy artefakty, to każde następne zadanie będzie miało do nich dostęp — będą znajdować się w tych samych ścieżkach względem korzenia repozytorium, w których zostały zbudowane z oryginalnego zadania. Artefakty są również dostępne do pobrania na stronie internetowej.
Teraz, gdy mamy gotowy (i sprawdzony) szkielet konfiguracji, możemy przejść do pisania skryptów dla zadań.
Pisanie skryptów
Być może gdzieś, dawno temu, w odległej galaktyce, zbieranie projektów (w tym na .net) z linii poleceń było bolączką. Teraz jednak, skompilować, przetestować i opublikować projekt można za pomocą 3 poleceń:
dotnet build
dotnet test
dotnet packOczywiście są pewne szczegóły, przez które nieco utrudnimy te polecenia.
- Chcemy wydania, a nie kompilacji debugującej, dlatego do każdego polecenia dodajemy
-c Release - Podczas testów chcemy zbierać dane o pokryciu kodu, dlatego musimy podłączyć analizator pokrycia do bibliotek testowych:
- Do wszystkich bibliotek testowych należy dodać pakiet
coverlet.msbuild:dotnet add package coverlet.msbuildz folderu projektu - Do polecenia uruchamiającego testy dodamy
/p:CollectCoverage=true - W konfiguracji zadania testowego dodamy klucz do uzyskania wyników pokrycia (patrz poniżej)
- Do wszystkich bibliotek testowych należy dodać pakiet
- Podczas pakowania kodu w pakiety nuget określimy katalog wyjściowy dla pakietów:
-o .
Zbieramy dane o pokryciu kodu
Coverlet po uruchomieniu testów wyświetla w konsoli statystyki dotyczące uruchamiania:
Obliczanie wyniku pokrycia...
Generowanie raportu 'C:Usersxxxsourcereposmy-projectmyProject.testscoverage.json'
+-------------+--------+--------+--------+
| Moduł | Linia | Gałąź | Metoda |
+-------------+--------+--------+--------+
| projekt 1 | 83,24% | 66,66% | 92,1% |
+-------------+--------+--------+--------+
| projekt 2 | 87,5% | 50% | 100% |
+-------------+--------+--------+--------+
| projekt 3 | 100% | 83,33% | 100% |
+-------------+--------+--------+--------+
+---------+--------+--------+--------+
| | Linia | Gałąź | Metoda |
+---------+--------+--------+--------+
| Całkow | 84,27% | 65,76% | 92,94% |
+---------+--------+--------+--------+
| Średnia | 90,24% | 66,66% | 97,36% |
+---------+--------+--------+--------+GitLab pozwala na wskazanie wyrażenia regularnego do uzyskania statystyk, które następnie można otrzymać w postaci badge'a. Wyrażenie regularne określa się w ustawieniach zadania za pomocą klucza coverage; w wyrażeniu musi znajdować się grupa przechwytująca, której wartość zostanie przekazana do badge'a:
test i zadanie pokrycia:
# snip
pokrycie: \/|s*Sumy*|s*(d+[,.]d+%)\/Tutaj uzyskujemy statystyki z linii o całkowitym pokryciu.
Publikujemy pakiety i dokumentację
Oba działania mamy zaplanowane na ostatni etap pipeline'u — skoro budowa i testy się powiodły, można podzielić się z światem naszymi osiągnięciami.
Na początek rozważymy publikację w źródle pakietów:
Jeśli w projekcie nie ma pliku konfiguracyjnego nuget (
nuget.config), stworzymy nowy:dotnet new nugetconfigDlaczego: w obrazie może być zablokowany dostęp do globalnych (użytkownika i maszyny) konfiguracji. Aby uniknąć błędów, po prostu stwórzmy nową lokalną konfigurację i pracujmy z nią.
- Dodajemy do lokalnej konfiguracji nowe źródło pakietów:
nuget sources add -name <name> -source <url> -username <organization> -password <gitlab variable> -configfile nuget.config -StorePasswordInClearTextname— lokalna nazwa źródła, nie jest to kluczoweurl— URL źródła z etapu "Przygotowujemy konta", pkt 6organization— nazwa organizacji w Azure DevOpsgitlab variable— nazwa zmiennej z tokenem dostępu, dodana w GitLab ("Przygotowujemy konta", pkt 11). Oczywiście w formacie$variableName-StorePasswordInClearText— hack do obejścia błędu odmowy dostępu ()- Na wypadek błędów może być przydatne dodanie
-verbosity detailed
- Wysyłamy pakiet do źródła:
nuget push -source <name> -skipduplicate -apikey <key> *.nupkg- Wysyłamy wszystkie pakiety z bieżącego katalogu, więc
*.nupkg. name— z kroku powyżej.key— dowolny ciąg. W Azure DevOps w oknie Połącz z feedem zawsze jako przykład podawana jest liniaaz.-skipduplicate— podczas próby wysłania już istniejącego pakietu bez tego klucza źródło zwróci błąd409 Konflikt; z kluczem wysyłka zostanie pominięta.
- Wysyłamy wszystkie pakiety z bieżącego katalogu, więc
Teraz skonfigurujmy tworzenie dokumentacji:
- Na początku, w repozytorium, w gałęzi master, inicjujemy projekt docfx. W tym celu z katalogu głównego musimy wykonać polecenie
docfx initi w trybie interaktywnym ustawimy kluczowe parametry dla budowy dokumentacji. Szczegółowy opis minimalnej konfiguracji projektu .- Podczas konfiguracji ważne jest, aby podać katalog wyjściowy
..public— GitLab domyślnie traktuje zawartość folderu public w głównym katalogu repozytorium jako źródło dla Pages. Ponieważ projekt będzie się znajdować w podkatalogu repozytorium — dodajemy do ścieżki wyjście na poziom wyżej.
- Podczas konfiguracji ważne jest, aby podać katalog wyjściowy
- Wyślemy zmiany do GitLab.
- Do konfiguracji pipeline'a dodajemy zadanie
pages(zarezerwowane słowo dla zadań publikacji stron w GitLab Pages):- Skrypt:
nuget install docfx.console -version 2.51.0— zainstaluje docfx; wersja podana dla pewności poprawności ścieżek instalacji pakietu..docfx.console.2.51.0toolsdocfx.exe .docfx_projectdocfx.json— zbieramy dokumentację
- Węzeł artifacts:
- Skrypt:
pages:
# snip
artifacts:
paths:
- publicLiryczne odstepienie o docfx
Kiedyś podczas konfigurowania projektu wskazywałem źródło kodu do dokumentacji jako plik rozwiązania. Główny minus — dokumentacja tworzona jest również dla projektów testowych. Jeżeli nie jest to konieczne, można ustawić takie wartości dla węzła metadata.src:
{
"metadata": [
{
"src": [
{
"src": "..\/",
"files": [
"**\/*.csproj"
],
"exclude":[
"*.tests*\/**"
]
}
],
\/\/ --- snip ---
},
\/\/ --- snip ---
],
\/\/ --- snip ---
}metadata.src.src: "..\/"— wychodzimy na poziom wyżej względem lokalizacjidocfx.json, ponieważ w wzorcach nie działa wyszukiwanie w górę po drzewie katalogów.metadata.src.files: ["**\/*.csproj"]— globalny wzorzec, zbieramy wszystkie projekty C# ze wszystkich katalogów.metadata.src.exclude: ["*.tests*\/**"]— globalny wzorzec, wykluczamy wszystko z folderów z.testsw nazwie
Pośredni wynik
Taką prostą konfigurację można stworzyć dosłownie w ciągu pół godziny i dwóch filiżanek kawy, która pozwoli przy każdym żądaniu scalania i wysyłania do master sprawdzić, czy kod się kompiluje, a testy przechodzą, zbierać nowy pakiet, aktualizować dokumentację i cieszyć oko pięknymi odznakami w README projektu.
Końcowy .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:
- masterA propos odznaków
Dzięki nim wszystko się zaczęło!
Odznaki ze statusami potoków i pokrycia kodu są dostępne w GitLab w ustawieniach CI/CD w bloku Gtntral pipelines:

Odznakę z linkiem do dokumentacji stworzyłem na platformie — tam wszystko jest dość proste, można stworzyć własny odznak i uzyskać go za pomocą zapytania.

Azure DevOps Artifacts również pozwala na tworzenie odznak dla pakietów z podaniem aktualnej wersji. W tym celu należy na stronie Azure DevOps kliknąć na Create badge dla wybranego pakietu i skopiować znacznik markdown:


Dodajemy estetykę
Wydobywamy wspólne fragmenty konfiguracji
Podczas pisania konfiguracji i przeszukiwania dokumentacji natknąłem się na interesującą możliwość YAML — ponowne wykorzystanie fragmentów.
Jak widać z ustawień zadań, wszystkie wymagają obecności tagu windows u runnera i są uruchamiane przy wysyłaniu do master/tylko po utworzeniu żądania o połączenie (z wyjątkiem dokumentacji). Dodajmy to do fragmentu, który będziemy ponownie wykorzystywać:
.common_tags: &common_tags
tags:
- windows
.common_only: &common_only
only:
- merge_requests
- masterA teraz w opisie zadania możemy wstawić wcześniej zadeklarowany fragment:
build job:
<<: *common_tags
<<: *common_onlyNazwy fragmentów muszą zaczynać się od kropki, aby nie były interpretowane jako zadanie.
Wersjonowanie pakietów
Podczas tworzenia pakietu kompilator sprawdza klucze linii poleceń, a w ich braku pliki projektów; znajdując węzeł Version, przyjmuje jego wartość jako wersję budowanego pakietu. Aby zbudować pakiet z nową wersją, należy zaktualizować ją w pliku projektu lub przekazać jako argument linii poleceń.
Dodamy jeszcze jedną funkcjonalność — niech dwa ostatnie numery w wersji będą rokiem i datą budowy pakietu, oraz dodamy wersje w fazie pre-releasu. Oczywiście można wprowadzać te dane do pliku projektu i sprawdzać przed każdym wysłaniem — ale można to zrobić także w pipeline, budując wersję pakietu z kontekstu i przekazując przez argument linii poleceń.
Umówmy się, że jeśli w wiadomości commit znajduje się ciąg o postaci release (v.\/ver.\/version) <numer wersji> (rev.\/rewizja <rewizja>)?, to z tego ciągu będziemy pobierać wersję pakietu, uzupełniać ją aktualną datą i przekazywać jako argument polecenia dotnet pack. W przypadku braku ciągu — po prostu nie będziemy budować pakietu.
Tego zadania podejmuje się następujący skrypt:
# регулярное выражение для поиска строки с версией
$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=$versionDodajemy skrypt do zadania pack and deploy job i obserwujemy, jak pakiety są budowane jedynie przy spełnieniu warunku istnienia podanego ciągu w wiadomości commit.
Podsumowując
Poświęcając około pół godziny do godziny na napisanie konfiguracji, debugowanie w lokalnym PowerShell oraz być może kilka nieudanych uruchomień, otrzymaliśmy prostą konfigurację do automatyzacji rutynowych zadań.
Oczywiście, GitLab CI/CD jest znacznie bardziej rozbudowane i złożone, niż może się wydawać po przeczytaniu tego przewodnika — . Tam nawet , umożliwiający
automatyczne wykrywanie, budowanie, testowanie, wdrażanie i monitorowanie aplikacji
Teraz planujemy skonfigurować pipeline do wdrażania aplikacji w Azure, używając Pulumi i automatycznego wykrywania środowiska docelowego, co zostanie omówione w następnym artykule.
Źródło: habr.com








