Cvičení: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14.

Na posledním cvičení shrneme znalosti ze všech dosud probraných témat. Začneme nástroji systému sestavení, které nám umožňují zachytit - a kodifikovat - proces sestavení, a pak se podíváme, jak lze nastavit GitLab, aby pravidelně kontroloval náš kód a udržoval tak náš projekt zdravý.

Průběžný příklad

Naposledy se vrátíme k našemu příkladu generování webových stránek a použijeme jej jako průběžný příklad pro toto cvičení.

Opět použijeme jednodušší verzi, která vypadala takto:

#!/bin/bash

set -ueo pipefail

pandoc --template template.html index.md >index.html
pandoc --template template.html rules.md >rules.html
./table.py <score.csv | pandoc --template template.html --metadata title="Score" - >score.html

Všimněte si, že pro index a rules máme Markdown soubory, ze kterých vytvoříme HTML. Stránka score je generována z CSV souboru.

Příprava

Prosím, vytvořte fork repozitáře s webem, abyste si mohli příklady sami vyzkoušet.

Motivace pro používání systémů sestavení

V našem příkladu je celý web sestaven v několika krocích, kdy jsou stránky HTML generovány z různých zdrojů. To je vlastně velmi podobné tomu, jak se software sestavuje ze zdrojových kódů (uvažujme zdrojové kódy v jazyce C, které se kompilují a linkují dohromady).

Zatímco výše uvedené kroky nevytvoří spustitelný soubor (což je typický případ pro vývoj softwaru), reprezentují obvyklý scénář.

Sestavení softwaru se obvykle skládá z mnoha kroků, které zahrnují tak odlišné činnosti jako třeba:

  • kompilace zdrojáků do nějakého meziformátu
  • linkování výsledné binárky
  • vytvoření bitmapové grafiky v různém rozlišení z jediného vektorového obrázku
  • generování dokumentace ze zdrojového kódu
  • příprava souborů pro lokalizaci (překlad)
  • vytvoření samorozbalujícího archívu
  • nahrání softwaru na webový server
  • zveřejnění artefaktu v repozitáři balíčků

Skoro všechny jsou vlastně hrozně jednoduché. Složité je poskládat je dohromady. To jest, jak je spustit ve správném pořadí a jak spustit jednotlivé programy se správnými parametry (volbami).

Například, než může být vytvořen instalátor, musí být nachystané všechny ostatní soubory. Soubory pro překlad obvykle závisí na předzpracování nějakých zdrojových souborů, ale musí být nachystány než je vytvořena výsledná binárka. Atd.

I pro malé projekty může být množství kroků poměrně velké. Ale jsou – svým způsobem – nezajímavé: nechcete si je pamatovat. Chcete ten software sestavit!

Všimněte si, že vám s tím vším často pomůže vaše IDE — jediným kliknutím. Ne každý však používá stejné IDE a možná dokonce grafické rozhraní vůbec nemáte.

Kromě toho chcete obvykle spustit sestavení jako součást každé revize — typickým příkladem jsou pipeline GitLabu, které používáme pro testy: spouštějí se bez grafického rozhraní, přesto chceme software sestavit (a také otestovat). Kodifikace tohoto postupu ve skriptu sestavení to zjednodušuje prakticky pro každého.

Náš výše zmíněný skript build.sh je vlastně docela pěkný. Je snadno pochopitelný, neobsahuje žádnou složitou logiku a nový člen týmu nemusí zkoumat všechny drobné detaily a může prostě spustit jediný skript build.sh.

Skript je v pohodě, ale zbytečně přepisuje soubory i když nedošlo ke změně. V našem malém příkladu to nevadí (konec konců, počítač máme dost rychlý).

Ale ve větším projektu, kde bychom pracovali s tisícovkami souborů (klidně se podívejte na zdrojáky Linuxového jádra, Firefoxu nebo LibreOffice) je to velký rozdíl. Pokud se vstupní soubor nezměnil (třeba jsme změnili jen rules.md) nemusíme přetvářet ostatní soubory (nemusíme znovu vytvářet index.html).

Trochu teď skript rozšíříme.

...

should_generate() {
    local barename="$1"
    if ! [ -e "${barename}.html" ]; then
        return 0
    fi
    if [ "${barename}.md" -nt "${barename}.html" ]; then
        return 0
    else
        return 1
    fi
}

...

should_generate index && pandoc --template template.html index.md >index.html
should_generate rules && pandoc --template template.html rules.md >rules.html

...

Tohle můžeme udělat pro každý příkaz a zrychlíme tím vytváření webu.

Ale.

To je dost práce. A pravděpodobně by ušetřený čas by promrhán přepisováním našeho skriptu. Nemluvě o tom, že výsledek je děsivý. A dost náročný na údržbu.

Často také potřebujeme sestavit jen část projektu: např. jen vygenerovat dokumentaci (bez dalšího zveřejnění, třeba). Ačkoliv rozšíření skriptu tímto způsobem je možné, pro velké projekty to nebude fungovat dobře.

if [ -z "$1" ]; then
    ... # build here
elif [ "${1:-}" = "clean" ]; then
    rm -f index.html rules.html score.html
elif [ "${1:-}" = "publish" ]; then
    cp index.html rules.html score.html /var/www/web-page/
else
    ...

Naštěstí je tu lepší cesta.

Existují speciální nástroje zvané build systémy (česky možná také nástroje pro řízení překladu/sestavení) které mají jediný účel: koordinovat proces sestavení. Uživateli dávají vysokoúrovňový jazyk, ve kterém může zachytit výše zmíněné kroky pro sestavení softwaru.

V tomto cvičení se zaměříme na make. make je poměrně starý systém, ale pořád je hojně používán. Je to také jeden z nejjednodušších nástrojů z této kategorie: hodně toho musíte připravit ručně, ale pro vysvětlení principů je to perfektní. Budeme mít plnou moc nad celým procesem a uvidíte, co se všechno děje.

make

Nejprve se přesuňte do kořenového adresáře (lokálního klonu vašeho forku) repozitáře příkladu s webem.

Soubory v tomto adresáři jsou prakticky stejné jako v našem shellovém skriptu výše, ale je zde jeden soubor navíc: Makefile. Všimněte si, že Makefile je napsán s velkým M, aby byl snadno rozlišitelný (ls v nelokalizovaném nastavení řadí velká písmena jako první).

Tento soubor je řídicím souborem pro sestavovací systém make, který dělá přesně to, co jsme se snažili napodobit v předchozím příkladu. Obsahuje posloupnost pravidel pro sestavování souborů.

K přesné syntaxi pravidel se dostaneme brzy, ale nejprve si s nimi pojďme pohrát. Spusťte následující příkaz:

make

Zobrazí se následující výstup (pokud jste už některé příkazy provedli ručně, může se výstup lišit):

pandoc --template template.html index.md >index.html
pandoc --template template.html rules.md >rules.html

make vypíše příkazy, které provede, a spustí je. Vytvořil pro nás webové stránky: všimněte si, že byly vygenerovány soubory HTML.

Soubor version.inc.html prozatím vůbec negenerujeme.

Spusťte znovu make.

make: Nothing to be done for 'all'.

Jak vidíte, make byl dost chytrý na to, aby rozpoznal, že vzhledem k tomu, že se žádný soubor nezměnil, není třeba nic spouštět.

Aktualizujte soubor index.md (funguje i touch index.md) a znovu spusťte make. Všimněte si, že soubor index.html byl znovu sestaven, zatímco soubor rules.html zůstal nedotčen.

pandoc --template template.html index.md >index.html

Tomuto postupu se říká inkrementální sestavení (sestavujeme pouze to, co bylo potřeba, místo abychom sestavovali vše od začátku).

Jak jsme uvedli výše: v našem malém příkladu to není příliš zajímavé. Jakmile však budou vstupních souborů tisíce, rozdíl bude obrovský.

Je také možné spustit make index.html a požádat o přestavbu pouze index.html. Sestavení je opět inkrementální.

Pokud si přejete vynutit sestavení, spusťte make s -B. Často se tomu říká nepodmíněné sestavení.

Jinými slovy, make nám umožňuje zachytit jednotlivé jednoduché příkazy potřebné pro sestavení projektu (bez ohledu na to, zda kompilujeme a linkujeme programy v jazyce C nebo generujeme webovou stránku) do uceleného skriptu.

Přestavuje pouze věci, které je třeba přestavět, a co je zajímavější, bere v potaz závislosti. Například pokud se scores.html generuje z scores.md, který se sestavuje z scores.csv, stačí zadat, jak se má sestavit scores.md z scores.csv a jak se má vytvořit scores.html z scores.md, a make zajistí správné pořadí.

vysvětlení formátu Makefile

Makefile je řídicí soubor pro systém sestavování s názvem make. V podstatě se jedná o jazyk specifický pro danou doménu (domain-specific language), který zjednodušuje nastavení skriptu bez nutnosti funkceshould_generate, kterou jsme zmínili výše.

Na rozdíl od většiny programovacích jazyků make rozlišuje tabulátory a mezery. Veškeré odsazení v souboru Makefile musí být provedeno pomocí tabulátorů. Musíte se ujistit, že váš editor nenahrazuje tabulátory na mezery. To je také častý problém při kopírování kusů kódu z webového prohlížeče.

(Obvykle váš editor rozpozná, že Makefile je speciální název souboru, a sám se přepne na politiku pouze tabulátory.) Pokud místo toho použijete mezery, obvykle se zobrazí chyba typu Makefile:LINE_NUMBER: *** missing separator. Stop..

Soubor Makefile obsahuje posloupnost pravidel. Pravidlo vypadá takto:

rules.html: rules.md template.html
      pandoc --template template.html rules.md >rules.html

Název před dvojtečkou je cíl pravidla. Obvykle je to název souboru, který chceme vytvořit. Zde je to rules.html.

Zbytek prvního řádku je seznam závislostí – souborů, ze kterých je cíl sestaven. V našem příkladu jsou závislostmi soubory rules.md a template.html. Jinými slovy: když se tyto soubory (rules.md a template.html) změní, musíme znovu sestavit rules.html.

Třetí částí jsou následující řádky, které musí být odsazeny tabulátorem. Obsahují příkazy, které je třeba provést, aby byl cíl sestaven. Zde je to volání příkazu pandoc.

make spustí příkazy, pokud je cíl zastaralý. To znamená, že buď chybí cílový soubor, nebo je jedna či více závislostí novější než cíl.

Zbytek souboru Makefile je podobný. Jsou zde pravidla pro další soubory a také několik speciálních pravidel.

Speciální pravidla

Speciální pravidla jsou all, clean a .PHONY. Neurčují soubory, které mají být sestaveny, ale spíše speciální akce.

all je tradiční název pro první pravidlo v souboru. Říká se mu výchozí pravidlo a je použito, pokud spustíte make bez argumentů. Obvykle nemá žádné příkazy a závisí na všech souborech, které by měly být sestaveny jako výchozí.

clean je speciální pravidlo, které obsahuje pouze příkazy, ale žádné závislosti. Jeho účelem je odstranit všechny vygenerované soubory, pokud chcete vyčistit svůj pracovní prostor. Obvykle clean odstraní všechny soubory, které nejsou verzovány (tj. nejsou pod kontrolou systému Git).

To lze považovat za nesprávné použití programu make, které má však dlouhou tradici. Z pohledu make jsou cíle all a clean stále považovány za názvy souborů. Pokud vytvoříte soubor s názvem clean, speciální pravidlo přestane fungovat, protože cíl bude považován za aktuální (existuje a žádná závislost není novější).

Chcete-li se této pasti vyhnout, měli byste výslovně říci make, že cílem není soubor. To se provede tak, že jej uvedete jako závislost speciálního cíle .PHONY (všimněte si úvodní tečky).

Obecně je vidět, že make má spoustu zvláštností. Často je to tak u programů, které začaly jako jednoduchý nástroj a prošly si 40 lety postupného vývoje, kdy pomalu přibývaly funkce. Přesto je to jeden z nejpoužívanějších build systémů. Často také slouží jako back-end pro pokročilejší nástroje — ty vygenerují Makefile z přívětivější specifikace a delegují práci na make.

Cvičení

Rozšiřte soubor Makefile o volání generovacího skriptu pro stránku score.html. Nezapomeňte aktualizovat pravidla all a clean.

Solution.

Podadresář out/ je prázdný (obsahuje pouze soubor .gitignore, který určuje, že všechny soubory v tomto adresáři budou systémem Git ignorovány a nebudou tedy zobrazeny v git status).

Aktualizujte Makefile pro generování souborů do tohoto adresáře. Důvody jsou zřejmé:

  • Vygenerované soubory nezaneřádí váš pracovní adresář (stejně z nich nechcete dělat commit).
  • Při synchronizaci s webovým serverem můžeme zadat celý adresář, který má být zkopírován (místo zadávání jednotlivých souborů).

Solution.

Přidejte speciální (.PHONY) cíl upload, který zkopíruje vygenerované soubory na počítač v Rotundě. Vytvořte si tam (ručně) adresář ~/WWW. Jeho obsah bude dostupný jako http://www.ms.mff.cuni.cz/~LOGIN/.

Poznamenejme, že je třeba přidat potřebná oprávnění souborového systému AFS pomocí příkazu fs setacl (vizte cvičení 08).

Solution.

Přidejte generování PDF z rules.md (pomocí LibreOffice). Všimněte si, že soffice podporuje parametr --outdir.

Zamyslete se nad následujícím:

  • Kam umístit mezisoubor ODT?
  • Má být pro generování souboru ODT vytvořeno zvláštní pravidlo, nebo má být provedeno jediným pravidlem se dvěma příkazy?

Solution.

Zlepšení udržovatelnosti souboru Makefile

Soubor Makefile začíná obsahovat příliš mnoho opakujícího se kódu.

Ale i s tím vám může make pomoci.

Odstraňme všechna pravidla pro generování out/*.html z *.md a nahraďme jej tímto pravidlem:

out/%.html: %.md template.html
      pandoc --template template.html -o $@ $<

To je vzorové pravidlo (pattern rule), které zachycuje myšlenku, že HTML je generováno z Markdown. Znak procenta ve specifikaci závislostí a cíle představuje tzv. stem — proměnlivou (tj. měnící se) část vzoru.

V příkazové části používáme proměnné make. Proměnné make začínají na dolar jako v shellu, ale nejsou stejné.

$@ je skutečný cíl a $< je první závislost.

Spusťte make clean && make a ověřte, zda se web generuje i při použití vzorových pravidel.

Kromě vzorových pravidel rozumí make také (uživatelským) proměnným. Ty mohou zlepšit čitelnost, protože můžete oddělit konfiguraci od příkazů. Například:

PAGES = \
      out/index.html \
      out/rules.html \
      out/score.html

all: $(PAGES) ...
...

Všimněte si, že na rozdíl od shellu jsou proměnné expandovány pomocí $(VAR) konstrukcí. (S výjimkou speciálních proměnných, jako je $<.)

Nepřenositelná rozšíření

make je velmi starý nástroj, který existuje v mnoha různých implementacích. Dosud zmíněné funkce by měly fungovat s jakoukoli verzí make. (Přinejmenším s přiměřeně nedávnou verzí. Staré verze make neměly .PHONY ani vzorová pravidla.)

Poslední doplněk bude fungovat pouze v GNU make (ale ten je v Linuxu výchozí, takže by s ním neměl být žádný problém).

Soubor Makefile změníme takto:

PAGES = \
      index \
      rules \
      score

PAGES_TMP=$(addsuffix .html, $(PAGES))
PAGES_HTML=$(addprefix out/, $(PAGES_TMP))

Uchováváme pouze základní název každé stránky a počítáme výstupní cestu. $(addsuffix ...) a $(addprefix ...) jsou volání vestavěných funkcí. Formálně jsou všechny argumenty funkcí řetězce, ale v tomto případě jsou jména oddělená čárkami považována za seznam.

Všimněte si, že jsme přidali PAGES_TMP pouze pro zlepšení čitelnosti při prvním použití této vlastnosti. Za normálních okolností byste do PAGES_HTML přiřazovali přímo toto.

PAGES_HTML=$(addprefix out/, $(addsuffix .html, $(PAGES)))

To bude ještě užitečnější, až budeme chtít pro každou stránku vygenerovat také soubor PDF. Můžeme přidat vzorové pravidlo a vytvořit seznam PDF pomocí $(addsuffix .pdf, $(PAGES)).

GitLab CI

Pokud jste ještě nikdy neslyšeli pojem kontinuální integrace (Continuous Integration — CI), pak je to v kostce následující.

O kontinuální integraci

Abyste zajistili, že software, který vytváříte, je ve zdravém stavu, měli byste na něm často provádět testy a co nejdříve opravovat nefunkční věci (protože náklady na opravu chyb dramaticky rostou s každým dnem, kdy nejsou odhaleny).

To znamená, že vývojář musí při každé revizi spustit testy. Protože je obtížné to vynutit, je lepší to dělat automaticky. CI ve své nejjednodušší podobě označuje stav, kdy se automatické testy (např. na bázi BATS nebo Pythonu) provádějí automaticky po každém odeslání (push), např. po odeslání změn v libovolné větvi do GitLabu.

CI však dokáže mnohem víc: pokud testy projdou, posloupnost příkazů (pipeline) může software zabalit a publikovat jako artefakt (např. jako instalační program). Nebo může spustit úlohu pro nasazení do produkčního prostředí a zpřístupnit jej zákazníkům. A tak dále.

Toto se často označuje jako CI/CD, což znamená kontinuální integrace a kontinuální dodávka (nebo nasazení).

Nastavení CI na GitLabu

V tomto cvičení uvidíte, jak si nastavit GitLab CI podle vašich potřeb.

Důležité je vědět, že GitLab CI může běžet nad Podmanovými kontejnery. Takže pro nastavení GitLabové pipeline si vyberete obraz pro Podman a příkazy, které je potřeba v takovém kontejneru spustit. GitLab pak vytvoří daný kontejner a spustí v něm vaše příkazy.

Podle výsledku celého skriptu (tj. jeho exit kódu) pak označí buď pipeline jako procházející nebo selhanou.

Vzpomeňte si na úkol 12/test-in-alpine.txt: ten byl vlastně přípravou na CI.

V tomto kurzu se zaměříme na nejjednodušší konfiguraci, kdy chceme provádět testy po každé revizi. GitLab lze nakonfigurovat i pro složitější úlohy, kdy lze software dokonce nasadit na virtuální cloudový stroj, ale to je bohužel mimo náš rozsah.

Pokud vás toto téma zajímá, GitLab má rozsáhlou dokumentaci. Dokumentace je často hustě zaplněna množstvím informací, ale je skvělým zdrojem znalostí nejen o GitLabu, ale o mnoha principech softwarového inženýrství obecně.

.gitlab-ci.yml

Konfigurace GitLab CI je uložena v souboru .gitlab-ci.yml, který musí být uložen v kořenovém adresáři projektu.

Očekáváme, že máte vlastní fork webového úložiště a že jste rozšířili původní soubor Makefile.

Nyní nastavíme úlohu CI, která sestaví pouze web. Bude to ta nejzákladnější CI, jakou si lze představit. Ale alespoň zajistí, že web bude vždy v sestavitelném stavu.

Pro urychlení však z našeho Makefile odstraníme generování PDF, protože instalace OpenOffice vyžaduje stažení 400 MB, což je pro každou revizi poměrně hodně.

image: fedora:37

build:
  script:
    - dnf install -y make pandoc
    - make

Určuje úlohu pipeline build (tento název se zobrazí ve webovém uživatelském rozhraní), která se spustí pomocí obrazu fedora a provede dva příkazy. První nainstaluje závislost a druhý spustí make.

Nepoužíváme Alpine, protože instalace Pandocu do Alpine je trochu složitější. Vyžaduje, abychom ji buď nainstalovali prostřednictvím nástrojů pro správu balíčků programovacího jazyka Haskell, nebo abychom si stáhli předpřipravenou statickou binárku.

Přidejte soubor .gitlab-ci.yml do svého úložiště Git (tj. do svého forku), odevzdejte jej (commit) a odešlete (push).

Pokud otevřete stránku projektu na webu GitLabu, měla by se vedle ní zobrazit ikona pipeline, která by měla nakonec zezelenat.

Log by pravděpodobně vypadal takto.

Running with gitlab-runner 15.11.0 (436955cb)
  on gitlab.mff docker Mtt-jvRo, system ID: s_7f0691b32461
Preparing the "docker" executor 00:03
Using Docker executor with image fedora:37 ...
Pulling docker image fedora:37 ...
Using docker image sha256:34354ac2c458e89615b558a15cefe1441dd6cb0fc92401e3a39a7b7012519123 for fedora:37 with digest fedora@sha256:e3012fe03ccee2d37a7940c4c105fb240cbb566bf228c609d9b510c9582061e0 ...
Preparing environment 00:00
Running on runner-mtt-jvro-project-11023-concurrent-0 via gitlab-runner...
Getting source from Git repository 00:01
Fetching changes with git depth set to 20...
Reinitialized existing Git repository in /builds/horkv6am/nswi-177-web/.git/
Checking out 58653aa3 as detached HEAD (ref is master)...
Removing out/index.html
Removing out/main.css
Removing out/rules.html
Removing out/score.html
Removing tmp/
Skipping Git submodules setup
Executing "step_script" stage of the job script 00:33
Using docker image sha256:34354ac2c458e89615b558a15cefe1441dd6cb0fc92401e3a39a7b7012519123 for fedora:37 with digest fedora@sha256:e3012fe03ccee2d37a7940c4c105fb240cbb566bf228c609d9b510c9582061e0 ...
$ dnf install -y make pandoc
Fedora 37 - x86_64                               43 MB/s |  82 MB     00:01
Fedora 37 openh264 (From Cisco) - x86_64        4.3 kB/s | 2.5 kB     00:00
Fedora Modular 37 - x86_64                       17 MB/s | 3.8 MB     00:00
Fedora 37 - x86_64 - Updates                     24 MB/s |  29 MB     00:01
Fedora Modular 37 - x86_64 - Updates            4.8 MB/s | 2.9 MB     00:00
Dependencies resolved.
================================================================================
 Package              Architecture  Version                 Repository     Size
================================================================================
Installing:
 make                 x86_64        1:4.3-11.fc37           fedora        542 k
 pandoc               x86_64        2.14.0.3-18.fc37        fedora         21 M
Installing dependencies:
 gc                   x86_64        8.0.6-4.fc37            fedora        103 k
 guile22              x86_64        2.2.7-6.fc37            fedora        6.5 M
 libtool-ltdl         x86_64        2.4.7-2.fc37            fedora         37 k
 pandoc-common        noarch        2.14.0.3-18.fc37        fedora        472 k
Transaction Summary
================================================================================
Install  6 Packages
Total download size: 29 M
Installed size: 204 M
Downloading Packages:
(1/6): libtool-ltdl-2.4.7-2.fc37.x86_64.rpm     846 kB/s |  37 kB     00:00
(2/6): make-4.3-11.fc37.x86_64.rpm              9.4 MB/s | 542 kB     00:00
(3/6): gc-8.0.6-4.fc37.x86_64.rpm               595 kB/s | 103 kB     00:00
(4/6): pandoc-common-2.14.0.3-18.fc37.noarch.rp 8.4 MB/s | 472 kB     00:00
(5/6): guile22-2.2.7-6.fc37.x86_64.rpm           18 MB/s | 6.5 MB     00:00
(6/6): pandoc-2.14.0.3-18.fc37.x86_64.rpm        56 MB/s |  21 MB     00:00
--------------------------------------------------------------------------------
Total                                            51 MB/s |  29 MB     00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1
  Installing       : pandoc-common-2.14.0.3-18.fc37.noarch                  1/6
  Installing       : libtool-ltdl-2.4.7-2.fc37.x86_64                       2/6
  Installing       : gc-8.0.6-4.fc37.x86_64                                 3/6
  Installing       : guile22-2.2.7-6.fc37.x86_64                            4/6
  Installing       : make-1:4.3-11.fc37.x86_64                              5/6
  Installing       : pandoc-2.14.0.3-18.fc37.x86_64                         6/6
  Running scriptlet: pandoc-2.14.0.3-18.fc37.x86_64                         6/6
  Verifying        : gc-8.0.6-4.fc37.x86_64                                 1/6
  Verifying        : guile22-2.2.7-6.fc37.x86_64                            2/6
  Verifying        : libtool-ltdl-2.4.7-2.fc37.x86_64                       3/6
  Verifying        : make-1:4.3-11.fc37.x86_64                              4/6
  Verifying        : pandoc-2.14.0.3-18.fc37.x86_64                         5/6
  Verifying        : pandoc-common-2.14.0.3-18.fc37.noarch                  6/6
Installed:
  gc-8.0.6-4.fc37.x86_64               guile22-2.2.7-6.fc37.x86_64
  libtool-ltdl-2.4.7-2.fc37.x86_64     make-1:4.3-11.fc37.x86_64
  pandoc-2.14.0.3-18.fc37.x86_64       pandoc-common-2.14.0.3-18.fc37.noarch
Complete!
$ make
pandoc --template template.html -o out/index.html index.md
pandoc --template template.html -o out/rules.html rules.md
./table.py <score.csv | pandoc --template template.html --metadata title="Score" - >out/score.html
cp main.css out/
Cleaning up project directory and file based variables 00:01
Job succeeded

Všimněte si, že GitLab nejprve připojí úložiště Git do kontejneru a poté provede příkazy uvnitř klonu. Příkazy se provádějí pomocí set -e: první neúspěšný příkaz ukončí celou pipeline.

Pokuste se emulovat výše uvedený běh lokálně. Hint. Solution.

Cvičení

Balíček aspell poskytuje nástroj pro kontrolu pravopisu, který lze použít z příkazového řádku.

Příkaz aspell list --master en čte standardní vstup a všechna slova s překlepy vypisuje na standardní výstup.

Rozšiřte svůj projekt web a zkontrolujte, zda se ve zdrojových stránkách nevyskytují překlepy.

Přidejte do GitLabu vlastní pipeline, která kontroluje, zda jako shebang nikdy nepoužíváte /usr/bin/python.

Hint.

Solution.

Další drobnosti

Všimněte si, jak je použití pipeline GitLab snadné. Najdete správný obraz (image), zadáte skript a GitLab se postará o zbytek.

Od této chvíle by měl mít každý Váš projekt vytvořený na GitLabu pipeline, která spustí testy (včetně Shellcheck, Pylint atd.). Nastavte ji TEĎ pro své úkoly v jiných předmětech. Nastavte si ji pro svůj ročníkový projekt (NPRG045) v příštím roce. Využijte možnosti nechat si pravidelně testovat svůj kód. Z dlouhodobého hlediska vám to ušetří čas.

Pokud si nejste jisti, který obraz zvolit, oficiální obrazy jsou dobrým začátkem. Skript může mít několik kroků, ve kterých před spuštěním programu nainstalujete chybějící závislosti.

Připomeňme, že nemusíte vytvářet virtuální prostředí: celý počítač je váš (a bude stejně odstraněn), takže můžete instalovat věci globálně. Vzpomeňte si na výše uvedený příklad, kdy jsme provedli pip install bez spuštění virtuálního prostředí.

Může být definováno více úloh, které jsou spouštěny paralelně (ve skutečnosti mezi nimi mohou existovat poměrně složité závislosti, ale v následujícím příkladu jsou všechny úlohy spuštěny najednou).

Následující příklad ukazuje fragment souboru .gitlab-ci.yml, který testuje projekt na více verzích jazyka Python.

# Default image if no other is specified
image: python:3.10

stages:
  - test

# Commands executed before each "script" section (for any job)
before_script:
    # To have a quick check that the version is correct
    - python3 --version
    # Install the project
    - python3 -m pip install ...

# Run unit tests under different versions
unittests3.7:
  stage: test
  image: "python:3.7"
  script:
    - pytest --log-level debug tests/

unittests3.8:
  stage: test
  image: "python:3.8"
  script:
    - pytest --log-level debug tests/

unittests3.9:
  stage: test
  image: "python:3.9"
  script:
    - pytest --log-level debug tests/

unittests3.10:
  stage: test
  image: "python:3.10"
  script:
    - pytest --log-level debug tests/

Úlohy před cvičením (deadline: začátek vašeho cvičení, týden 15. května – 19. května)

Následující úlohy musí být vyřešeny a odevzdány před příchodem na vaše cvičení. Pokud máte cvičení ve středu v 10.40, soubory musí být nahrány do vašeho projektu (repozitáře) na GitLabu nejpozději ve středu v 10.39.

Pro virtuální cvičení je deadline úterý 9:00 (každý týden, vždy ráno, bez ohledu na možné státní svátky apod.).

Všechny úlohy (pokud není explicitně uvedeno jinak) musí být odevzdány přes váš repozitář na úkoly. Pro většinu úloh existují automatické testy, které vám mohou pomoci zkontrolovat úplnost vašeho řešení (zde je popsáno jak číst jejich výsledky).

14/web/Makefile (100 bodů, skupina devel)

AKTUALIZACE

Prosím, přesuňte vaše řešení do 14/web aby nedocházelo ke konfliktům s úlohami po cvičení. Pokud jste již vaše řešení commitnuli, následující příkazy by ho měly přesunout (nezapomeňte změny commitnout).

git mv 14 14-web
mkdir -p 14/
git mv 14-web 14/web

K některým částem jsme přidali dovysvětlení, tyto části jsou zvýrazněné.

Kvůli výše uvedenému posouváme deadline cca o dva na 9.00 ráno. Pokud chodíte na cvičení v pondělí 15.40, podíváme se na stav vašeho repozitáře ve středu v 9.00. Věříme, že to je dostatek času navíc soubory přesunout.

Tato úloha rozšíří průběžný příklad, který jsme použili na tomto cvičení.

Následující jste již provedli (ale je to také součástí hodnocení tohoto úkolu):

  1. Generujte soubory index.html a rules.html z příslušných souborů *.md.
  2. Vygenerované soubory uložte do podadresáře out/.
  3. cíl clean odstraní všechny soubory v adresáři out/ (kromě souboru .gitignore).

Jako novou funkci očekáváme, že příklad rozšíříte o následující:

  1. Přesuňte zdrojové soubory do podadresáře src/. Toto je povinná část, bez tohoto přesunu nebude žádný z testů fungovat. Očekáváme, že soubory přesunute ručně, tj. ne během buildu. Cílem je trochu pročistit adresářovou strukturu. Takže byste měli mít commitnutý soubor 14/web/src/index.md ve vašem repozitáři.

  2. Generujte stránky ze souborů *.csv. Ze score.csv se již generuje soubor score.html. Předpokládáme, že přidáte soubory group-a.csv a group-b.csv, ze kterých se generují group-a.html a group-b.html (pomocí skriptu table.py jako pro score.csv). Soubory group-a.html a group-b.html by měly být vytvořeny automaticky.

  3. Generujte stránky ze souborů *.bin. Očekáváme, že soubor bude mít stejné základní jméno jako výsledný soubor .html a postará se o kompletní generování obsahu. Test si vytváří vlastní from-news.bin, vaše řešení musí používat vzorová pravidla (pattern rules) se správými stemy.

  4. Přidejte speciální cíl spelling, který zobrazí seznam překlepů v souborech Markdown. Předpokládáme, že pro tento úkol použijete aspell a jako hlavní jazyk použijete angličtinu.

Nápověda #1: seznam generovaných souborů si uložte do proměnné PAGES, protože Vám to zjednoduší údržbu vašeho Makefile.

Nápověda č. 2: následující příklad je jednoduchý příklad dynamicky generované webové stránky, která může být uložena v souboru src/news.bin. Skript je trochu záludný, protože data webové stránky jsou součástí skriptu a používá $0 pro čtení sám sebe (podobný trik se často používá při vytváření samorozbalovacích archivů pro Linux).

#!/bin/bash

set -ueo pipefail

sed '1,/^---NEWS-START-HERE---/d' "$0" | while read -r date comment; do
    echo "<dt>$date</dt>"
    echo "<dd>$comment</dd>"
done | pandoc --template template.html --metadata title="News" -

exit 0

# Actual news are stored below.
# Add each news item on a separate line
#
# !!! Do not modify the line NEWS-START-HERE !!!
#

---NEWS-START-HERE---
2023-05-01 Website running
2023-05-02 Registration open

Úlohy po cvičení (deadline: 4. června)

Očekáváme, že následující úlohy vyřešíte po cvičení, tj. poté, co budete mít zpětnou vazbu k vašim řešením úloh před cvičením.

Všechny úlohy (pokud není explicitně uvedeno jinak) musí být odevzdány přes váš repozitář na úkoly. Pro většinu úloh existují automatické testy, které vám mohou pomoci zkontrolovat úplnost vašeho řešení (zde je popsáno jak číst jejich výsledky).

14/cc/Makefile (40 bodů, skupina devel)

Převeďte shellový skript pro sestavení spustitelného souboru (ze zdrojových kódů C) na skript založený na make.

Zdrojáky jsou v repozitáři s příklady (v 14/cc).

Soubor Makefile, který vytvoříte, musí nabízet následující funkce:

  • Výchozí cíl all vytvoří spustitelný soubor example.
  • Speciální cíl clean odstraní všechny mezisoubory (*.o) i výsledný spustitelný soubor (example).
  • Objektové soubory (.o) se vytvářejí pro každý soubor zvlášť, doporučujeme použít vzorová pravidla (pattern rules).
  • Objektové soubory musí být závislé na zdrojovém souboru (odpovídajícím souboru .c) i na hlavičkovém souboru.

Prosím, commitněte do repozitáře i zdrojové soubory.

U složitějších projektů v jazyce C se často Makefile alespoň částečně generuje (včetně správných závislostí na vkládaných hlavičkových souborech). V této úloze očekáváme, že všechny závislosti zadáte ručně, abyste ukázali, že make ovládáte.

Existuje pouze jeden hlavičkový soubor, takže seznam závislostí bude ve skutečnosti poměrně krátký.

14/group-sum-ci.yml (60 bodů, skupina git)

Připravte si soubor CI pro svůj fork repozitáře group-sum, který bude automaticky spouštět testy při každém commitu.

Očekáváme, že stále máte svůj fork; pokud ne, forkněte jej znovu a nezapomeňte jej sloučit s větví tests repozitáře gitolite3@linux.ms.mff.cuni.cz:lab07-group-sum-ng.git tak, abyste měli soubor tests.bats.

Doporučujeme, abyste změnili viditelnost vašeho forku na privátní.

Nepřejmenovávejte žádné soubory, zejména zachovejte název souboru tests.bats.

V tomto repozitáři (tj. ve vašem forku projektu group-sum) vytvořte soubor .gitlab-ci.yml se správnou konfigurací, který bude schopen spustit BATSové testy.

Zkontrolujte, zda se po každém commitu (resp. pushnutí) spustí pipeline a zda testy prochází.

Poté zkopírujte soubor .gitlab-ci.yml do repozitáře s úlohami jako 14/group-sum-ci.yml. Neměňte konfigurace repozitáře s úlohami, zajímá nás pouze konfigurační soubor (ale ujistěte se, že vám ve vašem forku funguje).

Tato úloha je pouze částečně testována automatickými testy.

Učební výstupy

Učební výstupy podávají zhuštěný souhrn základních konceptů a dovedností, které byste měli umět vysvětlit a/nebo použít po každém cvičení. Také obsahují absolutní minimum, které je potřebné pro pochopení navazujících cvičení (a dalších předmětů).

Znalosti konceptů

Znalost konceptů znamená, že rozumíte významu a kontextu daného tématu a jste schopni témata zasadit do většího rámce. Takže, jste schopni …

  • vysvětlit principy continous integration

  • vysvětlit výhody používání continous integration

  • vyjmenovat několik kroků, které jsou často nutné k vytvoření distribuovatelného softwaru (např. balíček nebo instalační program) ze zdrojového kódu a dalších základních artefaktů

  • vysvětlit, proč by sestavování softwaru mělo být reprodukovatelným procesem

  • vysvětlit, jak je možné zachytit proces sestavení softwaru

  • vysvětlit pojmy jazyků, které se používají pro zachycení potřebných kroků pro sestavení (distribuci) softwaru

  • vysvětlit v širším smyslu, jak funguje GitLab CI

Praktické dovednosti

Praktické dovednosti se obvykle týkají použití daných programů pro vyřešení různých úloh. Takže, dokážete …

  • sestavit projekty používající make

  • vytvořit Makefile, který řídí sestavení jednoduchého projektu

  • používat pravidla se zástupnými znaky v Makefile

  • nastavit GitLab CI pro jednoduché projekty

  • volitelné: používat proměnné v Makefile

  • volitelné: používat základní rozšíření GNU Make pro zjednodušení složitějších Makefile

Seznam změn na této stránce

  • 2023-05-23: Poznámka o commitnutí zdrojáků v úloze po cvičení.

  • 2023-05-14: Přidány automatické testy a doplněno zadání pro úlohy před cvičením.

  • 2023-05-15: Přidány úlohy po cvičení.