Typowe sytuacje w ciągłej integracji

Poznałeś już polecenia Git, ale chcesz zobaczyć, jak ciągła integracja (Continuous Integration, CI) wygląda w praktyce? A może chcesz zoptymalizować swoje codzienne działania? Ten kurs zapewni Ci praktyczne umiejętności w zakresie ciągłej integracji przy użyciu repozytorium na GitHubie. Kurs nie jest zaprojektowany jako prosty kreator, który można przejść klikając, wręcz przeciwnie, będziesz wykonywać te same czynności, które ludzie faktycznie robią w pracy, w ten sam sposób, w jaki to robią. Będę tłumaczyć teorię w miarę przechodzenia przez związane z nią kroki.

Co będziemy robić?

W miarę postępu, stopniowo stworzymy listę typowych kroków CI, co jest doskonałym sposobem na zapamiętanie tej listy. Innymi słowy, stworzymy listę działań, które deweloperzy podejmują w trakcie wdrażania ciągłej integracji. Będziemy także używać prostego zestawu testów, aby przybliżyć nasz proces CI do rzeczywistości.

Ten GIF schematycznie pokazuje commity w Twoim repozytorium w miarę postępów w kursie. Jak widać, nie ma w tym nic trudnego, tylko to, co niezbędne.

Typowe sytuacje w ciągłej integracji

Przejdziesz przez następujące standardowe scenariusze CI:

  • Praca nad funkcjonalnością;
  • Zastosowanie testów automatycznych dla zapewnienia jakości;
  • Wdrażanie priorytetowego zadania;
  • Rozwiązywanie konfliktu podczas łączenia gałęzi (merge conflict);
  • Wystąpienie błędu w środowisku produkcyjnym.

Czego się nauczysz?

Będziesz w stanie odpowiedzieć na takie pytania:

  • Czym jest ciągła integracja (CI)?
  • Jakie typy testów automatycznych są używane w CI i w odpowiedzi na jakie działania są uruchamiane?
  • Czym jest pull request i kiedy są potrzebne?
  • Czym jest rozwój oparty na testach (Test Driven Development, TDD) i jak odnosi się do CI?
  • Czy łączyć (merge) czy aplikować zmiany na bazę (rebase)?
  • Cofnąć czy naprawić w następnej wersji?

Na początku wszędzie przekładałem takie rzeczy jak 'pull request', ale w rezultacie postanowiłem przywrócić angielskie frazy w niektórych miejscach, aby zmniejszyć poziom szaleństwa w tekście. Czasami będę używać 'programistycznego surżu' jak urokliwego czasownika 'zakommitować' tam, gdzie ludzie faktycznie go używają w pracy.

Czym jest ciągła integracja?

Ciągła integracja, albo CI, to techniczna praktyka, która polega na tym, że każdy członek zespołu integruje swój kod do wspólnego repozytorium przynajmniej raz dziennie, przy czym kod wynikowy musi być kompilowany bez błędów.

Istnieją różnice w interpretacji tego terminu.

Przedmiotem sporu jest częstotliwość integracji. Niektórzy twierdzą, że łączenie kodu tylko raz dziennie jest niewystarczające i że integracja powinna odbywać się w sposób ciągły. Przykładem jest zespół, w którym wszyscy pobierają świeży kod rano i integrują go raz wieczorem. Choć jest to rozsądne zastrzeżenie, ogólnie uważa się, że definicja „raz dziennie” jest wystarczająco praktyczna, konkretna i odpowiednia dla zespołów różnej wielkości.

Innym zastrzeżeniem jest to, że C++ od dawna nie jest jedynym językiem używanym w rozwoju, a proste wymaganie kompilacji bez błędów jako metody walidacji jest słabe. Pewien zestaw testów (na przykład testów jednostkowych, uruchamianych lokalnie) również powinien zakończyć się sukcesem. Obecnie społeczność skłania się ku temu, aby takie wymogi stały się obligatoryjne, a w przyszłości „kompilacja + testy jednostkowe” prawdopodobnie stanie się powszechne, jeśli już tak się nie stało.

Ciągła integracja różni się od ciągłego dostarczania (Continuous Delivery, CD) tym, że nie wymaga kandydata do wydania po każdym cyklu integracji.

Lista kroków, które będziemy używać w trakcie kursu.

  1. Pobierz najnowszy kod. Utwórz gałąź z master. Zacznij pracować.
  2. Twórz commity na swojej nowej gałęzi. Kompiluj i testuj lokalnie. Sukces? Przejdź do następnego kroku. Niepowodzenie? Napraw błędy lub testy i spróbuj ponownie.
  3. Wypchnij do swojego zdalnego repozytorium lub zdalnej gałęzi.
  4. Utwórz pull request. Dyskutuj wprowadzone zmiany, dodawaj więcej commitów, gdy dyskusja się toczy. Spraw, aby testy przebiegły pomyślnie na gałęzi funkcjonalnej.
  5. Scal/rebase commity z master. Upewnij się, że testy przechodzą na wyniku scalenia.
  6. Wdrażaj z gałęzi funkcjonalnej do produkcji.
  7. Jeśli wszystko jest w porządku w produkcji przez pewien czas, scal zmiany do master.

Typowe sytuacje w ciągłej integracji

️ Przygotowanie

Upewnij się, że masz odpowiednie oprogramowanie.

Aby przejść ten kurs, potrzebujesz Node.js i klient Git..

Możesz użyć dowolnego klienta Git, ale ja będę podawać polecenia tylko dla wiersza poleceń.

Upewnij się, że masz zainstalowanego klienta Git obsługującego wiersz poleceń.

Jeżeli jeszcze nie masz zainstalowanego klienta Git obsługującego wiersz poleceń, możesz znaleźć instrukcje dotyczące instalacji. tutaj.

Przygotuj repozytorium.

Będziesz musiał utworzyć osobistą kopię (fork) repozytorium szablonowego z kodem kursu na GitHubie. Umówmy się, że będziemy nazywać tę osobistą kopię. repo kursu.

Zrobione? Jeśli nie zmieniałeś domyślnych ustawień, twój repozytorium kursu prawdopodobnie nazywa się continuous-integration-team-scenarios-students, znajduje się w twoim koncie na GitHubie, a adres URL wygląda tak

https://github.com//continuous-integration-team-scenarios-students

Będę nazywał ten adres po prostu <URL репозитория>.

Kątowniki jak <тут> będą oznaczały, że masz zastąpić takie wyrażenie odpowiednią wartością.

Upewnij się, że GitHub actions są włączone dla tego repozytorium kursu. Jeśli nie będą włączone, proszę włącz je, naciskając dużą przycisk na środku strony, do której możesz przejść, klikając Actions w interfejsie GitHub.

Nie będziesz mógł przejść kursu, postępując zgodnie z moimi instrukcjami, jeśli GitHub Actions nie będą włączone.

Typowe sytuacje w ciągłej integracji

Zawsze możesz skorzystać z możliwości GitHub do wyświetlania Markdown, aby zobaczyć bieżący stan listy, którą tutaj tworzymy

https://github.com//continuous-integration-team-scenarios-students/blob/master/ci.md

O odpowiedziach

Chociaż najlepszym sposobem na ukończenie tego kursu jest samodzielne działanie, mogą wystąpić trudności.

Jeśli czujesz, że nie rozumiesz, co robić i nie możesz kontynuować, możesz zajrzeć do gałęzi solution, która znajduje się w twoim początkowym repozytorium.
Proszę, nie dokonuj scalania solution do master podczas kursu. Możesz użyć tej gałęzi, aby zrozumieć, co zrobić, lub aby porównać swój kod z oryginalnym, korzystając ze wszystkich możliwości, jakie daje nam Git. Jeśli całkowicie się zgubiłeś, możesz całkowicie zastąpić swoją gałąź master gałęzią solution a następnie zresetować swój katalog roboczy do kroku kursu, który potrzebujesz.

Używaj tego tylko wtedy, gdy naprawdę musisz

Zatwierdź (commit) swój kod

git add .
git commit -m "Kopia zapasowa mojej pracy"

Te polecenia

  • zmieniają nazwę master do master-backup;
  • zmieniają nazwę solution do master;
  • przełączają (checkout) na nową gałąź master i przepisują zawartość katalogu roboczego;
  • tworzą gałąź "solution" z "master" (która wcześniej była "solution") na wypadek, gdybyś w przyszłości potrzebował gałęzi "solution".

git branch -m master master-backup
git branch -m solution master
git checkout master -f
git branch solution

Po tych działaniach możesz użyć git log master aby ustalić, który commit potrzebujesz.
Możesz zresetować swój katalog roboczy do tego commita tak:

git reset --hard

Jeśli jesteś zadowolony z wyniku, w pewnym momencie będziesz musiał opublikować swoją wersję repozytorium w zdalnym repozytorium. Nie zapomnij wyraźnie określić zdalnej gałęzi, gdy to zrobisz.

git push --force origin master

Proszę zauważyć, że używamy git push --force. Mało prawdopodobne, że będziesz często tak postępować, ale mamy tutaj bardzo specyficzny scenariusz z jednym użytkownikiem repozytorium, który dodatkowo wie, co robi.

Zaczynamy pracować

Typowe sytuacje w ciągłej integracji

Zaczniemy tworzyć naszą listę kroków CI. Zwykle ten krok zaczynasz od pobrania najnowszej wersji kodu z zdalnego repozytorium, ale nie mamy jeszcze lokalnego repozytorium, więc zamiast tego klonujemy go zdalnie.

️ Zadanie: zaktualizuj lokalne repozytorium, utwórz gałąź z master, zacznij pracować

  1. Sklonuj repozytorium kursu z <URL репозитория>.
  2. Uruchom npm install w katalogu repozytorium kursu; potrzebujemy go do zainstalowania Jest, którego używamy do uruchamiania testów.
  3. Utwórz gałąź i nazwij ją feature. Przełącz się na tę gałąź.
  4. Dodaj kod testowy do ci.test.js między komentarzami z prośbą o to.

    it('1. pobierz najnowszy kod', () => {
      expect(/.*pull.*?/ig.test(fileContents)).toBe(true);
    });
    
    it('2. dodaj commit', () => {
      expect(/.*commit.*?/ig.test(fileContents)).toBe(true);
    });
    
    it('3. wypchnij do zdalnej gałęzi o tej samej nazwie', () => {
      expect(/.*push.*?/ig.test(fileContents)).toBe(true);
    });
    
    it('4. utwórz pull request i kontynuuj pracę', () => {
      expect(/.*pulls+request.*?/ig.test(fileContents)).toBe(true);
    });

  5. Dodaj tekst z pierwszymi 4 krokami do pliku ci.md.
    1. Pobierz najnowszy kod. Utwórz gałąź z `master`. Zacznij pracować.    
    2. Utwórz commity na swojej nowej gałęzi. Buduj i testuj lokalnie.  
    Udało się? Przejdź do następnego kroku. Nie udało się? Napraw błędy lub testy i spróbuj ponownie.  
    3. Wypchnij do swojego zdalnego repozytorium lub zdalnej gałęzi.  
    4. Utwórz pull request. Omów zmiany, dodawaj więcej commitów  
    w miarę postępu dyskusji. Sprawdź, czy testy przechodzą na gałęzi funkcjonalnej.  

    Polecenia

# Клонируйте репозиторий курса
git clone <repository URL>
cd <repository name>

# Выполните npm install в каталоге репозитория курса; он установит Jest, который мы используем для запуска тестов.
npm install

# Создайте ветку и назовите ее feature. Переключитесь на эту в ветку.
git checkout -b feature

# Отредактируйте ci.test.js как описано выше.
# Отредактируйте ci.md как описано выше

Twórz commity na nowej gałęzi, wykonuj budowę i testowanie lokalnie

Zamierzamy skonfigurować testy, aby uruchamiały się przed commitowaniem, a następnie zakomitować kod.

Typowe scenariusze, gdy testy uruchamiają się automatycznie

  • Lokalnie:
    • Ciągle lub w odpowiedzi na odpowiednie zmiany kodu;
    • Podczas zapisywania (dla języków interpretowanych lub kompilowanych JIT);
    • Podczas budowy (gdy wymagana jest kompilacja);
    • Podczas commitowania;
    • Podczas publikowania w ogólnym repozytorium.

  • Na serwerze kompilacyjnym lub w środowisku kompilacyjnym:
    • Gdy kod jest publikowany w osobistej gałęzi / repozytorium.
    • Kod jest testowany w tej gałęzi.
    • Potencjalny rezultat scalania jest testowany (zwykle z master).
    • Jako etap ciągłej integracji/ciągłego dostarczania

Zazwyczaj im szybciej wykonuje się zestaw testów, tym częściej można sobie pozwolić na jego uruchamianie. Typowy podział etapów może wyglądać tak.

  • Szybkie testy jednostkowe — przy budowie, w potoku CI
  • Wolne testy jednostkowe, szybkie testy komponentów i integracyjne — przy commicie, w potoku CI
  • Wolne testy komponentów i integracyjne — w potoku CI
  • Testy bezpieczeństwa, testy obciążeniowe i inne długoterminowe lub kosztowne testy — w potokach CI/CD, ale tylko w określonych trybach/etapach/potokach budowy, na przykład podczas przygotowania kandydata do wydania lub gdy są uruchamiane ręcznie.

️ Zadanie

Proponuję najpierw uruchomić testy ręcznie, używając polecenia npm test. Po tym dodajmy hook gita do uruchamiania naszych testów przy commicie. Jest jeden problem: Git hooki nie są częścią repozytorium, więc nie mogą być klonowane z GitHubem razem z innymi materiałami kursu. Aby zainstalować hook, musisz uruchomić install_hook.sh lub skopiować plik repo/hooks/pre-commit do lokalnego katalogu .git/hooks/.
Podczas commitu zobaczysz, że testy są uruchamiane i sprawdzają, czy w liście są określone słowa kluczowe.

  1. Uruchom testy ręcznie, wykonując polecenie npm test w katalogu repozytorium swojego kursu. Upewnij się, że testy zostały wykonane.
  2. Ustaw hook na commit (hook pre-commit), uruchamiając install_hook.sh.
  3. Zacommituj zmiany w lokalnym repozytorium.
  4. Upewnij się, że testy są uruchamiane przed commitem.

Twoje repozytorium powinno wyglądać tak po wykonaniu tych czynności.
Typowe sytuacje w ciągłej integracji

Polecenia

# Установите pre-commit hook выполнив install_hook.sh.  

# Закоммитьте изменения в локальный репозиторий. Используйте "Add first CI steps" в качестве сообщения при коммите.
git add ci.md ci.test.js
git commit -m "Add first CI steps"

# Убедитесь, что тесты запускаются перед коммитом.  

Opublikuj kod w zdalnym repozytorium lub zdalnej gałęzi

Po zakończeniu pracy lokalnie, programiści zazwyczaj publikują swój kod w celu jego późniejszej integracji z ogólnym. Dzięki GitHubowi zazwyczaj odbywa się to poprzez publikację pracy w osobistej kopii repozytorium (personal fork) lub w prywatnej gałęzi.

  • Podczas korzystania z forków programista klonuje zdalne repozytorium, tworząc jego kopię osobistą, znaną jako fork. Następnie klonuje to osobiste repozytorium, aby pracować nad nim lokalnie. Gdy prace są zakończone i utworzone zostaną commity, umieszcza je w swoim forku, gdzie są dostępne dla innych i mogą być zintegrowane z repozytorium ogólnym. To podejście jest zwykle stosowane w projektach open source na GitHubie. Używa się go również w moim zaawansowanym kursie [Team Work and CI with Git]http://devops.redpill.solutions/).
  • Inne podejście polega na używaniu tylko jednego zdalnego repozytorium i traktowaniu tylko gałęzi master wspólnego repozytorium jako "zabezpieczonej". W tym scenariuszu poszczególni programiści publikują swój kod w gałęziach zdalnego repozytorium, aby inni mogli ten kod zobaczyć, a jeśli wszystko jest w porządku, połączyć go z master repozytorium ogólnym.

W tym konkretnym kursie będziemy korzystać z procesu roboczego, który wykorzystuje gałęzie.

Opublikujmy nasz kod.

️ Zadanie

  • Opublikuj zmiany w zdalnej gałęzi o tej samej nazwie co twoja gałąź robocza

Polecenia

git push --set-upstream origin feature

Utwórz pull request

Utwórz pull request o tytule Kroki przeglądu. Ustaw feature jako "gałąź head" i master jako "gałąź bazową".

Upewnij się, że ustawiłeś master w swoim forku repozytorium jako "gałąź bazową", nie będę odpowiadać na prośby o zmiany w repozytorium z materiałami kursu.

W slangu GitHuba "gałąź bazowa" to gałąź, na której opierasz swoją pracę, a "gałąź head" to gałąź zawierająca proponowane zmiany.

Dyskutuj o zmianach, dodawaj nowe commity w miarę kontynuacji dyskusji

Pull request (PR)

Pull request (PR) to sposób na omówienie i udokumentowanie kodu, a także przeprowadzenie przeglądu kodu (code review). Pull requesty są nazwane na cześć ogólnego sposobu integrowania indywidualnych zmian w kod ogólny. Zwykle ktoś klonuje zdalne oficjalne repozytorium projektu i pracuje nad kodem lokalnie. Po zakończeniu umieszcza kod w swoim osobistym zdalnym repozytorium i prosi osoby odpowiedzialne za oficjalne repozytorium o zabraniepull) jego kodu do swoich lokalnych repozytoriów, gdzie go przeglądają i być może integrująmerge) go. To pojęcie jest znane także pod innymi nazwami, takimi jak merge request.

Nie musisz koniecznie korzystać z funkcji pull request w GitHubie lub podobnych platformach. Zespoły deweloperskie mogą komunikować się na inne sposoby, w tym za pośrednictwem osobistych spotkań, rozmów telefonicznych lub e-maili, jednak istnieje wiele powodów, dla których warto korzystać z pull requestów w stylu dyskusji na forum. Oto niektóre z nich:

  • zorganizowane dyskusje dotyczące konkretnych zmian w kodzie;
  • jako miejsce do przeglądania opinii o niewykonanej pracy zarówno od testów automatycznych, jak i od współpracowników;
  • formalizacja przeglądów kodu;
  • aby później można było ustalić powody i rozważania stojące za danym fragmentem kodu.

Zazwyczaj tworzysz pull request, gdy musisz coś omówić lub uzyskać opinię. Na przykład, jeśli pracujesz nad funkcją, którą można zrealizować na kilka sposobów, możesz stworzyć zaproszenie do zmian jeszcze przed napisaniem pierwszej linii kodu, aby podzielić się swoimi pomysłami i omówić plany z współautorami. W przypadku prostszych zadań pull request otwierany jest, gdy coś już zostało zrobione, zatwierdzone i może być omówione. W niektórych scenariuszach możesz otworzyć PR tylko w celach kontrolnych: aby uruchomić automatyczne testy lub zainicjować przegląd kodu. Cokolwiek postanowisz, pamiętaj, aby @wspomnieć osoby, których zatwierdzenie jest potrzebne w Twoim pull requestcie.

Zazwyczaj przy tworzeniu PR wykonujesz następujące kroki.

  • Określasz, co proponujesz zmienić i gdzie.
  • Piszesz opis, wyjaśniający cel zmian. Możesz chcieć:
    • dodać coś ważnego, co nie jest oczywiste z kodu, lub coś użytecznego dla zrozumienia kontekstu, na przykład odpowiednie #błędy i numery commitów;
    • @wspomnieć wszystkich, z którymi chcesz zacząć współpracować, lub możesz @wspomnieć ich w komentarzach później;
    • poprosić współpracowników o pomoc w czymś lub sprawdzenie czegoś konkretnego.

Po otwarciu PR uruchamiane są testy, które są skonfigurowane do uruchamiania w takich przypadkach. W naszym przypadku będzie to ten sam zestaw testów, który uruchamialiśmy lokalnie, ale w prawdziwym projekcie mogą być dodatkowe testy i kontrole.

Proszę czekać na zakończenie testów. Możesz zobaczyć status testów na dole dyskusji PR w interfejsie GitHub. Kontynuuj, gdy testy się zakończą.

️ Dodaj uwagę o dowolności listy kroków CI

Lista użyta w tym kursie jest dowolna i subiektywna, musimy dodać uwagę na ten temat.

️ Zadanie: stworzenie pull request do tej uwagi

  1. Przełącz się na gałąź master.
  2. Utwórz gałąź o nazwie bugfix.
  3. Dodaj tekst uwagi na końcu pliku ci.md.
    > **GitHub flow** jest czasami używane jako nazwa odnosząca się do odmiany rozwoju opartego na trunku  
    gdzie kod jest wdrażany bezpośrednio z gałęzi funkcji. Ta lista to po prostu interpretacja,  
    którą wykorzystuję w moich [kursach DevOps](http://redpill.solutions).  
    Oficjalny samouczek jest [tutaj](https://guides.github.com/introduction/flow/).
  4. Zatwierdź zmiany.
  5. Opublikuj gałąź bugfix w zdalnym repozytorium.
  6. Utwórz pull request o nazwie Dodanie uwagi do głównej gałęzi bugfix i gałęzi bazowejmaster.

Upewnij się, że ustawiłeś master w swoim forku repozytorium jako "gałąź bazową", nie będę odpowiadać na prośby o zmiany w repozytorium z materiałami kursu.

Oto jak powinno wyglądać Twoje repozytorium.
Typowe sytuacje w ciągłej integracji

Polecenia

# Переключитесь на ветку master. Создайте ветку bugfix.
git checkout master

# Создайте ветку bugfix-remark.
git checkout -b bugfix

# Добавьте текст примечания внизу ci.md.

# Закоммитьте изменения
git add ci.md
git commit -m "Add a remark about the list being opinionated"

# Опубликуйте ветку bugfix в удалённый репозиторий.
git push --set-upstream origin bugfix

# Создайте pull request при помощи интерфейса GitHub как описано выше

Zatwierdź pull request "Dodanie uwagi"

️ Zadanie

  1. Utwórz pull request.
  2. Kliknij "Scal pull request".
  3. Kliknij "Potwierdź scalanie".
  4. Kliknij "Usuń gałąź", nie jest już nam potrzebna.

To jest wykres commitów po scaleniu.
Typowe sytuacje w ciągłej integracji

️ Kontynuuj pracę i dodawaj testy

Wspólna praca nad pull request często prowadzi do konieczności dodatkowej pracy. Zwykle jest to efektem przeglądu kodu lub dyskusji, ale w naszym kursie zamierzamy to modelować, dodając nowe elementy do naszej listy kroków CI.

W ciągłej integracji zazwyczaj stosuje się pewne pokrycie testami. Wymagania dotyczące pokrycia testami różnią się i zazwyczaj znajdują się w dokumencie o nazwie podobnym do "wytyczne dla autorów" (contribution guidelines). My po prostu dodamy po teście do każdej pozycji na naszej liście kontrolnej.

Podczas realizacji zadań najpierw spróbuj zatwierdzić testy. Jeśli poprawnie skonfigurowałeś hook pre-commit wcześniej, właśnie dodany test zostanie uruchomiony, nie przejdzie, a nic nie zostanie zatwierdzone. Zauważ: w ten sposób dowiemy się, że nasze testy naprawdę coś sprawdzają. Ciekawe, że gdybyśmy zaczęli od kodu przed testami, przechodzenie testów mogłoby oznaczać zarówno to, że kod działa zgodnie z oczekiwaniami, jak i że testy w rzeczywistości nic nie sprawdzają. Ponadto, gdybyśmy w ogóle nie napisali testów, moglibyśmy je całkowicie zapomnieć, ponieważ nic by nam o tym nie przypominało.

Rozwój poprzez testowanie (TDD)

TDD zaleca pisanie testów przed kodem. Typowy proces pracy z wykorzystaniem TDD wygląda następująco.

  1. Dodaj test.
  2. Uruchom wszystkie testy i upewnij się, że nowy test nie przechodzi pomyślnie.
  3. Napisz kod.
  4. Uruchom testy, upewnij się, że wszystkie testy przechodzą pomyślnie.
  5. Przeprowadź refaktoryzację kodu.
  6. Powtórz.

Ponieważ wyniki testów, które nie zostały pomyślnie zaliczone, zazwyczaj są wyświetlane na czerwono, a te które były udane — na zielono, cykl ten znany jest również jako "czerwony-zielony-refaktoryzacja".

️ Zadanie

Najpierw spróbuj zatwierdzić testy i pozwól im zakończyć się niepowodzeniem, następnie dodaj i zatwierdź sam tekst listy kroków CI. Zobaczysz, że testy przechodzą ("zielone").
Następnie opublikuj nowy kod w zdalnym repozytorium i sprawdź, jak testy są wykonywane w interfejsie GitHub na dole dyskusji dotyczącej zgłoszenia zmian, oraz jak aktualizowany jest status PR.

  1. Przełącz się na gałąź feature.
  2. Dodaj te testy do ci.test.js po ostatnim wywołaniu it (...);.

    it('5. Scal/rebase commit z master. Sprawdź, czy testy przechodzą w wyniku scalenia.', () => {
      expect(/.*scal.*commit.*testy przechodzą.*\/ig.test(fileContents)).toBe(true);
    });
    
    it('6. Wdróż z gałęzi funkcjonalnej na produkcję.', () => {
      expect(/.*Wdróż.*na produkcję.*\/ig.test(fileContents)).toBe(true);
    });
    
    it('7. Jeśli wszystko jest w porządku w produkcji przez pewien okres czasu, scal zmiany do master.', () => {
      expect(/.*scal.*do master.*\/ig.test(fileContents)).toBe(true);
    });

  3. Spróbuj zatwierdzić testy. Jeśli hook pre-commit hook jest ustawiony, próba zatwierdzenia zakończy się błędem.
  4. Następnie dodaj ten tekst do ci.md.
    5. Scal/rebase commit z master. Sprawdź, czy testy przechodzą w wyniku scalenia.  
    6. Wdróż z gałęzi funkcjonalnej z ukrytym błędem na produkcję.
    7. Jeśli wszystko jest w porządku w produkcji przez pewien okres czasu, scal zmiany do master. 
  5. Wprowadź i zatwierdź zmiany lokalnie.
  6. Opublikuj zmiany w gałęzi feature.

Teraz powinieneś mieć coś takiego jak to
Typowe sytuacje w ciągłej integracji

Polecenia


# Переключительна ветку feature
git checkout feature

# Добавить тесты в ci.test.js как описано выше

# Добавьте в индекс ci.test.js чтобы позже закоммитить
git add ci.test.js

# Попытайтесь закоммитить тесты. Если pre-commit hook установлены, коммит не произойдёт.
git commit

# Теперь добавьте текст в ci.md как описано выше

# Внесите изменения и закоммитьте их
git add ci.md
git commit -m "Add the remaining CI steps"

# Опубликуйте изменения в ветку feature
git push

Konflikt scalenia

Przejdź do zgłoszenia zmian Kroki przeglądu.

Chociaż nie zrobiliśmy nic złego, a testy naszego kodu przeszły pomyślnie, nadal nie możemy zrealizować scalenia gałęzi feature i master. To dlatego, że inna gałąź bugfix została scalona z master podczas gdy pracowaliśmy nad tym PR.
Tworzy to sytuację, w której zdalna gałąź master ma nowszą wersję niż ta, na której opieraliśmy gałąź feature. Z tego powodu nie możemy po prostu cofnąć HEAD master do końca gałęzi feature. W tej sytuacji musimy albo zrealizować scalanie (merge), albo zastosować commity feature na wierzchu (rebase) masterGitHub faktycznie może wykonywać automatyczne łączenie, jeśli nie ma konfliktów. Niestety w naszej sytuacji obie gałęzie mają konkurencyjne zmiany w pliku. ci.mdTaka sytuacja nazywana jest konfliktem przy łączeniu (merge conflict) i musimy ją rozwiązać ręcznie.

Merge lub rebase

Merge

  • Tworzy dodatkowy commit łączenia (merge commit) i zachowuje historię pracy.
    • Zachowuje oryginalne commity gałęzi z oryginalnymi znacznikami czasu i autorami.
    • Zachowuje SHA commitów i odniesienia do nich w dyskusjach dotyczących zapytań o zmiany.
  • Wymaga jednokrotnego rozwiązania konfliktów.
  • Czyni historię nieliniową.
    • Historię może być trudno czytać z powodu dużej liczby gałęzi (przypomina kabel IDE).
    • Utrudnia automatyczne debugowanie, na przykład czyni git bisect mniej użytecznym — znajdzie tylko commit łączenia.

Rebase

  • Reprodukuje commity z bieżącej gałęzi na bazowej jeden po drugim.
    • Powstają nowe commity z nowymi SHA, w wyniku czego commity w GitHubie są powiązane z oryginalnymi pull requestami, ale nie z odpowiednimi komentarzami.
    • Commity mogą być rekombinowane i zmieniane w procesie lub nawet łączone w jeden.
  • Może być konieczne rozwiązanie kilku konfliktów.
  • Pozwala utrzymać liniową historię.
    • Historię może być łatwiej czytać, chyba że jest zbyt długa bez uzasadnionych powodów.
    • Automatyczne debugowanie i rozwiązywanie problemów jest nieco prostsze: czyni możliwym git bisect, może uczynić automatyczne wycofywanie bardziej przejrzystym i przewidywalnym.
  • Wymaga publikacji gałęzi z przeniesionymi commitami z flagą --force przy użyciu z zapytaniami o wprowadzenie zmian.

Zwykle zespoły zgadzają się zawsze stosować tę samą strategię, gdy muszą łączyć zmiany. Może to być "czyste" łączenie lub "czyste" zastosowanie commitów na wierzchu lub coś pośredniego, na przykład wykonywanie zastosowania commitów w trybie interaktywnym (git rebase -i) lokalnie dla gałęzi, które nie zostały opublikowane w ogólnym repozytorium, ale łączenie (merge) dla "publicznych" gałęzi.

Tutaj będziemy używać łączenia.

️ Zadanie

  1. Upewnij się, że kod w lokalnej gałęzi master jest zaktualizowany z zdalnego repozytorium.
  2. Przełącz się na gałąź feature.
  3. Rozpocznij łączenie z gałęzią master. Zostanie zgłoszony konflikt łączenia związany z konkurencyjnymi zmianami w ci.md.
  4. Rozwiąż konflikt tak, aby w tekście pozostała zarówno nasza lista kroków CI, jak i uwaga na jej temat.
  5. Opublikuj merge commit w zdalnej gałęzi. feature.
  6. Sprawdź status pull requesta w interfejsie użytkownika GitHub, poczekaj, aż konflikt zostanie rozwiązany.

Polecenia

# Убедитесь, что код в локальное ветке `master` обновлён из удалённого репозитория.
git checkout master
git pull

# Переключитесь на ветку feature
git checkout feature

# Инициируйте слияние с веткой master 
git merge master

# A merge conflict related to concurrent changes to ci.md will be reported
# => Auto-merging ci.md
#    CONFLICT (content): Merge conflict in ci.md
#    Automatic merge failed; fix conflicts and then commit the result.

# Разрешите конфликт так, чтобы и наш список шагов CI, и замечание о нем остались в тексте.
# отредактируйте ci.md чтоб он не содержал маркеров конфликта слияния
git add ci.md
git merge --continue
# при коммите можете оставить сообщение по умолчанию

# Опубликуйте коммит слияния в удаленную ветку feature.
git push

# Проверьте статус запроса на изменения в пользовательском интерфейсе GitHub, дождитесь пока слияние не будет разрешено.

Świetna robota!

Zakończyłeś pracę z listą, a teraz musisz zatwierdzić pull request w master.

️ Zadanie: Zatwierdź pull request "Steps review".

  1. Otwórz pull request.
  2. Kliknij "Scal pull request".
  3. Kliknij "Potwierdź scalanie".
  4. Kliknij "Delete branch", ponieważ już jej nie potrzebujemy.

To jest twój repozytorium w tej chwili.
Typowe sytuacje w ciągłej integracji

Błąd na produkcji.

Mówi się, że "testy można wykorzystać, aby pokazać obecność błędów, ale nigdy ich nieobecność". Mimo że mieliśmy testy, które nie wykazały żadnych błędów, podstępny błąd wkradł się do produkcji.

W takim scenariuszu musimy zwrócić uwagę na:

  • to, co jest wdrożone na produkcji;
  • kod w gałęzi master z błędem, od którego deweloperzy mogą rozpocząć nową pracę.

Cofnąć czy naprawić w kolejnej wersji?

"Cofanie" (rolling back) to wdrożenie znanej wersji bezbłędnej w środowisku produkcyjnym i anulowanie (revert) commitów zawierających błąd. "Naprawienie w kolejnej wersji" (fixing forward) to dodanie poprawki do master i jak najszybsze wdrożenie nowej wersji. Ponieważ API i schemy baz danych zmieniają się w miarę wdrażania kodu w środowisku produkcyjnym, przy ciągłej dostawie i dobrym pokryciu testami, cofanie jest zazwyczaj znacznie trudniejsze i bardziej ryzykowne niż naprawienie w kolejnej wersji.

Ponieważ cofanie nie niesie w naszej sytuacji żadnego ryzyka, pójdziemy tą drogą, ponieważ pozwala nam to

  • naprawić błąd na produkcji jak najszybciej;
  • sprawić, że kod w master będzie od razu gotowy do rozpoczęcia nowej pracy.

️ Zadanie

  1. Przełącz się na gałąź master lokalnie.
  2. Zaktualizuj lokalne repozytorium z zdalnego repozytorium.
  3. Cofnij merge commit PR. Kroki przeglądu do master.
  4. Opublikuj zmiany w zdalnym repozytorium.

To jest historia repozytorium z cofniętym merge commit.
Typowe sytuacje w ciągłej integracji

Polecenia

# Переключитесь на ветку master.
git checkout master

# Обновите локальный репозиторий из удалённого репозитория.
git pull

# Отмените коммит слияния PR Steps review в master.
# Мы отменяем коммит слияния, поэтому нам нужно выбрать ветку истории, которую мы захотим оставить
git show HEAD

# предположим, что коммит, который был последним в ветке master до слияния, был отображён предыдущей командой первым
git revert HEAD -m 1
# можете не менять сообщения коммитов

# Опубликуйте изменения в удалённый репозиторий
git push

️ Samoocena.

Upewnij się, że ci.md już nie zawiera tekstu "sneaky bug" po cofnięciu merge commita.

Popraw listę kroków CI i zwróć ją do master.

Całkowicie cofnęliśmy merge commit gałęzi feature. Dobrą wiadomością jest to, że teraz nie mamy błędu w master. Zła wiadomość jest taka, że zniknęła nasza cenna lista kroków ciągłej integracji. Tak więc, w idealnym przypadku, musimy zastosować poprawkę do commitów z feature i przywrócić je do master łącznie z poprawką.

Możemy podejść do zadania na różne sposoby:

  • cofnąć (revert) commit, który cofa scalanie feature z master;
  • przenieść commity z dawnej feature.

Różne zespoły deweloperów stosują różne podejścia w tej sytuacji, my jednak przeniesiemy pożyteczne commity do oddzielnej gałęzi i stworzymy osobny pull request dla tej nowej gałęzi.

️ Zadanie

  1. Utwórz gałąź o nazwie feature-fix i przełącz się na nią.
  2. Przenieś wszystkie commity z dawnej gałęzi feature do nowej gałęzi. Rozwiąż konflikty scalania, które wystąpiły podczas przenoszenia.

    Typowe sytuacje w ciągłej integracji

  3. Dodaj test regresyjny do ci.test.js:

    it('does not contain the sneaky bug', () => {
    expect( /.*sneakys+bug.*/gi.test(fileContents)).toBe(false);
    });

  4. Uruchom testy lokalnie, aby upewnić się, że nie kończą się one pomyślnie.
  5. Usuń tekst " with a sneaky bug" w ci.md.
  6. Dodaj do indeksu zmiany testów oraz zmiany w liście kroków i zakomituj je.
  7. Opublikuj gałąź w zdalnym repozytorium.

Powinieneś mieć coś podobnego
Typowe sytuacje w ciągłej integracji

Polecenia

# Создайте ветку под названием feature-fix и переключитесь на нее.
git checkout -b feature-fix

# Перенесите все коммиты из бывшей ветки feature в новую ветку. Разрешите конфликты слияния, которые возникли при переносе.
# используйте историю чтобы узнать хэши коммитов:
# - предшествующего коммиту с первой частью списка: C0
# - добавляющего последние элементы списка: C2
git log --oneline --graph
git cherry-pick C0..C2
# разрешите конфликты слияния
# - отредактируйте ci.md и/или ci.test.js
# - добавьте файлы в индекс
# - выполните "git cherry-pick --continue", можете не менять сообщение коммита

# Добавьте регрессионный тест в ci.test.js
# Запустите тесты локально, чтобы убедиться, что они не завершаются успешно.

# Удалите текст " with a sneaky bug" в ci.md.

# Добавьте в индекс изменения тестов и в списке шагов и закоммитьте их.
git add ci.md ci.test.js
git commit -m "Fix the bug in steps list"

# Опубликуйте ветку в удалённый репозиторий.
git push --set-upstream origin feature-fix

Utwórz pull request.

Utwórz pull request o tytule Fixing the feature. Ustaw feature-fix jako "head branch", a master jako "gałąź bazową".
Proszę poczekać, aż testy się zakończą. Możesz zobaczyć status testów na dole dyskusji PR.

Upewnij się, że ustawiłeś master w swoim forku repozytorium jako "gałąź bazową", nie będę odpowiadać na prośby o zmiany w repozytorium z materiałami kursu.

Zatwierdź pull request "Fixing the feature"

Dziękuję za poprawienie! Proszę zatwierdzić zmiany w master z pull requestu.

️ Zadanie

  1. Kliknij "Scal pull request".
  2. Kliknij "Potwierdź scalanie".
  3. Kliknij "Delete branch", ponieważ już jej nie potrzebujemy.

To, co powinieneś mieć w tej chwili
Typowe sytuacje w ciągłej integracji

Gratulacje!

Wykonałeś wszystkie kroki, które zwykle wykonują ludzie w procesie ciągłej integracji.

Jeśli zauważyłeś jakiekolwiek problemy z kursem lub masz pomysły, jak go poprawić, stwórz issue w repozytorium materiałów kursu. Ten kurs ma również interaktywną wersję używającą GitHub Learning Lab jako platformy.

Ź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