add gitea workflow
This commit is contained in:
274
.gitea/workflows/windows-release.yml
Normal file
274
.gitea/workflows/windows-release.yml
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user