From 732007edd832018b8e8bb291f543f49214b2f348 Mon Sep 17 00:00:00 2001 From: lennlouisgeek Date: Thu, 5 Feb 2026 01:20:55 +0800 Subject: [PATCH] add gitea workflow --- .gitea/workflows/windows-release.yml | 274 +++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 .gitea/workflows/windows-release.yml diff --git a/.gitea/workflows/windows-release.yml b/.gitea/workflows/windows-release.yml new file mode 100644 index 0000000..4a6c164 --- /dev/null +++ b/.gitea/workflows/windows-release.yml @@ -0,0 +1,274 @@ +name: windows-release + +on: + push: + tags: + - "v*" + workflow_dispatch: + inputs: + version: + description: "Override app version (e.g. 0.5.0). Defaults to tag name without leading v." + required: false + type: string + +jobs: + build_windows: + runs-on: windows-host + defaults: + run: + shell: cmd + + env: + QT_ROOT: C:\Qt\6.8.3\mingw_64 + BUILD_DIR: build-ci + DIST_DIR: dist + BUILD_TYPE: Release + APP_EXE_NAME: TactileIpc3D.exe + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Resolve version + run: | + set "APP_VERSION=${{ inputs.version }}" + if "%APP_VERSION%"=="" ( + if "%GITHUB_REF:~0,10%"=="refs/tags/" ( + set "APP_VERSION=%GITHUB_REF_NAME%" + ) else ( + if exist "VERSION.txt" ( + for /f "usebackq delims=" %%v in ("VERSION.txt") do set "APP_VERSION=%%v" + ) else ( + set "APP_VERSION=%GITHUB_REF_NAME%" + ) + ) + ) + if "%APP_VERSION:~0,1%"=="v" set "APP_VERSION=%APP_VERSION:~1%" + echo APP_VERSION=%APP_VERSION%>> "%GITHUB_ENV%" + echo Using APP_VERSION=%APP_VERSION% + + - name: Setup Qt env & sanity check + run: | + call "%QT_ROOT%\bin\qtenv2.bat" + echo ==== qmake / windeployqt ==== + where qmake + qmake -v + where windeployqt + where g++ + g++ --version + + # ========= 这里二选一:CMake 或 qmake ========= + # A) CMake 框架(推荐) + - name: Configure (CMake) + run: | + call "%QT_ROOT%\bin\qtenv2.bat" + if exist "%BUILD_DIR%" rmdir /s /q "%BUILD_DIR%" + mkdir "%BUILD_DIR%" + cmake -S . -B "%BUILD_DIR%" -G "MinGW Makefiles" ^ + -DCMAKE_BUILD_TYPE=%BUILD_TYPE% + + - name: Build (CMake) + run: | + call "%QT_ROOT%\bin\qtenv2.bat" + cmake --build "%BUILD_DIR%" --config %BUILD_TYPE% -j 8 + + # # B) qmake 框架(如果你用 qmake,把上面 CMake 三步注释掉,启用下面) + # - name: Build (qmake) + # run: | + # call "%QT_ROOT%\bin\qtenv2.bat" + # if exist "%BUILD_DIR%" rmdir /s /q "%BUILD_DIR%" + # mkdir "%BUILD_DIR%" + # cd "%BUILD_DIR%" + # qmake .. + # mingw32-make -j 8 + + # ========= 找到 exe & 产物目录 ========= + - name: Collect exe + run: | + call "%QT_ROOT%\bin\qtenv2.bat" + if exist "%DIST_DIR%" rmdir /s /q "%DIST_DIR%" + mkdir "%DIST_DIR%" + + if defined GITHUB_WORKSPACE ( + set "REPO_ROOT=%GITHUB_WORKSPACE%" + ) else ( + set "REPO_ROOT=%CD%" + ) + + set "RUNTIME_OUT_DIR=%BUILD_DIR%\out" + set "RUNTIME_OUT_DIR_CFG=%RUNTIME_OUT_DIR%\%BUILD_TYPE%" + + if exist "%RUNTIME_OUT_DIR_CFG%\%APP_EXE_NAME%" ( + set "RUNTIME_BASE=%RUNTIME_OUT_DIR_CFG%" + ) else ( + set "RUNTIME_BASE=%RUNTIME_OUT_DIR%" + ) + + if not exist "%RUNTIME_BASE%\%APP_EXE_NAME%" ( + echo EXE not found: "%RUNTIME_BASE%\%APP_EXE_NAME%" + exit /b 1 + ) + + echo ==== copy app exe ==== + copy /y "%RUNTIME_BASE%\%APP_EXE_NAME%" "%DIST_DIR%\%APP_EXE_NAME%" + + echo ==== copy plugin dlls ==== + if not exist "%DIST_DIR%\plugins\decoders" mkdir "%DIST_DIR%\plugins\decoders" + if not exist "%RUNTIME_BASE%\plugins\decoders\*.dll" ( + echo Plugin DLLs not found: "%RUNTIME_BASE%\plugins\decoders\*.dll" + exit /b 1 + ) + copy /y "%RUNTIME_BASE%\plugins\decoders\*.dll" "%DIST_DIR%\plugins\decoders\" + + echo ==== copy OpenCV runtime dlls ==== + set "OPENCV_LIB_DIR=%REPO_ROOT%\3rdpart\OpenCV\lib" + if not exist "%OPENCV_LIB_DIR%\libopencv_core4100.dll" ( + echo OpenCV DLL not found: "%OPENCV_LIB_DIR%\libopencv_core4100.dll" + exit /b 1 + ) + if not exist "%OPENCV_LIB_DIR%\libopencv_imgproc4100.dll" ( + echo OpenCV DLL not found: "%OPENCV_LIB_DIR%\libopencv_imgproc4100.dll" + exit /b 1 + ) + copy /y "%OPENCV_LIB_DIR%\libopencv_core4100.dll" "%DIST_DIR%\" + copy /y "%OPENCV_LIB_DIR%\libopencv_imgproc4100.dll" "%DIST_DIR%\" + + echo Copied to %DIST_DIR% + dir "%DIST_DIR%" + + - name: Deploy Qt runtime (windeployqt) + run: | + call "%QT_ROOT%\bin\qtenv2.bat" + "%QT_ROOT%\bin\windeployqt.exe" "%DIST_DIR%\%APP_EXE_NAME%" ^ + --release --compiler-runtime --no-translations + + - name: Build installer (Inno Setup) + run: | + if defined GITHUB_WORKSPACE ( + set "REPO_ROOT=%GITHUB_WORKSPACE%" + ) else ( + set "REPO_ROOT=%CD%" + ) + set "DIST_ABS=%REPO_ROOT%\%DIST_DIR%" + set "ISS_FILE=%REPO_ROOT%\installer\TactileIpc3D.iss" + + if not exist "%ISS_FILE%" ( + echo Inno Setup script not found: "%ISS_FILE%" + exit /b 1 + ) + if not exist "%DIST_ABS%" ( + echo Dist dir not found: "%DIST_ABS%" + exit /b 1 + ) + + where iscc || (echo ISCC not found & exit /b 1) + iscc /DMyAppVersion=%APP_VERSION% /DSourceDir="%DIST_ABS%" /DOutputDir="%DIST_ABS%" "%ISS_FILE%" + + # (可选)打包 zip + - name: Zip package + run: | + powershell -NoProfile -Command ^ + "if (Test-Path '%DIST_DIR%.zip') { Remove-Item -Force '%DIST_DIR%.zip' }; " ^ + "Compress-Archive -Path '%DIST_DIR%\*' -DestinationPath '%DIST_DIR%.zip'" + + - name: Publish Gitea Release + if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch' + shell: powershell + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + $ErrorActionPreference = "Stop" + + $token = $env:GITEA_TOKEN + if (-not $token) { throw "GITEA_TOKEN is not set. Please add it in repo secrets." } + + $api = $env:GITEA_API_URL + if (-not $api) { $api = $env:GITHUB_API_URL } + if (-not $api) { + if ($env:GITEA_SERVER_URL) { $api = "$($env:GITEA_SERVER_URL)/api/v1" } + elseif ($env:GITHUB_SERVER_URL) { $api = "$($env:GITHUB_SERVER_URL)/api/v1" } + } + if (-not $api) { throw "API URL not found. Set GITEA_API_URL or GITEA_SERVER_URL." } + + $repo = $env:GITHUB_REPOSITORY + if (-not $repo) { $repo = $env:GITEA_REPOSITORY } + if (-not $repo) { throw "Repository not found in env." } + + $ref = $env:GITHUB_REF + $isTag = $false + if ($ref) { $isTag = $ref.StartsWith("refs/tags/") } + if ($isTag) { + $tag = $env:GITHUB_REF_NAME + } else { + $tag = "v$($env:APP_VERSION)" + } + if (-not $tag) { throw "Release tag not found." } + + $owner, $repoName = $repo.Split("/") + if (-not $owner -or -not $repoName) { throw "Invalid repo format: $repo" } + + $headers = @{ Authorization = "token $token" } + + # Get or create release + $release = $null + try { + $release = Invoke-RestMethod -Method Get -Headers $headers -Uri "$api/repos/$owner/$repoName/releases/tags/$tag" + } catch { + $release = $null + } + + if (-not $release) { + $body = @{ + tag_name = $tag + name = $tag + draft = $false + prerelease = $false + } + if (-not $isTag) { + $body.target_commitish = $env:GITHUB_SHA + } + $body = $body | ConvertTo-Json + $release = Invoke-RestMethod -Method Post -Headers $headers -ContentType "application/json" -Body $body -Uri "$api/repos/$owner/$repoName/releases" + } + + $releaseId = $release.id + if (-not $releaseId) { throw "Release ID not found." } + + # Resolve dist dir + $repoRoot = $env:GITHUB_WORKSPACE + if (-not $repoRoot) { $repoRoot = (Get-Location).Path } + $distDir = Join-Path $repoRoot $env:DIST_DIR + if (-not (Test-Path $distDir)) { throw "Dist dir not found: $distDir" } + + $installer = Get-ChildItem -Path $distDir -Filter "TactileIpc3D-Setup-*.exe" | Sort-Object LastWriteTime -Descending | Select-Object -First 1 + if (-not $installer) { throw "Installer not found in $distDir" } + + $zipPath = Join-Path $repoRoot "$($env:DIST_DIR).zip" + $assets = @($installer.FullName) + if (Test-Path $zipPath) { $assets += $zipPath } + + # Delete existing assets with same name + $existing = Invoke-RestMethod -Method Get -Headers $headers -Uri "$api/repos/$owner/$repoName/releases/$releaseId/assets" + $existingMap = @{} + foreach ($a in $existing) { $existingMap[$a.name] = $a.id } + + foreach ($asset in $assets) { + $name = [System.IO.Path]::GetFileName($asset) + if ($existingMap.ContainsKey($name)) { + $assetId = $existingMap[$name] + Invoke-RestMethod -Method Delete -Headers $headers -Uri "$api/repos/$owner/$repoName/releases/assets/$assetId" + } + $uploadUrl = "$api/repos/$owner/$repoName/releases/$releaseId/assets?name=$name" + & curl.exe -sS -X POST -H "Authorization: token $token" -F "attachment=@$asset" $uploadUrl + if ($LASTEXITCODE -ne 0) { throw "Upload failed for $name" } + } + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: windows-${{ env.BUILD_TYPE }} + path: | + dist/** + dist.zip