Přejít k navigační liště

Zdroják » PHP » GitLab jako Continuous Integration (nejen) pro PHP

GitLab jako Continuous Integration (nejen) pro PHP

Články PHP

V článku si ukážeme, jak kromě hostování a správy git repositářů můžeme GitLab používat pro CI (Continuous Integration). Zajímavé na něm je, že na rozdíl od konkurence to nabízí i v hostované verzi zadarmo.

Znáte GitLab? Dlouho jsem si myslel, že to je jen nástroj pro pohodlnější správu git repositářů na vlastním serveru. Už to dávno není pravda, teď je to celá platforma pro řízení vývoje. Kromě hostování git repositáře umí issues a merge requesty pro code review. Jako nejdůležitější součást bych vyzdvihl integrované CI (Continuous Integration), které je podobné TravisCI. Ale na rozdíl od něj je zadarmo i pro private repositáře. Tím je odbouraný další důvod, proč na menších projektech nepoužívat CI.

GitLab nabízí tři varianty:

  1. hostovanou na Gitlab.com – zdarma neomezeně private repositářů, uživatelů a CI buildů (+možnost objednání lepšího supportu)
  2. self-hosted community edition (open-source)
  3. placenou Enterprise variantu (self-hosted), která navíc obsahuje další integrace a vychytávky pro větší týmy

Nám bude stačit ta první, tedy hostovaná varianta – funguje podobně jako GitHub, ale má navíc právě CI.

Continuous Integration

Jen stručně, co Continuous Integration (CI) je:

Kontinuální integrace je technika používaná při vývoji software, kdy členové týmu integrují svůj kód často, obvykle aspoň jednou za den, což vede k mnoha integracím každý den. Každá integrace je ověřena automatickým sestavením (včetně testů), aby byly případné problémy objeveny co nejdříve. Mnoho týmů zjistilo, že tento přístup vede k výraznému snížení problémů při integraci a umožňuje jim rychleji dodávat
kvalitnější software.

Přeloženo z článku Continuous Integration od Martina Fowlera

Zjednodušeně řečeno, pokud používáte branche a rebase před merge (což je vlastně integrace změn z masteru do vaší branche), tak se to budete snažit dělat co nejčastěji a průběžně budete spouštět testy a automatizované kontroly.

Jak vše nastavit?

Výhodou CI serveru je, že spouští build automaticky pro každou změnu (v tomto případě pro každý merge request nebo push do repositáře), takže se nestane, že by na to někdo mohl zapomenout. Aby bylo co spouštět, potřebujeme nejdříve build skript, který spustí různé nástroje – php lint, PHPUnit, kontrolu coding standards apod.

V článku vás provedu nastavením CI buildu na GitLabu pro PHP aplikaci. V první polovině článku se zaměřím na samotný build skript, který je na CI serveru nezávislý. V druhé polovině článku vám předvedu nastavení GitLab CI, které použije předtím vytvořený build skript.

Vytvoření build scriptu

Pro vytvoření build scriptu použijeme scripts přímo z Composeru. Pro komplexnější skripty můžete zvolit Phing, ale na začátku bych doporučoval dát šanci skriptům v Composeru. (Koneckonců v JS světě se teď také vracejí od buildovacích nástrojů Gulp/Grunt zpátky k npm skriptům.)

Nejjednodušší skript může vypadat nějak takto (předpokládá, že máme vytvořený phpunit.xml.dist s konfigurací PHPUnitu, aby ho šlo spouštět jen příkazem vendor/bin/phpunit):

{
    "require-dev": {
        "phpunit/phpunit": "5.6.1"
    },
    "scripts": {
        "test": "phpunit"
    }
}

A pokud zavoláme composer test (případně composer run-script test, pokud by se název skriptu překrýval s nativním příkazem Composeru), spustí se dle očekávání PHPUnit.

Pozn.: Composer automaticky přidá do cesty adresář vendor/bin/ takže ho není potřeba do příkazů vypisovat.

V dalším kroku si přidáme kontrolu coding standards:

{
    "require-dev": {
        ...
        "squizlabs/php_codesniffer": "2.7.1",
    },
    "scripts": {
        ...
        "phpcs": "phpcs --standard=PSR2 src tests"
    }
}

Jak jste se už jistě dovtípili, tak kontrolu můžeme zavolat pomocí composer phpcs.

Síla skriptů v Composeru je v možnosti volat je navzájem pomocí @. Vytvoříme tedy meta příkaz, který bude volat ostatní dva:

{
    "scripts": {
        "build": [
            "@test",
            "@phpcs"
        ],
        ...
    }
}

A composer build spustí jak testy, tak kontrolu coding standards.

Ještě se mi osvědčilo přidat si do buildu i volání composer install, aby build vždy proběhl se správnými verzemi balíčků. Výsledný build skript může vypadat následovně:

{
    "scripts": {
        "build": [
            "@composer install --no-progress --no-interaction --no-suggest",
            "@test",
            "@phpcs"
        ],
        "test": "phpunit",
        "phpcs": "phpcs --standard=PSR2 src tests"
    }
}

Při každém spuštění composer build se sice dozvíme, jestli testy a kontrola coding standards procházejí, ale nemáme jistotu, že na to některý vývojář nezapomene. A tady přichází ke slovu CI server, v našem případě GitlabCI.

Za domácí úkol doporučuji na začátek buildu přidat ještě PHP Parallel Lint, který kontroluje zda .php soubory jsou vůbec validní.

Nastavení buildu na GitlabCI

Registrací na GitLabu, vytvořením projektu a souvisejícími úkoly se tu zabývat nebudu, neměl by v tom být žádný problém. Pustíme se rovnou do konfigurace CI.

Pro konfiguraci se používá soubor .gitlab-ci.yml v rootu projektu, který v minimalistické podobě může vypadat takto:

image: geertw/docker-php-ci:7.0

my_app:
  script:
    - composer build

První řádek říká, na jakém image se build spustí (můžeme použít jakýkoliv image z Docker Hubu). Dále máme zapsaný úkol my_app, pro který se spustí příkaz composer build (proč je to takhle krkolomněji na dalším řádku, uvidíme později).

V GitLabu není potřeba nic nastavovat, pokud pushnete branch se souborem .gitlab-ci.yml, spustí se build automaticky. Detaily najdete v projektu na GitLabu v záložce Pipelines. Pokud se vám povede spustit tento skript, tak už máte vyhráno – dále už tu konfiguraci budeme jen vylepšovat.

Tip: Pro kontrolu validity konfigurace můžete použít jejich linter (je potřeba být přihlášen). Výhodou je, že nemusíte špinit git historii a čekat na failnutí buildu.

Výběr image a konfigurace

Nevybral jsem oficiální image s čistým PHP, ale jiný, který už je připravený pro použití v GitLabCI – obsahuje navíc git, Composer a některá rozšíření. Ještě místo geertw/docker-php-ci:7.0, který je v ukázce, může být vhodnější použít geertw/docker-php-ci:7.0-no-xdebug`, který mu tam před několika dny poslal Tomáš Fejfar. Pokud nepotřebujete sbírat code coverage z testů,  Xdebug nedává v CI smysl a jen bude build zpomalovat.

(V oficiální dokumentaci ukazují postup instalace závislostí do základního image v rámci buildu, což v během mého testování klidně minutu nebo dvě přidalo. Proto používám odlišný postup – už hotový image.)

Pokud pro svůj projekt máte specifické požadavky na rozšíření nebo nainstalované aplikace, tak vám nic nebrání vytvořit vlastní image a používat ten. Nicméně to už přesahuje rozsah článku, třeba se tématu chopí někdo povolanější.

Pokud se vám nechce vytvářet vlastní image a v rámci buildu potřebujete něco nastavit, tak je možné použít hook before_script. Pro ukázku jsem do něj přidal jen příkaz na vypsání verze PHP, což se nám bude hodit později. Jen pozor, že pokud budete něco instalovat v každém buildu, tak to zbytečně prodlouží jeho běh.

before_script:
  - php -v

Kde vlastně buildy běží? GitLab se domluvil s DigitalOcean a ten mu zadarmo poskytujete VPS pro běh buildů. (Případně by mělo být možné přidat vlastní VPS, ale to jsem nezkoušel.)

Spouštění na různých verzích PHP

Pokud potřebujete build spouštět na různých verzích PHP (ať už proto, že musíte podporovat i starší verze, nebo naopak chystáte přechod na novou), tak to v GitLabCI není problém. Stačí upravit konfiguraci takto (a odebrat původní image:):

my_app:5.6:
  image: geertw/docker-php-ci:5.6-no-xdebug
  script:
    - composer build

my_app:7.0:
  image: geertw/docker-php-ci:7.0-no-xdebug
  script:
    - composer build

Build se automaticky spustí na obou image.

Cachování

Zbytečně mnoho času stráví build na stahování závislostí přes Composer. Lze to snadno vylepšit pomocí nastavení cachování vybraných adresářů (v případě Composeru to bude vendor).

cache:
  paths:
    - vendor/

Po úspěšném buildu se vybraný adresář uloží mimo Docker container a při příštím běhu je obnoven. Přináší to docela znatelné zrychlení, tak to určitě nevynechejte.

Services

Pokud budete v rámci buildu potřebovat jakoukoliv další aplikaci (databázi, Redis, cokoliv), tak se to řeší prostřednictvím tzv. services – k hlavnímu kontejneru můžete napojit libovolné další.

Například pro MySQL by to vypadalo takto:

services:
  - mysql:latest

variables:
  # Configure mysql environment variables (https://hub.docker.com/r/_/mysql/)
  MYSQL_DATABASE: zdrojak_demo
  MYSQL_ROOT_PASSWORD: super_secure_password

mysql:latest říká, že chceme použít oficiální image pro MySQL v poslední verzi. Dále pak nastavíme konfigurační proměnné pro konkrétní image. Obdobně si můžeme nastavit jakoukoliv další service (tzn. připojit si jakýkoliv image).

Výsledek

Výsledná konfigurace .gitlab-ci.yml pro buildování aplikace, která pro testy potřebuje MySQL databázi, může vypadat takto:

before_script:
  - php -v

services:
  - mysql:latest

variables:
  MYSQL_DATABASE: "zdrojak_demo"
  MYSQL_ROOT_PASSWORD: "123456"

my_app:5.6:
  image: geertw/docker-php-ci:5.6-no-xdebug
  script:
    - composer build

my_app:7.0:
  image: geertw/docker-php-ci:7.0-no-xdebug
  script:
    - composer build

cache:
  paths:
    - vendor/

Závěr

Pro mě osobně je GitLab a jejich CI překvapení a své miniprojekty, které mám aktuálně na Bitbucketu bez CI, začnu postupně převádět na Gitlab a nastavovat k nim CI. A samozřejmě se nemusíte omezovat jen na projekty v PHP.

Teď už opravdu nevidím žádný důvod, proč CI nepoužívat. Pokud na nějaký přijdete, tak vám ho v komentářích rád zkusím vyvrátit. Případně vám pomohu s nastavením buildu.

Komentáře

Subscribe
Upozornit na
guest
17 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Kamil

Mě by se i líbil, jen ta jeho rozežranost se mi nezdá. 4GB RAM? Jakože na git!?

MichalKleiner

Díky za zajímavý článek.

Bitbucket nedávno spustil https://bitbucket.org/product/features/pipelines, předpokládám, že jde v podstatě o totéž. Má někdo zkušenost?

Jarda

Mam zkusenost, zkousel jsem to pred casem. Bylo to docela slozite rozchodit, ale nakonec to funguje v pohode. Nemuzes na to mit prilis velke naroky. Obcas potrebuju spoustet nejake buildy v navaznosti na jine a obcas mam i jinak slozite triggery a eventy, coz se moc od Pipelines neda ocekavat. Na jednoduche veci typu: push, testy, deploy to ale funguje dobre.

Jirka Ďoubek

Vypadá to hezky, akorát v mezičase podobné Pipelines implementoval i Bitbucket, takže se stačí mrknout na jejich nastavení (co jsem se díval na GitLabCI soubor, tak je to hodně podobné) a nemusíte vlastně nic migrovat :-)

maryo

Super. Škoda, že jsme nedávno nastavili bitbucket + wercker. Nebo teda neni to asi škoda :-). Taky zadarmo. Docela by mě zajímaly zkušenosti z obou.

zvedavec

Vdaka za zlanok, gitlab je naozaj lakavy.

Uz spominany Bitbucket + wercker pouzivam taktiez a celkom mi vyhovuje. Plus bitpucket poslednu dobu zavadza Pipelines co je nieco ako plugin system, cize sa da integrovat s viacerymi rozlicnymi sluzbami.

Co sa stane v pripade ze nastane chyba?
Chapem to spravne, ze workflow funguje nasledovne:
vytvoris pull request, ten sa zvaliduje, nasledne spravca cez web UI uvidi ze CI to oznacilo za ok, tak sa to mergne do main branche?

Ako by si nastavil CI + automaticky deploy bez rucnych kontrol? Teda ak niekto commitne a CI zbehne bez chyby, tak aby sa to automatickly merglo a nasledne deploylo?

Drobnost:
PHP_CodeSniffer verzia 2.7.1 neexistuje. posledna verzia z vetvy 2 je 2.7.0

frees

Vdaka za super clanok, mam vsak jeden dotaz. Ako riesite cely tento buildovaci proces v pripade ze sa aplikacia nahrava na jednoduchy php hosting ktory ma len ftp a nic viac? Mate po ruke nejaky dalsi dodatocny server ktory ma rovnake nastavenia ako ostre ftp kde sa to cele zbuildi otestuje a potom sa to len 1:1 preklopi alebo sa to ma riesit nejakym inym sposobom? Ide to cele zautomatizovat ze sa tenťo zbuildeny projekt rovno aj nahra na konkretne ostre ftp?

Vojta Svoboda

Lze nějak zapsat konfiguraci CI, které se vztahuje ke konkrétní branch? Aby se deploy na produkci provedl pouze při změně v master branch a deploy na stage se spustil při změně v beta branch?

lenoch

Jsem lama, ale uz jsem cosi zaslechl o CI i dockeru. Mame tady nainstalovany gitlab lokalne na nasem serveru a chci se zeptat, jestli ten navod plati i pro tuto situaci.
Musi se tam zprovoznit docker, nebo to jde i bez dockeru, popripade vubec nejde a je nutne pouzit gitlab.com?

(Mam urcite zbrany nahravat firemni zdrojaky na gitlab.com, i kdyz je mozne pouzit privatni repository)

Martin

Ano CI je stejne pro vsechny verze Gitlabu.
Samotny job Gitlab CI jde sestavit pouze z command line prikazu. Jestli se to bude zpracovavat primo nebo pres docker zalezi na uzivateli.
Rozdil v self-hsoted variante je ze si proste urcite kde a na kolika strojich build probehne a mate je plne pod kontrolou.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.