# TieMeasureFlow#76: setup.exe di TieMeasureFlow per Windows, generato al tag v*. # Cosa fa: submodule vendor/visionsuite (deploy key), build.ps1 (uv sync Python 3.13, Tailwind, # Nuitka --standalone, migrazioni .pyc, DLL di WeasyPrint, Inno Setup), poi il setup come # artifact e come asset della release Gitea del tag. # Da cosa dipende: un runner Gitea con label `windows` che giri su un host Windows (non in # container) con Visual Studio/Build Tools (MSVC), git e node (serve a actions/checkout e a # Tailwind); uv e Inno Setup li installa il workflow se mancano. Secret SUBMODULI_SSH_KEY # (deploy key di sola lettura di TieVision-Core, impostato sul repo il 17/10/2026). # Il runner `windows` e' act_runner in modalita' host su daitarn (capacity 1). # ⚠️ upload-artifact@v3: e' la versione che usa gia' vs-native.yml in TieVision-Core su questo # Gitea; la v4 usa un protocollo che act_runner puo' non supportare. # ⚠️ L'asset della release usa il token del job (secrets.GITHUB_TOKEN): se la chiamata risponde # 403 serve un token personale in un secret (es. RILASCI_TOKEN) al posto di GITHUB_TOKEN. # ⚠️ La build da freddo e' lunga (Nuitka compila backend, visione, plotly, opencv...): timeout 180 min. name: rilascio-windows on: push: tags: ['v*'] workflow_dispatch: {} jobs: setup-windows: runs-on: windows timeout-minutes: 180 defaults: run: shell: powershell steps: # Checkout senza ssh-key (come ci.yml): i submodule si inizializzano a parte, con la deploy key. - uses: actions/checkout@v4 - name: Submodule privati (deploy key in sola lettura) env: SUBMODULI_SSH_KEY: ${{ secrets.SUBMODULI_SSH_KEY }} run: | $ErrorActionPreference = 'Stop' # cartella temporanea del job, non ~/.ssh: su un runner host e' l'account dell'utente $ssh = Join-Path $env:TEMP ("submoduli-" + [guid]::NewGuid().ToString('N')) New-Item -ItemType Directory -Force $ssh | Out-Null $chiave = Join-Path $ssh 'chiave' # LF e newline finale: OpenSSH rifiuta una chiave con CRLF [System.IO.File]::WriteAllText($chiave, ($env:SUBMODULI_SSH_KEY.Trim() + "`n"), (New-Object System.Text.UTF8Encoding $false)) # OpenSSH su Windows rifiuta una chiave leggibile da altri utenti; (F) e non (R): # con la sola lettura Remove-Item finale non puo' cancellarla icacls $chiave /inheritance:r | Out-Null icacls $chiave /grant:r "$($env:USERNAME):(F)" | Out-Null $known = Join-Path $ssh 'known_hosts' [System.IO.File]::WriteAllText($known, "[git.tielogic.xyz]:222 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDvABW6Tvruqkf7KJhJZUiAX6NeCx0enwcNXzZbECQ8J`n", (New-Object System.Text.UTF8Encoding $false)) $env:GIT_SSH_COMMAND = "ssh -i $($chiave -replace '\\','/') -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$($known -replace '\\','/')" try { git submodule update --init --recursive if ($LASTEXITCODE -ne 0) { throw "git submodule update fallito" } } finally { # la deploy key non resta mai sul disco del runner Remove-Item $ssh -Recurse -Force -ErrorAction SilentlyContinue } - name: uv (se manca) run: | if (-not (Get-Command uv -ErrorAction SilentlyContinue)) { irm https://astral.sh/uv/install.ps1 | iex } # il PATH del passo successivo "$env:USERPROFILE\.local\bin" | Out-File -Append -Encoding utf8 $env:GITHUB_PATH - name: Node (se manca) run: | # serve a Tailwind (npx) in build.ps1 if (-not (Get-Command npx -ErrorAction SilentlyContinue)) { winget install --id OpenJS.NodeJS.LTS -e --silent --accept-package-agreements --accept-source-agreements } "$env:ProgramFiles odejs" | Out-File -Append -Encoding utf8 $env:GITHUB_PATH - name: Inno Setup (se manca) run: | $trovato = (Get-Command ISCC.exe -ErrorAction SilentlyContinue) -or (Test-Path "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe") -or (Test-Path "$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe") if (-not $trovato) { winget install --id JRSoftware.InnoSetup -e --silent --accept-package-agreements --accept-source-agreements } - name: Build (Nuitka + Inno Setup) # GITHUB_REF_NAME e' il tag (v0.1.0); con workflow_dispatch e' il ramo: build.ps1 rifiuta # un nome senza numeri, quindi in quel caso si passa 0.0.0 run: | $v = '${{ github.ref_name }}' if ($v -notmatch '^v?\d+\.\d+\.\d+') { $v = '0.0.0' } powershell -ExecutionPolicy Bypass -File packaging\windows\build.ps1 -Versione $v if ($LASTEXITCODE -ne 0) { throw "build.ps1 fallito" } - name: Setup come artifact uses: actions/upload-artifact@v3 with: name: TieMeasureFlow-setup path: dist/TieMeasureFlow-setup-*.exe if-no-files-found: error - name: Asset della release Gitea (solo ai tag) if: startsWith(github.ref, 'refs/tags/') env: TOKEN: ${{ secrets.GITHUB_TOKEN }} API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }} TAG: ${{ github.ref_name }} run: | $ErrorActionPreference = 'Stop' $h = @{ Authorization = "token $env:TOKEN" } # la release del tag: la crea il primo job che arriva, poi si riusa try { $rel = Invoke-RestMethod -Headers $h "$env:API/releases/tags/$env:TAG" } catch { $corpo = @{ tag_name = $env:TAG; name = "TieMeasureFlow $env:TAG" } | ConvertTo-Json $rel = Invoke-RestMethod -Method Post -Headers $h -ContentType 'application/json' -Body $corpo "$env:API/releases" } $setup = Get-ChildItem dist\TieMeasureFlow-setup-*.exe | Select-Object -First 1 # curl.exe (incluso in Windows 10+) fa il multipart senza codice a mano curl.exe --fail -sS -X POST -H "Authorization: token $env:TOKEN" -F "attachment=@$($setup.FullName)" "$env:API/releases/$($rel.id)/assets?name=$($setup.Name)" if ($LASTEXITCODE -ne 0) { throw "caricamento dell'asset fallito" }