Jak wygląda proces dostarczania oprogramowania oparty na CI/CD? 

Mateusz Mirecki | Rozwój oprogramowania | 27.05.2024

Główna korzyść z CI to wczesne wykrywanie błędów, co prowadzi do szybszego wdrażania nowych funkcji, większej stabilności oprogramowania i lepszej współpracy między programistami.

Aby zobrazować, jak CI działa w praktyce, można posłużyć się przykładem: kod źródłowy aplikacji został zmieniony, ponieważ powstała nowa funkcjonalność. Praca rozpoczyna się od utworzenia kopii głównego repozytorium kodu. System kontroli wersji przechowuje kod źródłowy w repozytorium. Aktualny stan aplikacji jest zwykle przechowywany w głównej gałęzi repozytorium (zwanej także jako „master”). Programista, zaczynając pracę nad nową funkcjonalnością, tworzy lokalnie kopię głównego repozytorium, która staje się bazą do stworzenia nowej funkcjonalności (a więc dokonania zmian w kodzie źródłowym).   

Automatyzacja i testowanie

Zmiany nie będą dotyczyły tylko kodu samej aplikacji, ale też testów (tworzenie testów jednostkowych nowej funkcjonalności). Jednym z kluczowych atrybutów ciągłej integracji jest wysoki stopień wykorzystania zautomatyzowanych testów. Po zakończeniu wprowadzania zmian na lokalnym komputerze wykonywany jest zautomatyzowany proces kompilacji (build). W procesie tym pobierany jest kod źródłowy z lokalnego repozytorium, który jest następnie kompilowany, łączony z plikiem wykonywalnym, a na końcu przeprowadzane są testy automatyczne. Build uznaje się za prawidłowy, gdy kompilacja oraz testy zakończą się poprawnie, bez błędów.  

Integracja i aktualizacja 

Następnym krokiem jest zatwierdzenie zmian w repozytorium. Na tym etapie należy uwzględnić zmiany wprowadzone przez innych członków w zespole, ponieważ w międzyczasie zmiany innego programisty mogły zostać już zintegrowane z głównym repozytorium tworzonego oprogramowania. Należy więc najpierw zaktualizować lokalną gałąź z kodem z głównej gałęzi (master) i ponownie uruchomić zautomatyzowaną kompilację (build). Jeżeli w trakcie tego procesu pojawią się konflikty (zmiany w kodzie kolidujące ze zmianami wprowadzonymi przez innych programistów), należy je rozwiązać i ponownie uruchomić kompilację. Gdy zakończy się ona powodzeniem, zmiany można zatwierdzić i zintegrować z głównym repozytorium. 

W tym momencie wykonywana jest ponowna kompilacja, lecz tym razem jest ona przeprowadzana na serwerze integracyjnym. Zdarza się, że podczas kompilacji na lokalnej stacji roboczej coś może zostać przeoczone, przez co główne repozytorium zostanie zaktualizowane w nieodpowiedni sposób. Dopiero gdy zmiany w głównym repozytorium zbudują się poprawnie na serwerze CI, można je będzie uznać za zakończone sukcesem. 

Jeśli dojdzie do konfliktów w plikach zmienionych przez innych programistów, zwykle będą one wychwycone, gdy programista zatwierdzający zmiany utworzy zaktualizowaną kopię roboczą, a sama kompilacja zakończy się niepowodzeniem. Błąd jest szybko wyłapany, a zadaniem programistów jest zlokalizowanie źródła błędów i naprawienie ich. W środowisku CI należy unikać sytuacji, w których przez dłuższy czas kompilacje integracyjne kończą się błędem – trzeba je naprawić najszybciej, jak to możliwe. 

Po pomyślnej kompilacji na serwerze ciągłej integracji nowe zmiany można wprowadzić na przykład na środowiska testowe, gdzie testerzy będą mogli przeprowadzać testy na aktualnej wersji oprogramowania zawierającej najnowsze zmiany. 

Zarządzanie błędami i powiadomienia 

Na każdym etapie procesu ciągłej integracji po stronie serwera, w razie niepowodzenia w budowaniu projektu, można zaimplementować narzędzia raportujące błędy. W ten sposób, w przypadku wystąpienia błędu w którymś kroku kompilacji – odpowiedni użytkownicy mogą zostać powiadomieni, na przykład za pomocą wiadomości e-mail lub powiadomienia na firmowym czacie. 

Przykładowy ogólny schemat procesu ciągłej integracji: 

blog 2024.05.16 graphic 2 - Jak wygląda proces dostarczania oprogramowania oparty na CI/CD? 

Praktyka DevOps 

Termin DevOps pochodzi z połączenia dwóch słów: development i operations (programowanie i operacje). Służy do określenia podejścia do rozwoju oprogramowania zakładającego zmniejszanie barier pomiędzy zespołami deweloperskimi i operacyjnymi firmy. Celem DevOps jest skrócenie czasu wprowadzenia produktu na rynek. Oznacza to przyjęcie i wdrożenie pewnych praktyk w celu skrócenia czasu od identyfikacji nowego wymagania do momentu jego wdrożenia dla klientów. W podejściu tym wykorzystywana jest omawiana ciągła integracja i ciągłe dostarczanie, które pomagają skrócić czas wprowadzenia produktu na rynek i stworzyć oprogramowanie lepszej jakości. 

Historia i rozwój  

Celem DevOps jest skrócenie czasu wprowadzenia produktu na rynek. Filozofia DevOps narodziła się w 2008 roku podczas konferencji Agile w Toronto, kiedy  Patrick Debois wygłosił wykład pod tytułem „Infrastructure and Operations“. Wyjaśnił w nim zastosowanie podejścia Agile do budowy infrastruktury, a na koniec zaproponował lepszą metodę komunikacji oraz pomysły, dzięki którym programiści mogliby „ poszerzać swoje horyzonty”, w sensie pogłębiania wiedzy systemowej niezbędnej do zapewnienia płynniejszego procesu wydawania oprogramowania. Mijały lata, a podejście DevOps stawało się coraz bardziej popularne, a w ślad za nim pojawiła się nowa rola w świecie IT – inżynier DevOps.  

Rola inżyniera DevOps 

Inżynier DevOps stanowi swego rodzaju pomost pomiędzy programistami a działem operacyjnym. W większości przypadków rola, jaką przyjmuje, jest ich mieszanką (inżynierowie ci muszą posiadać wiedzę niezbędną do doradzania i zarządzania problemem z obu dyscyplin). W niektórych przypadkach odpowiedzialność inżyniera DevOps związana jest z ciągłą integracją i dostarczaniem. Inne obowiązki obejmują zarządzanie infrastrukturą, zazwyczaj w postaci kodu (IaC) oraz pomoc we wdrażaniu optymalnych praktyk DevOps w całej firmie. Czasem inżyniera DevOps postrzega się go także jako osobę odpowiedzialną głównie za utrzymanie oprogramowania w środowisku produkcyjnym i automatyzację procesów, rozwiązywanie problemów, administrowanie systemem.  Rola inżyniera DevOps jest zróżnicowana i może zmieniać się w zależności od firmy. 

Zalety podejścia DevOps

Efektywność i współpraca 

Zespoły, które wdrażają podejście DevOps, stają się bardziej wydajne, dzięki czemu tworzone oprogramowanie wydawane jest nie tylko szybciej, ale też jest bardziej stabilne. Lepsza współpraca i zwiększona produktywność pozwalają też osiągać cele biznesowe, takie jak szybsze wprowadzenie produktu na rynek czy utrzymanie jego niezawodności i stabilności w każdych warunkach. Zastosowanie metodyki DevOps nie tylko pozwala zautomatyzować i optymalizować procesy za pomocą technologii. Jest to przede wszystkim zmiana kultury wewnątrz organizacji i ludzi zaangażowanych w ten proces.  

Wdrożenie kultury DevOps wymaga głębokich zmian w dotychczasowym sposobie pracy zespołów i przestrzegania określonych zasad, jednak te zmiany pozwalają stworzyć środowisko pracy o wysokiej wydajności.   Cechą charakterystyczną DevOps jest ścisła współpraca między zespołami. Różne zespoły, na przykład zespoły deweloperów i odpowiedzialne za operacje, muszą dzielić się swoimi procesami, priorytetami i problemami. Muszą także wspólnie planować pracę oraz cele i środki związane z ich osiągnięciem. W miarę jak zespoły dostosowują się do nowej rzeczywistości, obowiązki w poszczególnych rolach również zaczynają się poszerzać. Na przykład deweloperzy stają się odpowiedzialni nie tylko za tworzenie aplikacji w fazie programowania, ale też za wydajność i stabilność w fazie działania. Jednocześnie zespół operacji uwzględnia nadzór, zabezpieczenia i zgodność w fazach planowania i programowania.  

Elastyczność i reaktywność 

Elastyczność zespołów pozwala na wydawanie oprogramowania w krótszych cyklach. Łatwiej jest planować wdrażanie zmian i zarządzać ryzykiem – to droga do stworzenia stabilnego produktu. Krótsze cykle wydawania nowych wersji pozwalają także sprawniej reagować na zmiany zachodzące na rynku, dzięki czemu można szybciej dostosować się do zmian potrzeb klientów i nie odstawać od konkurencji. Podejście DevOps stanowi state-of-the-art nowoczesnego tworzenia oprogramowania i jest dziś pierwszym wyborem wielu firm z tego powodu, że promuje najlepsze praktyki niezbędne do poprawy jakości oprogramowania. DevOps wymaga zmiany nie tylko w sposobie myślenia o infrastrukturze, ale także w  zakresie dobrego projektowania i organizowania wewnętrznej infrastruktury firmy.   

Ciągłe testowanie 

Ciągłe testowanie (Continuous Testing, CT) to umiejętne wykorzystanie pewnych narzędzi i technik. Cytując sylabus ISTQB, ciągłe testowanie to:  

„Podejście obejmujące proces wczesnego, częstego, szerokiego, automatycznego testowania w celu otrzymania możliwie szybko informacji zwrotnej o poziomie ryzyka biznesowego związanego z aplikacją przed jej wydaniem”.  

Podejście to znacznie skraca czas potrzebny do wykonania testów manualnych. 

Głównym celem wprowadzenia podejścia CI/CD jest poprawa jakości wydawanego oprogramowania, a ciągłe testowanie i kontrola powinny być częścią tego procesu.  Celem ciągłego testowania jest zapewnienie, że wydawane oprogramowanie będzie niezawodne.  W tym celu tworzy się różnego rodzaju testy, które mogą być wykonywane automatycznie za każdym razem, gdy oprogramowanie jest budowane. 

Poziomy testów w ciągłym testowaniu 

blog 2024.05.16 graphic 3 - Jak wygląda proces dostarczania oprogramowania oparty na CI/CD? 
  1. Testy jednostkowe – bazę testów automatycznych stanowią testy jednostkowe. Są one wykonywane za każdym razem, gdy oprogramowanie jest kompilowane i budowane.  
  1. Testy integracyjne – kolejnym poziomem testów, który należy włączyć, są testy integracyjne. Są one przeprowadzane po testach jednostkowych i wykorzystują rzeczywiste dane. Testy integracyjne są ważną fazą w ciągłym testowaniu, ponieważ odpowiadają za testowanie całego systemu, a nie tylko tworzonego kodu.  
  1. Testy akceptacyjne (E2E) – ostatnią fazą są testy akceptacyjne. W tej fazie wykonywane są testy przygotowane przez zespół QA w celu przetestowania systemu z punktu widzenia użytkownika. Celem tej fazy jest weryfikacja wymagań użytkownika i ich walidacja. 

Kontrola kodu 

Oprócz różnych faz testowania, istnieje także faza kontroli kodu. Polega ona na sprawdzeniu kodu przy wykorzystaniu zestawu reguł wykorzystywanych do sporządzenia raportu na temat samego oprogramowania. Można ją podzielić na dwie fazy:  

  1. Przegląd kodu wykonywany przez programistę, który nie jest  jego autorem. Przed integracją z główną gałęzią (master) kod musi zostać zatwierdzony. Członkowie zespołu sprawdzają kod i dodają komentarze, jeśli jakieś fragmenty wymagają zmian. W tym przypadku autor kodu dokonuje zmian na ich podstawie, a po skończonej pracy kod ponownie trafia do przeglądu. Jeśli nikt nie będzie miał zastrzeżeń – kod zostanie zaakceptowany i scalony z główną gałęzią. 
  2. Faza statycznej analizy jest wykonywana przez odpowiednie narzędzia. Kod może zostać wtedy zweryfikowany przez pewne reguły, na przykład sprawdzające złożoność metod.  

Automatyzacja i shift-left testing 

Ciągłe testowanie wykorzystuje podejścia automatyzacji do przyspieszenia testowania poprzez przyjęcie podejścia shift-left testing, które łączy etapy wytwarzania oprogramowania i zapewniania jakości. Takie podejście może obejmować zestaw przepływów pracy testów automatycznych, które można łączyć z narzędziami raportującymi i metrykami w celu otrzymania jasnego obrazu jakości oprogramowania. 

Zapewnia to zespołom projektowym otrzymanie szybkiej informacji zwrotnej na temat jakości oprogramowania. Pozwala również testować na wcześniejszych etapach wytwarzania oprogramowania oraz zwiększyć pokrycie testami, eliminując wąskie gardła testowe, takie jak: dostęp do współdzielonych środowisk testowych czy oczekiwanie na stabilny interfejs użytkownika. 

Ciągłe testowanie niesie ze sobą szereg korzyści, takich jak: 

  • Integrowanie zespołów testowych, deweloperskich i operacyjnych na każdym etapie cyklu życia oprogramowania. 
  • Pozwala na wdrożenie testów automatycznych w takim zakresie, jak to tylko możliwe, aby stale testować kluczowe funkcje. 
  • Szybkie i ciągłe informacje zwrotne, które są istotne również dla biznesu. 
  • Usunięcie wąskich gardeł w kwestii dostępności środowisk testowych, które mogą być stale dostępne. 
  • Pozwala na stałe i aktywne zarządzanie jakością w całym etapie dostarczania oprogramowania.  

Fundamenty ciągłego testowania 

Ciągłe testowanie opiera się na kombinacji określonych narzędzi i technik. Odpowiednie ich wdrożenie tworzy system, dzięki któremu znacząco można ograniczyć liczbę błędów przedostających się na środowiska rozwojowe lub produkcyjne. Większość błędów ma bardzo krótką żywotność, ponieważ są one wyłapywane przez testy. Odpowiednie zaimplementowanie tego podejścia powinno rozpoczynać się na jak najwcześniejszym etapie cyklu życia oprogramowania, aby móc je odpowiednio budować, aktualizować i (w razie potrzeby) refaktoryzować. Sama budowa i działanie zależą w głównej mierze od potrzeb projektowych – inne testy i techniki będą wykorzystywane do testowania sklepu internetowego, inne do testowania systemów w branży automotive. Lecz niezależnie od przypadku, cel pozostanie ten sam – uzyskanie jak najszybciej informacji zwrotnej w przypadku wystąpienia błędu. 

Projektowanie małych komponentów i usług 

Idea ciągłego testowania polega na maksymalnym zautomatyzowaniu procesów testowania i wdrażania oraz zapewnieniu, że każdy komponent aplikacji może zostać poddany testom, gdy tylko zostanie opracowany. Przykłady, które mogą ułatwić implementację tego podejścia to: projektowanie małych komponentów i usług oraz projektowanie danych testowych wykorzystywanych w ciągłym testowaniu. 

Projektowanie małych komponentów i usług – nowe komponenty powinny nie tylko spełniać określone funkcje w trakcie działania programu, ale również być w pełni testowalne niezależnie od innych komponentów. Celem jest zapewnienie, że każda w pełni przetestowana usługa będzie spełniała swoje zadania zgodnie z założeniami, aby w trakcie ich łączenia i przejścia do etapu testów integracyjnych komponenty bezproblemowo współpracowały ze sobą.. Należy więc już na etapie projektowania odpowiednio przygotować architekturę i ograniczyć sprzężenie komponentów tak bardzo, jak to możliwe. W efekcie zyskamy komponenty bardziej stabilne, które zmniejsza ryzyko, że jakakolwiek zmiana dokonana w komponencie „A” spowoduje nieoczekiwaną zmianę zachowania w innych komponentach. Ograniczenie połączeń między nimi upraszcza proces testowania, rozwiązywania problemów oraz konserwacji. Dodatkowo w łatwiejszy sposób można izolować ewentualne problemy – analizie zostanie poddany konkretny komponent, bez potrzeby przeszukiwania ich grup i zależności między nimi. 

Projektowanie danych testowych wykorzystywanych w ciągłym testowaniu 

Posiadanie w pełni zautomatyzowanego rozwiązania do zarządzania danymi testowymi jest niezbędne do solidnego wdrożenia ciągłego testowania. Złym podejściem byłoby na przykład kopiowanie produkcyjnej bazy danych w celu utworzenia danych testowych, nie anonimizując uprzednio wrażliwych danych. Tworzenie nowych zestawów danych testowych od zera dla każdej serii testów również nie jest dobrym pomysłem ze względu na bardzo słabą efektywność, zwłaszcza gdy nie są generowane automatycznie. 

Jak zatem stworzyć skuteczne rozwiązania do generowania i zarządzania danymi testowymi? Z pomocą przychodzą pewne charakterystyki, do których można zaliczyć na przykład: 

  • Tworzenie i generowanie danych testowych 
    Daje możliwość tworzenia nowych, zbiorczych zestawów danych uwzględniających zależności, tak jakby pochodziły ze środowiska produkcyjnego. 
  • Możliwość pobrania pewnego podzbioru danych produkcyjnych 
    Na podstawie określonych kryteriów, maskowania wrażliwych pól i umieszczania ich w środowisku testowym, zachowując ich integralność referencyjną. Najtrudniejsza w realizacji jest ostatnia część: wrażliwe pola muszą być zamaskowane w taki sposób, aby zachować oryginalne powiązania między danymi. Przykładowo, jeśli wartość numeru PESEL musi zostać zamaskowana i zastąpiona niepowiązaną wartością, każde odwołanie do tego numeru PESEL w bazie danych musi zostać zamaskowane tą samą wartością. 
  • Możliwość maskowania i transformacji danych 
    Rozwiązanie powinno też zapewnić możliwość automatycznego porównania danych wstępnie zamaskowanych, aby upewnić się, że nie doszło do ich utraty i że proces maskowania nie spowodował błędów w ich integralności. 
  • Możliwość przesyłania danych 
    Proces polegający na przesyłaniu wyodrębnionych, zamaskowanych danych na środowiska testowe, z zachowaniem integralności. Proces ten powinien obejmować funkcje dodawania, edytowania, aktualizacji i usuwania. 
  • Możliwość odświeżania danych 
    Polega na okresowym przeglądzie i usuwaniu starych pakietów danych testowych oraz zamienianiu ich na nowy zestaw. 
  • Ekstrakcja danych i tworzenie ich podzbiorów 
    Pozwala na tworzenie mniejszych kopii danych produkcyjnych zdefiniowanych za pomocą określonych kryteriów. 
  • „Postarzanie” danych 
    Technika, w której dane są zmieniane w celu dopasowania ich do określonych, specyficznych warunków i wykorzystania ich w pewnych procesach (na przykład symulacji określonej godziny lub daty). 
  • Możliwość tworzenia i wyodrębniania danych testowych 
  • Zarządzanie zbiorami danych 
  • Wykorzystanie narzędzi, które umożliwiają nie tylko zarządzanie wieloma zbiorami danych, ale także ich archiwizację i wersjonowanie.  

Rola testów jednostkowych w ciągłym testowaniu 

Podstawę testów w podejściu ciągłego testowania, zgodnie z piramidą testów, stanowią testy jednostkowe. Są one najszybsze w wykonaniu i sprawdzają działanie oprogramowania we wczesnej fazie jego wytwarzania. Powinno ich więc być jak najwięcej (przy zachowaniu odpowiedniego stosunku liczby do jakości – nie jest prawdą, że większa liczba testów stanowi o jakości).  

Projektowanie testów jednostkowych 

Zdarza się, że testy jednostkowe są źle zaprojektowane i zamiast jednostek testują kompletne przypadki użycia (wywołanie metod, asercje, wywołanie większej liczby metod i tworzenie większej liczby asercji). Takie testy są zwykle niestabilne, a błędy wykryte w jednej części kodu mogą maskować inne błędy i utrudniać ich wykrycie. Aby temu zapobiec, należy przeanalizować takie testy, wyodrębnić z nich poszczególne, testowane funkcjonalności i asercje i rozbić je na mniejsze testy sprawdzające każdą funkcjonalność z osobna. 

Implementacja testów na różnych poziomach 

Testowanie bardziej złożonych ścieżek, dajmy na to przypadków użycia, powinno zostać zaimplementowane na przykład w testach akceptacyjnych. W ciągłym testowaniu można wykonywać wszystkie rodzaje testów, lecz im wyższy poziom testów, tym liczba przypadków testowych powinna być mniejsza (są one mniej stabilne, czas ich wykonywania jest dłuższy, wykrywają błędy w późniejszych etapach, przez co wydłuża się czas naprawy, a koszt rośnie). 

Dotyczy to zwłaszcza testów UI (User Interface), gdy testowana jest logika biznesowa i zachowanie interfejsu użytkownika. Może tu dojść do wielu współzależnych awarii. Oddzielenie warstwy interfejsu od systemu bazowego, aby logika biznesowa mogła zostać opatrzona zaślepkami (mock) jest istotną zmianą zbliżającą nas do większej stabilności testów. 

Jednym z podejść jest uruchamianie testów jednostkowych w sposób ciągły, a testów wyższych poziomów – na żądanie (nie muszą one być uruchamiane automatycznie w trakcie budowy projektu w narzędziu ciągłej integracji – zamiast tego, istnieje możliwość uruchomienia ich w sposób manualny, gdy potrzeba). 

Rola podejścia TDD 

Praktykowanie podejścia TDD (Test-Driven Development) w wytwarzaniu oprogramowania ułatwia zrozumienie i wdrożenie ciągłego testowania. W TDD testy tworzone są przed implementacją funkcjonalności. Najpierw tworzony jest mały test, po którym następuje implementowanie powiązanego fragmentu całej funkcjonalności. Następnie dokonuje się refaktoryzacji w celu ulepszenia kodu i wyeliminowania ewentualnych powieleń. Dzięki ciągłemu testowaniu otrzymujemy natychmiastową informację zwrotną na każdym z tych kroków. Nie tylko z tego jednego testu, który jest w danym momencie pisany, lecz ze wszystkich powiązanych testów, bez dodatkowego wysiłku i zaangażowania ze strony programisty. Dzięki temu może on skupić się w pełni na projektowaniu i pisaniu kodu, zamiast rozpraszać się koniecznością uruchamiania testów. 

Cel ciągłego testowania 

Zarówno w podejściu TDD, jak i w ciągłym testowaniu, celem jest jak najszybsze uzyskanie informacji zwrotnej. Pod wieloma względami naturalnym rezultatem skutecznego stosowania TDD jest dobrej jakości zestaw testów. Różnica polega na tym, że stosując ciągłe testowanie, zyskuje się dodatkowe źródła informacji zwrotnych. Stary aksjomat podejścia TDD mówi, że testy sprawdzają poprawność kodu, z kolei kod weryfikuje poprawność testów. Testy sprawdzają również projekt kodu – źle zaprojektowany kod jest trudny do przetestowania.  

Jakie narzędzia wykorzystywane są w procesie dostarczania oprogramowania z CI/CD? 

Jenkins 

Jenkins to serwer ciągłej integracji (CI) typu open source.  Kontroluje kilka etapów procesu dostarczania oprogramowania, takie jak testowanie, kompilacja i wdrażanie. Popularność tego narzędzia wynika między innymi z jego możliwości śledzenia i monitorowania powtarzalnych działań pojawiających się w trakcie prac nad projektem. Każda zmiana w aplikacji jest kompilowana i testowana, a w razie wykrycia błędu Jenkins ostrzeże zespół o problemach. 

Wdrożenie kodu na produkcję 

Jednym z podstawowych zastosowań Jenkinsa jest możliwość wdrażania kodu na produkcję. Jeśli wszystkie testy opracowane dla danej funkcji lub releasu zakończą się powodzeniem, Jenkins może automatycznie opublikować kod na środowisku staging lub produkcyjnym (jest to właśnie przykład Continuous Deployment opisanego w poprzednim artykule). 

Automatyzacja workflow i różnych zadań 

Innym przypadkiem, w którym można użyć Jenkinsa, jest m.in. automatyzacja workflow. Na przykład, gdy programista pracuje na kilku środowiskach, w pewnym momencie zajdzie konieczność instalacji lub aktualizacji pewnych komponentów na każdym z nich. Jeśli instalacja lub aktualizacja wymaga wykonania wielu kroków, przeprowadzenie jej ręcznie może skutkować pojawieniem się błędów, a dodatkowo będzie czasochłonne. Zamiast tego wszystkie kroki potrzebne do finalizacji można odpowiednio skonfigurować w Jenkinsie. Dzięki temu cały proces będzie stabilny i szybki, bo też zawsze będzie wykonywany identycznie. 

Konfiguracja zadań 

Jenkins umożliwia tworzenie zadań (Jenkins Jobs) na różne sposoby. Konfigurację można stworzyć całkowicie przez UI, przeklikując odpowiednie opcje, lecz lepszym wyborem jest utworzenie pliku konfiguracyjnego i zdefiniowanie w nim wszystkich niezbędnych kroków. W Jenkinsie wykorzystuje się w tym celu skrypty pisane w języku Groovy. Zaletą w stosowaniu tej opcji jest dodatkowo to, że plik konfiguracyjny można przechowywać wraz z kodem dotyczącej go aplikacji. Dzięki temu mamy zapewnione wersjonowanie zmian i powstaje kopia zapasowa, przydatna w przypadku wystąpienia awarii. 

Rozszerzalność poprzez pluginy 

Możliwości Jenkinsa można rozszerzać dzięki wielu pluginom dostępnym na stronie https://plugins.jenkins.io/. Ich liczba pozwala na dowolne skonfigurowanie serwera pod konkretne potrzeby, począwszy od zmiany wyglądu elementów interfejsu użytkownika po możliwość integracji z zewnętrznymi serwisami lub aplikacjami czy modyfikujące kroki w tworzonych jobach. 

GitLab 

Innym narzędziem, o którym warto wspomnieć, jest GitLab. Serwis ten nie tylko pozwala na tworzenie i przechowywanie repozytoriów kodu, ale także udostępnia narzędzia do wersjonowania oprogramowania, zarządzania zadaniami oraz procesami CI/CD. Pozwala on wszystkim członkom zespołu współpracować na wszystkich etapach projektu, upraszczając tworzenie oprogramowania. 

Funkcjonalności GitLaba 

GitLab to internetowe repozytorium Git, które umożliwia zespołom programistów planowanie, kodowanie, testowanie, wdrażanie i monitorowanie zmian tworzonego oprogramowania w jednym miejscu. Natomiast Git to dobrze wszystkim znany system kontroli wersji. 

Jedną z istotnych możliwości jest śledzenie błędów: GitLab posiada wbudowany system umożliwiający zespołom tworzenie, przypisywanie i śledzenie błędów. Zapewnia także tablicę zarządzania projektami z konfigurowalnymi przepływami pracy (workflow) w celu wizualizacji zadań i postępów. 

Inną kluczową funkcjonalnością GitLaba są zintegrowane potoki CI/CD (pipelines). Dzięki temu można łatwo zautomatyzować procesy testowania, budowania i wdrażania, zapewniając dokładne testowanie zmian w kodzie przed połączeniem z główną bazą kodu i wdrożeniem w środowisku produkcyjnym. 

GitLab posiada także wewnętrzny system wiki, umożliwiający zespołom tworzenie i utrzymywanie dokumentacji projektowej. 

Podsumowanie 

Podejście Continuous Integration wraz z Continuous Development i Continuous Testing stanowią komplementarne praktyki. Continuous Development umożliwia obserwowanie wdrażanych zmian w czasie rzeczywistym i jednocześnie eliminuje proces ręcznego śledzenia zmian. Błędy znalezione na jak najwcześniejszym etapie są najszybsze i najtańsze w naprawie. 

Budowanie aplikacji wraz z przeprowadzeniem testów na lokalnym środowisku może zająć kilka minut, a ich przeprowadzenie daje pewność, że wprowadzone zmiany będą przygotowane do integracji z główną gałęzią repozytorium. Czasem zmiany mogą budzić szczególne wątpliwości –   na przykład, gdy modyfikacji wymagają pliki konfiguracyjne. W takim przypadku można wykonać pełną kompilację i uruchomić wszystkie testy, aby mieć pewność, że zmiana nie spowodowała błędów w innych obszarach aplikacji, a kod jest bezpieczny i może zostać dodany do głównego repozytorium. 

Ciągła integracja ma na celu identyfikowanie problemów, ale może również posłużyć jako narzędzie do zmniejszania kosztów uruchamiania testów wyższego poziomu – wykrycie błędów na etapie testów jednostkowych sprawi, że testy z pozostałych poziomów będą bardziej stabilne, co daje dodatkową pewność co do jakości. 

TOPICS