Wybrane przypadki zastosowania obiektu cause w Jenkinsie

Wybrane przypadki zastosowania obiektu cause w Jenkinsie
Jak testerzy mogą używać cause w systemie Jenkins do celów kontroli i zapewnienia jakości?

Wprowadzenie

W procesie wytwarzania oprogramowania często spotykamy się z takim pojęciem jak ciągła integracja. Jak wspomniano w pozycji [1] "ciągła integracja (CI) to koncepcja, która rozwiązuje problem budowania, testowania oraz integracji kodu. Pozwala ona upewnić się, czy zmiany w kodzie nie wprowadziły nowych defektów albo regresu, ponieważ CI uruchamia wszystkie testy, w tym akceptacyjne". Jenkins to open-source’owe narzędzie, które umożliwia automatyzację procesów ciągłego integrowania i dostarczania oprogramowania. Główne zastosowania Jenkinsa to:

  1. Ciągła integracja (CI): Jenkins może  automatycznie budować, a następnie testować aplikację, zgodnie z wprowadzonymi regułami, które opisują politykę zmian w kodzie.
  2. Ciągłe dostarczanie (CD): Jenkins może automatycznie wdrażać aplikację na środowiskach testowych, stagingowych, a nawet produkcyjnych. 
  3. Automatyzacja: Możliwość automatyzacji różnych etapów w procesie tworzenia oprogramowania – od kompilacji, poprzez testowanie, aż po wdrożenie.
  4. Monitoring: Jenkins pozwala śledzić status buildów, raporty testów jak również metryki zdefiniowane w czasie rzeczywistym – umożliwia to szybką reakcję zainteresowanych osób np. na awarie lub testy zakończone niepowodzeniem.

Jenkins jest jednym z najpopularniejszych narzędzi w tej dziedzinie. Musi jednak istnieć jakiś powód, zgodnie z którym uruchamiane są jenkinsowe pipeline‘y. Powodami tymi są "cause‘y", które są głównym tematem niniejszej publikacji. Pisząc artykuł zakładamy, że czytelnik posiada podstawową wiedzę na temat Jenkinsa.

1. Wybrane rodzaje cause'ów w Jenkinsie

Cause'y w Jenkinsie  odnoszą się do powodów, dla których pipeline został uruchomiony.  Jenkins kategoryzuje je na różne sposoby. Oto przykładowe typy cause'ów w Jenkinsie:

  1. User Trigger (Manual Trigger) – powodem uruchomienie pipeline'a jest ręczne kliknięcie przycisku [Build] za pośrednictwem interfejsu użytkownika.
  2. SCM (Source Code Management) Trigger - zmiana w repozytorium kodu źródłowego (takim jak np. Git). Przykładem może być commit lub merge, co Jenkins wykrywa na podstawie sondowania (ang. polling) lub innego wyzwalacza typu webhook.
  3. Timer Trigger – Jenkins uruchamia pipeline na podstawie zdefiniowanego harmonogramu, np.:

    czym-jest-cause-w-jenkinsie-1-main-script.png

    Po uruchomieniu pojawi się wiadomość z logu Jankinsa: "Started by timer".
  4. Replay Trigger – powodem uruchomiania pipeline'a jest kliknięcie opcji [Replay] za pośrednictwem interfejsu użytkownika, a następnie kliknięcie przycisku [Run]:

    czym-jest-cause-w-jenkinsie-2-replay.png
  5. Parameter Trigger – uruchomienie pipeline'a za pomocą parametrów przekazanych poprzez API lub interfejs użytkownika.
  6. Upstream Trigger – pipeline wyzwolony jako część łańcucha zadań. Oznacza, że zadanie wyższe w hierarchii (upstream) wyzwala  zadanie niższe (downstream). "Upstream Trigger" oznacza, że build w jednym zadaniu wyzwala uruchomienie kolejnego zadania w wyniku jego zakończenia.
  7. Downstream Trigger – oznacza, że zadanie niższe w hierarchii (downstream) zależne od zadania wyższego, jest przez nie uruchamiane.

Wymienione w podpunktach (a) – (g) cause'y nie są wszystkimi dostępnymi triggerami w Jenkinsie. Celem artykułu jest przede wszystkim pokazanie, jak można je wykorzystać w samym pipelinie.

2. Sterowanie Jenkinsem za pomocą cause'ów

W celu zaprezentowania przykładów związanych z tematem publikacji posłużymy się językiem Groovy. Listę cause’ów, które pojawiły się podczas uruchomienia builda możemy uzyskać za pomocą wyrażenia:

def causes = currentBuild.rawBuild.getCauses().toString(),

gdzie:

currentBuild - to zmienna, która reprezentuje aktualny build. Jest to obiekt zawierający informacje o bieżącym procesie budowania np. status,

rawBuild - to obiekt zawierający surowe informacje o buildzie, które nie są przetwarzane przez Jenkins,

getCauses() - to metoda zwracająca listę przyczyn (ang. "causes") uruchomienia zadania,

toString() - to metoda standardowa w Groovy konwertująca obiekt na jego reprezentację tekstową.

Wobec tego, zmienna causes zawiera teraz tekstową informację o przyczynach uruchomienia buildu.

Przykład 1.

Załóżmy, że mamy prosty pipeline, który pobiera listę cause'ów:

czym-jest-cause-w-jenkinsie-3-main-script.png

Jeśli użytkownik uruchomi pipeline za pomocą funkcji [Replay], wówczas w logu pojawi się komunikat "This build was triggered by a replay action!"

Jeśli pipeline zostanie uruchomiony w inny sposób, otrzymamy komunikat:

czym-jest-cause-w-jenkinsie-4-pipeline.png

Możemy nieco zmodyfikować nasz pipeline, tak, aby sprawdzać jeszcze jeden rodzaj cause'a:

czym-jest-cause-w-jenkinsie-5-main-script.png

Uruchamiając build manualnie, otrzymamy komunikat "This build was triggered by a userId action".

Możemy również dodać instrukcje println(causes), która wydrukuje listę cause'ów.  Jeżeli wywołamy nasz za pomocą [Replay], wówczas w jego logu pojawi się wpis:

czym-jest-cause-w-jenkinsie-6-pipeline-echo.png

 Wspomniana instrukcja może się przydać do tego, aby sprawdzić jakie cause’y występują w dowolnym pipelinie. 

Przykład 2. 

W tym przykładzie pokażemy, jak za pomocą obiektu cause pipeline może wywołać siebie samego. Dodamy też warunek, aby odbywało się to tylko w przypadku, gdy pipeline bedzie wywołany za pomocą funkcjonalności [Replay]. W praktyce może zaistnieć taka sytuacja, ponieważ pipeline może przyjmować różne rodzaje parametrów, a co za tym idzie różne konfiguracje. Należy jednak zwrócić uwagę na to, aby pipeline nie wywoływał się cyklicznie nieskończenie wiele razy – w przypadku multibrancha mogło by to doprowadzić do „zabicia” maszyny, na której postawiony jest Jenkins.

Wywołanie pipeline'a za pomocą samego siebie, to rekurencja, natomiast jej zatrzymanie to problem programistyczny. Można to osiągnąć na różne sposoby np. poprzez dodanie dodatkowego parametru. Spójrzmy zatem na kolejny pipeline:

czym-jest-cause-w-jenkinsie-7-main-script.png

gdzie:

  • sekcja parameters { ... }  definiuje parametry, które mogą być przekazywane do pipeline'u przed jego uruchomieniem,
  • sekcja environment { ... } definiuje zmienne środowiskowe dostępne w całym pipeline,
  • warunek if (causes.contains('ReplayCause') && !params.triggeredBySelf) { ... }  sprawdza, czy przyczyną uruchomienia pipeline'a jest ReplayCause oraz czy parametr triggeredBySelf jest ustawiony na false (co oznacza, że build nie był wywołany przez siebie).
  • when { ... } określa warunek, który musi zostać spełniony, aby dany stage mógł zostać uruchomiony.

Zgodnie z zaprezentowanym powyżej kodem, stage “Trigger pipeline by self” zostanie uruchomiony w przypadku gdy:

  1. przyczyną uruchomienia pipeline'a będzie ReplayCause
  2. parametr triggeredBySelf ma wartość false.

Jeżeli natomiast build zostanie uruchomiony bez użycia funkcjonalności [Replay], to pipeline nie wywoła sam siebie.

W celu przetestowania pipeline'a zostały wykonane następujące kroki w odpowiedniej kolejności:

  1. uruchomienie za pomocą przycisku [Build] nr #104,
  2. uruchomienie za pomocą funkcjonalności [Replay], nr #105. 

Rezultat testów jest widoczny niżej:

czym-jest-cause-w-jenkinsie-8-test-mz.png

Przebieg #106 został wywołany, ponieważ przebieg #105 zawierał ReplayCause oraz parameter triggeredBySelf miał wartość false. Przebieg #105 wykonał stage “Trigger pipeline by self”, a ten z kolei uruchomił sam siebie, ale z parametrem triggeredBySelf = true. Wchodząc w szczegóły przebiegu #106,  widzimy komunikat “Started by upstream project TEST_MZ”:

czym-jest-cause-w-jenkinsie-9-test-mz.png

co oznacza, że proces budowania pipeline'a został rozpoczęty za pomocą upstream cause.

Przykład 3.

W tym przykładzie pokażemy pipeline, który analizuje przyczynę uruchomienia builda i na jego podstawie wykonuje różne akcje, takie jak uruchomienie odpowiednich funkcji oraz wypisanie komunikatów informujących o tym, jak pipeline został wywołany:

czym-jest-cause-w-jenkinsie-10-przyklad.png

Zmienna środowiskowa BUILD_TRIGGER jest zainicjowana pustym stringiem, który zostanie zaktualizowany w zależności od przyczyny uruchomienia pipeline'u. Podczas etapu ‘Check cause’ skrypt sprawdza, jaki cause jest przyczyną uruchomienie pipeline'u, wykorzystując tym celu funkcję currentBuild.rawBuild.getCauses(). Log z manualnego uruchomienia ma postać:

czym-jest-cause-w-jenkinsie-11-pipeline-echo.png


Przykład 4.

Podczas korzystania z Jenkinsa niekiedy zachodzi konieczność ręcznego przerwania pipeline'a. Za pomocą wykorzystania funkcjonalności cause możemy otrzymać informację o tym, kto przerwał pipeline. Spójrzmy na kolejny przykład:

czym-jest-cause-w-jenkinsie-12-przyklad.png
Wyżej przedstawiony pipeline to prosty skrypt wykonujący kilka operacji, w tym sprawdzanie, czy zadanie zostało przerwane przez użytkownika, a także wypisuje informację, kto go przerwał (jeśli przerwanie manualne miało miejsce). Metoda getAbortUser() sprawdza, czy proces budowania został przerwany przez użytkownika oraz zwraca nazwę użytkownika, który przerwał build. Dzieje się tak dlatego, ponieważ blok instrukcji actions.each { action -> ... }  iteruje przez wszystkie akcje przerywania pipeline'a (jeżeli istnieją). Dla każdej operacji przerwania builda następuje sprawdzenie jaka była tego przyczyna. Jeśli zrobił to zalogowany użytkownik, wypisuje jego nazwę, co widać poniżej:

czym-jest-cause-w-jenkinsie-13-pipeline.png

3. Podsumowanie

Niniejszy artykuł przedstawia oraz wyjaśnia czytelnikowi czym jest cause w systemie Jenkins. Główny temat publikacji to prezentacja wybranych przypadków użycia funkcjonalności cause w Jenkinsie. W niniejszej pracy zaprezentowane zostały wybrane scenariusze, za pomocą których użyte causy pozwalają na zarządzanie zależnościami pomiędzy zadaniami w ramach różnych etapów pipeline'ów oraz pozwalają na prezentowanie oczekiwanych informacji z wybranych akcji.

 

 

Recenzent: Marcin Misiorny
 

Źródła:
https://testerzy.pl/baza-wiedzy/artykuly/piramida-testow-i-ciagla-integracja
https://javadoc.jenkins-ci.org/hudson/model/cause.html

To powinno Cię zainteresować