From 9499c7792bd744d7da825ea0aab7c45e0ee40b4c Mon Sep 17 00:00:00 2001 From: Andrea Manzi Date: Sun, 1 Nov 2026 10:58:38 +0100 Subject: [PATCH] Le Gitea Actions: test unitari a ogni push su main e sui tag, e sul tag vX.Y.Z la release con i commit dal tag prima (.gitea/workflows/test.yml); il runner sul PC si crea o riavvia con make runner (tools/gitea-runner, scripts/runner.sh, token di registrazione chiesto a Gitea con le credenziali di git); hook pre-push con check-public (make hooks) (Andrea) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GiECd9RWGMKV7n3K1mdy8T --- .gitea/workflows/test.yml | 45 +++++++++++++++++++++++++++ CLAUDE.md | 1 + Makefile | 11 +++++-- scripts/git-hooks/pre-push | 5 +++ scripts/runner.sh | 29 +++++++++++++++++ tools/gitea-runner/config.yaml | 13 ++++++++ tools/gitea-runner/docker-compose.yml | 19 +++++++++++ 7 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 .gitea/workflows/test.yml create mode 100755 scripts/git-hooks/pre-push create mode 100755 scripts/runner.sh create mode 100644 tools/gitea-runner/config.yaml create mode 100644 tools/gitea-runner/docker-compose.yml diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml new file mode 100644 index 0000000..6d5e7fb --- /dev/null +++ b/.gitea/workflows/test.yml @@ -0,0 +1,45 @@ +# Le Gitea Actions del gioco: girano sul runner del PC di Andrea (make runner; label ubuntu-latest = node:22-bookworm). +# A ogni push su main e a ogni tag i test unitari; su un tag vX.Y.Z, se passano, la release con i commit dal tag prima. +# Il controllo dei file pubblicabili non sta qui (a pipeline partita il push è già pubblico): è l'hook pre-push. +name: test +on: + push: + branches: [main] + tags: ['v*'] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Test unitari + run: node --version && node --test tests/*.test.mjs + + release: + needs: test + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Release del tag + env: + TOKEN: ${{ secrets.GITEA_TOKEN }} + TAG: ${{ github.ref_name }} + API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }} + run: | + prev=$(git describe --tags --abbrev=0 "$TAG^" 2>/dev/null || true) + { + echo "Si gioca su https://50037.manzolo.it; qui sotto lo zip di questa versione." + echo + echo "Cosa cambia${prev:+ da $prev}:" + echo + git log --no-merges --format='- %s' ${prev:+$prev..}"$TAG" | grep -v -e '^- Versione [0-9]' | cut -c1-400 + } > note.md + node -e 'const fs=require("fs");process.stdout.write(JSON.stringify({tag_name:process.env.TAG,name:"Versione "+process.env.TAG.slice(1),body:fs.readFileSync("note.md","utf8")}))' > release.json + code=$(curl -s -o risposta.json -w '%{http_code}' -X POST -H "Authorization: token $TOKEN" -H 'Content-Type: application/json' --data @release.json "$API/releases") + cat risposta.json | head -c 400; echo + [ "$code" = 201 ] || [ "$code" = 409 ] diff --git a/CLAUDE.md b/CLAUDE.md index 1b6aece..1e5040d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,3 +25,4 @@ i suoi ricordi: non inventare persone, luoghi o fatti del paese al posto suoi; p - **Pubblicare (dal 2026-11-01)**: origin è https://git.manzolo.it/manzolo/leggenda-del-regolo, pubblico: prima `make check-public`, poi `git push origin main --tags`, solo se Andrea lo chiede. `make deploy` costruisce l'immagine dal tag della versione, la spinge su `git.manzolo.it/manzolo/leggenda-regolo:vX.Y.Z` (e `:latest`); sul VPS il compose fissa quel tag e fa `docker compose pull && up -d`. Per tornare indietro: sul VPS (`Workspaces/docker/leggenda-regolo/docker-compose.yml`) si rimette il tag precedente e si rifà pull e up. + Hook pre-push (`make hooks`, una volta per clone) lancia check-public; le Gitea Actions (`.gitea/workflows/test.yml`: test, e release sui tag) girano sul runner del PC, che si crea o riavvia con `make runner`. diff --git a/Makefile b/Makefile index 660df0b..9186f59 100644 --- a/Makefile +++ b/Makefile @@ -23,8 +23,8 @@ DST ?= assets/scenes/$(notdir $(SRC)) CROP ?= COLORS ?= 64 -.PHONY: help serve open test browser verify check-public bump voci voci-elenco sfondi sfondi-genera sfondi-confronto background character \ - build up down restart logs ps shell image-size deploy deploy-logs clean distclean +.PHONY: help serve open test browser verify check-public hooks bump voci voci-elenco sfondi sfondi-genera sfondi-confronto background character \ + build up down restart logs ps shell image-size deploy deploy-logs runner clean distclean ## ------------------------------------------------------------ sviluppo @@ -55,6 +55,10 @@ verify: test browser check-public ## Tutti i controlli check-public: ## Prima di pubblicare: niente prompt, fogli grezzi, segreti o nomi della rete di casa (tutta la storia) bash scripts/check-public.sh +hooks: ## Attiva gli hook del repo (pre-push: check-public prima di ogni push) + git config core.hooksPath scripts/git-hooks + @echo "hook attivi da scripts/git-hooks: $$(ls scripts/git-hooks | tr '\n' ' ')" + bump: ## Nuova versione (PARTE=patch|minor|major): verifica, commit e tag v; poi make deploy scripts/bump.sh $(or $(PARTE),patch) @@ -166,6 +170,9 @@ deploy: ## Pubblica la versione dell'ultimo commit: test, immagine provata qui, curl -s $(DEPLOY_URL)/src/version.js | grep -qF "$$v" || { echo "$(DEPLOY_URL) non serve $$v"; exit 1; } @echo "→ $(DEPLOY_URL) ($(DEPLOY_IMAGE):$(DEPLOY_VER), $$(git log -1 --format='%h %s' $(DEPLOY_VER)))" +runner: ## Crea (se manca) e avvia sul PC il runner delle Gitea Actions (tools/gitea-runner, scripts/runner.sh) + bash scripts/runner.sh + deploy-logs: ## Log del container sul server di deploy @test -n "$(DEPLOY_HOST)" || { echo "manca DEPLOY_HOST: scrivilo in deploy.local.mk"; exit 2; } ssh $(DEPLOY_HOST) 'cd $(DEPLOY_DIR) && docker compose logs -f --tail 50' diff --git a/scripts/git-hooks/pre-push b/scripts/git-hooks/pre-push new file mode 100755 index 0000000..104d438 --- /dev/null +++ b/scripts/git-hooks/pre-push @@ -0,0 +1,5 @@ +#!/bin/bash +# Prima di ogni push: il repo su git.manzolo.it è pubblico, quindi niente che check-public bocci deve partire. +# Si attiva una volta con `make hooks` (core.hooksPath = scripts/git-hooks). +cd "$(git rev-parse --show-toplevel)" || exit 1 +bash scripts/check-public.sh || { echo; echo "pre-push: push bloccato da check-public (vedi sopra)."; exit 1; } diff --git a/scripts/runner.sh b/scripts/runner.sh new file mode 100755 index 0000000..d4a53db --- /dev/null +++ b/scripts/runner.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Crea (se manca) e avvia il runner delle Gitea Actions su questo PC: `make runner`. +# Rifarlo da zero: `docker compose -f tools/gitea-runner/docker-compose.yml down`, cancellare $RUNNER_DATA e il runner +# vecchio da Gitea (repo → Impostazioni → Actions → Runner), poi di nuovo `make runner`. +# Il token di registrazione si chiede all'API di Gitea con le credenziali di git (serve lo scope write:repository). +set -euo pipefail +ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd) +COMPOSE="$ROOT/tools/gitea-runner/docker-compose.yml" +REPO=${RUNNER_REPO:-manzolo/leggenda-del-regolo} +export RUNNER_DATA=${RUNNER_DATA:-$HOME/.local/share/gitea-runner} +export GITEA_RUNNER_NAME=${GITEA_RUNNER_NAME:-pc-$(hostname | tr '[:upper:]' '[:lower:]')} +mkdir -p "$RUNNER_DATA" + +if [[ ! -s $RUNNER_DATA/.runner ]]; then + pass=$(printf 'protocol=https\nhost=git.manzolo.it\n\n' | git credential fill | sed -n 's/^password=//p') + user=$(printf 'protocol=https\nhost=git.manzolo.it\n\n' | git credential fill | sed -n 's/^username=//p') + [[ -n $pass ]] || { echo "nessuna credenziale git per git.manzolo.it"; exit 1; } + tok=$(curl -sf -X POST -u "$user:$pass" "https://git.manzolo.it/api/v1/repos/$REPO/actions/runners/registration-token" | + python3 -c 'import json,sys; print(json.load(sys.stdin)["token"])') || + { echo "Gitea non ha dato il token di registrazione (scope write:repository?)"; exit 1; } + echo "registro il runner $GITEA_RUNNER_NAME su $REPO" + GITEA_RUNNER_REGISTRATION_TOKEN=$tok docker compose -f "$COMPOSE" up -d + for _ in $(seq 30); do [[ -s $RUNNER_DATA/.runner ]] && break; sleep 1; done + [[ -s $RUNNER_DATA/.runner ]] || { docker logs --tail 20 gitea-runner; echo "registrazione non riuscita"; exit 1; } + chmod 600 "$RUNNER_DATA/.runner" 2>/dev/null || true +fi +# Senza token nell'ambiente del container: da qui in poi si autentica con .runner. +docker compose -f "$COMPOSE" up -d +sleep 2; docker logs --tail 1 gitea-runner diff --git a/tools/gitea-runner/config.yaml b/tools/gitea-runner/config.yaml new file mode 100644 index 0000000..a346f61 --- /dev/null +++ b/tools/gitea-runner/config.yaml @@ -0,0 +1,13 @@ +# Configurazione di act_runner (vedi docker-compose.yml accanto). +log: + level: info +runner: + file: .runner + capacity: 2 + timeout: 30m +container: + network: "" + privileged: false + options: "--memory=4g" + valid_volumes: [] + force_pull: false diff --git a/tools/gitea-runner/docker-compose.yml b/tools/gitea-runner/docker-compose.yml new file mode 100644 index 0000000..ea3101b --- /dev/null +++ b/tools/gitea-runner/docker-compose.yml @@ -0,0 +1,19 @@ +# Runner delle Gitea Actions di git.manzolo.it, sul PC di Andrea (dal 2026-11-01). Si crea e si avvia con +# `make runner` (scripts/runner.sh): registra il runner sul repo se manca e lo lascia acceso (riparte con Docker). +# I job girano in container fratelli tramite il socket Docker del PC; le credenziali del runner stanno fuori dal repo. +name: gitea-runner +services: + runner: + image: gitea/act_runner:0.6.1 + container_name: gitea-runner + restart: unless-stopped + environment: + CONFIG_FILE: /config.yaml + GITEA_INSTANCE_URL: https://git.manzolo.it + GITEA_RUNNER_REGISTRATION_TOKEN: ${GITEA_RUNNER_REGISTRATION_TOKEN:-} + GITEA_RUNNER_NAME: ${GITEA_RUNNER_NAME:-pc-andrea} + GITEA_RUNNER_LABELS: ubuntu-latest:docker://node:22-bookworm + volumes: + - ./config.yaml:/config.yaml:ro + - ${RUNNER_DATA:?}:/data + - /var/run/docker.sock:/var/run/docker.sock