name: Build Fritzing on Windows on: push: branches: [ master ] workflow_dispatch: # Necesario para que GITHUB_TOKEN (token de Actions de Gitea) pueda crear la Release. permissions: contents: write env: QT_VERSION: '6.8.3' QT_ARCH: 'win64_msvc2022_64' LIBGIT2_VERSION: '1.7.1' jobs: build: # Gitea no tiene runners en la nube: esto se ejecuta en un runner # self-hosted registrado con la etiqueta "windows". runs-on: windows steps: # ── 0. Checkout repositories ────────────────────────────────────────── - name: Checkout fritzing-build uses: actions/checkout@v4 with: path: fritzing-build # fritzing-app y fritzing-parts viven en GitHub, no en este Gitea, así # que se clonan directamente en vez de usar actions/checkout (que # asumiría el mismo host que este repo). - name: Checkout fritzing-app run: git clone --depth 1 https://github.com/fritzing/fritzing-app.git fritzing-app shell: pwsh - name: Checkout fritzing-parts run: git clone --depth 1 https://github.com/fritzing/fritzing-parts.git fritzing-parts shell: pwsh # ── 1. Setup MSVC 2022 environment ──────────────────────────────────── - name: Setup MSVC environment uses: ilammy/msvc-dev-cmd@v1 with: arch: amd64 # ── 2. Install Qt ───────────────────────────────────────────────────── - name: Install Qt uses: jurplel/install-qt-action@v4 with: version: ${{ env.QT_VERSION }} host: windows target: desktop arch: ${{ env.QT_ARCH }} modules: 'qtserialport qt5compat' cache: true # ── 3. Cache built dependencies ─────────────────────────────────────── - name: Cache dependencies id: deps-cache uses: actions/cache@v4 with: path: | zlib libgit2 quazip-1.4 quazip-${{ env.QT_VERSION }}-1.4intuisphere Clipper1-6.4.2 boost_1_85_0 svgpp-1.3.1 ngspice-42 key: deps-manual-v3-shared-git2-${{ runner.os }}-qt-${{ env.QT_VERSION }} # ── 4. Build ZLib ───────────────────────────────────────────────────── - name: Download ZLib if: steps.deps-cache.outputs.cache-hit != 'true' run: | Invoke-WebRequest ` -Uri "https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.gz" ` -OutFile zlib.tar.gz tar -xzf zlib.tar.gz Rename-Item zlib-1.3 zlib Remove-Item zlib.tar.gz shell: pwsh - name: Build ZLib if: steps.deps-cache.outputs.cache-hit != 'true' working-directory: zlib run: | mkdir build cd build cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release .. nmake copy zconf.h .. shell: cmd # ── 5. Build libgit2 as DLL ─────────────────────────────────────────── - name: Clone libgit2 if: steps.deps-cache.outputs.cache-hit != 'true' run: | git clone ` --branch "v${{ env.LIBGIT2_VERSION }}" ` --depth 1 ` https://github.com/libgit2/libgit2.git ` libgit2 shell: pwsh - name: Build libgit2 shared if: steps.deps-cache.outputs.cache-hit != 'true' working-directory: libgit2 run: | set ZLIB_ROOT=%GITHUB_WORKSPACE%\zlib mkdir build64 cd build64 cmake -G "NMake Makefiles" ^ -DCMAKE_BUILD_TYPE=Release ^ -DBUILD_SHARED_LIBS=ON ^ -DBUILD_TESTS=OFF ^ -DBUILD_CLI=OFF ^ -DUSE_BUNDLED_ZLIB=OFF ^ -DZLIB_LIBRARY="%ZLIB_ROOT%\build\zlibstatic.lib" ^ -DZLIB_INCLUDE_DIR="%ZLIB_ROOT%" ^ .. nmake shell: cmd - name: Verify libgit2 build if: steps.deps-cache.outputs.cache-hit != 'true' run: | $GitLib = Get-ChildItem "libgit2\build64" ` -Recurse ` -Filter "git2.lib" | Select-Object -First 1 $GitDll = Get-ChildItem "libgit2\build64" ` -Recurse ` -Filter "git2.dll" | Select-Object -First 1 if (-not $GitLib) { throw "git2.lib was not produced" } if (-not $GitDll) { throw "git2.dll was not produced" } Write-Host "Import library: $($GitLib.FullName)" Write-Host "DLL: $($GitDll.FullName)" shell: pwsh # ── 6. Build QuaZip ─────────────────────────────────────────────────── - name: Download QuaZip if: steps.deps-cache.outputs.cache-hit != 'true' run: | Invoke-WebRequest ` -Uri "https://github.com/stachenov/quazip/archive/refs/tags/v1.4.tar.gz" ` -OutFile quazip.tar.gz tar -xzf quazip.tar.gz Remove-Item quazip.tar.gz shell: pwsh - name: Build QuaZip if: steps.deps-cache.outputs.cache-hit != 'true' working-directory: quazip-1.4 run: | $ZlibRoot = "$env:GITHUB_WORKSPACE\zlib" New-Item -ItemType Directory -Force -Path build Push-Location build cmake -G "NMake Makefiles" ` -DZLIB_LIBRARY="$ZlibRoot\build\zlibstatic.lib" ` -DZLIB_INCLUDE_DIR="$ZlibRoot" ` -DCMAKE_BUILD_TYPE=Release ` .. nmake Pop-Location shell: pwsh - name: Setup QuaZip sibling directory if: steps.deps-cache.outputs.cache-hit != 'true' run: | $QuazipSibling = "quazip-${{ env.QT_VERSION }}-1.4intuisphere" New-Item -ItemType Directory -Force ` -Path "$QuazipSibling\lib" New-Item -ItemType Directory -Force ` -Path "$QuazipSibling\include\QuaZip-Qt6-1.4\quazip" Copy-Item ` "quazip-1.4\build\quazip\quazip1-qt6.lib" ` "$QuazipSibling\lib\" Copy-Item ` "quazip-1.4\build\quazip\quazip1-qt6.dll" ` "$QuazipSibling\lib\" ` -ErrorAction SilentlyContinue Copy-Item ` "quazip-1.4\quazip\*.h" ` "$QuazipSibling\include\QuaZip-Qt6-1.4\quazip\" shell: pwsh # ── 7. Setup Clipper ────────────────────────────────────────────────── - name: Download and build Clipper if: steps.deps-cache.outputs.cache-hit != 'true' run: | curl.exe -L ` -o clipper.zip ` "https://sourceforge.net/projects/polyclipping/files/clipper_ver6.4.2.zip/download" Expand-Archive ` -Path clipper.zip ` -DestinationPath clipper-src Remove-Item clipper.zip New-Item -ItemType Directory -Force ` -Path "Clipper1-6.4.2\include\polyclipping" New-Item -ItemType Directory -Force ` -Path "Clipper1-6.4.2\lib" $cppDir = Get-ChildItem ` -Path "clipper-src" ` -Recurse ` -Filter "clipper.hpp" | Select-Object -First 1 -ExpandProperty DirectoryName if (-not $cppDir) { throw "clipper.hpp not found" } Copy-Item ` "$cppDir\clipper.hpp" ` "Clipper1-6.4.2\include\polyclipping\" Copy-Item ` "$cppDir\clipper.cpp" ` "Clipper1-6.4.2\include\polyclipping\" Push-Location "Clipper1-6.4.2" cl /c /O2 /EHsc /MD ` /Iinclude\polyclipping ` include\polyclipping\clipper.cpp lib /OUT:polyclipping.lib clipper.obj Move-Item polyclipping.lib lib\ Remove-Item clipper.obj ` -ErrorAction SilentlyContinue Pop-Location Remove-Item "clipper-src" ` -Recurse ` -Force ` -ErrorAction SilentlyContinue shell: pwsh # ── 8. Header-only and pre-built dependencies ───────────────────────── - name: Download Boost if: steps.deps-cache.outputs.cache-hit != 'true' run: | Invoke-WebRequest ` -Uri "https://archives.boost.io/release/1.85.0/source/boost_1_85_0.tar.gz" ` -OutFile boost.tar.gz tar -xzf boost.tar.gz Remove-Item boost.tar.gz shell: pwsh - name: Download SVG++ if: steps.deps-cache.outputs.cache-hit != 'true' run: | Invoke-WebRequest ` -Uri "https://github.com/svgpp/svgpp/archive/refs/tags/v1.3.1.tar.gz" ` -OutFile svgpp.tar.gz tar -xzf svgpp.tar.gz Remove-Item svgpp.tar.gz shell: pwsh - name: Download ngspice if: steps.deps-cache.outputs.cache-hit != 'true' run: | curl.exe -L ` -o ngspice.7z ` "https://sourceforge.net/projects/ngspice/files/ng-spice-rework/old-releases/42/ngspice-42_dll_64.7z/download" 7z x ngspice.7z -ongspice-extract if (Test-Path "ngspice-extract\Spice64_dll") { Move-Item ` "ngspice-extract\Spice64_dll" ` "ngspice-42" } elseif (Test-Path "ngspice-extract\ngspice-42") { Move-Item ` "ngspice-extract\ngspice-42" ` . } else { Rename-Item ` "ngspice-extract" ` "ngspice-42" } Remove-Item ngspice.7z ` -ErrorAction SilentlyContinue Remove-Item ngspice-extract ` -Recurse ` -Force ` -ErrorAction SilentlyContinue shell: pwsh # ── 9. Verify dependency structure ──────────────────────────────────── - name: Verify dependency layout run: | Write-Host "=== Directory Structure ===" Write-Host "--- libgit2 ---" Get-ChildItem ` "libgit2\include\git2.h" ` -ErrorAction SilentlyContinue Get-ChildItem ` "libgit2\build64" ` -Recurse ` -Filter "git2.lib" ` -ErrorAction SilentlyContinue Get-ChildItem ` "libgit2\build64" ` -Recurse ` -Filter "git2.dll" ` -ErrorAction SilentlyContinue Write-Host "--- QuaZip ---" $qz = "quazip-${{ env.QT_VERSION }}-1.4intuisphere" Get-ChildItem ` "$qz\lib\*" ` -ErrorAction SilentlyContinue Get-ChildItem ` "$qz\include\QuaZip-Qt6-1.4\quazip\*.h" ` -ErrorAction SilentlyContinue | Select-Object -First 3 Write-Host "--- Clipper ---" Get-ChildItem ` "Clipper1-6.4.2\include\polyclipping\*" ` -ErrorAction SilentlyContinue Get-ChildItem ` "Clipper1-6.4.2\lib\*" ` -ErrorAction SilentlyContinue Write-Host "--- Boost ---" Test-Path "boost_1_85_0\boost\version.hpp" Write-Host "--- SVG++ ---" Test-Path "svgpp-1.3.1\include" Write-Host "--- ngspice ---" Test-Path "ngspice-42\include" shell: pwsh # ── 10. Configure Fritzing ──────────────────────────────────────────── - name: Clean qmake cache working-directory: fritzing-app run: | if (Test-Path .qmake.cache) { Remove-Item .qmake.cache } if (Test-Path .qmake.stash) { Remove-Item .qmake.stash } shell: pwsh - name: Setup libgit2 compatibility directory run: | $CompatDir = "libgit2-${{ env.LIBGIT2_VERSION }}" if (Test-Path $CompatDir) { Remove-Item ` $CompatDir ` -Recurse ` -Force } New-Item ` -ItemType Directory ` -Force ` -Path "$CompatDir\include" New-Item ` -ItemType Directory ` -Force ` -Path "$CompatDir\lib" Copy-Item ` "libgit2\include\*" ` "$CompatDir\include\" ` -Recurse $GitLib = Get-ChildItem ` "libgit2\build64" ` -Recurse ` -Filter "git2.lib" | Select-Object -First 1 $GitDll = Get-ChildItem ` "libgit2\build64" ` -Recurse ` -Filter "git2.dll" | Select-Object -First 1 if (-not $GitLib) { throw "git2.lib not found" } if (-not $GitDll) { throw "git2.dll not found" } Copy-Item ` $GitLib.FullName ` "$CompatDir\lib\git2.lib" Copy-Item ` $GitDll.FullName ` "$CompatDir\lib\git2.dll" Write-Host "libgit2 compatibility layout:" Get-ChildItem ` $CompatDir ` -Recurse | Select-Object FullName shell: pwsh - name: Configure Fritzing (qmake) working-directory: fritzing-app run: | qmake phoenix.pro shell: pwsh - name: Build Fritzing (nmake) working-directory: fritzing-app run: nmake release shell: cmd # ── 11. Deploy Qt runtime DLLs ──────────────────────────────────────── - name: Deploy Qt (windeployqt) working-directory: release64 run: | windeployqt Fritzing.exe shell: cmd # ── 12. Copy Third-Party DLLs & Runtime Data ────────────────────────── - name: Copy third-party DLLs and data folders run: | # QuaZip Copy-Item ` "quazip-${{ env.QT_VERSION }}-1.4intuisphere\lib\*.dll" ` "release64\" ` -ErrorAction SilentlyContinue # libgit2 Copy-Item ` "libgit2-${{ env.LIBGIT2_VERSION }}\lib\git2.dll" ` "release64\" ` -Force # ngspice Copy-Item ` "ngspice-42\*.dll" ` "release64\" ` -ErrorAction SilentlyContinue # Qt 5 compatibility runtime Copy-Item ` "$env:QT_ROOT_DIR\bin\Qt6Core5Compat.dll" ` "release64\" ` -ErrorAction SilentlyContinue # Runtime data Copy-Item ` "fritzing-app\help" ` "release64\" ` -Recurse ` -Force Copy-Item ` "fritzing-app\sketches" ` "release64\" ` -Recurse ` -Force Copy-Item ` "fritzing-app\translations" ` "release64\" ` -Recurse ` -Force shell: pwsh # ── 13. Extract Fritzing version ────────────────────────────────────── - name: Extract Fritzing Version run: | $verFile = "fritzing-app\src\version\version.cpp" $content = Get-Content ` -Raw ` -Path $verFile $major = ( [regex]'m_majorVersion\("(.*?)"\)' ).Match($content).Groups[1].Value $minor = ( [regex]'m_minorVersion\("(.*?)"\)' ).Match($content).Groups[1].Value $patch = ( [regex]'m_minorSubVersion\("(.*?)"\)' ).Match($content).Groups[1].Value $mod = ( [regex]'m_modifier\("(.*?)"\)' ).Match($content).Groups[1].Value $versionStr = "$major.$minor.$patch$mod" echo "FRITZING_VER=$versionStr" >> $env:GITHUB_ENV Write-Host "Fritzing version: $versionStr" shell: pwsh # ── 14. Create base ZIP ──────────────────────────────────────────────── - name: Create base Windows ZIP run: | $zipName = "Fritzing-$env:FRITZING_VER-Windows-x64.zip" Compress-Archive ` -Path "release64\*" ` -DestinationPath $zipName echo "BASE_ZIP_FILE=$zipName" >> $env:GITHUB_ENV shell: pwsh # ── 15. Prepare Online Installer ────────────────────────────────────── - name: Zip fritzing-parts for Online Installer run: | git clone ` --no-hardlinks ` fritzing-parts ` fritzing-parts-zip/fritzing-parts git ` -C fritzing-parts-zip/fritzing-parts ` remote set-url origin ` https://github.com/fritzing/fritzing-parts.git Push-Location fritzing-parts-zip 7z a ` -tzip ` ..\fritzing-parts.zip ` fritzing-parts Pop-Location Remove-Item ` fritzing-parts-zip ` -Recurse ` -Force shell: pwsh - name: Compile Online Setup run: | Copy-Item ` "fritzing-build\fritzing_setup.iss" ` ".\" ` -Force # Apunta al release de este Gitea (no al de GitHub). $PartsUrl = ` "${{ github.server_url }}/${{ github.repository }}/releases/download/$env:FRITZING_VER/fritzing-parts.zip" & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" ` /dMyAppVersion="$env:FRITZING_VER" ` /dOnlineInstaller=1 ` /dPartsDownloadUrl="$PartsUrl" ` "fritzing_setup.iss" echo ` "ONLINE_SETUP_FILE=Fritzing-$env:FRITZING_VER-OnlineSetup-Windows-x64.exe" ` >> $env:GITHUB_ENV shell: pwsh # ── 16. Bundle fritzing-parts for Offline/Portable ──────────────────── - name: Clone fritzing-parts into release64 run: | git clone \ --no-hardlinks \ fritzing-parts \ release64/fritzing-parts git \ -C release64/fritzing-parts \ remote set-url origin \ https://github.com/fritzing/fritzing-parts.git shell: bash # ── 17. Create Portable ZIP ──────────────────────────────────────────── - name: Compress Portable ZIP run: | $zipName = ` "Fritzing-$env:FRITZING_VER-Portable-Windows-x64.zip" Push-Location release64 7z a ` -tzip ` "..\$zipName" ` * Pop-Location echo "ZIP_FILE=$zipName" >> $env:GITHUB_ENV shell: pwsh # ── 18. Compile Offline Installer ───────────────────────────────────── - name: Compile Offline Setup run: | & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" ` /dMyAppVersion="$env:FRITZING_VER" ` /dOnlineInstaller=0 ` "fritzing_setup.iss" echo ` "OFFLINE_SETUP_FILE=Fritzing-$env:FRITZING_VER-OfflineSetup-Windows-x64.exe" ` >> $env:GITHUB_ENV shell: pwsh # ── 19. Upload Artifacts ─────────────────────────────────────────────── # # MUY IMPORTANTE: # aunque el paso posterior de la Release falle, estos ficheros # quedarán disponibles en Actions -> Summary -> Artifacts. # - name: Upload Fritzing build artifacts uses: actions/upload-artifact@v4 with: name: Fritzing-${{ env.FRITZING_VER }}-Windows-x64 path: | ${{ env.BASE_ZIP_FILE }} ${{ env.ZIP_FILE }} ${{ env.ONLINE_SETUP_FILE }} ${{ env.OFFLINE_SETUP_FILE }} fritzing-parts.zip if-no-files-found: error compression-level: 0 retention-days: 30 # ── 20. Create Gitea Release ─────────────────────────────────────────── # # Gitea Actions expone un token de API equivalente al GITHUB_TOKEN de # GitHub (secrets.GITHUB_TOKEN), válido contra la API de este mismo # Gitea. No hay acción "release" oficial de Gitea instalada, así que # se usa la API REST directamente (igual que ya hace el resto del # workflow con curl.exe para otras descargas). # - name: Create Gitea Release and upload assets if: github.ref == 'refs/heads/master' shell: pwsh env: GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITEA_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }} run: | $headers = @{ Authorization = "token $env:GITEA_TOKEN" } $releaseBody = @{ tag_name = $env:FRITZING_VER name = "Fritzing $env:FRITZING_VER" draft = $true } | ConvertTo-Json $release = Invoke-RestMethod ` -Uri "$env:GITEA_API/releases" ` -Method Post ` -Headers $headers ` -Body $releaseBody ` -ContentType "application/json" $releaseId = $release.id Write-Host "Created release id $releaseId ($env:FRITZING_VER)" $files = @( $env:BASE_ZIP_FILE, $env:ZIP_FILE, $env:ONLINE_SETUP_FILE, $env:OFFLINE_SETUP_FILE, "fritzing-parts.zip" ) foreach ($f in $files) { Write-Host "Uploading asset: $f" curl.exe -sS -f -X POST ` -H "Authorization: token $env:GITEA_TOKEN" ` -F "attachment=@$f" ` "$env:GITEA_API/releases/$releaseId/assets?name=$f" if ($LASTEXITCODE -ne 0) { throw "Failed to upload $f" } }