Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

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:

Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

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 GitLab Workflow (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źć też nie jest trudno. 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

  1. Tworzymy konto w Microsoft Azure

  2. Przechodzimy do Azure DevOps

  3. Tworzymy nowy projekt

    1. Nazwa — dowolna
    2. Widoczność — dowolna
      Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

  4. 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)
    Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

  5. Przechodzimy do Atrifacts, klikamy Create feed

    1. Wprowadzamy nazwę źródła
    2. Wybieramy widoczność
    3. Usuwamy zaznaczenie Include packages from common public sources, aby źródło nie stało się śmietnikiem klonów nuget
      Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

  6. Klikamy Connect to feed, wybieramy Visual Studio, z bloku Machine Setup kopiujemy Source
    Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

  7. Idziemy do ustawień konta, wybieramy Personal Access Token
    Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

  8. Tworzymy nowy token dostępu

    1. Nazwa — dowolna
    2. Organizacja — bieżąca
    3. Okres ważności — maksymalnie 1 rok
    4. Zakres działania (scope) — Packaging/Read & Write
      Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

  9. Kopiujemy utworzony token — po zamknięciu okna modalnego wartość będzie niedostępna

  10. Wchodzimy w ustawienia repozytorium w GitLab, wybieramy ustawienia CI/CD
    Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

  11. Rozwijamy blok Variables, dodajemy nową

    1. Nazwa — dowolna bez spacji (będzie dostępna w powłoce komend)
    2. Wartość — token dostępu z p. 9
    3. Wybieramy Mask variable
      Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

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 stronę obrazów .Net Core w Docker Hub. W GitHub 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.1

Teraz 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 .pre etapie,
  • 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
  - deploy

Dla 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 Version

Pozostał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 ok

Rozpoczynamy 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: deploy

Uzyskaliś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: only/except i rules. 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ń (when w GitLab CI/CD).

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_request

Teraz 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
    - master

Jak 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ć wymienionych tutaj zmiennych; 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 artefakty:

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 pack

Oczywiście są pewne szczegóły, przez które nieco utrudnimy te polecenia.

  1. Chcemy wydania, a nie kompilacji debugującej, dlatego do każdego polecenia dodajemy -c Release
  2. Podczas testów chcemy zbierać dane o pokryciu kodu, dlatego musimy podłączyć analizator pokrycia do bibliotek testowych:
    1. Do wszystkich bibliotek testowych należy dodać pakiet coverlet.msbuild: dotnet add package coverlet.msbuild z folderu projektu
    2. Do polecenia uruchamiającego testy dodamy /p:CollectCoverage=true
    3. W konfiguracji zadania testowego dodamy klucz do uzyskania wyników pokrycia (patrz poniżej)
  3. 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:

  1. Jeśli w projekcie nie ma pliku konfiguracyjnego nuget (nuget.config), stworzymy nowy: dotnet new nugetconfig

    Dlaczego: 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ą.

  2. 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 -StorePasswordInClearText
    1. name — lokalna nazwa źródła, nie jest to kluczowe
    2. url — URL źródła z etapu "Przygotowujemy konta", pkt 6
    3. organization — nazwa organizacji w Azure DevOps
    4. gitlab variable — nazwa zmiennej z tokenem dostępu, dodana w GitLab ("Przygotowujemy konta", pkt 11). Oczywiście w formacie $variableName
    5. -StorePasswordInClearText — hack do obejścia błędu odmowy dostępu (nie ja pierwszy na te pułapki wpadłem)
    6. Na wypadek błędów może być przydatne dodanie -verbosity detailed
  3. Wysyłamy pakiet do źródła: nuget push -source <name> -skipduplicate -apikey <key> *.nupkg
    1. Wysyłamy wszystkie pakiety z bieżącego katalogu, więc *.nupkg.
    2. name — z kroku powyżej.
    3. key — dowolny ciąg. W Azure DevOps w oknie Połącz z feedem zawsze jako przykład podawana jest linia az.
    4. -skipduplicate — podczas próby wysłania już istniejącego pakietu bez tego klucza źródło zwróci błąd 409 Konflikt; z kluczem wysyłka zostanie pominięta.

Teraz skonfigurujmy tworzenie dokumentacji:

  1. Na początku, w repozytorium, w gałęzi master, inicjujemy projekt docfx. W tym celu z katalogu głównego musimy wykonać polecenie docfx init i w trybie interaktywnym ustawimy kluczowe parametry dla budowy dokumentacji. Szczegółowy opis minimalnej konfiguracji projektu tutaj.
    1. 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.
  2. Wyślemy zmiany do GitLab.
  3. Do konfiguracji pipeline'a dodajemy zadanie pages (zarezerwowane słowo dla zadań publikacji stron w GitLab Pages):
    1. Skrypt:
      1. nuget install docfx.console -version 2.51.0 — zainstaluje docfx; wersja podana dla pewności poprawności ścieżek instalacji pakietu.
      2. .docfx.console.2.51.0toolsdocfx.exe .docfx_projectdocfx.json — zbieramy dokumentację
    2. Węzeł artifacts:

pages:
  # snip
  artifacts:
    paths:
      - public

Liryczne 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 ---
}

  1. metadata.src.src: "..\/" — wychodzimy na poziom wyżej względem lokalizacji docfx.json, ponieważ w wzorcach nie działa wyszukiwanie w górę po drzewie katalogów.
  2. metadata.src.files: ["**\/*.csproj"] — globalny wzorzec, zbieramy wszystkie projekty C# ze wszystkich katalogów.
  3. metadata.src.exclude: ["*.tests*\/**"] — globalny wzorzec, wykluczamy wszystko z folderów z .tests w 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:
    - master

A 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:

Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

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

![Przykład z Shields.io](https://img.shields.io/badge/custom-badge-blue)

Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

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:

Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

Przewodnik po CI/CD w GitLab dla (prawie) absolutnych nowicjuszy

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
    - master

A teraz w opisie zadania możemy wstawić wcześniej zadeklarowany fragment:

build job:
  <<: *common_tags
  <<: *common_only

Nazwy 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=$version

Dodajemy 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 — to zdecydowanie nieprawda. Tam nawet Auto DevOps jest, 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

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster