diff --git a/.gitea/workflows/windows.yml b/.gitea/workflows/windows.yml new file mode 100644 index 0000000..18e48f5 --- /dev/null +++ b/.gitea/workflows/windows.yml @@ -0,0 +1,735 @@ +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" + } + }