Jekyll: build do vlastní větve

Přechod na statický generátor mi dost usnadnil život, web je teď kompletně v Gitu. Včetně Jekyllem vygenerovaného výstupu, aby se snáz hledal zdroj případné chyby a nebylo třeba komplikovaně řešit deploy.

Co vidíte jako ALES.NET je vlastně obsah složky www na větvi production. Krásně efektivní řešení Blueboardu, které jsem chtěl využít naplno. V první zkušební verzi jsem tedy prostě souběžně s ručními změnami commitoval i výsledné soubory. Strašně tím ale trpěla čitelnost jednotlivých commitů a vznikalo velké množství merge konfliktů.

Například každá změna CSS musela automaticky sáhnout na všechny HTML soubory a přepsat vygenerovaný cache-obcházející hash v <head>. Kvůli čemuž bylo zároveň potřeba při vývoji žonglovat mezi plným a přírůstkovým buildem. Ten je sice experimentální, ale funguje dobře a potřebný čas stáhne klidně na pětinu.


Jak z toho ven?

Řešením konfliktů bude commitovat složku www jen na větvi production a všude jinde ji ignorovat. Při vývoji se navíc naplno využije rychlost přírůstkového buildu s livereloadem a před nasazením změn se spustí ten plnohodnotný. To vše automaticky pomocí jednoduchého skriptu.

Pre-push hook krok za krokem (celý skript níže)

Jakmile teď tedy v hlavní vývojové větvi main nastřádám dost změn k nasazení, stačí se přepnout na production a pushnout. Pak se spustí to správný tóčo. Tedy po kontrole aktuální větve:

if [ "$(git rev-parse --symbolic-full-name --abbrev-ref HEAD)" == "production" ]; then

Poté se změny z main začlení a Jekyll udělá čistý build:

git merge main
docker exec alesnet-jekyll-1 jekyll clean
docker exec alesnet-jekyll-1 jekyll build

Vynutí se commit adresáře www s buildem, který je jinak .gitignorován, aby při přepínání větví nevznikaly problémy. Commit díky podmínce neproběhne, pokud v adresáři není nic nového. A pokud ano, rovnou se pushne a tím i nasadí:

git add www -f
if ! git diff-index --quiet HEAD; then
  git commit -m "Jekyll build"
  git push --no-verify
fi

Pokud Jekyll změnil sitemapu, pingne se Googlu a zobrazí osekaná odpověď:

if ! git diff HEAD~1 HEAD --exit-code -s www/sitemap.xml; then
  curl --silent "https://www.google.com/ping?sitemap=https://ales.net/sitemap.xml" | grep "<h2>"
fi

Pak se automaticky vrátíme na větev main. Tím však přijdeme o obsah složky www, který jsme nechali na předešlé větvi. Proto ještě Jekylla donutíme k novému buildu:

git checkout main
docker exec alesnet-jekyll-1 jekyll build

A jsme zpátky na vývojové verzi. Tentokrát ovšem se změnami procpanými na produkci a bez zaplevelené historie.


Celý soubor .githooks/pre-push

Když se všechno poslepuje, vznikne finální soubor:

#!/bin/sh

set -e

if [ "$(git rev-parse --symbolic-full-name --abbrev-ref HEAD)" == "production" ]; then
  git merge main
  docker exec alesnet-jekyll-1 jekyll clean
  docker exec alesnet-jekyll-1 jekyll build

  git add www -f
  if ! git diff-index --quiet HEAD; then
    git commit -m "Jekyll build"
    git push --no-verify
  fi

  if ! git diff HEAD~1 HEAD --exit-code -s www/sitemap.xml; then
    curl --silent "https://www.google.com/ping?sitemap=https://ales.net/sitemap.xml" | grep "<h2>"
  fi

  git checkout main
  docker exec alesnet-jekyll-1 jekyll build
fi

Git neverzuje svou složku .git/hooks, takže jsem hook hodil do vlastní, nastavil mu chmod +x a teprve pak commitnul. Aby se hook s následujícím pushem použil, stačí už jen upravit .git/config příkazem:

git config core.hooksPath .githooks

Tadá, od teď bude historie změn a jejich nasazení jako ze škatulky. ✨