26 Commits
Author SHA1 Message Date
LucaZanni b94bd6936a 🔒 fix(ci): la guardia Dockerfile blocca, e le ARG valgono solo nel loro stage
- via `continue-on-error`: i 56 repo difettosi sono stati corretti (tappa 2
  di PZeta_Touch/flux-repo#133), e su 238 Dockerfile del portale ne restano
  due, che non sono repository git e non passano di qui
- le ARG non si ereditano da `FROM <stage>`, come dice la documentazione
  Docker: la versione precedente presumeva il contrario e lasciava passare
  proprio i casi come nuxt-vue-components-docs, cioè quelli che tirano
  dentro npm 12 e fanno fallire la build al tag
- messaggi da ::warning a ::error, e uscita 1 quando trova qualcosa

Fixes #14 @1h30m
2026-09-12 10:32:27 +02:00
LucaZanni 5973ec9fcc 🐛 fix(ci): la guardia Dockerfile ignora le variabili assegnate nel RUN
- in un RUN espande la shell: una variabile assegnata nel comando stesso
  (VERSIONE="$(...)" && ... ${VERSIONE}) non è la ARG omonima. Era un falso
  avviso su algorithmic-trading, venues/ibkr-gateway/Dockerfile:143
- COPY, LABEL e le altre istruzioni espanse da Docker restano controllate
- collaudo con gawk e gawk --posix: algorithmic-trading 0 avvisi,
  pzeta-king prima della correzione 2, scada-runtime su main 10, Dockerfile
  sintetici con gli esiti attesi; bash -n sullo step estratto dallo YAML

Fixes #13 @25m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:40:53 +02:00
LucaZanni 715860c357 🐛 fix(ci): la guardia Dockerfile dice quando non riesce a leggere le ARG
- l'analisi delle ARG diventa la funzione arg_scope, e all'avvio gira su
  un Dockerfile di prova con una ARG fuori scope nota: se l'awk del runner
  non la riconosce, un ::warning lo dice, il controllo delle ARG salta e
  quello del registry resta, invece di dichiarare in regola ciò che non ha
  potuto leggere
- regex portabile: [$][{]? al posto di \$\{?, che gawk --posix segnalava
  come escape sconosciuto
- collaudo su gawk e gawk --posix (Dockerfile sintetico, pzeta-king prima
  della correzione, vue-pzportal, node-xmlvalidation) e con un awk rotto;
  stesso step, identico, nelle due varianti quality-gates

Fixes #12 @25m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:38:14 +02:00
LucaZanni 9b5159d89e ✨ feat(ci): la guardia Dockerfile anche in quality-gates-github
- stesso step di quality-gates.yml, identico, prima dell'install: i sei
  repository sulla variante -github, fra cui vue-pzportal, ne restavano
  fuori
- solo bash, indipendente da dove si scaricano le action; solo avviso come
  nell'originale

Fixes #11 @25m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:27:00 +02:00
LucaZanni c593f29b0f 🐛 fix(ci): la guardia Dockerfile vede le ARG ereditate da uno stage padre
- una ARG passa agli stage che derivano da quello che la dichiara
  (FROM <stage>), come le ENV: lo prova il log BuildKit di
  nuxt-vue-components-docs v1.0.13, dove deps espande la NPM_VERSION di base
- prima era un falso avviso su ogni Dockerfile con la ARG in uno stage base
- nomi di stage confrontati senza distinzione di maiuscole, come in Docker
- collaudo su un Dockerfile sintetico (ARG globale, padre, fratello,
  nipote, ENV, predefinite, commenti nelle continuazioni): segnala solo i
  due casi attesi

Fixes #10 @25m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:25:21 +02:00
LucaZanni 8949bc7f31 ✨ feat(ci): avviso sui Dockerfile col registry in minuscolo o ARG fuori stage
- quality-gates.yml: nuovo step prima dell'install che scansiona i Dockerfile
  del repository e segnala con ::warning file/riga, più una tabella nel job
  summary, (a) il registry @pzeta scritto pzeta_touch o pzeta e (b) le ARG
  usate in uno stage che non le dichiara
- solo avviso (continue-on-error, uscita sempre 0): bloccante oggi
  fermerebbe i ~46 repo che reggono solo perché pinnano npm 11; lo diventa
  con la tappa 2 di flux-repo#133
- analisi per stage in awk POSIX, collaudata anche con gawk --posix:
  scada-runtime 19 avvisi, pzeta-king 2, vue-pzportal 1, node-xmlvalidation 0

Fixes #9 @1h30m
refs PZeta_Touch/flux-repo#133
2026-09-11 21:21:24 +02:00
LucaZanni 81c871422e 🔧 fix(ci): la deroga al gate dei ruoli arriva allo step che deve saltare
- quality-gates.yml: `owns-auth-roles` esce dal campo `if:` dello step e viene
  letta come env `OWNS_AUTH_ROLES`. In posizione `if:` i valori `with:` del
  chiamante non raggiungono il contesto `inputs` di act_runner, quindi il gate
  bocciava proprio node-user-profiling, l'unico repo autorizzato a dichiarare
  ruoli: tre run rossi e ogni gate successivo saltato
- il nome del repository fa da rete di sicurezza accanto all'input: una deroga
  dichiarata e una constatata, cosi' regge anche se `inputs` non arrivasse
- verificato sui tre casi: deroga via input, deroga via nome con input vuoto,
  repo terzo con le stesse migrazioni (continua a fallire, nessuna regressione)

Fixes #8 @1h30m
2026-09-07 21:31:08 +02:00
LucaZanni 67fccd84e2 ✨ feat(ci): nessun modulo puo' dichiarare ruoli in auth.ruoli
- nuovo step in quality-gates.yml: cerca INSERT INTO auth.ruoli nei file .sql di
  migrations, seeds, sql e database/migrations, e fallisce spiegando cosa fare
  invece — dichiarare un gruppo d'area con i propri permessi, scegliendo il
  livello fra i tredici di piattaforma
- il contratto esisteva dal seed 13 di node-user-profiling e prevedeva questo
  controllo, che non era mai stato scritto: nove microfrontend lo hanno
  disatteso, 21 ruoli creati e 27 su 35 senza omonimo PostgreSQL. Un ruolo cosi'
  nel claim role del JWT e' un SET ROLE che non riesce, e l'utenza di collaudo
  del timesheet ne era la prova
- il boundary dopo `ruoli` tiene fuori auth.ruolipermessi; le righe di commento
  sono ignorate perche' spesso spiegano proprio questa regola
- una-tantum e rollback sono escluse: raccolgono delta generati e script di
  ritorno, fotografie di stati passati che riscrivere falserebbe
- nuovo input owns-auth-roles (default false): solo node-user-profiling, che
  possiede lo schema, lo mette a true. Unica deroga, ed e' esplicita
- verificato su tutti i 30 frontend con migrazioni e sui backend principali:
  nessuno fallisce dopo la ripulitura dei nove repo

Fixes #7 @1h
2026-08-28 10:40:25 +02:00
LucaZanni 6aca13b460 🐛 fix(capacitor-android): il wrapper gradle riceve il bit che Windows non gli da
- Aggiunto lo step "Rendi eseguibile gradlew" prima dei build APK e AAB
- Allineati capacitor-android.yml e la variante GitHub

Fixes #6 @1h30m
2026-08-27 18:47:34 +02:00
LucaZanni c1a4b2723f ✨ feat(capacitor-android): inietta versionName e versionCode da package.json
- Nuovo step "Inject Android version" dopo il sync Capacitor: riscrive versionName e versionCode in android/app/build.gradle prima della build
- versionCode derivato come major*10000 + minor*100 + patch, monotono crescente fra release; pre-release e build metadata scartati dal calcolo ma mantenuti nel versionName
- Nuovo input opzionale version-code per forzare un valore esplicito
- Supporto Groovy e Kotlin DSL; fallisce con diagnostica se la piattaforma manca, la versione non e' semver, minor/patch superano 99 o l'iniezione non produce il valore atteso
- Allineata la variante -github, corpo dello step identico

Fixes #5 @1h30m
2026-08-11 08:51:01 +02:00
LucaZanni c0524722e4 🔧 fix(ci): allinea a PZeta_Touch il registry npm dei workflow riusabili
- .gitea/workflows/*.yml: il registry @pzeta scritto in ~/.npmrc passa da
  `pzeta_touch` a `PZeta_Touch` (12 file, 24 righe). E' la stessa causa dei
  Dockerfile: i package-lock.json della flotta risolvono i tarball su
  `.../api/packages/PZeta_Touch/npm/`, npm confronta gli URL come stringhe e
  con la grafia minuscola tratta il pacchetto come tarball remota (EALLOWREMOTE
  da npm 11) e non applica il _authToken
- e' il punto di massima leva: quality-gates.yml e docker-release.yml sono
  chiamati via `uses:` da 51 repo `node-*` ed eseguono `npm ci` sul runner
  PRIMA di `docker build`, quindi la release si ferma li' anche con il
  Dockerfile gia' corretto
- il REGISTRY delle immagini (`gitea.pzetatouch.it/pzeta_touch`) resta
  minuscolo: i nomi dei repository Docker devono esserlo, ed e' la grafia usata
  dai defaults di flux-repo

refs PZeta_Touch/flux-repo#129 @45m
2026-08-04 10:31:04 +02:00
LucaZanni dae2a74437 ✨ feat(ci): aggiungi l'input working-directory ai reusable workflow Node
- quality-gates, dependency-check, dependency-outdated, npm-publish e
  auto-release accettano ora working-directory (default "."), applicato via
  defaults.run a livello di job: copre tutti gli step run senza toccare gli
  step uses, che devono restare sulla root
- Allineate le varianti -github dei cinque workflow
- Sblocca i repo dove package.json non e' in root (pzeta-calendar in
  typescript/, pzeta-king in server/), che finora dovevano rinunciare ai
  template e reinlineare i job, perdendo la working-directory a ogni
  riallineamento
- Retrocompatibile: con l'input omesso il comportamento resta identico

refs #4
2026-08-01 19:30:03 +02:00
LucaZanni f0896d775d feat(ci): aggiungi varianti -github dei reusable e fix audit Python
- crea gemelli X-github.yml per ogni reusable con action da github.com (fallback mirror gitea.com)
- python-dependency-check/outdated: audit in venv isolata (fix falsi positivi da runner ML)
- python-dependency-check/outdated: deduplica issue (commento invece di nuova issue)
- examples: aggiungi ci-github.yml e release-github.yml in tutte le cartelle

Fixes #3 @3h
2026-07-06 19:53:01 +02:00
LucaZanni e5411d9d2d feat(docker-release): aggiungi build-args con vars fallback per versioni Docker
- NODE_VERSION da vars.NODE_DOCKER_VERSION (fallback: 24.16.0-alpine3.22)
- NGINX_VERSION da vars.NGINX_DOCKER_VERSION (fallback: 1.30.2-alpine3.23)
- NPM_VERSION da vars.NPM_VERSION (fallback: 11.16.0)

Fixes #0 @25m
2026-06-06 14:49:45 +02:00
LucaZanni 94767592c5 fix(ci): downgrade upload-artifact v4->v3 gitea.com
github.com/actions/upload-artifact@v4 non supportato su GHES/Gitea self-hosted.
gitea.com/actions/upload-artifact@v3 usa la API artifact compatibile.
2026-06-06 14:43:38 +02:00
LucaZanni 0fc0251233 fix(ci): sostituisce node -e con jq per leggere package.json
node -e con quoting " dentro block scalar YAML causa syntax error nella shell
("require(" interpretato come subshell). jq evita il problema.
2026-06-06 14:37:23 +02:00
LucaZanni b609947f46 chore(examples): aggiorna node-version a 24.16.0 nel commento di esempio 2026-06-06 14:24:38 +02:00
LucaZanni b21c3877c6 chore(ci): aggiorna node-version default a 24.16.0
Node.js 24.16.0 LTS sostituisce 22.17 come versione di default in tutti i workflow.
2026-06-06 14:24:11 +02:00
LucaZanni 392cdf2580 fix(ci): sostituisce gitea.com/actions/cache con github.com in tutti i workflow
gitea.com/actions/cache@v4 restituisce HTTP 500 in modo intermittente.
github.com/actions/cache@v4 già usato dal runner per altri step (setup-java, ecc.).
2026-06-06 14:05:29 +02:00
LucaZanni 0ed7e2b58a fix(ci): sostituisce gitea.com/actions/cache con github.com - HTTP 500
gitea.com/actions/cache@v4 restituisce 500 impedendo l'avvio del job android.
2026-06-06 13:59:52 +02:00
LucaZanni 3b49d18d5b fix(ci): aggiunge input npm-version per compatibilità lockfile npm@11
- quality-gates.yml: nuovo input npm-version con step condizionale upgrade
- docker-release.yml: idem
- examples/documentazione: ci.yml e release.yml passano npm-version: '11'

Fixes #2 @25m
2026-06-06 13:36:22 +02:00
LucaZanni 53b1c7a9c4 feat(examples): aggiungi template documentazione Nuxt 4
- ci.yml: quality-gates condivisi con paths-ignore su content/**
- release.yml: docker-release + auto-release con needs
- maintenance.yml: schedule martedì 02:00 audit, 1° mese 03:00 outdated

refs #1 @25m
2026-06-06 13:28:46 +02:00
LucaZanni 0f7688ac5e chore(ci): aggiorna action versions, fix auto-release e migrazione self-hosted
- Aggiorna checkout v4→v6, setup-python v5→v5.2.0, setup-android v3→v4
- Aggiorna upload-artifact v3→v4, docker/login-action v3→v4
- Aggiunge needs su auto-release in tutti gli esempi (fix esecuzione parallela)
- Aggiunge token esplicito nel checkout come workaround bug Gitea #31900
- Aggiunge job dependency-outdated mancante in libreria-npm/maintenance.yml
- Aggiorna schedule: libreria-npm mercoledì 02:00, microservizio lunedì 02:00
- Migra tutti i riferimenti da gitea.com/Punga78 a gitea.pzetatouch.it/devops

Fixes #1 @3h
2026-06-06 13:21:01 +02:00
LucaZanni 54c74d9c6a feat(ci): aggiungi label OCI per collegare container al repository Gitea
- Aggiunto org.opencontainers.image.source con URL del repository
- Aggiunto org.opencontainers.image.revision con SHA del commit
- Aggiunto org.opencontainers.image.version con versione del pacchetto
- Applicato a docker-release.yml e python-docker-release.yml

@25m
2026-04-11 18:53:05 +02:00
LucaZanni 86a0cd416f 🐛 fix(ci): correggi passaggio NPM_TOKEN come Docker secret e runs-on workaround
- Sostituisce build-args con secrets in docker-release.yml per compatibilità
  con Dockerfile che usa --mount=type=secret,id=npm_token
- Aggiunge runs-on: catthehacker-latest negli esempi (workaround Gitea bug #34986)
2026-04-09 19:54:25 +02:00
LucaZanni 3ee135b020 👷 ci(release): aggiungi workaround per bug runs-on in Gitea
- aggiunta runs-on: catthehacker-latest per aggirare bug #34986
- commento esplicativo sul motivo della modifica
- garantita corretta esecuzione workflow_call su Gitea
2026-04-09 19:46:59 +02:00
49 changed files with 2355 additions and 130 deletions
+59
View File
@@ -0,0 +1,59 @@
name: Auto Release
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
jobs:
auto-release:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
with:
fetch-depth: 0
token: ${{ gitea.token }}
- name: Generate changelog
id: changelog
run: |
CURRENT_TAG=${GITHUB_REF#refs/tags/}
PREV_TAG=$(git tag --sort=-version:refname | sed -n '2p')
if [ -z "$PREV_TAG" ]; then
CHANGELOG=$(git log --pretty=format:"- %s (%h)" "$CURRENT_TAG")
else
CHANGELOG=$(git log --pretty=format:"- %s (%h)" "${PREV_TAG}..${CURRENT_TAG}")
fi
echo "$CHANGELOG" > /tmp/changelog.txt
echo "current_tag=$CURRENT_TAG" >> $GITHUB_OUTPUT
- name: Create release
env:
GITEA_TOKEN: ${{ gitea.token }}
SERVER_URL: ${{ gitea.server_url }}
REPOSITORY: ${{ gitea.repository }}
run: |
CURRENT_TAG=${{ steps.changelog.outputs.current_tag }}
APP_NAME=$(jq -r '.name' package.json)
CHANGELOG=$(cat /tmp/changelog.txt)
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/releases" \
-d "{
\"tag_name\": \"$CURRENT_TAG\",
\"name\": \"$APP_NAME $CURRENT_TAG\",
\"body\": $(echo "$CHANGELOG" | jq -Rs .),
\"draft\": false,
\"prerelease\": false
}"
+10 -1
View File
@@ -2,15 +2,24 @@ name: Auto Release
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
jobs:
auto-release:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
with:
fetch-depth: 0
token: ${{ gitea.token }}
- name: Generate changelog
id: changelog
@@ -0,0 +1,261 @@
name: Capacitor Android
on:
workflow_call:
inputs:
node-version:
type: string
default: '24.16.0'
java-version:
type: string
default: '21'
runner:
type: string
default: 'ubuntu-latest'
build-type:
description: 'debug | release'
type: string
default: 'debug'
output-format:
description: 'apk (sideload/test) | aab (Play Store)'
type: string
default: 'apk'
version-code:
description: 'versionCode Android esplicito. Se vuoto viene derivato da package.json: major*10000 + minor*100 + patch'
type: string
default: ''
secrets:
NPM_TOKEN:
required: false
KEYSTORE_BASE64:
required: false
KEYSTORE_PASSWORD:
required: false
KEY_ALIAS:
required: false
KEY_PASSWORD:
required: false
GOOGLE_SERVICES_JSON:
required: false
jobs:
android-build:
runs-on: ${{ inputs.runner }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Node.js
uses: https://github.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Setup Java
uses: https://github.com/actions/setup-java@v4
with:
distribution: temurin
java-version: ${{ inputs.java-version || '17' }}
- name: Setup Android SDK
uses: https://github.com/android-actions/setup-android@v4
- name: Cache npm
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Cache Gradle
uses: https://github.com/actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Read app info from package.json
id: app-info
run: |
echo "name=$(jq -r '.name' package.json)" >> $GITHUB_OUTPUT
echo "version=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
- name: Install dependencies
run: npm ci
- name: Build web app
run: npm run build
- name: Add Android platform
run: npx cap add android || true
- name: Sync Capacitor
run: npx cap sync android
# La piattaforma Android puo essere generata da 'cap add' (default Capacitor:
# versionName "1.0", versionCode 1) oppure versionata nel repo consumer.
# In entrambi i casi la versione pubblicata deve derivare da package.json,
# unica fonte di verita, altrimenti l'APK/AAB dichiara una versione diversa
# da quella del tag e Play Store rifiuta upload con versionCode non crescente.
- name: Inject Android version
id: android-version
env:
PKG_VERSION: ${{ steps.app-info.outputs.version }}
VERSION_CODE_OVERRIDE: ${{ inputs.version-code }}
run: |
set -euo pipefail
if [ -f android/app/build.gradle ]; then
GRADLE_FILE="android/app/build.gradle"
KTS=0
elif [ -f android/app/build.gradle.kts ]; then
GRADLE_FILE="android/app/build.gradle.kts"
KTS=1
else
echo "::error::Nessun build.gradle in android/app/ — piattaforma Android non generata"
exit 1
fi
VERSION_NAME="$PKG_VERSION"
if [ -n "$VERSION_CODE_OVERRIDE" ]; then
VERSION_CODE="$VERSION_CODE_OVERRIDE"
else
CORE="${PKG_VERSION%%-*}" # scarta il pre-release: 1.2.3-beta.1 -> 1.2.3
CORE="${CORE%%+*}" # scarta il build metadata: 1.2.3+abc -> 1.2.3
MAJOR="$(echo "$CORE" | cut -d. -f1)"
MINOR="$(echo "$CORE" | cut -d. -f2)"
PATCH="$(echo "$CORE" | cut -d. -f3)"
MINOR="${MINOR:-0}"
PATCH="${PATCH:-0}"
case "${MAJOR}${MINOR}${PATCH}" in
''|*[!0-9]*)
echo "::error::Versione package.json non semver: '$PKG_VERSION'. Passare version-code esplicito."
exit 1
;;
esac
if [ "$MINOR" -gt 99 ] || [ "$PATCH" -gt 99 ]; then
echo "::error::minor/patch > 99 non rappresentabili ('$PKG_VERSION'). Passare version-code esplicito."
exit 1
fi
VERSION_CODE=$(( MAJOR * 10000 + MINOR * 100 + PATCH ))
fi
if [ "$KTS" -eq 1 ]; then
sed -i -E "s/versionCode[[:space:]]*=[[:space:]]*[0-9]+/versionCode = ${VERSION_CODE}/" "$GRADLE_FILE"
sed -i -E "s/versionName[[:space:]]*=[[:space:]]*\"[^\"]*\"/versionName = \"${VERSION_NAME}\"/" "$GRADLE_FILE"
else
sed -i -E "s/versionCode[[:space:]]+[0-9]+/versionCode ${VERSION_CODE}/" "$GRADLE_FILE"
sed -i -E "s/versionName[[:space:]]+\"[^\"]*\"/versionName \"${VERSION_NAME}\"/" "$GRADLE_FILE"
fi
# Il sed silenzioso e' peggio di un fallimento: senza questa verifica una
# variazione del template Capacitor produrrebbe build con versione sbagliata.
# Si confrontano i valori estratti, non si rilegge il file con una regex
# costruita sulla versione: '+' e '.' di un semver sono metacaratteri ERE.
# '|| true': senza, pipefail farebbe uscire lo step su un file privo di
# versionCode/versionName, perdendo la diagnostica del blocco sottostante.
ACTUAL_CODE="$(grep -oE 'versionCode[[:space:]]*=?[[:space:]]*[0-9]+' "$GRADLE_FILE" | head -1 | grep -oE '[0-9]+$' || true)"
ACTUAL_NAME="$(grep -oE 'versionName[[:space:]]*=?[[:space:]]*"[^"]*"' "$GRADLE_FILE" | head -1 | cut -d'"' -f2 || true)"
if [ "$ACTUAL_CODE" != "$VERSION_CODE" ] || [ "$ACTUAL_NAME" != "$VERSION_NAME" ]; then
echo "::error::Iniezione versione fallita in $GRADLE_FILE"
echo " atteso: versionName='${VERSION_NAME}' versionCode=${VERSION_CODE}"
echo " trovato: versionName='${ACTUAL_NAME}' versionCode=${ACTUAL_CODE}"
grep -nE 'versionCode|versionName' "$GRADLE_FILE" || true
exit 1
fi
echo "version-name=${VERSION_NAME}" >> $GITHUB_OUTPUT
echo "version-code=${VERSION_CODE}" >> $GITHUB_OUTPUT
echo "Android: versionName=${VERSION_NAME} versionCode=${VERSION_CODE} ($GRADLE_FILE)"
- name: Setup google-services.json
if: secrets.GOOGLE_SERVICES_JSON != ''
run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > android/app/google-services.json
- name: Setup release keystore
if: inputs.build-type == 'release'
run: echo '${{ secrets.KEYSTORE_BASE64 }}' | base64 -d > android/app/keystore.jks
# Il wrapper arriva dal repo senza bit di esecuzione quando il progetto e'
# committato da Windows: git registra mode 100644 e il checkout sul runner
# Linux produce "./gradlew: Permission denied". Il chmod qui vale per ogni
# repo Capacitor, cosi' il difetto non va rincorso uno per uno.
- name: Rendi eseguibile gradlew
run: chmod +x android/gradlew
- name: Build Android (APK)
if: inputs.output-format == 'apk'
working-directory: android
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: |
if [ "${{ inputs.build-type }}" = "release" ]; then
./gradlew assembleRelease
else
./gradlew assembleDebug
fi
- name: Rename APK
if: inputs.output-format == 'apk'
run: |
APP="${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-${{ inputs.build-type }}"
APK_DIR="android/app/build/outputs/apk/${{ inputs.build-type }}"
mv "$APK_DIR"/app-${{ inputs.build-type }}.apk "$APK_DIR/${APP}.apk" 2>/dev/null || \
mv "$APK_DIR"/app-${{ inputs.build-type }}-unsigned.apk "$APK_DIR/${APP}.apk" 2>/dev/null || \
find "$APK_DIR" -name "*.apk" ! -name "${APP}.apk" -exec mv {} "$APK_DIR/${APP}.apk" \;
- name: Build Android (AAB)
if: inputs.output-format == 'aab'
working-directory: android
env:
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
run: ./gradlew bundleRelease
- name: Rename AAB
if: inputs.output-format == 'aab'
run: |
APP="${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-release"
AAB_DIR="android/app/build/outputs/bundle/release"
find "$AAB_DIR" -name "*.aab" ! -name "${APP}.aab" -exec mv {} "$AAB_DIR/${APP}.aab" \;
- name: Upload APK artifact
if: inputs.output-format == 'apk'
uses: https://github.com/actions/upload-artifact@v3
with:
name: ${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-${{ inputs.build-type }}-apk
path: android/app/build/outputs/apk/${{ inputs.build-type }}/${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-${{ inputs.build-type }}.apk
retention-days: 14
- name: Upload AAB artifact
if: inputs.output-format == 'aab'
uses: https://github.com/actions/upload-artifact@v3
with:
name: ${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-release-aab
path: android/app/build/outputs/bundle/release/${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-release.aab
retention-days: 14
- name: Upload Gradle build reports
if: always()
uses: https://github.com/actions/upload-artifact@v3
with:
name: gradle-build-reports
path: android/build/reports/
retention-days: 7
if-no-files-found: ignore
+105 -13
View File
@@ -5,7 +5,7 @@ on:
inputs:
node-version:
type: string
default: '22.17'
default: '24.16.0'
java-version:
type: string
default: '21'
@@ -20,6 +20,10 @@ on:
description: 'apk (sideload/test) | aab (Play Store)'
type: string
default: 'apk'
version-code:
description: 'versionCode Android esplicito. Se vuoto viene derivato da package.json: major*10000 + minor*100 + patch'
type: string
default: ''
secrets:
NPM_TOKEN:
required: false
@@ -39,12 +43,12 @@ jobs:
runs-on: ${{ inputs.runner }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Node.js
uses: https://gitea.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '22.17' }}
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Setup Java
uses: https://github.com/actions/setup-java@v4
@@ -53,10 +57,10 @@ jobs:
java-version: ${{ inputs.java-version || '17' }}
- name: Setup Android SDK
uses: https://github.com/android-actions/setup-android@v3
uses: https://github.com/android-actions/setup-android@v4
- name: Cache npm
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
@@ -64,7 +68,7 @@ jobs:
${{ runner.os }}-node-
- name: Cache Gradle
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: |
~/.gradle/caches
@@ -75,14 +79,14 @@ jobs:
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/pzeta_touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/pzeta_touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Read app info from package.json
id: app-info
run: |
echo "name=$(node -e \"console.log(require('./package.json').name)\")" >> $GITHUB_OUTPUT
echo "version=$(node -e \"console.log(require('./package.json').version)\")" >> $GITHUB_OUTPUT
echo "name=$(jq -r '.name' package.json)" >> $GITHUB_OUTPUT
echo "version=$(jq -r '.version' package.json)" >> $GITHUB_OUTPUT
- name: Install dependencies
run: npm ci
@@ -96,6 +100,87 @@ jobs:
- name: Sync Capacitor
run: npx cap sync android
# La piattaforma Android puo essere generata da 'cap add' (default Capacitor:
# versionName "1.0", versionCode 1) oppure versionata nel repo consumer.
# In entrambi i casi la versione pubblicata deve derivare da package.json,
# unica fonte di verita, altrimenti l'APK/AAB dichiara una versione diversa
# da quella del tag e Play Store rifiuta upload con versionCode non crescente.
- name: Inject Android version
id: android-version
env:
PKG_VERSION: ${{ steps.app-info.outputs.version }}
VERSION_CODE_OVERRIDE: ${{ inputs.version-code }}
run: |
set -euo pipefail
if [ -f android/app/build.gradle ]; then
GRADLE_FILE="android/app/build.gradle"
KTS=0
elif [ -f android/app/build.gradle.kts ]; then
GRADLE_FILE="android/app/build.gradle.kts"
KTS=1
else
echo "::error::Nessun build.gradle in android/app/ — piattaforma Android non generata"
exit 1
fi
VERSION_NAME="$PKG_VERSION"
if [ -n "$VERSION_CODE_OVERRIDE" ]; then
VERSION_CODE="$VERSION_CODE_OVERRIDE"
else
CORE="${PKG_VERSION%%-*}" # scarta il pre-release: 1.2.3-beta.1 -> 1.2.3
CORE="${CORE%%+*}" # scarta il build metadata: 1.2.3+abc -> 1.2.3
MAJOR="$(echo "$CORE" | cut -d. -f1)"
MINOR="$(echo "$CORE" | cut -d. -f2)"
PATCH="$(echo "$CORE" | cut -d. -f3)"
MINOR="${MINOR:-0}"
PATCH="${PATCH:-0}"
case "${MAJOR}${MINOR}${PATCH}" in
''|*[!0-9]*)
echo "::error::Versione package.json non semver: '$PKG_VERSION'. Passare version-code esplicito."
exit 1
;;
esac
if [ "$MINOR" -gt 99 ] || [ "$PATCH" -gt 99 ]; then
echo "::error::minor/patch > 99 non rappresentabili ('$PKG_VERSION'). Passare version-code esplicito."
exit 1
fi
VERSION_CODE=$(( MAJOR * 10000 + MINOR * 100 + PATCH ))
fi
if [ "$KTS" -eq 1 ]; then
sed -i -E "s/versionCode[[:space:]]*=[[:space:]]*[0-9]+/versionCode = ${VERSION_CODE}/" "$GRADLE_FILE"
sed -i -E "s/versionName[[:space:]]*=[[:space:]]*\"[^\"]*\"/versionName = \"${VERSION_NAME}\"/" "$GRADLE_FILE"
else
sed -i -E "s/versionCode[[:space:]]+[0-9]+/versionCode ${VERSION_CODE}/" "$GRADLE_FILE"
sed -i -E "s/versionName[[:space:]]+\"[^\"]*\"/versionName \"${VERSION_NAME}\"/" "$GRADLE_FILE"
fi
# Il sed silenzioso e' peggio di un fallimento: senza questa verifica una
# variazione del template Capacitor produrrebbe build con versione sbagliata.
# Si confrontano i valori estratti, non si rilegge il file con una regex
# costruita sulla versione: '+' e '.' di un semver sono metacaratteri ERE.
# '|| true': senza, pipefail farebbe uscire lo step su un file privo di
# versionCode/versionName, perdendo la diagnostica del blocco sottostante.
ACTUAL_CODE="$(grep -oE 'versionCode[[:space:]]*=?[[:space:]]*[0-9]+' "$GRADLE_FILE" | head -1 | grep -oE '[0-9]+$' || true)"
ACTUAL_NAME="$(grep -oE 'versionName[[:space:]]*=?[[:space:]]*"[^"]*"' "$GRADLE_FILE" | head -1 | cut -d'"' -f2 || true)"
if [ "$ACTUAL_CODE" != "$VERSION_CODE" ] || [ "$ACTUAL_NAME" != "$VERSION_NAME" ]; then
echo "::error::Iniezione versione fallita in $GRADLE_FILE"
echo " atteso: versionName='${VERSION_NAME}' versionCode=${VERSION_CODE}"
echo " trovato: versionName='${ACTUAL_NAME}' versionCode=${ACTUAL_CODE}"
grep -nE 'versionCode|versionName' "$GRADLE_FILE" || true
exit 1
fi
echo "version-name=${VERSION_NAME}" >> $GITHUB_OUTPUT
echo "version-code=${VERSION_CODE}" >> $GITHUB_OUTPUT
echo "Android: versionName=${VERSION_NAME} versionCode=${VERSION_CODE} ($GRADLE_FILE)"
- name: Setup google-services.json
if: secrets.GOOGLE_SERVICES_JSON != ''
run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > android/app/google-services.json
@@ -104,6 +189,13 @@ jobs:
if: inputs.build-type == 'release'
run: echo '${{ secrets.KEYSTORE_BASE64 }}' | base64 -d > android/app/keystore.jks
# Il wrapper arriva dal repo senza bit di esecuzione quando il progetto e'
# committato da Windows: git registra mode 100644 e il checkout sul runner
# Linux produce "./gradlew: Permission denied". Il chmod qui vale per ogni
# repo Capacitor, cosi' il difetto non va rincorso uno per uno.
- name: Rendi eseguibile gradlew
run: chmod +x android/gradlew
- name: Build Android (APK)
if: inputs.output-format == 'apk'
working-directory: android
@@ -145,7 +237,7 @@ jobs:
- name: Upload APK artifact
if: inputs.output-format == 'apk'
uses: https://github.com/actions/upload-artifact@v3
uses: https://gitea.com/actions/upload-artifact@v3
with:
name: ${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-${{ inputs.build-type }}-apk
path: android/app/build/outputs/apk/${{ inputs.build-type }}/${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-${{ inputs.build-type }}.apk
@@ -153,7 +245,7 @@ jobs:
- name: Upload AAB artifact
if: inputs.output-format == 'aab'
uses: https://github.com/actions/upload-artifact@v3
uses: https://gitea.com/actions/upload-artifact@v3
with:
name: ${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-release-aab
path: android/app/build/outputs/bundle/release/${{ steps.app-info.outputs.name }}-${{ steps.app-info.outputs.version }}-release.aab
@@ -161,7 +253,7 @@ jobs:
- name: Upload Gradle build reports
if: always()
uses: https://github.com/actions/upload-artifact@v3
uses: https://gitea.com/actions/upload-artifact@v3
with:
name: gradle-build-reports
path: android/build/reports/
@@ -0,0 +1,75 @@
name: Dependency Audit
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
node-version:
type: string
default: '24.16.0'
workflow_dispatch:
jobs:
dependency-audit:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Node.js
uses: https://github.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Cache npm
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Install dependencies
run: npm ci
- name: Security audit
id: audit
run: |
npm audit --audit-level=high --json > audit.json 2>/dev/null || true
VULNS=$(jq '(.metadata.vulnerabilities.high // 0) + (.metadata.vulnerabilities.critical // 0)' audit.json 2>/dev/null || echo "0")
echo "vulnerabilities=$VULNS" >> $GITHUB_OUTPUT
- name: Open issue if vulnerabilities found
if: steps.audit.outputs.vulnerabilities != '0'
env:
GITEA_TOKEN: ${{ gitea.token }}
SERVER_URL: ${{ gitea.server_url }}
REPOSITORY: ${{ gitea.repository }}
run: |
VULNS="${{ steps.audit.outputs.vulnerabilities }}"
DATE=$(date '+%Y-%m-%d')
VULN_LIST=$(jq -r '.vulnerabilities | to_entries[] | "- \(.key): \(.value.severity)"' audit.json 2>/dev/null | head -20 || echo "N/A")
printf '## Security Audit — %s\n\n### Vulnerabilità (high/critical): %s\n\n```\n%s\n```\n' \
"$DATE" "$VULNS" "$VULN_LIST" > /tmp/body.md
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues" \
-d "{
\"title\": \"[$DATE] Security: $VULNS vulnerabilità high/critical\",
\"body\": $(jq -Rs . /tmp/body.md)
}"
+13 -6
View File
@@ -3,25 +3,32 @@ name: Dependency Audit
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
node-version:
type: string
default: '22.17'
default: '24.16.0'
workflow_dispatch:
jobs:
dependency-audit:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Node.js
uses: https://gitea.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '22.17' }}
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Cache npm
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
@@ -30,8 +37,8 @@ jobs:
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/pzeta_touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/pzeta_touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Install dependencies
run: npm ci
@@ -0,0 +1,75 @@
name: Dependency Outdated
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
node-version:
type: string
default: '24.16.0'
workflow_dispatch:
jobs:
dependency-outdated:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Node.js
uses: https://github.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Cache npm
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Install dependencies
run: npm ci
- name: Check outdated packages
id: outdated
run: |
npm outdated --json > outdated.json 2>/dev/null || true
OUTDATED=$(jq 'keys | length' outdated.json 2>/dev/null || echo "0")
echo "count=$OUTDATED" >> $GITHUB_OUTPUT
- name: Open issue if packages outdated
if: steps.outdated.outputs.count != '0'
env:
GITEA_TOKEN: ${{ gitea.token }}
SERVER_URL: ${{ gitea.server_url }}
REPOSITORY: ${{ gitea.repository }}
run: |
OUTDATED="${{ steps.outdated.outputs.count }}"
DATE=$(date '+%Y-%m-%d')
OUTDATED_LIST=$(jq -r 'to_entries[] | "- \(.key): \(.value.current) → \(.value.latest)"' outdated.json 2>/dev/null | head -20 || echo "N/A")
printf '## Dipendenze Obsolete — %s\n\n### Pacchetti da aggiornare: %s\n\n```\n%s\n```\n' \
"$DATE" "$OUTDATED" "$OUTDATED_LIST" > /tmp/body.md
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues" \
-d "{
\"title\": \"[$DATE] Dipendenze: $OUTDATED pacchetti obsoleti\",
\"body\": $(jq -Rs . /tmp/body.md)
}"
+13 -6
View File
@@ -3,25 +3,32 @@ name: Dependency Outdated
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
node-version:
type: string
default: '22.17'
default: '24.16.0'
workflow_dispatch:
jobs:
dependency-outdated:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Node.js
uses: https://gitea.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '22.17' }}
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Cache npm
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
@@ -30,8 +37,8 @@ jobs:
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/pzeta_touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/pzeta_touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Install dependencies
run: npm ci
@@ -0,0 +1,99 @@
name: Docker Release
on:
workflow_call:
inputs:
node-version:
type: string
default: '24.16.0'
npm-version:
type: string
default: ''
runner:
type: string
default: 'catthehacker-latest'
jobs:
docker-release:
runs-on: ${{ inputs.runner }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Node.js
uses: https://github.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Upgrade npm
if: inputs.npm-version != ''
run: npm install -g npm@${{ inputs.npm-version }}
- name: Cache npm
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Install dependencies
run: npm ci
- name: Type check
run: npm run typecheck
- name: Lint
run: npm run lint:check
- name: Format check
run: npm run format:check
- name: Build
run: npm run build
- name: Test
run: npm run test
- name: Login to container registry
uses: https://github.com/docker/login-action@v4
with:
registry: gitea.pzetatouch.it
username: ${{ secrets.G_USER }}
password: ${{ secrets.NPM_TOKEN }}
- name: Determine image tags
id: tags
run: |
RAW_NAME=$(jq -r '.name' package.json)
APP_NAME=$(echo "$RAW_NAME" | sed 's|^@[^/]*/||')
VERSION=$(jq -r '.version' package.json)
REGISTRY="gitea.pzetatouch.it/pzeta_touch"
echo "version_tag=${REGISTRY}/${APP_NAME}:${VERSION}" >> $GITHUB_OUTPUT
echo "latest_tag=${REGISTRY}/${APP_NAME}:latest" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: https://github.com/docker/build-push-action@v6
with:
push: true
context: .
file: ./Dockerfile
tags: |
${{ steps.tags.outputs.version_tag }}
${{ steps.tags.outputs.latest_tag }}
labels: |
org.opencontainers.image.source=${{ gitea.server_url }}/${{ gitea.repository }}
org.opencontainers.image.revision=${{ gitea.sha }}
org.opencontainers.image.version=${{ steps.tags.outputs.version }}
build-args: |
NODE_VERSION=${{ vars.NODE_DOCKER_VERSION || '24.16.0-alpine3.22' }}
NGINX_VERSION=${{ vars.NGINX_DOCKER_VERSION || '1.30.2-alpine3.23' }}
NPM_VERSION=${{ vars.NPM_VERSION || '11.16.0' }}
secrets: |
npm_token=${{ secrets.NPM_TOKEN }}
+24 -8
View File
@@ -5,7 +5,10 @@ on:
inputs:
node-version:
type: string
default: '22.17'
default: '24.16.0'
npm-version:
type: string
default: ''
runner:
type: string
default: 'catthehacker-latest'
@@ -15,15 +18,19 @@ jobs:
runs-on: ${{ inputs.runner }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Node.js
uses: https://gitea.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '22.17' }}
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Upgrade npm
if: inputs.npm-version != ''
run: npm install -g npm@${{ inputs.npm-version }}
- name: Cache npm
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
@@ -32,8 +39,8 @@ jobs:
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/pzeta_touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/pzeta_touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Install dependencies
run: npm ci
@@ -54,7 +61,7 @@ jobs:
run: npm run test
- name: Login to container registry
uses: https://gitea.com/docker/login-action@v3
uses: https://gitea.com/docker/login-action@v4
with:
registry: gitea.pzetatouch.it
username: ${{ secrets.G_USER }}
@@ -69,6 +76,7 @@ jobs:
REGISTRY="gitea.pzetatouch.it/pzeta_touch"
echo "version_tag=${REGISTRY}/${APP_NAME}:${VERSION}" >> $GITHUB_OUTPUT
echo "latest_tag=${REGISTRY}/${APP_NAME}:latest" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: https://gitea.com/docker/build-push-action@v6
@@ -79,5 +87,13 @@ jobs:
tags: |
${{ steps.tags.outputs.version_tag }}
${{ steps.tags.outputs.latest_tag }}
labels: |
org.opencontainers.image.source=${{ gitea.server_url }}/${{ gitea.repository }}
org.opencontainers.image.revision=${{ gitea.sha }}
org.opencontainers.image.version=${{ steps.tags.outputs.version }}
build-args: |
NPM_TOKEN=${{ secrets.NPM_TOKEN }}
NODE_VERSION=${{ vars.NODE_DOCKER_VERSION || '24.16.0-alpine3.22' }}
NGINX_VERSION=${{ vars.NGINX_DOCKER_VERSION || '1.30.2-alpine3.23' }}
NPM_VERSION=${{ vars.NPM_VERSION || '11.16.0' }}
secrets: |
npm_token=${{ secrets.NPM_TOKEN }}
+61
View File
@@ -0,0 +1,61 @@
name: Publish npm Package
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
node-version:
type: string
default: '24.16.0'
jobs:
npm-publish:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Node.js
uses: https://github.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Cache npm
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint:check
- name: Type check
run: npm run typecheck
- name: Format check
run: npm run format:check
- name: Build
run: npm run build
- name: Test
run: npm run test
- name: Publish
run: npm publish
+13 -6
View File
@@ -3,24 +3,31 @@ name: Publish npm Package
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
node-version:
type: string
default: '22.17'
default: '24.16.0'
jobs:
npm-publish:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Node.js
uses: https://gitea.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '22.17' }}
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Cache npm
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
@@ -29,8 +36,8 @@ jobs:
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/pzeta_touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/pzeta_touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Install dependencies
run: npm ci
@@ -0,0 +1,70 @@
name: Python Auto Release
on:
workflow_call:
inputs:
working-directory:
description: 'Directory di lavoro se il progetto non è in root'
type: string
default: '.'
jobs:
python-auto-release:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
with:
fetch-depth: 0
token: ${{ gitea.token }}
- name: Generate changelog
id: changelog
run: |
CURRENT_TAG=${GITHUB_REF#refs/tags/}
PREV_TAG=$(git tag --sort=-version:refname | sed -n '2p')
if [ -z "$PREV_TAG" ]; then
CHANGELOG=$(git log --pretty=format:"- %s (%h)" "$CURRENT_TAG")
else
CHANGELOG=$(git log --pretty=format:"- %s (%h)" "${PREV_TAG}..${CURRENT_TAG}")
fi
echo "$CHANGELOG" > /tmp/changelog.txt
echo "current_tag=$CURRENT_TAG" >> $GITHUB_OUTPUT
- name: Read app name from pyproject.toml
id: app-info
run: |
APP_NAME=$(python3 -c "
import re, pathlib
content = pathlib.Path('pyproject.toml').read_text()
m = re.search(r'^name\s*=\s*[\"\'](.*?)[\"\']', content, re.MULTILINE)
print(m.group(1) if m else 'app')
" 2>/dev/null || echo 'app')
echo "name=$APP_NAME" >> $GITHUB_OUTPUT
- name: Create release
env:
GITEA_TOKEN: ${{ gitea.token }}
SERVER_URL: ${{ gitea.server_url }}
REPOSITORY: ${{ gitea.repository }}
run: |
CURRENT_TAG=${{ steps.changelog.outputs.current_tag }}
APP_NAME=${{ steps.app-info.outputs.name }}
CHANGELOG=$(cat /tmp/changelog.txt)
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/releases" \
-d "{
\"tag_name\": \"$CURRENT_TAG\",
\"name\": \"$APP_NAME $CURRENT_TAG\",
\"body\": $(echo "$CHANGELOG" | jq -Rs .),
\"draft\": false,
\"prerelease\": false
}"
+2 -1
View File
@@ -16,9 +16,10 @@ jobs:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
with:
fetch-depth: 0
token: ${{ gitea.token }}
- name: Generate changelog
id: changelog
@@ -0,0 +1,120 @@
name: Python Dependency Audit
on:
workflow_call:
inputs:
python-version:
type: string
default: '3.11'
install-extras:
type: string
default: 'dev'
working-directory:
type: string
default: '.'
workflow_dispatch:
jobs:
python-dependency-audit:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Python
uses: https://github.com/actions/setup-python@v5.2.0
with:
python-version: ${{ inputs.python-version || '3.11' }}
- name: Cache pip
uses: https://github.com/actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
restore-keys: |
${{ runner.os }}-pip-${{ inputs.python-version }}-
${{ runner.os }}-pip-
- name: Install dependencies (isolated venv)
run: |
# venv pulita: audita SOLO le dipendenze dichiarate dal repo,
# non l'ambiente globale del runner (che su runner ML/GPU è contaminato)
python -m venv .audit-venv
.audit-venv/bin/pip install --upgrade pip pip-audit
if [ -n "${{ inputs.install-extras }}" ]; then
.audit-venv/bin/pip install -e ".[${{ inputs.install-extras }}]"
elif [ -f requirements.txt ]; then
.audit-venv/bin/pip install -r requirements.txt
else
.audit-venv/bin/pip install -e "."
fi
- name: Security audit (pip-audit)
id: audit
run: |
.audit-venv/bin/pip-audit --format=json --output=audit.json 2>/dev/null || true
VULNS=$(python3 -c "
import json, sys
try:
data = json.load(open('audit.json'))
deps = data.get('dependencies', [])
count = sum(len(d.get('vulns', [])) for d in deps)
print(count)
except Exception:
print(0)
")
echo "vulnerabilities=$VULNS" >> $GITHUB_OUTPUT
- name: Open or update issue if vulnerabilities found
if: steps.audit.outputs.vulnerabilities != '0'
env:
GITEA_TOKEN: ${{ gitea.token }}
SERVER_URL: ${{ gitea.server_url }}
REPOSITORY: ${{ gitea.repository }}
run: |
VULNS="${{ steps.audit.outputs.vulnerabilities }}"
DATE=$(date '+%Y-%m-%d')
TITLE_PREFIX="Security Python:"
VULN_LIST=$(python3 -c "
import json
try:
data = json.load(open('audit.json'))
lines = []
for dep in data.get('dependencies', []):
for v in dep.get('vulns', []):
lines.append(f\"- {dep['name']} {dep.get('version','?')}: {v.get('id','?')} ({v.get('description','')[:80]})\")
print('\n'.join(lines[:20]))
except Exception:
print('N/A')
")
printf '## Security Audit Python — %s\n\n### Vulnerabilità trovate: %s\n\n```\n%s\n```\n' \
"$DATE" "$VULNS" "$VULN_LIST" > /tmp/body.md
# Deduplica: se esiste già una issue aperta con lo stesso prefisso,
# aggiungi un commento invece di aprirne una nuova
EXISTING=$(curl -s \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues?state=open&type=issues&limit=50" \
| jq -r --arg p "$TITLE_PREFIX" '[.[] | select(.title | contains($p))] | (first // {}) | .number // empty')
if [ -n "$EXISTING" ]; then
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues/$EXISTING/comments" \
-d "{ \"body\": $(jq -Rs . /tmp/body.md) }"
else
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues" \
-d "{
\"title\": \"[$DATE] Security Python: $VULNS vulnerabilità rilevate\",
\"body\": $(jq -Rs . /tmp/body.md)
}"
fi
+36 -17
View File
@@ -22,15 +22,15 @@ jobs:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Python
uses: https://github.com/actions/setup-python@v5
uses: https://github.com/actions/setup-python@v5.2.0
with:
python-version: ${{ inputs.python-version || '3.11' }}
- name: Cache pip
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
@@ -38,21 +38,24 @@ jobs:
${{ runner.os }}-pip-${{ inputs.python-version }}-
${{ runner.os }}-pip-
- name: Install dependencies
- name: Install dependencies (isolated venv)
run: |
python -m pip install --upgrade pip pip-audit
# venv pulita: audita SOLO le dipendenze dichiarate dal repo,
# non l'ambiente globale del runner (che su runner ML/GPU è contaminato)
python -m venv .audit-venv
.audit-venv/bin/pip install --upgrade pip pip-audit
if [ -n "${{ inputs.install-extras }}" ]; then
pip install -e ".[${{ inputs.install-extras }}]"
.audit-venv/bin/pip install -e ".[${{ inputs.install-extras }}]"
elif [ -f requirements.txt ]; then
pip install -r requirements.txt
.audit-venv/bin/pip install -r requirements.txt
else
pip install -e "."
.audit-venv/bin/pip install -e "."
fi
- name: Security audit (pip-audit)
id: audit
run: |
pip-audit --format=json --output=audit.json 2>/dev/null || true
.audit-venv/bin/pip-audit --format=json --output=audit.json 2>/dev/null || true
VULNS=$(python3 -c "
import json, sys
try:
@@ -65,7 +68,7 @@ jobs:
")
echo "vulnerabilities=$VULNS" >> $GITHUB_OUTPUT
- name: Open issue if vulnerabilities found
- name: Open or update issue if vulnerabilities found
if: steps.audit.outputs.vulnerabilities != '0'
env:
GITEA_TOKEN: ${{ gitea.token }}
@@ -74,6 +77,7 @@ jobs:
run: |
VULNS="${{ steps.audit.outputs.vulnerabilities }}"
DATE=$(date '+%Y-%m-%d')
TITLE_PREFIX="Security Python:"
VULN_LIST=$(python3 -c "
import json
@@ -91,11 +95,26 @@ jobs:
printf '## Security Audit Python — %s\n\n### Vulnerabilità trovate: %s\n\n```\n%s\n```\n' \
"$DATE" "$VULNS" "$VULN_LIST" > /tmp/body.md
curl -s -X POST \
-H "Content-Type: application/json" \
# Deduplica: se esiste già una issue aperta con lo stesso prefisso,
# aggiungi un commento invece di aprirne una nuova
EXISTING=$(curl -s \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues" \
-d "{
\"title\": \"[$DATE] Security Python: $VULNS vulnerabilità rilevate\",
\"body\": $(jq -Rs . /tmp/body.md)
}"
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues?state=open&type=issues&limit=50" \
| jq -r --arg p "$TITLE_PREFIX" '[.[] | select(.title | contains($p))] | (first // {}) | .number // empty')
if [ -n "$EXISTING" ]; then
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues/$EXISTING/comments" \
-d "{ \"body\": $(jq -Rs . /tmp/body.md) }"
else
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues" \
-d "{
\"title\": \"[$DATE] Security Python: $VULNS vulnerabilità rilevate\",
\"body\": $(jq -Rs . /tmp/body.md)
}"
fi
@@ -0,0 +1,108 @@
name: Python Dependency Outdated
on:
workflow_call:
inputs:
python-version:
type: string
default: '3.11'
install-extras:
type: string
default: 'dev'
working-directory:
type: string
default: '.'
workflow_dispatch:
jobs:
python-dependency-outdated:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Python
uses: https://github.com/actions/setup-python@v5.2.0
with:
python-version: ${{ inputs.python-version || '3.11' }}
- name: Cache pip
uses: https://github.com/actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
restore-keys: |
${{ runner.os }}-pip-${{ inputs.python-version }}-
${{ runner.os }}-pip-
- name: Install dependencies (isolated venv)
run: |
# venv pulita: elenca come obsolete SOLO le dipendenze dichiarate dal repo,
# non i pacchetti globali del runner (torch/cuda/nvidia su runner ML/GPU)
python -m venv .audit-venv
.audit-venv/bin/pip install --upgrade pip
if [ -n "${{ inputs.install-extras }}" ]; then
.audit-venv/bin/pip install -e ".[${{ inputs.install-extras }}]"
elif [ -f requirements.txt ]; then
.audit-venv/bin/pip install -r requirements.txt
else
.audit-venv/bin/pip install -e "."
fi
- name: Check outdated packages
id: outdated
run: |
.audit-venv/bin/pip list --outdated --format=json > outdated.json 2>/dev/null || echo '[]' > outdated.json
COUNT=$(python3 -c "import json; print(len(json.load(open('outdated.json'))))")
echo "count=$COUNT" >> $GITHUB_OUTPUT
- name: Open or update issue if packages outdated
if: steps.outdated.outputs.count != '0'
env:
GITEA_TOKEN: ${{ gitea.token }}
SERVER_URL: ${{ gitea.server_url }}
REPOSITORY: ${{ gitea.repository }}
run: |
COUNT="${{ steps.outdated.outputs.count }}"
DATE=$(date '+%Y-%m-%d')
TITLE_PREFIX="Dipendenze Python:"
OUTDATED_LIST=$(python3 -c "
import json
try:
data = json.load(open('outdated.json'))
lines = [f\"- {p['name']}: {p['version']} → {p['latest_version']}\" for p in data[:20]]
print('\n'.join(lines))
except Exception:
print('N/A')
")
printf '## Dipendenze Python Obsolete — %s\n\n### Pacchetti da aggiornare: %s\n\n```\n%s\n```\n' \
"$DATE" "$COUNT" "$OUTDATED_LIST" > /tmp/body.md
# Deduplica: se esiste già una issue aperta con lo stesso prefisso,
# aggiungi un commento invece di aprirne una nuova
EXISTING=$(curl -s \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues?state=open&type=issues&limit=50" \
| jq -r --arg p "$TITLE_PREFIX" '[.[] | select(.title | contains($p))] | (first // {}) | .number // empty')
if [ -n "$EXISTING" ]; then
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues/$EXISTING/comments" \
-d "{ \"body\": $(jq -Rs . /tmp/body.md) }"
else
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues" \
-d "{
\"title\": \"[$DATE] Dipendenze Python: $COUNT pacchetti obsoleti\",
\"body\": $(jq -Rs . /tmp/body.md)
}"
fi
+36 -17
View File
@@ -22,15 +22,15 @@ jobs:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Python
uses: https://github.com/actions/setup-python@v5
uses: https://github.com/actions/setup-python@v5.2.0
with:
python-version: ${{ inputs.python-version || '3.11' }}
- name: Cache pip
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
@@ -38,25 +38,28 @@ jobs:
${{ runner.os }}-pip-${{ inputs.python-version }}-
${{ runner.os }}-pip-
- name: Install dependencies
- name: Install dependencies (isolated venv)
run: |
python -m pip install --upgrade pip
# venv pulita: elenca come obsolete SOLO le dipendenze dichiarate dal repo,
# non i pacchetti globali del runner (torch/cuda/nvidia su runner ML/GPU)
python -m venv .audit-venv
.audit-venv/bin/pip install --upgrade pip
if [ -n "${{ inputs.install-extras }}" ]; then
pip install -e ".[${{ inputs.install-extras }}]"
.audit-venv/bin/pip install -e ".[${{ inputs.install-extras }}]"
elif [ -f requirements.txt ]; then
pip install -r requirements.txt
.audit-venv/bin/pip install -r requirements.txt
else
pip install -e "."
.audit-venv/bin/pip install -e "."
fi
- name: Check outdated packages
id: outdated
run: |
pip list --outdated --format=json > outdated.json 2>/dev/null || echo '[]' > outdated.json
.audit-venv/bin/pip list --outdated --format=json > outdated.json 2>/dev/null || echo '[]' > outdated.json
COUNT=$(python3 -c "import json; print(len(json.load(open('outdated.json'))))")
echo "count=$COUNT" >> $GITHUB_OUTPUT
- name: Open issue if packages outdated
- name: Open or update issue if packages outdated
if: steps.outdated.outputs.count != '0'
env:
GITEA_TOKEN: ${{ gitea.token }}
@@ -65,6 +68,7 @@ jobs:
run: |
COUNT="${{ steps.outdated.outputs.count }}"
DATE=$(date '+%Y-%m-%d')
TITLE_PREFIX="Dipendenze Python:"
OUTDATED_LIST=$(python3 -c "
import json
@@ -79,11 +83,26 @@ jobs:
printf '## Dipendenze Python Obsolete — %s\n\n### Pacchetti da aggiornare: %s\n\n```\n%s\n```\n' \
"$DATE" "$COUNT" "$OUTDATED_LIST" > /tmp/body.md
curl -s -X POST \
-H "Content-Type: application/json" \
# Deduplica: se esiste già una issue aperta con lo stesso prefisso,
# aggiungi un commento invece di aprirne una nuova
EXISTING=$(curl -s \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues" \
-d "{
\"title\": \"[$DATE] Dipendenze Python: $COUNT pacchetti obsoleti\",
\"body\": $(jq -Rs . /tmp/body.md)
}"
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues?state=open&type=issues&limit=50" \
| jq -r --arg p "$TITLE_PREFIX" '[.[] | select(.title | contains($p))] | (first // {}) | .number // empty')
if [ -n "$EXISTING" ]; then
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues/$EXISTING/comments" \
-d "{ \"body\": $(jq -Rs . /tmp/body.md) }"
else
curl -s -X POST \
-H "Content-Type: application/json" \
-H "Authorization: token $GITEA_TOKEN" \
"$SERVER_URL/api/v1/repos/$REPOSITORY/issues" \
-d "{
\"title\": \"[$DATE] Dipendenze Python: $COUNT pacchetti obsoleti\",
\"body\": $(jq -Rs . /tmp/body.md)
}"
fi
@@ -0,0 +1,121 @@
name: Python Docker Release
on:
workflow_call:
inputs:
python-version:
type: string
default: '3.11'
install-extras:
description: 'Extras pip da installare (es: dev, test)'
type: string
default: 'dev'
runner:
type: string
default: 'catthehacker-latest'
working-directory:
description: 'Directory di lavoro se il progetto non è in root'
type: string
default: '.'
dockerfile:
description: 'Path al Dockerfile'
type: string
default: './Dockerfile'
jobs:
python-docker-release:
runs-on: ${{ inputs.runner }}
defaults:
run:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Python
uses: https://github.com/actions/setup-python@v5.2.0
with:
python-version: ${{ inputs.python-version || '3.11' }}
- name: Cache pip
uses: https://github.com/actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
restore-keys: |
${{ runner.os }}-pip-${{ inputs.python-version }}-
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -n "${{ inputs.install-extras }}" ]; then
pip install -e ".[${{ inputs.install-extras }}]"
elif [ -f requirements-dev.txt ]; then
pip install -r requirements-dev.txt
elif [ -f requirements.txt ]; then
pip install -r requirements.txt
else
pip install -e "."
fi
- name: Lint (ruff)
run: ruff check .
- name: Format check (ruff)
run: ruff format --check .
- name: Type check (mypy)
run: mypy .
- name: Test (pytest)
run: pytest --tb=short -q
- name: Login to container registry
uses: https://github.com/docker/login-action@v4
with:
registry: gitea.pzetatouch.it
username: ${{ secrets.G_USER }}
password: ${{ secrets.NPM_TOKEN }}
- name: Determine image tags
id: tags
run: |
APP_NAME=$(python -c "
import tomllib, pathlib
data = tomllib.loads(pathlib.Path('pyproject.toml').read_text())
print(data['project']['name'])
" 2>/dev/null || python3 -c "
import re, pathlib
content = pathlib.Path('pyproject.toml').read_text()
m = re.search(r'^name\s*=\s*[\"\'](.*?)[\"\']', content, re.MULTILINE)
print(m.group(1) if m else 'unknown')
")
VERSION=$(python -c "
import tomllib, pathlib
data = tomllib.loads(pathlib.Path('pyproject.toml').read_text())
print(data['project']['version'])
" 2>/dev/null || python3 -c "
import re, pathlib
content = pathlib.Path('pyproject.toml').read_text()
m = re.search(r'^version\s*=\s*[\"\'](.*?)[\"\']', content, re.MULTILINE)
print(m.group(1) if m else '0.0.0')
")
REGISTRY="gitea.pzetatouch.it/pzeta_touch"
echo "version_tag=${REGISTRY}/${APP_NAME}:${VERSION}" >> $GITHUB_OUTPUT
echo "latest_tag=${REGISTRY}/${APP_NAME}:latest" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: https://github.com/docker/build-push-action@v6
with:
push: true
context: ${{ inputs.working-directory }}
file: ${{ inputs.dockerfile }}
tags: |
${{ steps.tags.outputs.version_tag }}
${{ steps.tags.outputs.latest_tag }}
labels: |
org.opencontainers.image.source=${{ gitea.server_url }}/${{ gitea.repository }}
org.opencontainers.image.revision=${{ gitea.sha }}
org.opencontainers.image.version=${{ steps.tags.outputs.version }}
+9 -4
View File
@@ -30,15 +30,15 @@ jobs:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Python
uses: https://github.com/actions/setup-python@v5
uses: https://github.com/actions/setup-python@v5.2.0
with:
python-version: ${{ inputs.python-version || '3.11' }}
- name: Cache pip
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
@@ -72,7 +72,7 @@ jobs:
run: pytest --tb=short -q
- name: Login to container registry
uses: https://gitea.com/docker/login-action@v3
uses: https://gitea.com/docker/login-action@v4
with:
registry: gitea.pzetatouch.it
username: ${{ secrets.G_USER }}
@@ -104,6 +104,7 @@ jobs:
REGISTRY="gitea.pzetatouch.it/pzeta_touch"
echo "version_tag=${REGISTRY}/${APP_NAME}:${VERSION}" >> $GITHUB_OUTPUT
echo "latest_tag=${REGISTRY}/${APP_NAME}:latest" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: https://gitea.com/docker/build-push-action@v6
@@ -114,3 +115,7 @@ jobs:
tags: |
${{ steps.tags.outputs.version_tag }}
${{ steps.tags.outputs.latest_tag }}
labels: |
org.opencontainers.image.source=${{ gitea.server_url }}/${{ gitea.repository }}
org.opencontainers.image.revision=${{ gitea.sha }}
org.opencontainers.image.version=${{ steps.tags.outputs.version }}
@@ -0,0 +1,65 @@
name: Python Quality Gates
on:
workflow_call:
inputs:
python-version:
type: string
default: '3.11'
install-extras:
description: 'Extras pip da installare (es: dev, test). Lasciare vuoto per solo requirements.txt'
type: string
default: 'dev'
working-directory:
description: 'Directory di lavoro se il progetto non è in root'
type: string
default: '.'
jobs:
python-quality-gates:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Python
uses: https://github.com/actions/setup-python@v5.2.0
with:
python-version: ${{ inputs.python-version || '3.11' }}
- name: Cache pip
uses: https://github.com/actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
restore-keys: |
${{ runner.os }}-pip-${{ inputs.python-version }}-
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -n "${{ inputs.install-extras }}" ]; then
pip install -e ".[${{ inputs.install-extras }}]"
elif [ -f requirements-dev.txt ]; then
pip install -r requirements-dev.txt
elif [ -f requirements.txt ]; then
pip install -r requirements.txt
else
pip install -e "."
fi
- name: Lint (ruff)
run: ruff check .
- name: Format check (ruff)
run: ruff format --check .
- name: Type check (mypy)
run: mypy .
- name: Test (pytest)
run: pytest --tb=short -q
+3 -3
View File
@@ -23,15 +23,15 @@ jobs:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Python
uses: https://github.com/actions/setup-python@v5
uses: https://github.com/actions/setup-python@v5.2.0
with:
python-version: ${{ inputs.python-version || '3.11' }}
- name: Cache pip
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ inputs.python-version }}-${{ hashFiles('**/pyproject.toml', '**/requirements*.txt') }}
+254
View File
@@ -0,0 +1,254 @@
name: Quality Gates
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
node-version:
type: string
default: '24.16.0'
npm-version:
type: string
default: ''
jobs:
quality-gates:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://github.com/actions/checkout@v6
- name: Setup Node.js
uses: https://github.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Upgrade npm
if: inputs.npm-version != ''
run: npm install -g npm@${{ inputs.npm-version }}
- name: Cache npm
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Dockerfile - registry @pzeta e ARG per stage
shell: bash
# BLOCCANTE dal 12/09/2026, chiusa la tappa 2 di PZeta_Touch/flux-repo#133.
# Prima era solo un avviso, perche' 56 repo avevano ancora uno dei due
# difetti e bloccare li avrebbe fatti diventare rossi tutti insieme. Ora
# sono corretti: su 238 Dockerfile del portale ne restano difettosi due,
# `vue-conservazione` e `telegram-media-bot`, che non sono repository git
# e quindi non passano di qui.
run: |
# Due difetti che hanno rotto le release di node-xmlvalidation per due
# mesi senza che nessuno se ne accorgesse (PZeta_Touch/flux-repo#129,
# #133): (a) il registry @pzeta scritto in minuscolo nell'.npmrc
# generato dal Dockerfile, mentre i lockfile risolvono su PZeta_Touch;
# (b) una ARG usata in uno stage che non la dichiara, e che li' arriva
# vuota. Insieme, `npm install -g npm@` installa npm 12, che rifiuta
# l'URL scritto diverso (EALLOWREMOTE). Questo job non puo' accorgersene
# da solo: qui l'immagine non si costruisce, e la release fallisce solo
# al tag.
set +e
# La radice del repository e non working-directory: i Dockerfile stanno
# spesso fuori dalla cartella del package.
cd "${GITHUB_WORKSPACE:-.}" || exit 0
files=$(find . \( -name node_modules -o -name .git -o -name dist -o -name build \
-o -name .nuxt -o -name .output -o -name coverage \) -prune -o \
-type f \( -name 'Dockerfile' -o -name 'Dockerfile.*' -o -name '*.Dockerfile' \
-o -name '*.dockerfile' \) -print 2>/dev/null | sed 's|^\./||' | sort)
if [ -z "$files" ]; then
echo "Nessun Dockerfile: controllo non applicabile."
exit 0
fi
# (b) ARG fuori scope: una ARG vale SOLO nello stage che la dichiara.
# Quelle dichiarate prima del primo FROM valgono solo nelle righe FROM,
# e vanno ridichiarate dentro lo stage per essere viste dai RUN
# (documentazione Docker, "Scoping" in build/building/variables).
# Nessuna eredita' da `FROM <stage>`: le ENV si ereditano, le ARG no.
# Una versione precedente di questa guardia presumeva il contrario e
# lasciava passare proprio i casi come nuxt-vue-components-docs, dove
# la ARG dichiarata in `base` veniva usata in `deps` (#133).
arg_scope() {
${AWK:-awk} '
function trim(s) { sub(/^[ \t]+/, "", s); sub(/[ \t]+$/, "", s); return s }
# Nomi dichiarati da ARG/ENV: "A", "A=1", "A=1 B=2", "A valore".
function declared(rest, out, n, i, t) {
rest = trim(rest)
split("", out)
if (rest !~ /=/) { n = split(rest, t, /[ \t]+/); if (n > 0) out[t[1]] = 1; return }
n = split(rest, t, /[ \t]+/)
for (i = 1; i <= n; i++)
if (t[i] ~ /^[A-Za-z_][A-Za-z0-9_]*(=|$)/) { sub(/=.*/, "", t[i]); out[t[i]] = 1 }
}
function handle(kw, rest, ln, n, i, t, base, alias, k, p, s, v, d) {
if (pass == 1) {
if (kw == "ARG") { declared(rest, d); for (k in d) allargs[k] = 1 }
return
}
if (kw == "FROM") {
n = split(trim(rest), t, /[ \t]+/); i = 1
while (i <= n && t[i] ~ /^--/) i++
base = tolower(t[i]); alias = ""
if (i + 2 <= n && toupper(t[i + 1]) == "AS") alias = tolower(t[i + 2])
stages++
stage = (alias != "" ? alias : "#" stages)
# Scope nuovo e vuoto: niente viene ereditato dallo stage di base.
# (Nessun apostrofo qui dentro: chiuderebbe la stringa awk.)
split("", scope)
return
}
if (stage == "") return
if (kw == "ARG") { declared(rest, d); for (k in d) { scope[k] = 1; varof[stage, k] = 1 }; return }
s = rest
while (match(s, /[$][{]?[A-Za-z_][A-Za-z0-9_]*/)) {
v = substr(s, RSTART, RLENGTH); sub(/^[$][{]?/, "", v)
s = substr(s, RSTART + RLENGTH)
# In un RUN espande la shell: una variabile assegnata nel comando
# stesso (VERSIONE="$(...)" && ... ${VERSIONE}) non va scambiata per la ARG.
if (kw == "RUN" && match(rest, "(^|[^A-Za-z0-9_$])" v "=")) continue
if ((v in allargs) && !(v in scope) && !(v in predefined) && !((ln, v) in seen)) {
seen[ln, v] = 1
printf "%d\t%s\t%s\n", ln, v, stage
}
}
if (kw == "ENV") { declared(rest, d); for (k in d) { scope[k] = 1; varof[stage, k] = 1 } }
}
function flush() {
if (buf != "" && match(buf, /^[ \t]*[A-Za-z]+/)) {
kw = toupper(trim(substr(buf, RSTART, RLENGTH)))
handle(kw, substr(buf, RSTART + RLENGTH), start)
}
buf = ""
}
BEGIN {
np = split("TARGETPLATFORM TARGETOS TARGETARCH TARGETVARIANT BUILDPLATFORM BUILDOS BUILDARCH BUILDVARIANT HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY ALL_PROXY http_proxy https_proxy ftp_proxy no_proxy all_proxy", pp, " ")
for (i = 1; i <= np; i++) predefined[pp[i]] = 1
}
FNR == 1 { pass++; buf = ""; stage = ""; stages = 0; split("", scope); split("", varof) }
{
line = $0; sub(/\r$/, "", line)
if (line ~ /^[ \t]*#/) next # commenti, anche dentro una continuazione
if (buf == "" && line ~ /^[ \t]*$/) next
if (buf == "") start = FNR
if (line ~ /\\[ \t]*$/) { sub(/\\[ \t]*$/, " ", line); buf = buf line; next }
buf = buf line
flush()
}
' "$1" "$1"
}
# Caso di prova: se l'awk di questo runner non riconosce una ARG fuori
# scope nota, il controllo (b) non e' affidabile e lo si dice, invece di
# dichiarare in regola un Dockerfile che non si e' potuto leggere.
argcheck=1
prova=$(mktemp)
printf 'ARG X=1\nFROM scratch AS a\nRUN echo ${X}\n' > "$prova"
if [ "$(arg_scope "$prova" 2>/dev/null | cut -f2)" != "X" ]; then
argcheck=0
echo "::warning::Guardia Dockerfile: l'analisi delle ARG non funziona con l'awk di questo runner ($(${AWK:-awk} -W version 2>&1 | head -1)). Il controllo (b) e' saltato, il (a) resta."
fi
rm -f "$prova"
findings=""
for f in $files; do
# (a) registry: npm confronta l'URL del lockfile come stringa, e i lockfile
# risolvono tutti su PZeta_Touch.
reg=$(grep -nE 'packages/(pzeta_touch|pzeta)/' "$f" 2>/dev/null | cut -d: -f1 | tr '\n' ' ' | sed 's/ *$//')
if [ -n "$reg" ]; then
findings="${findings}${f} ${reg%% *} registry $(echo "$reg" | sed 's/ /, /g') -
"
fi
# (b) ARG fuori scope, con arg_scope definita sopra.
args=""
[ "$argcheck" = "1" ] && args=$(arg_scope "$f" 2>/dev/null)
while IFS=' ' read -r n v st; do
[ -n "$n" ] || continue
findings="${findings}${f} ${n} arg ${v} ${st}
"
done <<EOF
$args
EOF
done
if [ -z "$findings" ]; then
if [ "$argcheck" = "1" ]; then
echo "Dockerfile: registry @pzeta e ARG per stage in regola."
else
echo "Dockerfile: registry @pzeta in regola; ARG per stage non verificate (vedi l'avviso sopra)."
fi
exit 0
fi
summary="## ❌ Dockerfile: difetti della #133"$'\n\n'"| File | Riga | Difetto |"$'\n'"|---|---|---|"$'\n'
count=0
while IFS=' ' read -r f n kind v st; do
[ -n "$f" ] || continue
count=$((count + 1))
if [ "$kind" = "registry" ]; then
msg="registry @pzeta in minuscolo (righe ${v}): i lockfile risolvono su PZeta_Touch e da npm 12 un URL scritto diverso viene rifiutato (EALLOWREMOTE). Scrivere https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/"
else
case "$st" in \#*) st="n. ${st#\#}, senza AS" ;; esac
effetto="il valore e' vuoto"
[ "$v" = "NPM_VERSION" ] && effetto="e' vuota, e 'npm install -g npm@' installa l'ultima ignorando il pin"
msg="ARG ${v} usata nello stage '${st}' senza dichiararla: li' ${effetto}. Aggiungere 'ARG ${v}' dopo il FROM dello stage."
fi
echo "::error file=${f},line=${n}::${msg}"
summary="${summary}| \`${f}\` | ${n} | ${msg} |"$'\n'
done <<EOF
$findings
EOF
echo ""
parola="difetti"; [ "$count" -eq 1 ] && parola="difetto"
echo "${count} ${parola}. Il job si ferma qui: con npm 12 la build dell'immagine"
echo "fallirebbe al tag, cioe' molto piu' tardi e su un log che nessuno guarda"
echo "(e' andata cosi' per due mesi con node-xmlvalidation, PZeta_Touch/flux-repo#129)."
if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
printf '%s\n%s\n' "$summary" "Riferimento: PZeta_Touch/flux-repo#133" >> "$GITHUB_STEP_SUMMARY" 2>/dev/null
fi
exit 1
- name: Check outdated packages
run: npm outdated || true
- name: Install dependencies
run: npm ci
- name: Security audit
run: npm audit --audit-level=high || true
- name: Lint
run: npm run lint:check
- name: Type check
run: npm run typecheck
- name: Format check
run: npm run format:check
- name: Build
run: npm run build
- name: Test
run: npm run test
+282 -6
View File
@@ -3,24 +3,45 @@ name: Quality Gates
on:
workflow_call:
inputs:
working-directory:
description: 'Cartella che contiene package.json, relativa alla root del repo. Default: la root.'
type: string
default: '.'
node-version:
type: string
default: '22.17'
default: '24.16.0'
npm-version:
type: string
default: ''
owns-auth-roles:
description: >-
Solo per il repository proprietario di auth.ruoli (node-user-profiling):
gli consente di dichiarare ruoli nelle proprie migrazioni. Ogni altro
repo deve lasciarlo a false, e il gate qui sotto glielo impedisce.
type: boolean
default: false
jobs:
quality-gates:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory || '.' }}
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
uses: https://gitea.com/actions/checkout@v6
- name: Setup Node.js
uses: https://gitea.com/actions/setup-node@v4
with:
node-version: ${{ inputs.node-version || '22.17' }}
node-version: ${{ inputs.node-version || '24.16.0' }}
- name: Upgrade npm
if: inputs.npm-version != ''
run: npm install -g npm@${{ inputs.npm-version }}
- name: Cache npm
uses: https://gitea.com/actions/cache@v4
uses: https://github.com/actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
@@ -29,8 +50,263 @@ jobs:
- name: Configure npm private registry
run: |
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/pzeta_touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/pzeta_touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
echo "@pzeta:registry=https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/" >> ~/.npmrc
echo "//gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
- name: Nessun ruolo dichiarato fuori da node-user-profiling
shell: bash
env:
# La deroga stava nel campo `if:` dello step, e li' non arriva: nel
# workflow_call di act_runner i valori `with:` del chiamante non
# raggiungono il contesto `inputs` in quella posizione, quindi
# `!inputs.owns-auth-roles` restava vero anche con l'input a true e il
# gate falliva proprio in node-user-profiling, l'unico repository
# autorizzato a dichiarare ruoli. Letta come variabile d'ambiente la
# deroga arriva, e la si confronta come stringa.
OWNS_AUTH_ROLES: ${{ inputs.owns-auth-roles }}
run: |
# `auth.ruoli` appartiene a node-user-profiling e il suo contratto (seed
# 13, esteso dalla migrazione 19) vieta agli altri moduli di crearne.
# Non e' una formalita': il claim `role` del JWT e' il primo ruolo
# applicativo dell'utente e PostgREST ci fa un SET ROLE, ma i ruoli
# PostgreSQL esistono solo per i tredici livelli di piattaforma. Un
# ruolo per-modulo in quel claim e' una sessione che non parte.
# Nove microfrontend lo avevano disatteso: 21 ruoli, 27 su 35 senza
# omonimo PostgreSQL. Questo controllo esiste perche' non si ripeta.
set -uo pipefail
# Il nome del repository e' la rete di sicurezza della deroga: se
# nemmeno l'env dovesse arrivare, il proprietario dello schema si
# riconosce lo stesso e non resta bloccato dal proprio gate. Le due
# condizioni dicono la stessa cosa, una dichiarata e una constatata.
repo="${GITHUB_REPOSITORY:-}"
if [ "${OWNS_AUTH_ROLES:-}" = "true" ] || [ "${repo##*/}" = "node-user-profiling" ]; then
echo "Repository proprietario di auth.ruoli: controllo non applicabile."
exit 0
fi
dirs=""
for d in migrations seeds sql database/migrations; do
[ -d "$d" ] && dirs="$dirs $d"
done
if [ -z "$dirs" ]; then
echo "Nessuna cartella di migrazioni: controllo non applicabile."
exit 0
fi
# Il boundary dopo `ruoli` evita che auth.ruolipermessi finisca fra i
# match; il filtro sulle righe che iniziano per -- lascia passare i
# commenti, che spiegano spesso proprio questa regola.
# Fuori dal controllo le cartelle che non alimentano il catalogo delle
# migrazioni: `una-tantum` raccoglie i delta generati per riallineare a
# mano un tenant, `rollback` gli script di ritorno. Sono strumenti
# operativi, spesso fotografie di uno stato passato, e riscriverli
# significherebbe falsare la storia che documentano.
hits=$(grep -rniE --include='*.sql' \
--exclude-dir=una-tantum --exclude-dir=rollback \
'insert[[:space:]]+into[[:space:]]+auth\.ruoli([[:space:]]|\(|$)' \
$dirs 2>/dev/null \
| awk -F: '{ riga=$0; sub(/^[^:]*:[^:]*:/, "", riga); gsub(/^[[:space:]]+/, "", riga); if (riga !~ /^--/) print }' || true)
if [ -n "$hits" ]; then
echo "::error::Questo repository dichiara ruoli in auth.ruoli, che appartiene a node-user-profiling."
echo ""
echo "$hits"
echo ""
echo "Cosa fare invece: dichiarare un GRUPPO d'area con i permessi del modulo."
echo " INSERT INTO auth.gruppi (nome, nomecompleto, descrizione, tipogruppo, idruololivello)"
echo " ... poi INSERT INTO auth.gruppipermessi per collegarvi i propri permessi."
echo ""
echo "Il livello che accompagna il gruppo si sceglie fra i tredici di piattaforma"
echo "(manager, contabile, auditor, cfo, dipendente, viewer, operatore, cliente):"
echo "sono gli unici ad avere un ruolo PostgreSQL, senza il quale il SET ROLE fallisce."
echo "Esempio: vue-timesheet/migrations/12_gruppi_area.sql"
exit 1
fi
echo "Nessun INSERT INTO auth.ruoli: contratto rispettato."
- name: Dockerfile - registry @pzeta e ARG per stage
shell: bash
# BLOCCANTE dal 12/09/2026, chiusa la tappa 2 di PZeta_Touch/flux-repo#133.
# Prima era solo un avviso, perche' 56 repo avevano ancora uno dei due
# difetti e bloccare li avrebbe fatti diventare rossi tutti insieme. Ora
# sono corretti: su 238 Dockerfile del portale ne restano difettosi due,
# `vue-conservazione` e `telegram-media-bot`, che non sono repository git
# e quindi non passano di qui.
run: |
# Due difetti che hanno rotto le release di node-xmlvalidation per due
# mesi senza che nessuno se ne accorgesse (PZeta_Touch/flux-repo#129,
# #133): (a) il registry @pzeta scritto in minuscolo nell'.npmrc
# generato dal Dockerfile, mentre i lockfile risolvono su PZeta_Touch;
# (b) una ARG usata in uno stage che non la dichiara, e che li' arriva
# vuota. Insieme, `npm install -g npm@` installa npm 12, che rifiuta
# l'URL scritto diverso (EALLOWREMOTE). Questo job non puo' accorgersene
# da solo: qui l'immagine non si costruisce, e la release fallisce solo
# al tag.
set +e
# La radice del repository e non working-directory: i Dockerfile stanno
# spesso fuori dalla cartella del package.
cd "${GITHUB_WORKSPACE:-.}" || exit 0
files=$(find . \( -name node_modules -o -name .git -o -name dist -o -name build \
-o -name .nuxt -o -name .output -o -name coverage \) -prune -o \
-type f \( -name 'Dockerfile' -o -name 'Dockerfile.*' -o -name '*.Dockerfile' \
-o -name '*.dockerfile' \) -print 2>/dev/null | sed 's|^\./||' | sort)
if [ -z "$files" ]; then
echo "Nessun Dockerfile: controllo non applicabile."
exit 0
fi
# (b) ARG fuori scope: una ARG vale SOLO nello stage che la dichiara.
# Quelle dichiarate prima del primo FROM valgono solo nelle righe FROM,
# e vanno ridichiarate dentro lo stage per essere viste dai RUN
# (documentazione Docker, "Scoping" in build/building/variables).
# Nessuna eredita' da `FROM <stage>`: le ENV si ereditano, le ARG no.
# Una versione precedente di questa guardia presumeva il contrario e
# lasciava passare proprio i casi come nuxt-vue-components-docs, dove
# la ARG dichiarata in `base` veniva usata in `deps` (#133).
arg_scope() {
${AWK:-awk} '
function trim(s) { sub(/^[ \t]+/, "", s); sub(/[ \t]+$/, "", s); return s }
# Nomi dichiarati da ARG/ENV: "A", "A=1", "A=1 B=2", "A valore".
function declared(rest, out, n, i, t) {
rest = trim(rest)
split("", out)
if (rest !~ /=/) { n = split(rest, t, /[ \t]+/); if (n > 0) out[t[1]] = 1; return }
n = split(rest, t, /[ \t]+/)
for (i = 1; i <= n; i++)
if (t[i] ~ /^[A-Za-z_][A-Za-z0-9_]*(=|$)/) { sub(/=.*/, "", t[i]); out[t[i]] = 1 }
}
function handle(kw, rest, ln, n, i, t, base, alias, k, p, s, v, d) {
if (pass == 1) {
if (kw == "ARG") { declared(rest, d); for (k in d) allargs[k] = 1 }
return
}
if (kw == "FROM") {
n = split(trim(rest), t, /[ \t]+/); i = 1
while (i <= n && t[i] ~ /^--/) i++
base = tolower(t[i]); alias = ""
if (i + 2 <= n && toupper(t[i + 1]) == "AS") alias = tolower(t[i + 2])
stages++
stage = (alias != "" ? alias : "#" stages)
# Scope nuovo e vuoto: niente viene ereditato dallo stage di base.
# (Nessun apostrofo qui dentro: chiuderebbe la stringa awk.)
split("", scope)
return
}
if (stage == "") return
if (kw == "ARG") { declared(rest, d); for (k in d) { scope[k] = 1; varof[stage, k] = 1 }; return }
s = rest
while (match(s, /[$][{]?[A-Za-z_][A-Za-z0-9_]*/)) {
v = substr(s, RSTART, RLENGTH); sub(/^[$][{]?/, "", v)
s = substr(s, RSTART + RLENGTH)
# In un RUN espande la shell: una variabile assegnata nel comando
# stesso (VERSIONE="$(...)" && ... ${VERSIONE}) non va scambiata per la ARG.
if (kw == "RUN" && match(rest, "(^|[^A-Za-z0-9_$])" v "=")) continue
if ((v in allargs) && !(v in scope) && !(v in predefined) && !((ln, v) in seen)) {
seen[ln, v] = 1
printf "%d\t%s\t%s\n", ln, v, stage
}
}
if (kw == "ENV") { declared(rest, d); for (k in d) { scope[k] = 1; varof[stage, k] = 1 } }
}
function flush() {
if (buf != "" && match(buf, /^[ \t]*[A-Za-z]+/)) {
kw = toupper(trim(substr(buf, RSTART, RLENGTH)))
handle(kw, substr(buf, RSTART + RLENGTH), start)
}
buf = ""
}
BEGIN {
np = split("TARGETPLATFORM TARGETOS TARGETARCH TARGETVARIANT BUILDPLATFORM BUILDOS BUILDARCH BUILDVARIANT HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY ALL_PROXY http_proxy https_proxy ftp_proxy no_proxy all_proxy", pp, " ")
for (i = 1; i <= np; i++) predefined[pp[i]] = 1
}
FNR == 1 { pass++; buf = ""; stage = ""; stages = 0; split("", scope); split("", varof) }
{
line = $0; sub(/\r$/, "", line)
if (line ~ /^[ \t]*#/) next # commenti, anche dentro una continuazione
if (buf == "" && line ~ /^[ \t]*$/) next
if (buf == "") start = FNR
if (line ~ /\\[ \t]*$/) { sub(/\\[ \t]*$/, " ", line); buf = buf line; next }
buf = buf line
flush()
}
' "$1" "$1"
}
# Caso di prova: se l'awk di questo runner non riconosce una ARG fuori
# scope nota, il controllo (b) non e' affidabile e lo si dice, invece di
# dichiarare in regola un Dockerfile che non si e' potuto leggere.
argcheck=1
prova=$(mktemp)
printf 'ARG X=1\nFROM scratch AS a\nRUN echo ${X}\n' > "$prova"
if [ "$(arg_scope "$prova" 2>/dev/null | cut -f2)" != "X" ]; then
argcheck=0
echo "::warning::Guardia Dockerfile: l'analisi delle ARG non funziona con l'awk di questo runner ($(${AWK:-awk} -W version 2>&1 | head -1)). Il controllo (b) e' saltato, il (a) resta."
fi
rm -f "$prova"
findings=""
for f in $files; do
# (a) registry: npm confronta l'URL del lockfile come stringa, e i lockfile
# risolvono tutti su PZeta_Touch.
reg=$(grep -nE 'packages/(pzeta_touch|pzeta)/' "$f" 2>/dev/null | cut -d: -f1 | tr '\n' ' ' | sed 's/ *$//')
if [ -n "$reg" ]; then
findings="${findings}${f} ${reg%% *} registry $(echo "$reg" | sed 's/ /, /g') -
"
fi
# (b) ARG fuori scope, con arg_scope definita sopra.
args=""
[ "$argcheck" = "1" ] && args=$(arg_scope "$f" 2>/dev/null)
while IFS=' ' read -r n v st; do
[ -n "$n" ] || continue
findings="${findings}${f} ${n} arg ${v} ${st}
"
done <<EOF
$args
EOF
done
if [ -z "$findings" ]; then
if [ "$argcheck" = "1" ]; then
echo "Dockerfile: registry @pzeta e ARG per stage in regola."
else
echo "Dockerfile: registry @pzeta in regola; ARG per stage non verificate (vedi l'avviso sopra)."
fi
exit 0
fi
summary="## ❌ Dockerfile: difetti della #133"$'\n\n'"| File | Riga | Difetto |"$'\n'"|---|---|---|"$'\n'
count=0
while IFS=' ' read -r f n kind v st; do
[ -n "$f" ] || continue
count=$((count + 1))
if [ "$kind" = "registry" ]; then
msg="registry @pzeta in minuscolo (righe ${v}): i lockfile risolvono su PZeta_Touch e da npm 12 un URL scritto diverso viene rifiutato (EALLOWREMOTE). Scrivere https://gitea.pzetatouch.it/api/packages/PZeta_Touch/npm/"
else
case "$st" in \#*) st="n. ${st#\#}, senza AS" ;; esac
effetto="il valore e' vuoto"
[ "$v" = "NPM_VERSION" ] && effetto="e' vuota, e 'npm install -g npm@' installa l'ultima ignorando il pin"
msg="ARG ${v} usata nello stage '${st}' senza dichiararla: li' ${effetto}. Aggiungere 'ARG ${v}' dopo il FROM dello stage."
fi
echo "::error file=${f},line=${n}::${msg}"
summary="${summary}| \`${f}\` | ${n} | ${msg} |"$'\n'
done <<EOF
$findings
EOF
echo ""
parola="difetti"; [ "$count" -eq 1 ] && parola="difetto"
echo "${count} ${parola}. Il job si ferma qui: con npm 12 la build dell'immagine"
echo "fallirebbe al tag, cioe' molto piu' tardi e su un log che nessuno guarda"
echo "(e' andata cosi' per due mesi con node-xmlvalidation, PZeta_Touch/flux-repo#129)."
if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
printf '%s\n%s\n' "$summary" "Riferimento: PZeta_Touch/flux-repo#133" >> "$GITHUB_STEP_SUMMARY" 2>/dev/null
fi
exit 1
- name: Check outdated packages
run: npm outdated || true
+30
View File
@@ -0,0 +1,30 @@
# Copia in: .gitea/workflows/ci.yml
# Trigger: push su qualsiasi branch → quality gates + build debug Android
#
# Il debug APK viene uplodato come artifact scaricabile dalla PR.
# Non richiede firma: usato per test interni su device fisico o emulatore.
name: CI
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches:
- main
jobs:
quality-gates:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/quality-gates-github.yml@v1
secrets: inherit
android-debug:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/capacitor-android-github.yml@v1
secrets: inherit
with:
build-type: debug
output-format: apk
+2 -2
View File
@@ -19,11 +19,11 @@ on:
jobs:
quality-gates:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/quality-gates.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/quality-gates.yml@v1
secrets: inherit
android-debug:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/capacitor-android.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/capacitor-android.yml@v1
secrets: inherit
with:
build-type: debug
+3 -3
View File
@@ -18,19 +18,19 @@ on:
jobs:
branch-cleanup:
if: gitea.event_name == 'pull_request' && gitea.event.pull_request.merged == true
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/branch-cleanup.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/branch-cleanup.yml@v1
secrets: inherit
dependency-audit:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 8 * * 1')
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/dependency-check.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/dependency-check.yml@v1
secrets: inherit
dependency-outdated:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 8 1 * *')
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/dependency-outdated.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/dependency-outdated.yml@v1
secrets: inherit
+49
View File
@@ -0,0 +1,49 @@
# Copia in: .gitea/workflows/release.yml
# Trigger: git tag v* → APK firmato + AAB Play Store + release Gitea
#
# Secrets richiesti nel repository consumer:
# KEYSTORE_BASE64 — keystore codificato in base64
# KEYSTORE_PASSWORD — password del keystore
# KEY_ALIAS — alias della chiave
# KEY_PASSWORD — password della chiave
# GOOGLE_SERVICES_JSON — contenuto del file google-services.json (se Firebase)
#
# Prerequisito build.gradle (android/app/build.gradle):
# signingConfigs {
# release {
# storeFile file("keystore.jks")
# storePassword System.getenv("KEYSTORE_PASSWORD")
# keyAlias System.getenv("KEY_ALIAS")
# keyPassword System.getenv("KEY_PASSWORD")
# }
# }
#
# NOTA: gitea-release attende entrambe le build Android via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di auto-release.yml.
name: Release
on:
push:
tags:
- 'v*'
jobs:
android-apk:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/capacitor-android-github.yml@v1
secrets: inherit
with:
build-type: release
output-format: apk
android-aab:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/capacitor-android-github.yml@v1
secrets: inherit
with:
build-type: release
output-format: aab
gitea-release:
needs: [android-apk, android-aab]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/auto-release-github.yml@v1
secrets: inherit
+6 -5
View File
@@ -18,8 +18,8 @@
# }
# }
#
# NOTA: i job girano in parallelo (no needs).
# Gitea bug #31900: needs + workflow_call + checkout causa errori di autenticazione.
# NOTA: gitea-release attende entrambe le build Android via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di auto-release.yml.
name: Release
@@ -30,19 +30,20 @@ on:
jobs:
android-apk:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/capacitor-android.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/capacitor-android.yml@v1
secrets: inherit
with:
build-type: release
output-format: apk
android-aab:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/capacitor-android.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/capacitor-android.yml@v1
secrets: inherit
with:
build-type: release
output-format: aab
gitea-release:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/auto-release.yml@v1
needs: [android-apk, android-aab]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/auto-release.yml@v1
secrets: inherit
+26
View File
@@ -0,0 +1,26 @@
# Copia in: .gitea/workflows/ci.yml
# Usato da: siti documentazione Nuxt 4 con SSR e Docker
#
# Prerequisiti:
# - package.json con script: lint:check, typecheck, format:check, build, test
# - Secrets: NPM_TOKEN (accesso registry @pzeta privato)
name: CI
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'content/**'
pull_request:
branches:
- main
jobs:
quality-gates:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/quality-gates-github.yml@v1
secrets: inherit
with:
npm-version: '11' # lockfile generato con npm@11, runner usa npm@10 di default
+26
View File
@@ -0,0 +1,26 @@
# Copia in: .gitea/workflows/ci.yml
# Usato da: siti documentazione Nuxt 4 con SSR e Docker
#
# Prerequisiti:
# - package.json con script: lint:check, typecheck, format:check, build, test
# - Secrets: NPM_TOKEN (accesso registry @pzeta privato)
name: CI
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'content/**'
pull_request:
branches:
- main
jobs:
quality-gates:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/quality-gates.yml@v1
secrets: inherit
with:
npm-version: '11' # lockfile generato con npm@11, runner usa npm@10 di default
+36
View File
@@ -0,0 +1,36 @@
# Copia in: .gitea/workflows/maintenance.yml
# Trigger:
# - PR merged → cleanup branch sorgente
# - Ogni martedì 02:00 → security audit vulnerabilità (settimanale)
# - Ogni 1° del mese → controllo pacchetti obsoleti (mensile)
# - Manuale → workflow_dispatch (esegue tutti i job di manutenzione)
name: Maintenance
on:
pull_request:
types: [closed]
schedule:
- cron: '0 2 * * 2' # ogni martedì alle 02:00 → security audit
- cron: '0 3 1 * *' # ogni 1° del mese alle 03:00 → outdated check
workflow_dispatch:
jobs:
branch-cleanup:
if: gitea.event_name == 'pull_request' && gitea.event.pull_request.merged == true
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/branch-cleanup.yml@v1
secrets: inherit
dependency-audit:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 2 * * 2')
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/dependency-check.yml@v1
secrets: inherit
dependency-outdated:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 3 1 * *')
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/dependency-outdated.yml@v1
secrets: inherit
@@ -0,0 +1,30 @@
# Copia in: .gitea/workflows/release.yml
# Trigger: git tag v* → build Docker + crea release Gitea
#
# NOTA: auto-release attende docker-release via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di auto-release.yml.
#
# Secrets richiesti nel repository consumer:
# NPM_TOKEN — accesso registry @pzeta (npm install + Docker secret)
# G_USER — username Docker registry Gitea
name: Release
on:
push:
tags:
- 'v*'
jobs:
docker-release:
runs-on: catthehacker-latest # workaround Gitea bug #34986: runs-on non rispettato in workflow_call
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/docker-release-github.yml@v1
secrets: inherit
with:
runner: catthehacker-latest # runner con Docker pre-installato
npm-version: '11' # lockfile generato con npm@11, runner usa npm@10 di default
auto-release:
needs: [docker-release]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/auto-release-github.yml@v1
secrets: inherit
+30
View File
@@ -0,0 +1,30 @@
# Copia in: .gitea/workflows/release.yml
# Trigger: git tag v* → build Docker + crea release Gitea
#
# NOTA: auto-release attende docker-release via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di auto-release.yml.
#
# Secrets richiesti nel repository consumer:
# NPM_TOKEN — accesso registry @pzeta (npm install + Docker secret)
# G_USER — username Docker registry Gitea
name: Release
on:
push:
tags:
- 'v*'
jobs:
docker-release:
runs-on: catthehacker-latest # workaround Gitea bug #34986: runs-on non rispettato in workflow_call
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/docker-release.yml@v1
secrets: inherit
with:
runner: catthehacker-latest # runner con Docker pre-installato
npm-version: '11' # lockfile generato con npm@11, runner usa npm@10 di default
auto-release:
needs: [docker-release]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/auto-release.yml@v1
secrets: inherit
+20
View File
@@ -0,0 +1,20 @@
# Copia in: .gitea/workflows/ci.yml
# Usato da: librerie npm pubblicate su registry @pzeta
name: CI
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches:
- main
jobs:
quality-gates:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/quality-gates-github.yml@v1
secrets: inherit
+1 -1
View File
@@ -16,5 +16,5 @@ on:
jobs:
quality-gates:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/quality-gates.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/quality-gates.yml@v1
secrets: inherit
+20 -6
View File
@@ -1,5 +1,9 @@
# Copia in: .gitea/workflows/maintenance.yml
# Combina branch-cleanup (PR merge) e dependency-check (settimanale)
# Trigger:
# - PR merged → cleanup branch sorgente
# - Ogni lunedì 08:00 → security audit vulnerabilità (settimanale)
# - Ogni 1° del mese → controllo pacchetti obsoleti (mensile)
# - Manuale → workflow_dispatch (esegue tutti i job di manutenzione)
name: Maintenance
@@ -7,16 +11,26 @@ on:
pull_request:
types: [closed]
schedule:
- cron: '0 8 * * 1'
- cron: '0 2 * * 3' # ogni mercoledì alle 02:00 → security audit
- cron: '0 2 1 * *' # ogni 1° del mese alle 02:00 → outdated check
workflow_dispatch:
jobs:
branch-cleanup:
if: gitea.event_name == 'pull_request' && gitea.event.pull_request.merged == true
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/branch-cleanup.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/branch-cleanup.yml@v1
secrets: inherit
dependency-check:
if: gitea.event_name == 'schedule' || gitea.event_name == 'workflow_dispatch'
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/dependency-check.yml@v1
dependency-audit:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 2 * * 3')
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/dependency-check.yml@v1
secrets: inherit
dependency-outdated:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 2 1 * *')
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/dependency-outdated.yml@v1
secrets: inherit
+22
View File
@@ -0,0 +1,22 @@
# Copia in: .gitea/workflows/release.yml
# Trigger: git tag v* → pubblica su npm + crea release Gitea
#
# NOTA: auto-release attende npm-publish via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di auto-release.yml.
name: Release
on:
push:
tags:
- 'v*'
jobs:
npm-publish:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/npm-publish-github.yml@v1
secrets: inherit
auto-release:
needs: [npm-publish]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/auto-release-github.yml@v1
secrets: inherit
+5 -4
View File
@@ -1,8 +1,8 @@
# Copia in: .gitea/workflows/release.yml
# Trigger: git tag v* → pubblica su npm + crea release Gitea
#
# NOTA: i job girano in parallelo (non sequenziali con needs).
# Gitea bug #31900: needs + workflow_call + checkout causa errori di autenticazione.
# NOTA: auto-release attende npm-publish via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di auto-release.yml.
name: Release
@@ -13,9 +13,10 @@ on:
jobs:
npm-publish:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/npm-publish.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/npm-publish.yml@v1
secrets: inherit
auto-release:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/auto-release.yml@v1
needs: [npm-publish]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/auto-release.yml@v1
secrets: inherit
+22
View File
@@ -0,0 +1,22 @@
# Copia in: .gitea/workflows/ci.yml
# Usato da: microservizi Node.js con deploy Docker
name: CI
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches:
- main
jobs:
quality-gates:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/quality-gates-github.yml@v1
secrets: inherit
# with:
# node-version: '24.16.0' # opzionale, default già impostato
+2 -2
View File
@@ -16,7 +16,7 @@ on:
jobs:
quality-gates:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/quality-gates.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/quality-gates.yml@v1
secrets: inherit
# with:
# node-version: '22.17' # opzionale, default già impostato
# node-version: '24.16.0' # opzionale, default già impostato
+7 -7
View File
@@ -11,26 +11,26 @@ on:
pull_request:
types: [closed]
schedule:
- cron: '0 8 * * 1' # ogni lunedì alle 08:00 → security audit
- cron: '0 8 1 * *' # ogni 1° del mese alle 08:00 → outdated check
- cron: '0 2 * * 1' # ogni lunedì alle 02:00 → security audit
- cron: '0 4 1 * *' # ogni 1° del mese alle 04:00 → outdated check
workflow_dispatch:
jobs:
branch-cleanup:
if: gitea.event_name == 'pull_request' && gitea.event.pull_request.merged == true
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/branch-cleanup.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/branch-cleanup.yml@v1
secrets: inherit
dependency-audit:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 8 * * 1')
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/dependency-check.yml@v1
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 2 * * 1')
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/dependency-check.yml@v1
secrets: inherit
dependency-outdated:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 8 1 * *')
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/dependency-outdated.yml@v1
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 4 1 * *')
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/dependency-outdated.yml@v1
secrets: inherit
+25
View File
@@ -0,0 +1,25 @@
# Copia in: .gitea/workflows/release.yml
# Trigger: git tag v* → build Docker + crea release Gitea
#
# NOTA: auto-release attende docker-release via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di auto-release.yml.
name: Release
on:
push:
tags:
- 'v*'
jobs:
docker-release:
runs-on: catthehacker-latest # workaround Gitea bug #34986: runs-on non rispettato in workflow_call
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/docker-release-github.yml@v1
secrets: inherit
with:
runner: catthehacker-latest # runner con Docker pre-installato
auto-release:
needs: [docker-release]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/auto-release-github.yml@v1
secrets: inherit
+6 -4
View File
@@ -1,8 +1,8 @@
# Copia in: .gitea/workflows/release.yml
# Trigger: git tag v* → build Docker + crea release Gitea
#
# NOTA: i job girano in parallelo (non sequenziali con needs).
# Gitea bug #31900: needs + workflow_call + checkout causa errori di autenticazione.
# NOTA: auto-release attende docker-release via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di auto-release.yml.
name: Release
@@ -13,11 +13,13 @@ on:
jobs:
docker-release:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/docker-release.yml@v1
runs-on: catthehacker-latest # workaround Gitea bug #34986: runs-on non rispettato in workflow_call
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/docker-release.yml@v1
secrets: inherit
with:
runner: catthehacker-latest # runner con Docker pre-installato
auto-release:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/auto-release.yml@v1
needs: [docker-release]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/auto-release.yml@v1
secrets: inherit
+31
View File
@@ -0,0 +1,31 @@
# Copia in: .gitea/workflows/ci.yml
# Usato da: microservizi Python con FastAPI / pyproject.toml
#
# Requisiti pyproject.toml:
# [project.optional-dependencies]
# dev = ["ruff", "mypy", "pytest", ...]
#
# Input opzionali:
# python-version: '3.11' # default già impostato
# install-extras: 'dev' # default già impostato
name: CI
on:
push:
branches:
- main
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches:
- main
jobs:
quality-gates:
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/python-quality-gates-github.yml@v1
secrets: inherit
# with:
# python-version: '3.11' # opzionale, default già impostato
# install-extras: 'dev' # opzionale, default già impostato
+1 -1
View File
@@ -24,7 +24,7 @@ on:
jobs:
quality-gates:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/python-quality-gates.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/python-quality-gates.yml@v1
secrets: inherit
# with:
# python-version: '3.11' # opzionale, default già impostato
+3 -3
View File
@@ -18,14 +18,14 @@ on:
jobs:
branch-cleanup:
if: gitea.event_name == 'pull_request' && gitea.event.pull_request.merged == true
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/branch-cleanup.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/branch-cleanup.yml@v1
secrets: inherit
dependency-audit:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 8 * * 1')
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/python-dependency-check.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/python-dependency-check.yml@v1
secrets: inherit
# with:
# python-version: '3.11'
@@ -35,7 +35,7 @@ jobs:
if: >
gitea.event_name == 'workflow_dispatch' ||
(gitea.event_name == 'schedule' && gitea.event.schedule == '0 8 1 * *')
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/python-dependency-outdated.yml@v1
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/python-dependency-outdated.yml@v1
secrets: inherit
# with:
# python-version: '3.11'
+32
View File
@@ -0,0 +1,32 @@
# Copia in: .gitea/workflows/release.yml
# Trigger: git tag v* → build Docker + crea release Gitea
#
# NOTA: auto-release attende docker-release via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di python-auto-release.yml.
#
# Prerequisiti:
# - Dockerfile presente nella root del progetto
# - pyproject.toml con [project] name e version
# - Secrets: G_USER (docker login), NPM_TOKEN (usato come password registry)
name: Release
on:
push:
tags:
- 'v*'
jobs:
docker-release:
runs-on: catthehacker-latest # workaround Gitea bug #34986: runs-on non rispettato in workflow_call
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/python-docker-release-github.yml@v1
secrets: inherit
with:
runner: catthehacker-latest # runner con Docker pre-installato
# python-version: '3.11' # opzionale
# install-extras: 'dev' # opzionale
auto-release:
needs: [docker-release]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/python-auto-release-github.yml@v1
secrets: inherit
+6 -4
View File
@@ -1,8 +1,8 @@
# Copia in: .gitea/workflows/release.yml
# Trigger: git tag v* → build Docker + crea release Gitea
#
# NOTA: i job girano in parallelo (non sequenziali con needs).
# Gitea bug #31900: needs + workflow_call + checkout causa errori di autenticazione.
# NOTA: auto-release attende docker-release via needs.
# Workaround Gitea bug #31900: token esplicito nel checkout di python-auto-release.yml.
#
# Prerequisiti:
# - Dockerfile presente nella root del progetto
@@ -18,7 +18,8 @@ on:
jobs:
docker-release:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/python-docker-release.yml@v1
runs-on: catthehacker-latest # workaround Gitea bug #34986: runs-on non rispettato in workflow_call
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/python-docker-release.yml@v1
secrets: inherit
with:
runner: catthehacker-latest # runner con Docker pre-installato
@@ -26,5 +27,6 @@ jobs:
# install-extras: 'dev' # opzionale
auto-release:
uses: https://gitea.com/Punga78/shared-actions/.gitea/workflows/python-auto-release.yml@v1
needs: [docker-release]
uses: https://gitea.pzetatouch.it/devops/shared-actions/.gitea/workflows/python-auto-release.yml@v1
secrets: inherit