diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index 6d5e7fb..9254db1 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -1,11 +1,13 @@ # Le Gitea Actions del gioco: girano sul runner del PC di Andrea (make runner; label ubuntu-latest = node:22-bookworm). -# A ogni push su main e a ogni tag i test unitari; su un tag vX.Y.Z, se passano, la release con i commit dal tag prima. +# A ogni push su main e a ogni tag i test unitari; su un tag vX.Y.Z (o a mano, «Run workflow») anche le venti prove nel +# browser, una per job nell'immagine di Playwright (due alla volta sul runner); se passa tutto, la release. # Il controllo dei file pubblicabili non sta qui (a pipeline partita il push è già pubblico): è l'hook pre-push. name: test on: push: branches: [main] tags: ['v*'] + workflow_dispatch: jobs: test: @@ -15,8 +17,27 @@ jobs: - name: Test unitari run: node --version && node --test tests/*.test.mjs - release: + # Le prove nel browser, una per job: l'elenco è SUITES di scripts/verify.mjs (verify.test.mjs pretende che coincidano), + # l'immagine ha la stessa versione di Playwright di package-lock.json (idem). + browser: needs: test + if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + container: + image: mcr.microsoft.com/playwright:v1.64.1-noble + strategy: + fail-fast: false + matrix: + prova: [principale, minigiochi, telefoni, ambient, veicoli, ingorgo, smarronata, briscola, tressette, scopa, biliardo, flipper, micro, cerbottana, condor, campana, bruciate, gara, telefono, risveglio] + steps: + - uses: actions/checkout@v4 + - name: Playwright + run: npm ci --no-audit --no-fund + - name: Prova ${{ matrix.prova }} + run: node scripts/verify.mjs ${{ matrix.prova }} + + release: + needs: [test, browser] if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest permissions: diff --git a/CLAUDE.md b/CLAUDE.md index 9560ce7..96150ed 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -28,4 +28,4 @@ i suoi ricordi: non inventare persone, luoghi o fatti del paese al posto suoi; p - **Pubblicare (dal 2026-11-01)**: origin è https://git.manzolo.it/manzolo/leggenda-del-regolo, pubblico: prima `make check-public`, poi `git push origin main --tags`, solo se Andrea lo chiede. `make deploy` costruisce l'immagine dal tag della versione, la spinge su `git.manzolo.it/manzolo/leggenda-regolo:vX.Y.Z` (e `:latest`); sul VPS il compose fissa quel tag e fa `docker compose pull && up -d`. Per tornare indietro: sul VPS (`Workspaces/docker/leggenda-regolo/docker-compose.yml`) si rimette il tag precedente e si rifà pull e up. - Hook pre-push (`make hooks`, una volta per clone) lancia check-public; le Gitea Actions (`.gitea/workflows/test.yml`: test, e release sui tag) girano sul runner del PC, che si crea o riavvia con `make runner`. + Hook pre-push (`make hooks`, una volta per clone) lancia check-public; le Gitea Actions (`.gitea/workflows/test.yml`: test unitari a ogni push; sui tag, o a mano, anche le venti prove nel browser, una per job, poi la release) girano sul runner del PC, che si crea o riavvia con `make runner`. diff --git a/scripts/verify.mjs b/scripts/verify.mjs index 0472ce5..6fdd0ae 100644 --- a/scripts/verify.mjs +++ b/scripts/verify.mjs @@ -121,7 +121,7 @@ async function main() { const why = all ? 'tutte' : named.includes(t.name) ? 'chiesta' : !ok[t.name] ? 'mai provata' : !t.changed.length ? "cambiato l'elenco dei file da cui dipende" : `cambiati ${t.changed.slice(0, 4).join(', ')}${t.changed.length > 4 ? ` e altri ${t.changed.length - 4}` : ''}`; console.log(`da rifare: ${t.name}${t.seconds ? ` (~${t.seconds} s)` : ''}: ${why}`); } - if (green.length) console.log(`già verdi: ${green.join(', ')}`); + if (green.length && !named.length) console.log(`già verdi: ${green.join(', ')}`); if (onlyPlan) return; const jobs = Math.max(1, Number(process.env.JOBS) || Math.min(2, Math.floor(cpus().length / 4))); const queue = todo.sort((a, b) => (b.seconds || 999) - (a.seconds || 999)), results = []; @@ -137,7 +137,7 @@ async function main() { for (const r of results.sort((a, b) => a.name.localeCompare(b.name))) console.log(`${r.code === 0 ? 'OK ' : 'FAIL'} ${r.name} (${r.seconds} s)`); const failed = results.filter(r => r.code !== 0).map(r => r.name); if (failed.length) { console.log(`Prove fallite: ${failed.join(', ')}`); process.exit(1); } - console.log(`Prove nel browser OK: ${results.length} rifatte, ${green.length} già verdi.`); + console.log(`Prove nel browser OK: ${results.length} rifatte${named.length ? '' : `, ${green.length} già verdi`}.`); } if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) main(); diff --git a/tests/verify.test.mjs b/tests/verify.test.mjs index 39b316f..63887f6 100644 --- a/tests/verify.test.mjs +++ b/tests/verify.test.mjs @@ -2,7 +2,7 @@ // e l'impronta cambia solo se cambia un ingresso. import { test } from 'node:test'; import assert from 'node:assert/strict'; -import { readdirSync } from 'node:fs'; +import { readdirSync, readFileSync } from 'node:fs'; import { SUITES, ENGINE, inputsOf, ignored, fingerprint, plan } from '../scripts/verify.mjs'; const FILES = ['index.html', 'style.css', 'src/main.js', 'src/version.js', 'package.json', 'package-lock.json', 'Makefile', 'README.md', @@ -71,3 +71,11 @@ test("l'impronta cambia solo se cambia un ingresso, e il piano dice quali", () = assert.deepEqual(after.find(p => p.name === 'briscola').changed, ['src/engine/briscola.js']); assert.notEqual(fingerprint(['a'], () => '1'), fingerprint(['a'], () => '2')); }); + +test('la pipeline di Gitea prova le stesse prove, con lo stesso Playwright del progetto', () => { + const wf = readFileSync('.gitea/workflows/test.yml', 'utf8'); + const listed = wf.match(/prova: \[([^\]]*)\]/)[1].split(',').map(s => s.trim()); + assert.deepEqual([...listed].sort(), Object.keys(SUITES).sort()); + const lock = JSON.parse(readFileSync('package-lock.json', 'utf8')).packages['node_modules/playwright'].version; + assert.match(wf, new RegExp(`mcr\\.microsoft\\.com/playwright:v${lock.replace(/\./g, '\\.')}-`), `immagine di Playwright diversa da ${lock}`); +});