name: CI on: push: branches: [main] tags: ["v*"] pull_request: branches: [main] workflow_dispatch: # Targets a self-hosted Windows runner inside mainland China. See README # "Continuous integration" for runner prerequisites. Key points: # * github.com is unreachable here, so the checkout action is pulled from the # gitea.com mirror. If gitea.com is also unreachable, use the manual # checkout fallback below (it clones from your own Gitea instance). # * Flutter must be pre-installed on the runner (the dev machine). We do NOT # download the SDK. # * pub/Flutter use the flutter-io.cn mirrors; the sqlite3 native binary is # vendored (vendor/sqlite3/), so neither is downloaded from GitHub. # * The flutter_onnxruntime plugin downloads the ONNX Runtime native lib from # GitHub during the Windows build; we route that through the local proxy. env: PUB_HOSTED_URL: https://pub.flutter-io.cn FLUTTER_STORAGE_BASE_URL: https://storage.flutter-io.cn jobs: windows: name: Windows build runs-on: windows-latest steps: - name: Checkout uses: https://gitea.com/actions/checkout@v4 # Ensure Flutter is available. The runner's Actions shell does not have # Flutter on PATH, so: use it if present (PATH / FLUTTER_ROOT / common # dirs), otherwise install the pinned SDK from the flutter-io.cn mirror # into a persistent dir (C:\flutter-ci) that is reused across runs. # Pin Flutter 3.44.2 DETERMINISTICALLY. pdfrx needs Windows stylus + # multitouch, which only landed in Flutter 3.44.0 (WM_POINTER migration). # We install into a version-pinned dir and PREPEND it to PATH so this # version shadows any older Flutter already on the runner (a stale # C:\flutter-ci from prior runs must NOT win, or pen input breaks again). - name: Set up Flutter (pinned 3.44.2) shell: powershell run: | $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' $ver = '3.44.2' $root = "C:\flutter-$ver" $bin = Join-Path $root 'flutter\bin' if (-not (Test-Path (Join-Path $bin 'flutter.bat'))) { $url = "https://storage.flutter-io.cn/flutter_infra_release/releases/stable/windows/flutter_windows_$ver-stable.zip" $zip = Join-Path $env:TEMP "flutter_$ver.zip" New-Item -ItemType Directory -Force -Path $root | Out-Null Write-Host "Downloading Flutter $ver from $url" $ok = $false $curl = "$env:SystemRoot\System32\curl.exe" if (Test-Path $curl) { & $curl -L --fail --retry 3 --retry-delay 5 -o $zip $url if ($LASTEXITCODE -eq 0 -and (Test-Path $zip)) { $ok = $true } else { Write-Host "curl download failed (exit $LASTEXITCODE), falling back" } } if (-not $ok) { for ($i = 1; $i -le 3 -and -not $ok; $i++) { try { Invoke-WebRequest -Uri $url -OutFile $zip -UseBasicParsing; $ok = $true } catch { Write-Host "IWR attempt $i failed: $_"; Start-Sleep 5 } } } if (-not $ok) { Write-Error "Failed to download Flutter $ver"; exit 1 } Write-Host "Extracting to $root (slow on first run)" Expand-Archive -Path $zip -DestinationPath $root -Force Remove-Item $zip -Force } if (-not (Test-Path (Join-Path $bin 'flutter.bat'))) { Write-Error "Flutter $ver install failed"; exit 1 } # Prepend (first line wins in GITHUB_PATH) so 3.44.2 shadows any # system/cached Flutter on the runner. Add-Content -Path $env:GITHUB_PATH -Value $bin Write-Host "Flutter $ver pinned at $bin" - name: Flutter version run: flutter --version # pdfrx REQUIRES Windows Developer Mode (its build creates symbolic links; # without Dev Mode `flutter build windows` fails). Enable it on the runner # by setting the AppModelUnlock registry key (idempotent — a no-op if it is # already on). Requires the runner to be elevated; if it is not, this fails # loudly here, which is correct since the build cannot proceed regardless. - name: Enable Windows Developer Mode (pdfrx symlinks) shell: powershell run: | $ErrorActionPreference = 'Stop' $key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' if (-not (Test-Path $key)) { New-Item -Path $key -Force | Out-Null } New-ItemProperty -Path $key -Name 'AllowDevelopmentWithoutDevLicense' ` -Value 1 -PropertyType DWORD -Force | Out-Null $v = (Get-ItemProperty -Path $key -Name 'AllowDevelopmentWithoutDevLicense').AllowDevelopmentWithoutDevLicense Write-Host "AllowDevelopmentWithoutDevLicense = $v (1 = Developer Mode on)" - name: Install dependencies run: flutter pub get # Quality gates run but never block the build, so a usable .exe is always # produced even if a different toolchain version reports new lints. - name: Format check (non-blocking) continue-on-error: true run: dart format --output=none --set-exit-if-changed lib test - name: Analyze (non-blocking) continue-on-error: true run: flutter analyze - name: Test (non-blocking) continue-on-error: true run: flutter test --reporter expanded - name: Enable Windows desktop run: flutter config --enable-windows-desktop # pdfrx -> pdfium_dart pulls pdfium.dll from github.com at build time via a # native-assets build hook (hook/build.dart) that uses package:http, which # IGNORES HTTP_PROXY. Behind the GFW that direct download fails. The hook # skips downloading when its output file already exists, so we (1) pre-fetch # pdfium.dll through a CN-accessible GitHub mirror and pre-place it at the # hook's deterministic shared-output path, and (2) also rewrite the hook's # hardcoded GitHub URL to the mirror as a fallback. - name: Pre-fetch PDFium (pdfrx native asset) shell: powershell run: | $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' $rel = 'chromium/7811' # Deterministic native-assets shared output path (verified from a real # build: .dart_tool/hooks_runner/shared/pdfium_dart/build//). $dst = '.dart_tool\hooks_runner\shared\pdfium_dart\build\chromium_7811\win-x64' $dll = Join-Path $dst 'pdfium.dll' if (-not (Test-Path $dll)) { New-Item -ItemType Directory -Force -Path $dst | Out-Null $tgz = Join-Path $env:TEMP 'pdfium-win-x64.tgz' $gh = "github.com/bblanchon/pdfium-binaries/releases/download/$rel/pdfium-win-x64.tgz" $urls = @("https://gh-proxy.com/https://$gh", "https://ghfast.top/https://$gh", "https://$gh") $curl = "$env:SystemRoot\System32\curl.exe" $ok = $false foreach ($u in $urls) { Write-Host "Fetching PDFium: $u" & $curl -L --fail --retry 2 --retry-delay 5 -o $tgz $u if ($LASTEXITCODE -eq 0 -and (Test-Path $tgz)) { $ok = $true; break } Write-Host " failed (exit $LASTEXITCODE)" } if (-not $ok) { Write-Error "Failed to fetch PDFium from all mirrors"; exit 1 } $ex = Join-Path $env:TEMP 'pdfium_extract' if (Test-Path $ex) { Remove-Item -Recurse -Force $ex } New-Item -ItemType Directory -Force -Path $ex | Out-Null & tar -xzf $tgz -C $ex if ($LASTEXITCODE -ne 0) { Write-Error "tar extract failed"; exit 1 } Copy-Item (Join-Path $ex 'bin\pdfium.dll') $dll -Force Remove-Item $tgz -Force if (-not (Test-Path $dll)) { Write-Error "pdfium.dll not placed"; exit 1 } Write-Host "PDFium pre-placed at $dll" } else { Write-Host "pdfium.dll already present at $dll" } # Fallback: rewrite the hook's hardcoded GitHub URL to the mirror, in # case the pre-placed path is not consulted for some build config. $roots = @($env:PUB_CACHE, "$env:LOCALAPPDATA\Pub\Cache", "$env:APPDATA\Pub\Cache") | Where-Object { $_ -and (Test-Path $_) } foreach ($r in $roots) { $hook = Get-ChildItem -Path $r -Recurse -Filter build.dart -ErrorAction SilentlyContinue | Where-Object { $_.FullName -match 'pdfium_dart-[\d.]+[\\/]hook[\\/]build\.dart' } | Select-Object -First 1 if ($hook) { $orig = 'https://github.com/bblanchon/pdfium-binaries/releases/download/' $mirror = 'https://gh-proxy.com/https://github.com/bblanchon/pdfium-binaries/releases/download/' $c = Get-Content -Raw -LiteralPath $hook.FullName if ($c -notmatch [regex]::Escape($mirror)) { Set-Content -LiteralPath $hook.FullName -Value ($c.Replace($orig, $mirror)) -NoNewline Write-Host "Patched hook URL to mirror: $($hook.FullName)" } break } } # The flutter_onnxruntime plugin downloads the ONNX Runtime native lib # from github.com during the build, which is blocked here. Pre-place the # extracted SDK where the plugin expects it (via a China-accessible GitHub # proxy) so it skips the download and still bundles onnxruntime.dll. - name: Pre-fetch ONNX Runtime shell: powershell run: | $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' $ver = 'onnxruntime-win-x64-1.22.0' $dst = 'build\windows\x64\plugins\flutter_onnxruntime\onnxruntime' $marker = Join-Path $dst "$ver\include\onnxruntime_cxx_api.h" if (Test-Path $marker) { Write-Host "ONNX Runtime already present"; exit 0 } New-Item -ItemType Directory -Force -Path $dst | Out-Null $zip = Join-Path $env:TEMP 'ort.zip' $gh = "github.com/microsoft/onnxruntime/releases/download/v1.22.0/$ver.zip" $urls = @("https://gh-proxy.com/https://$gh", "https://ghfast.top/https://$gh", "https://$gh") $curl = "$env:SystemRoot\System32\curl.exe" $ok = $false foreach ($u in $urls) { Write-Host "Fetching ONNX Runtime: $u" & $curl -L --fail --retry 2 --retry-delay 5 -o $zip $u if ($LASTEXITCODE -eq 0 -and (Test-Path $zip)) { $ok = $true; break } Write-Host " failed (exit $LASTEXITCODE)" } if (-not $ok) { Write-Error "Failed to fetch ONNX Runtime from all mirrors"; exit 1 } Expand-Archive -Path $zip -DestinationPath $dst -Force Remove-Item $zip -Force if (-not (Test-Path $marker)) { Write-Error "ONNX Runtime not in expected layout"; exit 1 } Write-Host "ONNX Runtime ready at $dst\$ver" # Proxy vars are kept as a fallback in case the pre-fetch above is bypassed # (CMake's file(DOWNLOAD) honours them). - name: Build Windows release env: HTTP_PROXY: http://192.168.31.189:7890 HTTPS_PROXY: http://192.168.31.189:7890 http_proxy: http://192.168.31.189:7890 https_proxy: http://192.168.31.189:7890 shell: powershell run: | $sha = if ($env:GITHUB_SHA) { $env:GITHUB_SHA.Substring(0, [Math]::Min(12, $env:GITHUB_SHA.Length)) } else { "unknown" } $built = Get-Date -Format "yyyy-MM-ddTHH:mm:ssK" flutter build windows --release ` --dart-define="BADNOTE_GIT_SHA=$sha" ` --dart-define="BADNOTE_BUILD_TIME=$built" - name: Show build output shell: powershell run: Get-ChildItem build\windows\x64\runner\Release - name: Package artifact shell: powershell run: Compress-Archive -Path "build/windows/x64/runner/Release/*" -DestinationPath "badnote-windows-x64.zip" -Force - name: Upload artifact (best-effort) continue-on-error: true uses: https://gitea.com/actions/upload-artifact@v3 with: name: badnote-windows-x64 path: badnote-windows-x64.zip if-no-files-found: warn