Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

Вы вывучылі каманды Git але хочаце ўяўляць, як бесперапынная інтэграцыя (Continuous Integration, CI) адбываецца ў рэальнасці? Ці можа вы хочаце аптымізаваць свае штодзённыя дзеянні? Гэты курс дасць вам практычныя навыкі бесперапыннай інтэграцыі з выкарыстаннем рэпазітара на GitHub. Дадзены курс не задуманы як нейкі візард, які можна проста праклікаць, наадварот, вы будзеце здзяйсняць тыя ж дзеянні, што людзі насамрэч робяць на працы, тым жа спосабам, якім яны гэта робяць. Я буду тлумачыць тэорыю па меры праходжання вамі якія маюць да яе стаўленне крокаў.

Што мы будзем рабіць?

Па меры пасоўвання, мы будзем паступова ствараць спіс тыпавых крокаў CI, што ёсць выдатны спосаб запомніць гэты спіс. Іншымі словамі, мы будзем ствараць спіс дзеянняў, якія распрацоўшчыкі здзяйсняюць, ажыццяўляючы бесперапынную інтэграцыю, ажыццяўляючы бесперапынную інтэграцыю. Таксама мы будзем выкарыстоўваць просты набор тэстаў, каб наблізіць наш працэс CI да рэальнага.

Гэты GIF схематычна паказвае коміты ў вашым рэпазітары па меры прасоўвання па курсе. Як бачыце, тут няма нічога складанага і толькі самае неабходнае.

Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

Вы пройдзеце такія стандартныя для CI сцэнары:

  • Праца над фічай;
  • Ужыванне аўтатэстаў для забеспячэння якасці;
  • Рэалізацыя прыярытэтнай задачы;
  • Дазвол канфлікту пры зліцці галін (merge conflict);
  • Узнікненне памылкі ў прадуктыўным асяроддзі.

Што вы даведаецеся?

Вы зможаце адказаць на такія пытанні:

  • Што такое бесперапынная інтэграцыя (CI)?
  • Якія тыпы аўтатэстаў выкарыстоўваюцца пры CI, і ў адказ на якія дзеянні яны запускаюцца?
  • Што такое pull request і калі яны патрэбны?
  • Што такое распрацоўка праз тэсціраванне (Test Driven Development, TDD) і як яна суадносіцца з CI?
  • Ажыццяўляць зліццё (merge) або ўжываць змены па-над (rebase)?
  • Адкочваць або правіць у наступнай версіі?

Я спачатку ўсюды перакладаў штукі тыпу "pull request", але ў выніку вырашыў вярнуць фразы на ангельскай у некаторых месцах каб зменшыць градус утрапёнасці ў тэксце. Я часам буду выкарыстоўваць "праграмісцкі суржык" накшталт цудоўнага дзеяслова "закаміціць" там, дзе людзі насамрэч на працы яго выкарыстоўваюць.

Што такое бесперапынная інтэграцыя?

Бесперапынная інтэграцыя, або CI, гэта тэхнічная практыка, якая заключаецца ў тым, што кожны член каманды інтэгруе свой код у агульны рэпазітар хоць бы раз у дзень, прычым выніковы код пры гэтым павінен хаця б збірацца без памылак.

Існуюць розначытанні з нагоды гэтага тэрміна

Прадметам спрэчкі з'яўляецца частата інтэграцыі. Некаторыя сцвярджаюць, што аб'ядноўваць код толькі раз у дзень недастаткова насамрэч інтэгравацца бесперапынна. У прыклад прыводзіцца каманда, дзе ўсё бяруць свежы код раніцай і інтэгруюцца адзін раз увечар. Хоць гэта і разумнае пярэчанне, усё ж у цэлым лічыцца, што варыянт вызначэння "раз у дзень" дастаткова практычны, канкрэтны, і падыходзіць для каманд розных памераў.

Іншае пярэчанне складаецца ў тым, што C++ даўно не адзіная мова, выкарыстоўваны пры распрацоўцы, і простае патрабаванне зборкі без памылак, як спосаб валідацыі, слабавата. Нейкі набор тэстаў (напрыклад, модульных (unit), выкананых лакальна) таксама павінен завяршыцца паспяхова. У дадзены момант, супольнасць імкнецца да таго, каб такое патрабаванне было абавязковым, і, у будучыні "зборка + модульныя тэсты", мабыць, стане агульнапрынятым, калі гэта ўжо не адбылося.

Бесперапынная інтэграцыя адрозніваецца ад бесперапыннай пастаўкі (Continuous Delivery, CD) тым, што не патрабуе рэліз-кандыдата пасля кожнага цыкла інтэграцыі.

Спіс крокаў, які мы будзем выкарыстоўваць на працягу курса

  1. Pull in the latest code. Create a branch from master. Start working.
  2. Create commits on your new branch. Build and test locally. Pass? Перайдзіце да наступнага кроку. Fail? Fix errors or tests and try again.
  3. Падышоўце да вашай вежы рэпазітары або рачной палачкі.
  4. Create a pull request. Абразкі змяненняў, таму больш мерапрыемствы з'яўляюцца discussion continues. Давайце тэсты pass on feature branch.
  5. Merge/rebase commits from master. Вызначце тэсты прайшлі па меры рэзультату.
  6. Deploy from the feature branch to production.
  7. Калі ўсё гэта добра ў вытворцы для некаторых часоў, змяненне змяненняў у майстар.

Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

️ Падрыхтоўка

Пераканайцеся ў наяўнасці патрэбнага ПЗ

Каб прайсці гэты курс вам спатрэбіцца Node.js и Git-кліент.

Можаце выкарыстоўваць любы Git-кліент, але я буду прыводзіць каманды толькі для каманднага радка.

Пераканайцеся, што ў вас усталяваны Git-кліент, які падтрымлівае камандны радок.

Калі ў вас пакуль не ўсталяваны Git-кліент, які падтрымлівае камандны радок, можаце знайсці інструкцыі па ўсталёўцы тут.

Падрыхтуйце рэпазітар

Вам спатрэбіцца стварыць асабістую копію(fork) рэпазітара-шаблона з кодам для курса на GitHub. Давайце дамовімся называць гэтую асабістую копію рэпазітаром курса.

Зрабілі? Калі вы не мянялі налады па змаўчанні, ваш рэпазітар курса хутчэй за ўсё называецца continuous-integration-team-scenarios-students, ён знаходзіцца ў вашым акаўнце на GitHub, і URL выглядае так

https://github.com/<ваше имя ползователя на GitHub>/continuous-integration-team-scenarios-students

Я буду называць гэты адрас проста <URL репозитория>.

Кутнія дужкі як <тут> будуць азначаць, што вы павінны замяніць такі выраз на адпаведнае значэнне.

Пераканайцеся, што GitHub actions уключаны для дадзенага рэпазітара курса. Калі яны не будуць уключаны, калі ласка, уключыце іх, націснуўшы на вялікую кнопку ў сярэдзіне старонкі, на якую вы можаце патрапіць, клікнуўшы Actions у інтэрфейсе GitHub.

У вас не атрымаецца прайсці курс, прытрымліваюся маім інструкцыям, калі GitHub Actions не будуць уключаны.

Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

Вы заўсёды можаце выкарыстоўваць здольнасць GitHub адлюстроўваць Markdown каб убачыць бягучы стан спісу, які мы складаем, тут

https://github.com/<your GitHub user name>/continuous-integration-team-scenarios-students/blob/master/ci.md

Пра адказы

Хоць лепшы спосаб завяршыць гэты курс - гэта рабіць усё сваімі рукамі, у вас могуць і ўзнікнуць складанасці.

Калі вы адчуваеце, што не разумееце што рабіць і не можаце працягваць, можаце падглядзець у галінку solution, якая ёсць у вашым стартавым рэпазітары.
Калі ласка, не здзяйсняйце зліццё solution в master падчас курса. Вы можаце выкарыстоўваць гэтую галінку каб разабрацца, што рабіць, або каб параўноўваць свой код з аўтарскім, выкарыстоўваючы ўсе магчымасці, якія дае нам Git. Калі вы зусім згубіліся, можаце цалкам замяніць сваю галінку master на галінку solution і затым скінуць сваю працоўную дырэкторыю да таго кроку курса, які вам патрэбен.

Выкарыстоўвайце гэта толькі калі вам гэта сапраўды трэба

Закамміцьце(commit) свой код

git add .
git commit -m "Backing up my work"

Гэтыя каманды

  • пераназываюць master в master-backup;
  • пераназываюць solution в master;
  • перамыкаюць(checkout) на новую галінку master і перапісваюць змесціва працоўнай дырэкторыі;
  • ствараюць галінку "solution" з "master" (якая раней была "solution") на выпадак, калі вам у будучыні спатрэбіцца галінка "solution".

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

Пасля гэтых дзеянняў вы можаце выкарыстоўваць git log master каб высветліць, які коміт вам патрэбен.
Вы можаце скінуць сваю працоўную дырэкторыю на гэты коміт так:

git reset --hard <the SHA you need>

Калі вы задаволены вынікам, у нейкі момант вам спатрэбіцца апублікаваць вашу версій рэпазітара ў выдалены рэпазітар (remote). Не забудзьцеся відавочна паказаць выдаленую галінку калі будзеце гэта рабіць.

git push --force origin master

Калі ласка, звярніце ўвагу, што мы выкарыстоўваем git push --force. Ці наўрад вы часта захочаце так паступаць, але ў нас тут вельмі спецыфічны сцэнар з адным карыстачом рэпазітара, які ў дадатак, разумее, што ён робіць.

Starting working

Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

Пачнём складаць наш спіс крокаў CI. Звычайна вы пачынаеце гэты крок з вымання апошняй версіі кода з выдаленага рэпазітара, але ў нас яшчэ няма лакальнага рэпазітара, таму замест гэтага мы клануем яго з выдаленага.

️ Заданне: абнавіце лакальны рэпазітар, стварыце галінку з master, пачніце працаваць

  1. Клануйце рэпазітар курса з <URL репозитория>.
  2. запусціце npm install у каталогу рэпазітара курса; ён патрэбен нам для ўстаноўкі Jest, які мы выкарыстоўваем для запуску тэстаў.
  3. Стварыце галінку і назавіце яе feature. Пераключыцеся на гэтую галінку.
  4. Дадайце тэставы код у ci.test.js паміж каментарамі з просьбай зрабіць гэта.

    it('1. pull latest code', () => {
      expect(/.*pull.*/ig.test(fileContents)).toBe(true);
    });
    
    it('2. add commits', () => {
      expect(/.*commit.*/ig.test(fileContents)).toBe(true);
    });
    
    it('3. push to the remote branch with the same name', () => {
      expect(/.*push.*/ig.test(fileContents)).toBe(true);
    });
    
    it('4. create a pull request and continue working', () => {
      expect(/.*pulls+request.*/ig.test(fileContents)).toBe(true);
    });

  5. Дадайце тэкст з першымі 4 крокамі ў файл ci.md.
    1. Pull in the latest code. Create a branch from `master`. Start working.    
    2. Create commits on your new branch. Build and test locally.  
    Pass? Go to the next step. Fail? Fix errors or tests and try again.  
    3. Push to your remote repository or remote branch.  
    4. Create a pull request. Discuss the changes, add more commits  
    as discussion continues. Make tests pass on the feature branch.  

    каманды

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

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

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

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

Стварайце коміты ў новай галінцы, ажыццяўляйце зборку і тэсціраванне лакальна.

Мы збіраемся наладзіць тэсты, каб яны запускаліся перад комітам, а затым закамміціць код.

Тыпавыя сцэнары, калі тэсты запускаюцца аўтаматычна

  • Лакальна:
    • Пастаянна або ў адказ на адпаведныя змены кода;
    • Пры захаванні (для інтэрпрэтаваных або JIT-кампіляваных моў);
    • Пры зборцы (калі патрабуецца кампіляцыя);
    • Пры коміце;
    • Пры публікацыі ў агульны рэпазітар.

  • На серверы зборкі (build server) або ў асяроддзі зборкі:
    • Калі код публікуецца ў персанальную галінку / рэпазітар.
    • Тэстуецца код у гэтай галінцы.
    • Тэстуецца патэнцыйны вынік зліцця (звычайна з master).
    • У якасці этапу бесперапыннай інтэграцыі/канвеера бесперапыннай пастаўкі

Як правіла, чым хутчэй выконваецца набор тэстаў, тым гушчару вы можаце дазволіць сабе яго запускаць. Тыповае размеркаванне па этапах можа выглядаць так.

  • Хуткія модульныя тэсты - пры зборцы, у канвееры CI
  • Павольныя модульныя тэсты, хуткія кампанентныя і інтэграцыйныя тэсты - пры коміце, у канвееры CI
  • Павольныя кампанентныя і інтэграцыйныя тэсты - у канвееры CI
  • Тэставанне бяспекі, нагрузачнае і іншыя працяглыя ці дарагія тэсты - у канвеерах CI/CD, але толькі ў вызначаных рэжымах/этапах/канвеерах зборкі, напрыклад, пры падрыхтоўцы рэліз-кандыдата або пры запуску ўручную.

️ Заданне

Я прапаную спачатку запусціць тэсты ўручную, выкарыстоўваючы каманду npm test. Пасля гэтага давайце дадамо git hook для запуску нашых тэстаў пры комiте. Ёсць адна загваздка: Git hooks не лічацца часткай рэпазітара і таму не могуць быць кланаваныя з GitHub разам з астатнімі матэрыяламі курса. Каб усталяваць hook, вам трэба запусціць install_hook.sh ці скапіяваць файл repo/hooks/pre-commit у лакальны каталог .git/hooks/.
Пры коміце вы ўбачыце, што выконваюцца тэсты, і яны правяраюць, ці прысутнічаюць у спісе пэўныя ключавыя словы.

  1. Запусціце тэсты ўручную, выканаўшы каманду npm test у тэчцы рэпазітара вашага курса. Пераканайцеся, што тэсты былі выкананы.
  2. Усталюйце hook на коміт (pre-commit hook), запусціўшы install_hook.sh.
  3. Закамміцьце змены ў лакальны рэпазітар.
  4. Упэўніцеся, што тэсты выконваюцца перад комітам.

Ваш рэпазітар павінен выглядаць так пасля выканання гэтых дзеянняў.
Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

каманды

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

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

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

Апублікуйце код у выдалены рэпазітар або выдаленую галінку

Завяршыўшы працаваць лакальна, распрацоўшчыкі звычайна робяць свой код агульнадаступным, каб яго можна было ў канчатковым выніку інтэграваць з агульным. З дапамогай GitHub гэта звычайна дасягаецца публікацыяй працы альбо ў персанальнай копіі рэпазітара (personal fork, форк), альбо ў асабістай галінцы.

  • Пры выкарыстанні форкаў распрацоўнік клануе выдалены агульны рэпазітар, ствараючы яго асабістую выдаленую копію, таксама вядомую як форк. Пасля гэтага ён клануе гэты асабісты рэпазітар, каб працаваць з ім лакальна. Калі праца завершана і коміты створаны, ён змяшчае іх у свой форк, дзе яны даступныя іншым і могуць быць інтэграваныя ў агульны рэпазітар. Гэты падыход звычайна выкарыстоўваецца ў праектах з адчыненым зыходным кодам на GitHub. Ён таксама выкарыстоўваецца ў маім пашыраным курсе [Team Work and CI with Git] (http://devops.redpill.solutions/).
  • Іншы падыход складаецца ў тым, каб выкарыстоўваць толькі адзін выдалены рэпазітар і лічыць толькі галінку master сумесна выкарыстоўванага рэпазітара "абароненай". У гэтым сцэнары асобныя распрацоўшчыкі публікуюць свой код у галінкі выдаленага рэпазітара, каб іншыя маглі гэты код паглядзець, калі ўсё ў парадку, аб'яднаць з master агульнага рэпазітара.

У гэтым канкрэтным курсе мы будзем выкарыстоўваць працоўны працэс, які выкарыстоўвае галінкі.

Давайце апублікуем наш код.

️ Заданне

  • Апублікуйце змены ў выдаленую галіну з тым жа імем, што і ваша працоўная галінка

каманды

git push --set-upstream origin feature

Стварыце pull request

Стварыце pull request з назвай Steps review. Усталюйце feature як "head branch" і master як "base branch".

Пераканайцеся, што вы ўстанавілі master у сваім форцы рэпазітара у якасці "base branch", я не буду адказваць на запыты на змены ў рэпазітар з матэрыяламі курса.

На слэнгу GitHub "base branch" - гэта галінка, на якой вы засноўваеце сваю працу, а "head branch" - гэта галінка, якая змяшчае прапанаваныя змены.

Абмяркуйце змены, дадайце новыя коміты па меры працягу абмеркавання

Pull request(PR)

Pull request(PR) - Гэта спосаб абмеркаваць і задакументаваць код, а таксама правесці праверку (code review) кода. Pull request названы ў гонар агульнага спосабу інтэграцыі асобных змен у агульны код. Звычайна чалавек клануе выдалены афіцыйны рэпазітар праекта і працуе над кодам лакальна. Пасля гэтага ён змяшчае код у свой асабісты выдалены рэпазітар і просіць адказных за афіцыйны рэпазітар забраць(цягнуць) яго код у свае лакальныя рэпазітары, дзе яны праглядаюць і, магчыма, інтэгруюць(зліццё) яго. Гэтае паняцце вядома і пад іншымі назвамі, напрыклад, merge request.

Насамрэч вам не абавязкова выкарыстоўваць функцыю pull request GitHub ці аналагічных платформаў. Каманды распрацоўшчыкаў могуць выкарыстоўваць іншыя спосабы сувязі, уключаючы асабістыя зносіны, галасавыя званкі ці электронную пошту, але ёсць усё ж шэраг прычын выкарыстоўваць такія pull requests у стылі абмеркавання на форуме. Вось некаторыя з іх:

  • арганізаваныя абмеркаванні, звязаныя з канкрэтнымі зменамі ў кодзе;
  • як месца для прагляду водгукаў аб незавершанай працы як ад аўтатэстаў, так і ад калег;
  • фармалізацыя праверак кода;
  • каб пазней можна было высветліць прычыны і меркаванні, якія стаяць за тым ці іншым фрагментам кода.

Звычайна вы ствараеце pull request калі вам трэба нешта абмеркаваць ці атрымаць зваротную сувязь. Напрыклад, калі вы працуеце над функцыяй, якая можа быць рэалізавана некалькімі спосабамі, вы можаце стварыць запыт на занясенне змен яшчэ да напісання першага радка кода, каб падзяліцца сваімі ідэямі і абгаварыць свае планы з суаўтарамі. Калі праца прасцейшая, pull request адкрываецца, калі нешта ўжо зроблена, зафіксавана і можа быць абмеркавана. У некаторых сцэнарах вы можаце адкрыць PR толькі з меркаванняў кантролю якасці: каб запусціць аўтаматычныя тэсты або ініцыяваць праверку кода. Што б вы ні вырашылі, не забывайце @згадваць людзей, ухвала якіх патрабуецца ў вашым pull request'е.

Звычайна пры стварэнні PR вы робіце наступнае.

  • Указваеце, што вы прапануеце змяніць і дзе.
  • Пішаце апісанне, якое тлумачыць мэту змен. Вы можаце захацець:
    • дадаць што-небудзь важнае, што не з'яўляецца відавочным з кода, ці што-небудзь карыснае для разумення кантэксту, напрыклад адпаведныя #багі і нумары коммітаў;
    • @згадаць усіх, з кім хочаце пачаць працаваць разам, ці вы можаце @згадаць іх у каментарах пазней;
    • папрасіць калегаў дапамагчы з чымсьці ці праверыць штосьці канкрэтнае.

Пасля таго як вы адкрыеце PR, выконваюцца тэсты, настроеныя для запуску ў такіх выпадках. У нашым выпадку гэта будзе той самы набор тэстаў, які мы запускалі лакальна, але ў рэальным праекце могуць быць дадатковыя тэсты і праверкі.

Калі ласка, пачакайце, пакуль завершацца тэсты. Вы можаце ўбачыць статут тэстаў у ніжняй частцы абмеркавання PR у інтэрфейсе GitHub. Працягвайце калі тэсты будуць завершаны.

️ Дадайце заўвагу аб адвольнасці спісу крокаў CI

Спіс, выкарыстаны ў гэтым курсе, з'яўляецца адвольным і суб'ектыўным, мы павінны дадаць заўвагу аб гэтым.

️ Заданне: стварэнне pull request для дадзенага заўвагі

  1. Пераключыцеся на галінку master.
  2. Стварыце галінку з імем bugfix.
  3. Дадайце тэкст нататкі ў канец файла ci.md.
    > **GitHub flow** is sometimes used as a nickname to refer to a flavor of trunk-based development  
    when code is deployed straight from feature branches. This list is just an interpretation  
    that I use in my [DevOps courses](http://redpill.solutions).  
    The official tutorial is [here](https://guides.github.com/introduction/flow/).
  4. Закамміцьце змены.
  5. Апублікуйце галінку bugfix у выдалены рэпазітар.
  6. Стварыце pull request з імем Adding a remark з галаўной галінкай bugfix і базавай галінкайmaster.

Пераканайцеся, што вы ўстанавілі master у сваім форцы рэпазітара у якасці "base branch", я не буду адказваць на запыты на змены ў рэпазітар з матэрыяламі курса.

Вось як павінен выглядаць ваш рэпазітар.
Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

каманды

# Переключитесь на ветку 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 как описано выше

Зацвердзіце pull request "Adding a remark"

️ Заданне

  1. Стварыце pull request.
  2. Націсніце "Merge pull request".
  3. Націсніце "Confirm merge".
  4. Націсніце "Delete branch", яна нам больш не патрэбна.

Гэта дыяграма комітаў пасля зліцця.
Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

️ Працягвайце працаваць і дадаваць тэсты

Сумесная праца над pull request часта прыводзіць да неабходнасці дадатковай працы. Звычайна гэта вынік праверкі кода або абмеркавання, але ў нашым курсе мы збіраемся змадэляваць гэта, дадаўшы новыя элементы ў наш спіс крокаў CI.

Пры бесперапыннай інтэграцыі звычайна ўжываецца некаторае тэставае пакрыццё. Патрабаванні да пакрыцця тэстамі адрозніваюцца і звычайна знаходзяцца ў дакуменце з назвай кшталту „кіраўніцтва для аўтараў” (contribution guidelines). Мы паступім проста і дадамо па тэсце для кожнага радка ў нашым кантрольным спісе.

Пры выкананні заданняў спачатку паспрабуйце закамаміціць тэсты. Калі вы правільна ўсталявалі pre-commit hook раней, толькі што дададзены тэст будзе запушчаны, не будзе пройдзены, і нічога не будзе закаммічана. Звярніце ўвагу: дык мы даведаемся, што нашы тэсты сапраўды нешта правяраюць. Цікаўна, што калі б мы пачалі з кода да тэстаў, праходжанне тэстаў магло азначаць альбо тое, што код працуе так, як чакалася, альбо што тэсты насамрэч нічога не правяраюць. Акрамя таго, калі б мы не напісалі тэсты ў першую чаргу, мы маглі б зусім іх забыцца, паколькі нішто не нагадвала б нам пра гэта.

Распрацоўка праз тэсціраванне (TDD)

TDD раіць пісаць тэсты перад кодам. Звычайны працэс працы з выкарыстаннем TDD выглядае так.

  1. Дадайце тэст.
  2. Запусціце ўсе тэсты і пераканайцеся, што новы тэст не праходзіць паспяхова.
  3. Напішыце код.
  4. Запусціце тэсты, упэўніцеся, што ўсе тэсты праходзяць паспяхова.
  5. Правядзіце рэфактарынг кода.
  6. Паўтарыце.

Паколькі вынікі працы тэстаў, якія не былі пройдзеныя паспяхова, звычайна адлюстроўваецца чырвоным, а выкананыя паспяхова - зялёным, цыкл таксама вядомы як "чырвоны-зялёны-рэфактарынг" (red-green-refactor).

️ Заданне

Спачатку паспрабуйце закаміціць тэсты і даць ім завяршыцца няўдала, затым дадайце і закаміце сам тэкст спісу крокаў CI. Вы ўбачыце, што тэсты праходзяць ("зялёныя").
Затым апублікуйце новы код у выдалены рэпазітар і паглядзіце, як выконваюцца тэсты ў інтэрфейсе GitHub у ніжняй частцы абмеркавання запыту на занясенне змен, і абнаўляецца статут PR.

  1. Пераключыцеся на галінку feature.
  2. Дадайце гэтыя тэсты ў ci.test.js пасля апошняга выкліку it (...);.

    it('5. Merge/rebase commits from master. Make tests pass on the merge result.', () => {
      expect(/.*merge.*commits.*testss+pass.*/ig.test(fileContents)).toBe(true);
    });
    
    it('6. Deploy from the feature branch to production.', () => {
      expect(/.*Deploy.*tos+production.*/ig.test(fileContents)).toBe(true);
    });
    
    it('7. If everything is good in production for some period of time, merge changes to master.', () => {
      expect(/.*merge.*tos+master.*/ig.test(fileContents)).toBe(true);
    });

  3. Паспрабуйце закамаміціць тэсты. Калі pre-commit hook усталяваны, спроба коміту завершыцца памылкай.
  4. Пасля дадайце гэты тэкст у ci.md.
    5. Merge/rebase commits from master. Make tests pass on the merge result.  
    6. Deploy from the feature branch with a sneaky bug to production.
    7. If everything is good in production for some period of time, merge changes to master. 
  5. Унясіце і закамміцьце змены лакальна.
  6. Апублікуйце змены ў галінку feature.

Цяпер у вас павінна атрымацца нешта накшталт гэтага
Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

каманды


# Переключительна ветку 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

Канфлікт зліцця

Перайдзіце да запыту на ўнясенне змен Steps review.

Нягледзячы на ​​тое, што мы не зрабілі нічога дрэннага, і тэсты для нашага кода прайшлі паспяхова, мы ўсё яшчэ не можам ажыццявіць зліццё галінкі. feature и master. Гэта таму, што іншая галінка bugfix была аб'яднана з master пакуль мы працавалі над гэтым PR.
Гэта стварае сітуацыю, калі выдаленая галінка master мае навейшую версію, чым тая, на якой мы засноўвалі галінку feature. З-за гэтага мы не можам проста пераматаць HEAD master да канца галінкі feature. У гэтай сітуацыі нам трэба або ажыццявіць зліццё(merge), або прымяніць коміты. feature па-над(rebase) master. GitHub на самой справе можа выконваць аўтаматычнае зліццё, калі няма канфліктаў. Нажаль, у нашай сітуацыі абедзве галінкі маюць канкуруючыя змены ў файле. ci.md. Гэтая сітуацыя вядомая як канфлікт пры зліцці (merge conflict), і нам трэба вырашыць яе ўручную.

Merge ці rebase

Зліццё

  • Стварае дадатковы комміт зліцця (merge commit) і захоўвае гісторыю працы.
    • Захоўвае зыходныя коміты галінак з зыходнымі адзнакамі часу і аўтарамі.
    • Захоўвае SHA комітаў і спасылкі на іх у абмеркаваннях запытаў на змены.
  • Патрабуе аднаразовага вырашэння канфліктаў.
  • Робіць гісторыю нелінейнай.
    • Гісторыю можа быць цяжка чытаць з-за вялікай колькасці галінак (нагадвае кабель IDE).
    • Ускладняе аўтаматычную адладку, напрыклад, робіць git bisect менш карысным - ён толькі знойдзе коміт зліцця.

База дадзеных

  • Прайгравае коміты з бягучай галінкі па-над базавай адзін за адным.
    • Фармуюцца новыя коміты з новымі SHA, у выніку чаго коміты ў GitHub суадносяцца з зыходнымі pull requests, але не з адпаведнымі каментарамі.
    • Каміты могуць быць рэкамбінаваны і зменены ў працэсе або нават аб'яднаны ў адзін.
  • Можа спатрэбіцца вырашыць некалькі канфліктаў.
  • Дазваляе падтрымліваць лінейную гісторыю.
    • Гісторыю можа быць прасцей чытаць, калі толькі яна не з'яўляецца занадта доўгай без разумных на тое прычын.
    • Аўтаматычная адладка і ўхіленне непаладак некалькі прасцей: робіць магчымым git bisect, можа зрабіць аўтаматычныя адкаты больш выразнымі і прадказальнымі.
  • Патрабуецца публікацыі галіны з перанесенымі комітамі са сцягам. --force пры выкарыстанні з запытамі на ўнясенне змен.

Звычайна каманды згаджаюцца заўсёды выкарыстоўваць адну і тую ж стратэгію, калі ім трэба аб'ядноўваць змены. Гэта можа быць "чыстае" зліццё або "чысты" ужыванне комітаў па-над ці нешта прамежкавае, напрыклад, выкананне ўжыванне комітаў па-над інтэрактыўным рэжыме(git rebase -i) лакальна для галінак, не апублікаваных у агульным рэпазітары, але зліццё(merge) для "агульнадаступных" галінак.

Тут мы будзем выкарыстоўваць зліццё.

️ Заданне

  1. Пераканайцеся, што код у лакальнай галінцы master абноўлены з выдаленага рэпазітара.
  2. Пераключыцеся на галінку feature.
  3. Ініцыюйце зліццё з галінкай master. Будзе паведамлена аб канфлікце зліцця, звязаным з канкуруючымі зменамі ў ci.md.
  4. Дазвольце канфлікт так, каб у тэксце застаўся і наш спіс крокаў CI, і заўвага аб ім.
  5. Апублікуйце коміт зліцця ў выдаленую галінку feature.
  6. Праверце статут pull request'а ў карыстацкім інтэрфейсе GitHub, дачакайцеся пакуль зліццё не будзе дазволенае.

каманды

# Убедитесь, что код в локальное ветке `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, дождитесь пока слияние не будет разрешено.

Выдатная праца!

Вы скончылі працу са спісам, і зараз вам трэба зацвердзіць pull request у master.

️ Заданне: Зацвердзіце pull request "Steps review"

  1. Адкрыйце pull request.
  2. Націсніце "Merge pull request".
  3. Націсніце "Confirm merge".
  4. Націсніце "Delete branch", бо яна нам больш не патрэбна.

Гэта ваш рэпазітар у дадзены момант
Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

Памылка на прадукты

Кажуць, што "тэставанне можна выкарыстоўваць, каб паказаць наяўнасць памылак, але ніколі каб паказаць іх адсутнасць". Нягледзячы на ​​тое, што ў нас былі тэсты, і яны не паказалі нам ніякіх памылак, падступная памылка пракралася ў прадакшн.

У падобным сцэнары нам трэба паклапаціцца аб:

  • тым, што разгорнута на прадуктыве;
  • кодзе ў галінцы master з памылкай, з якога распрацоўшчыкі могуць пачынаць новую працу.

Адкочваць ці выпраўляць у наступнай версіі?

"Адкачванне"(rolling back) — гэтае разгортванне загадзя спраўнай больш ранняй версіі ў прадуктыўнае асяроддзе і адмена(revert) комітаў, утрымоўвальных памылку. "Выпраўленне ў наступнай версіі"(fixing forward) — гэта даданне выпраўлення ў master і разгортванне новай версіі як мага хутчэй. Паколькі API і схемы баз дадзеных змяняюцца па меры разгортвання кода ў вытворчым асяроддзі, пры бесперапыннай пастаўцы і наяўнасці добрага пакрыцця тэстамі, адкочванне, як правіла, нашмат складаней і рызыкоўней, чым выпраўленне ў наступнай версіі.

Паколькі адкочванне не нясе ў нашым выпадку ніякай рызыкі, мы пойдзем гэтым шляхам, бо гэта дазваляе нам

  • выправіць памылку на прадуктыве як мага хутчэй;
  • зрабіць код у master адразу прыдатным для пачатку новай працы.

️ Заданне

  1. Пераключыцеся на галінку master лакальна.
  2. Абнавіце лакальны рэпазітар з выдаленага рэпазітара.
  3. Адмяніце коміт зліцця PR Steps review в master.
  4. Апублікаваць змены ў выдалены рэпазітар.

Гэта гісторыя рэпазітара з адмененым комітам зліцця
Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

каманды

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

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

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

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

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

️ Самаправерка

Пераканайцеся, што ci.md больш не змяшчае тэксту "sneaky bug" пасля адмены комміта зліцця.

Выправіць спіс крокаў CI і вярнуць яго ў master

Мы цалкам адмянілі коміт зліцця галінкі feature. Добрая навіна ў тым, што зараз у нас няма памылкі ў master. Дрэнная навіна ў тым, што знік і наш каштоўны спіс крокаў бесперапыннай інтэграцыі. Такім чынам, у ідэале, нам трэба прымяніць выпраўленне да комітаў з feature і вярнуць іх у master разам з выпраўленьнем.

Мы можам падысці да задачы па-рознаму:

  • адмяніць(revert) коміт, якая адмяняе зліццё feature с master;
  • перанесці коміты з былой feature.

Розныя каманды распрацоўнікаў у дадзеным выпадку выкарыстоўваюць розныя падыходы, мы ж перанясём карысныя коміты ў асобную галіну і створым асобны pull request для гэтай новай галінкі.

️ Заданне

  1. Стварыце галінку пад назвай feature-fix і пераключыцеся на яе.
  2. Перанясіце ўсе коміты з былой галінкі feature у новую галінку. Дазвольце канфлікты зліцця, якія ўзніклі пры пераносе.

    Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

  3. Дадайце рэгрэсійны тэст у ci.test.js:

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

  4. Запусціце тэсты лакальна, каб пераканацца, што яны не завяршаюцца паспяхова.
  5. Выдаліце ​​тэкст " with a sneaky bug" у ci.md.
  6. Дадайце ў індэкс змены тэстаў і змены ў спісе крокаў і закаміць іх.
  7. Апублікуйце галінку ў выдалены рэпазітар.

У вас у выніку павінна атрымацца нешта падобнае
Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

каманды

# Создайте ветку под названием 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

Стварыце pull request.

Стварыце pull request з назвай Fixing the feature. Усталюйце feature-fix як "head branch", а master як "base branch".
Калі ласка, пачакайце, пакуль скончацца тэсты. Вы можаце ўбачыць статут тэстаў у ніжняй частцы абмеркавання PR.

Пераканайцеся, што вы ўстанавілі master у сваім форцы рэпазітара у якасці "base branch", я не буду адказваць на запыты на змены ў рэпазітар з матэрыяламі курса.

Зацвердзіце pull request "Fixing the feature"

Дзякуй за выпраўленне! Калі ласка, зацвердзіце змены ў master з pull request.

️ Заданне

  1. Націсніце "Merge pull request".
  2. Націсніце "Confirm merge".
  3. Націсніце "Delete branch", бо яна нам больш не патрэбна.

Гэта тое, што ў вас павінна быць у дадзены момант
Тыпавыя сітуацыі пры бесперапыннай інтэграцыі

Віншую!

Вы выканалі ўсе дзеянні, якія людзі звычайна здзяйсняюць падчас бесперапыннай інтэграцыі.

Калі вы заўважылі якія-небудзь праблемы з курсам ці ведаеце як яго палепшыць, стварыце issue у рэпазітары з матэрыяламі курса. У гэтага курса таксама ёсць інтэрактыўная версія якая выкарыстоўвае GitHub Learning Lab у якасці платформы.

Крыніца: habr.com

Дадаць каментар