Workflow Gitea Actions (ci e release) e guida all'installazione su Unraid

ci.yml compila con gli avvisi come errori, esegue i test e costruisce l'immagine a
ogni push; release.yml pubblica l'immagine sul registro di Gitea e crea la release
con il template Unraid a ogni tag, in modo idempotente rispetto alla catena locale.
Sul server non c'è ancora un runner: docs/DOCKER.md spiega come registrarlo e quale
segreto serve. Il README di deploy/unraid guida passo per passo l'installazione,
compreso il registro in HTTP da dichiarare a Docker di Unraid.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-23 14:19:43 +02:00
co-authored by Claude Fable 5.1
parent e9ace47501
commit e2e471f12c
8 changed files with 196 additions and 24 deletions
+36
View File
@@ -0,0 +1,36 @@
# Verifica a ogni push e pull request: compilazione con gli avvisi come errori e la
# suite dei test. Un secondo lavoro costruisce l'immagine (senza pubblicarla) per
# accorgersi subito di una Dockerfile rotta: richiede un runner con Docker.
#
# Runner: act_runner con l'etichetta ubuntu-latest (vedi docs/DOCKER.md, «Gitea Actions»).
name: ci
on:
push:
branches: [main]
pull_request:
jobs:
verifica:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "10.0.x"
- name: Compilazione (avvisi = errori)
run: dotnet build Encelado.slnx -c Release -nologo -warnaserror
- name: Test
run: dotnet test tests/Encelado.Tests -c Release --no-build --nologo -v q
immagine:
runs-on: ubuntu-latest
needs: verifica
steps:
- uses: actions/checkout@v4
- name: Costruzione dell'immagine (i test girano anche dentro la build)
run: |
docker build --pull \
--build-arg VERSION=ci \
--build-arg GIT_COMMIT="${GITHUB_SHA::12}" \
-t encelado:ci .
+78
View File
@@ -0,0 +1,78 @@
# Rilascio a ogni tag vX.Y.Z: l'immagine sul registro dei container di Gitea
# (<host>/alby96/encelado:X.Y.Z e :latest) e la release con il template Unraid allegato.
#
# È la stessa cosa che fa build/Release.proj -t:Rilascia dal PC; qui gira sul runner
# quando il tag arriva sul server. Idempotente: un'immagine già presente viene
# sovrascritta con lo stesso contenuto, una release già creata dalla catena viene
# lasciata com'è e le manca solo l'allegato, che viene aggiunto se non c'è.
#
# Serve il segreto REGISTRY_TOKEN (Impostazioni ▸ Actions ▸ Segreti del repository):
# un token dell'utente con i permessi package:write e repository:write.
# Solo linux/amd64: la build esegue la suite dei test, e sotto QEMU (arm64) sarebbe
# lentissima; il server Unraid è amd64.
name: release
on:
push:
tags: ["v*"]
jobs:
immagine:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Versione e registro dal tag e dall'indirizzo del server
run: |
echo "VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"
echo "REGISTRY=$(echo "${{ gitea.server_url }}" | sed -E 's#^https?://##; s#/$##')" >> "$GITHUB_ENV"
echo "OWNER=$(echo "${{ gitea.repository_owner }}" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_ENV"
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- uses: docker/setup-buildx-action@v3
with:
# Il registro di Gitea è in HTTP: buildx deve poterlo trattare come insicuro.
driver-opts: network=host
buildkitd-config-inline: |
[registry."${{ env.REGISTRY }}"]
http = true
insecure = true
- uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
push: true
build-args: |
VERSION=${{ env.VERSION }}
GIT_COMMIT=${{ gitea.sha }}
tags: |
${{ env.REGISTRY }}/${{ env.OWNER }}/encelado:${{ env.VERSION }}
${{ env.REGISTRY }}/${{ env.OWNER }}/encelado:latest
- name: Release con il template Unraid allegato
env:
TOKEN: ${{ secrets.REGISTRY_TOKEN }}
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
run: |
set -eu
TAG="${GITHUB_REF_NAME}"
ASSET="encelado-unraid-${VERSION}.xml"
cp deploy/unraid/encelado.xml "$ASSET"
ID=$(curl -sf -H "Authorization: token $TOKEN" "$API/releases/tags/$TAG" | sed -n 's/.*"id":\([0-9]*\).*/\1/p' | head -1 || true)
if [ -z "$ID" ]; then
BODY=$(printf '{"tag_name":"%s","name":"Encelado %s","body":"Versione %s.\\n\\nImmagine: `%s/%s/encelado:%s` (anche `:latest`). Template Unraid allegato.","draft":false,"prerelease":false}' "$TAG" "$VERSION" "$VERSION" "$REGISTRY" "$OWNER" "$VERSION")
ID=$(curl -sf -H "Authorization: token $TOKEN" -H "Content-Type: application/json" --data-binary "$BODY" "$API/releases" | sed -n 's/.*"id":\([0-9]*\).*/\1/p' | head -1)
echo "release $TAG creata (id $ID)"
else
echo "release $TAG già presente (id $ID): aggiungo solo l'allegato mancante"
fi
if ! curl -sf -H "Authorization: token $TOKEN" "$API/releases/$ID/assets" | grep -q "\"name\":\"$ASSET\""; then
curl -sf -H "Authorization: token $TOKEN" -F "attachment=@$ASSET" "$API/releases/$ID/assets?name=$ASSET" > /dev/null
echo "allegato $ASSET caricato"
fi
+1 -1
View File
@@ -23,7 +23,7 @@ Bot di trading in C# (.NET 10) su **eToro** con la strategia "Correlation Basket
| `docs/QUESTIONS.md` | domande poste per fase, risposte o default applicati, con data |
| `docs/PIANO_5.0.md`, `docs/PROMPT_5.0.md`, `docs/POSTMORTEM_ordini_pendenti.md` | il piano della 5.0 (fasi, stime, decisioni vincolanti), la specifica originale e il post-mortem delle gambe orfane del 16-21/9/2026 |
| `docs/GLOSSARY.md`, `docs/KNOWN_ISSUES.md`, `CHANGELOG.md`, `docs/adr/` | glossario, problemi noti, cronologia, decisioni architetturali |
| `build/README.md` | catena di verifica, pacchetto (immagine Docker) e rilascio |
| `build/README.md` | catena di verifica, pacchetto (immagine Docker) e rilascio; `.gitea/workflows/` per le Actions |
## Progetti
+1 -1
View File
@@ -50,7 +50,7 @@ dotnet msbuild build/Release.proj -t:Docker # l'immagine, con
scripts\screenshots.ps1 # rigenera docs/img dal server campione
```
Attività di VS Code: `verifica`, `backtest`, `avvia in locale (script)`, `avvia in docker`, `ferma docker`, `screenshot`, `immagine docker`, `pacchetto`, `rilascia su Gitea`.
Attività di VS Code: `verifica`, `backtest`, `avvia in locale (script)`, `avvia in docker`, `ferma docker`, `screenshot`, `immagine docker`, `pacchetto`, `rilascia su Gitea`. Su Gitea, `.gitea/workflows/ci.yml` verifica ogni push e `release.yml` pubblica l'immagine a ogni tag (serve un runner: `docs/DOCKER.md`).
```
src/Encelado.Core logica pura: basket, cross sintetici, decisore, cost gate, sizing, esecutore, registro ordini, kill-switch, apprendimento, notifiche
+4
View File
@@ -71,6 +71,10 @@ dotnet msbuild build/Release.proj -t:Backtest -p:Dati="%USERPROFILE%\Documents\E
5. `Pacchetto`: zip portabile `bin/installer/Encelado_<v>_portabile.zip`, copia del template `deploy/unraid/encelado.xml` con la versione nel nome, **tag** `v<versione>` (solo ora, a pacchetto pronto, e solo con l'albero pulito).
6. `Rilascia`: `git push --tags` e verifica che il tag sia sul remoto; `docker login` sul registro di Gitea con il token (via stdin), `docker push` dei due tag, `docker logout`; release su Gitea con lo zip e il template allegati.
## Gitea Actions
`.gitea/workflows/ci.yml` (build + test + `docker build` a ogni push) e `release.yml` (immagine sul registro e release a ogni tag `v*`) fanno sul server quello che `Verifica` e `Rilascia` fanno dal PC. Richiedono un runner registrato e il segreto `REGISTRY_TOKEN`: vedi `docs/DOCKER.md`, «Gitea Actions». La catena resta il percorso di riferimento finché il runner non c'è.
## Chi chiede la versione
MSBuild non può chiedere niente a nessuno: è un motore di compilazione. La domanda la fa
+59 -22
View File
@@ -1,32 +1,69 @@
# Encelado su Unraid
Il template `encelado.xml` installa il container dall'immagine sul registro di Gitea
(`192.168.30.23:3000/alby96/encelado:latest`). Istruzioni complete su volumi, variabili,
healthcheck e aggiornamento in `docs/DOCKER.md`.
(`192.168.30.23:3000/alby96/encelado:latest`). Dettagli su volumi, variabili, healthcheck e
aggiornamento in `docs/DOCKER.md`; guida operativa in `docs/RUNBOOK.md`.
## Installazione
## 1. Il registro di Gitea è in HTTP: dillo a Docker di Unraid
1. **Registro privato**: se il registro di Gitea è in HTTP, Unraid deve fidarsi.
In *Impostazioni ▸ Docker* (modalità avanzata) aggiungi `192.168.30.23:3000` agli
`insecure-registries` del demone, oppure crea `/boot/config/docker.cfg` con
`DOCKER_OPTS="--insecure-registry 192.168.30.23:3000"`. Se il pacchetto è privato,
dal terminale di Unraid: `docker login 192.168.30.23:3000` con utente e token Gitea.
2. **Template**: *Docker ▸ Aggiungi container ▸ Template* e incolla l'URL raw
`http://192.168.30.23:3000/Alby96/Encelado/raw/branch/main/deploy/unraid/encelado.xml`,
oppure copia il file in `/boot/config/plugins/dockerMan/templates-user/`.
3. Compila **ENCELADO_WEB_TOKEN** (obbligatorio: senza, l'interfaccia resta chiusa in
localhost), le chiavi eToro (o lascia vuoto e inseriscile poi da *Impostazioni ▸
Chiavi eToro* con `ENCELADO_KEY_PASSPHRASE` impostata), `TZ`, eventualmente Telegram.
4. Avvia. Al primo avvio il container semina `encelado.json` e `strategy.json` in
`/mnt/user/appdata/encelado/config`. L'interfaccia è su `http://IP:8080/`; il token
va inserito una volta e resta in un cookie per trenta giorni.
Docker rifiuta un registro senza TLS finché non è dichiarato «insecure». Su Unraid, dal
terminale (o da *Tools ▸ Terminal*):
## Aggiornamento
```sh
echo 'DOCKER_OPTS="--insecure-registry 192.168.30.23:3000"' >> /boot/config/docker.cfg
/etc/rc.d/rc.docker restart # oppure Impostazioni ▸ Docker: disabilita e riabilita
docker info | grep -A2 "Insecure Registries" # deve elencare 192.168.30.23:3000
```
*Docker ▸ Controlla aggiornamenti*: il tag `latest` segue l'ultima release. Il container si
ferma con SIGTERM (45 s di grazia): i basket aperti restano sul conto con gli stop
nativi e vengono ripresi dallo stato salvato e dalla riconciliazione al riavvio
(`docs/RUNBOOK.md`, «Recupero dopo inattività»).
Il repository Encelado è pubblico, quindi anche il pacchetto lo è: `docker pull` non ha
bisogno di login. Se un giorno diventa privato: `docker login 192.168.30.23:3000` con
utente Gitea e un token con permesso `package:read`.
## 2. Installa dal template
*Docker ▸ Add Container*, in fondo alla pagina **Template repositories** non serve: incolla
l'URL del template nel campo **Template** (in alto, «Select a template» ▸ voce vuota, poi il
campo URL), oppure scarica il file e mettilo in `/boot/config/plugins/dockerMan/templates-user/`:
```
http://192.168.30.23:3000/Alby96/Encelado/raw/branch/main/deploy/unraid/encelado.xml
```
Lo stesso file è allegato a ogni release su Gitea con la versione nel nome.
## 3. Compila i campi
| Campo | Cosa mettere |
|---|---|
| **Porta web** | `8080` (o un'altra libera: la WebUI del container la segue) |
| **/config**, **/data** | lascia i default `/mnt/user/appdata/encelado/config` e `/data` |
| **ENCELADO_WEB_TOKEN** | **obbligatorio**: una stringa lunga a piacere. Senza, il server ascolta solo dentro il container e dalla rete non si vede niente |
| **ETORO_API_KEY**, **ETORO_USER_KEY** | le chiavi del conto **demo** (dal portale sviluppatori eToro; demo e reale hanno chiavi diverse). Oppure lasciale vuote e inseriscile poi dall'interfaccia, mettendo una **ENCELADO_KEY_PASSPHRASE** |
| **ETORO_ENVIRONMENT** | `demo` |
| **ENCELADO_EXECUTION_MODE** | `Demo` |
| **TZ** | `Europe/Rome` |
| **TELEGRAM_BOT_TOKEN**, **TELEGRAM_CHAT_ID** | facoltativi: notifiche ogni ora, eventi, riepilogo serale e comandi dalla chat |
| PUID / PGID | `99` / `100` (nobody:users, i default di Unraid) |
`ENCELADO_CONFIRM_LIVE` resta vuoto: serve solo per il conto reale, che oggi non è praticabile.
## 4. Primo avvio
1. **Apply**. Il container semina `encelado.json` e `strategy.json` in `/mnt/user/appdata/encelado/config`.
2. Apri `http://<ip-unraid>:8080/`, inserisci il token (resta in un cookie per trenta giorni).
3. Se non hai messo le chiavi nelle variabili: **Impostazioni ▸ Chiavi eToro ▸ Verifica e salva** (vengono provate contro eToro e salvate cifrate in `/config/etoro.keys.enc`).
4. Con `ENCELADO_AUTOSTART` al default (`1`) il motore è già partito; altrimenti **AVVIA**. Il chip in basso a sinistra dice `DEMO`.
5. Per un test lungo guarda: contatore «in attesa · orfane · esterne» (orfane deve restare 0), **Storico ▸ Ordini** (unità richieste ed eseguite uguali, esito `Filled`), il log. Il kill-switch è il pulsante in alto a destra, o un file `STOP` in `/mnt/user/appdata/encelado/config`.
Il log è in `docker logs encelado` e in `/mnt/user/appdata/encelado/data/logs/encelado.log`; il ledger in `.../data/data/ledger/`.
## 5. Aggiornamento
*Docker ▸ Check for Updates*: il tag `latest` segue l'ultima release. Il container si ferma
con SIGTERM (45 s di grazia): i basket aperti restano sul conto con gli stop nativi e
vengono ripresi dallo stato salvato e dalla riconciliazione al riavvio (`docs/RUNBOOK.md`,
«Recupero dopo inattività»). Per tornare a una versione precisa cambia il tag nel campo
**Repository** (`…/encelado:5.0.0`).
## Icona
+1
View File
@@ -32,6 +32,7 @@ Encelado.slnx
│ wwwroot/ (index.html, login.html, app.css, app.js, icon.svg, manifest.webmanifest — incorporati)
├── tools/Encelado.Backtest ticks, baskets, falsify, learn (referenzia Core ed Engine)
├── tests/Encelado.Tests xunit (net10.0, gira su Windows e nello stadio di build dell'immagine)
├── .gitea/workflows/ ci.yml (build, test, docker build a ogni push), release.yml (immagine sul registro e release a ogni tag)
├── deploy/docker/ entrypoint.sh (TZ, PUID/PGID, gosu, exec)
├── deploy/unraid/ encelado.xml (template Container v2), README.md
├── Dockerfile, docker-compose.yml, .dockerignore
+16
View File
@@ -67,6 +67,22 @@ Il server ascolta su tutte le interfacce **solo** quando `ENCELADO_WEB_TOKEN` è
Il Gitea dell'utente è raggiunto in HTTP: chi fa `docker pull` deve dichiararlo `insecure-registry` (Docker Desktop: *Settings ▸ Docker Engine*`"insecure-registries": ["192.168.30.23:3000"]`; Unraid: vedi `deploy/unraid/README.md`). Il push dalla catena di rilascio (`-t:Rilascia`) fa `docker login` con il token di `build/gitea.json` e `docker logout` subito dopo.
## Gitea Actions
Due workflow in `.gitea/workflows/`, sul modello di Rea:
| Workflow | Quando | Cosa fa |
|---|---|---|
| `ci.yml` | push su `main`, pull request | `dotnet build -warnaserror` e `dotnet test`; poi `docker build` dell'immagine (senza pubblicarla) per accorgersi di una Dockerfile rotta |
| `release.yml` | tag `v*` | costruisce e pubblica `<host>/alby96/encelado:<versione>` e `:latest` sul registro di Gitea (solo `linux/amd64`: la build esegue i test e sotto QEMU sarebbe lentissima), poi crea la release con il template Unraid allegato; se la release esiste già (creata dalla catena) aggiunge solo l'allegato mancante |
Servono due cose che al 2026-09-23 **mancano**:
1. **Un runner.** Sul server non ce n'è nessuno (`/api/v1/repos/Alby96/Encelado/actions/runners` è vuoto): i workflow restano in coda. Il modo più semplice è un container `gitea/act_runner` su Unraid con il socket di Docker montato (`/var/run/docker.sock`), registrato con il token di *Site Administration ▸ Actions ▸ Runners ▸ Create new runner* e con l'etichetta `ubuntu-latest:docker://catthehacker/ubuntu:act-latest`. Con il registro in HTTP il runner (e la sua immagine di lavoro) deve avere `192.168.30.23:3000` fra gli `insecure-registries`.
2. **Il segreto `REGISTRY_TOKEN`** nel repository (*Impostazioni ▸ Actions ▸ Segreti*): un token dell'utente con `package:write` e `repository:write` (lo stesso di `build/gitea.json` va bene).
Finché il runner non c'è, il rilascio si fa dal PC con `dotnet msbuild build/Release.proj -t:Rilascia -p:Versione=X.Y.Z`, che produce lo stesso risultato (immagine sul registro, tag, release con allegati); i due percorsi sono idempotenti fra loro.
## Prove in locale: la sandbox `deploy/local`
`deploy/local/config` e `deploy/local/data` (ignorate da git) sono il `/config` e il `/data` delle prove sul PC, in tutti e tre i modi di avvio: