name: build # Buduje obrazy usług, które dzielą warstwę logiczną i łącze: data, logic, # presentation, astrodemo. Render i silnik B mają własne pipeline'y, bo są ciężkie # i rzadko się zmieniają (build-render.yaml, build-swisseph.yaml). on: push: branches: [master] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: # Dwa commity, bo porównujemy z poprzednim. Domyślny płytki klon ma # jeden i `HEAD^` w nim nie istnieje. fetch-depth: 2 - name: Login run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login gitea.czernobog.pl -u gitea --password-stdin - name: Build & push (tylko usługi, które się zmieniły) run: | set -eu TAG=${GITHUB_SHA::8} USLUGI="data logic presentation astrodemo astroklient" # Usługi z własnym pipeline'em — celowo poza tą pętlą. OSOBNE="render engine-swisseph" # Usługa, której nie ma na żadnej z list, nigdy się nie zbuduje i NIKT # tego nie zauważy: brak obrazu wygląda potem na problem z rejestrem. # Ten sam mechanizm już nas kosztował przy liście obserwowanych obrazów # w image-updaterze. Lepiej zatrzymać budowanie i powiedzieć wprost. for KATALOG in services/*/; do NAZWA=$(basename "$KATALOG") case " $USLUGI $OSOBNE " in *" $NAZWA "*) ;; *) echo "BŁĄD: usługa '$NAZWA' nie jest na żadnej liście budowania." echo "Dopisz ją do USLUGI w tym pliku albo daj jej własny workflow" echo "(jak render i engine-swisseph), zależnie od tego, czy ma" echo "powstawać z każdego commita produktu." exit 1 ;; esac done # Kontekstem budowania każdego obrazu jest WYŁĄCZNIE ./services/, # więc zmiana poza tym katalogiem nie może wpłynąć na jego zawartość. # Dzięki temu porównanie ścieżek jest dokładne, a nie przybliżone. if POPRZEDNI=$(git rev-parse --verify HEAD^ 2>/dev/null); then ZMIENIONE=$(git diff --name-only "$POPRZEDNI" HEAD) else # Pierwszy commit albo przepisana historia — nie ma z czym porównać, # więc budujemy wszystko. Lepiej zbudować za dużo niż wypuścić obraz # ze starym kodem pod nowym tagiem. echo "Brak poprzedniego commita — buduję komplet." ZMIENIONE="" fi # Zmiana w samym pliku workflow dotyczy wszystkich obrazów naraz. if [ -z "$ZMIENIONE" ] || echo "$ZMIENIONE" | grep -q '^\.gitea/workflows/build\.yaml$'; then DO_BUDOWY="$USLUGI" else DO_BUDOWY="" for SVC in $USLUGI; do if echo "$ZMIENIONE" | grep -q "^services/$SVC/"; then DO_BUDOWY="$DO_BUDOWY $SVC" fi done # astroklient bierze rdzeń z warstwy prezentacji, więc zmiana TAMTEJ # też go dotyczy. Bez tego jego obraz zostawałby ze starymi ekranami, # a różnicy nie byłoby widać aż do zgłoszenia użytkownika. if echo "$ZMIENIONE" | grep -q "^services/presentation/" \ && ! echo "$DO_BUDOWY" | grep -q "astroklient"; then DO_BUDOWY="$DO_BUDOWY astroklient" fi fi if [ -z "$(echo "$DO_BUDOWY" | tr -d ' ')" ]; then echo "Żadna z usług się nie zmieniła — nie ma czego budować." echo "Wdrożone tagi zostają na poprzednich wersjach, i tak ma być." exit 0 fi echo "Buduję:$DO_BUDOWY (tag $TAG)" for SVC in $DO_BUDOWY; do # astroklient buduje się z KORZENIA repozytorium, bo jego Dockerfile # sięga po rdzeń do services/presentation. Pozostałe mają kontekst # ograniczony do własnego katalogu — i tak ma zostać, bo to właśnie # ten kontekst gwarantuje, że nie wciągną niczego spoza siebie. if [ "$SVC" = "astroklient" ]; then docker build -f services/astroklient/Dockerfile \ -t gitea.czernobog.pl/gitea/astrololo-$SVC:$TAG . else docker build -t gitea.czernobog.pl/gitea/astrololo-$SVC:$TAG ./services/$SVC fi docker push gitea.czernobog.pl/gitea/astrololo-$SVC:$TAG done echo "Tag: $TAG" # Sprzątanie ZAWSZE, także po nieudanym budowaniu — to właśnie po awarii # zostaje najwięcej śmieci, a kolejny przebieg zaczyna od mniejszego zapasu # miejsca niż poprzedni. Tak zatkał się dysk przy budowaniu rendera. - name: Sprzątanie po budowaniu if: always() run: | docker system df || true # `until=168h` zostawia tydzień: warstwy bazowe i cache z ostatnich dni # przeżywają, więc kolejny build nie zaczyna od zera, a stare znikają. docker system prune -af --filter "until=168h" || true docker builder prune -f --filter "until=168h" || true docker system df || true