diff --git a/deploy-client.yml b/deploy-client.yml new file mode 100644 index 0000000..485627c --- /dev/null +++ b/deploy-client.yml @@ -0,0 +1,116 @@ +name: deploy-client + +# 此文件放在公开仓库 HighErpAgent-Release 的 .gitea/workflows/ 目录下 +# 由私有仓库构建完成后推送 deploy-cv*.*.* 标签触发 + +on: + push: + tags: + - 'deploy-cv*.*.*' + +jobs: + deploy: + runs-on: hea + steps: + - name: Deploy client from public release + shell: pwsh + env: + DEPLOY_ZIP_PASSWORD: ${{ secrets.DEPLOY_ZIP_PASSWORD }} + run: | + Set-StrictMode -Version Latest + $ErrorActionPreference = 'Stop' + + # 从触发标签解析版本号: deploy-cv1.2.3 -> 1.2.3 + $deployTag = '${{ github.ref_name }}' + if (-not ($deployTag -match '^deploy-cv(\d+\.\d+\.\d+)$')) { + throw "Trigger tag '$deployTag' must match deploy-cvx.x.x." + } + $version = $Matches[1] + + $baseUrl = '${{ github.server_url }}' + $releaseOwner = '${{ github.repository_owner }}' + $releaseRepo = 'HighErpAgent-Release' + $releaseTag = "cv$version" + $assetName = "HighErpAgent-cv$version-deploy.7z" + $deployRoot = 'D:\HighErpAgent' + $tmpDir = Join-Path -Path $deployRoot -ChildPath 'temp' + $targetDir = Join-Path -Path $deployRoot -ChildPath 'files' + $sevenZipPath = Join-Path -Path $env:ProgramFiles -ChildPath '7-Zip\7z.exe' + $downloadUrl = "$baseUrl/$releaseOwner/$releaseRepo/releases/download/$releaseTag/$assetName" + $encryptedZipPath = Join-Path -Path $tmpDir -ChildPath $assetName + + Write-Host 'Client deploy configuration:' + Write-Host " - Base URL: $baseUrl" + Write-Host " - Release Repo: $releaseOwner/$releaseRepo" + Write-Host " - Version: $version" + Write-Host " - Release Tag: $releaseTag" + Write-Host " - Asset Name: $assetName" + Write-Host " - Download URL: $downloadUrl" + Write-Host " - Download Path: $encryptedZipPath" + Write-Host " - Deploy Root: $deployRoot" + Write-Host " - Temp Dir: $tmpDir" + Write-Host " - Target Dir: $targetDir" + Write-Host " - 7-Zip Path: $sevenZipPath" + Write-Host " - PowerShell: $($PSVersionTable.PSVersion)" + + if ([string]::IsNullOrWhiteSpace($version)) { throw 'Version could not be parsed from trigger tag.' } + if ([string]::IsNullOrWhiteSpace($env:ProgramFiles)) { throw 'ProgramFiles environment variable is missing.' } + if (-not (Test-Path -Path $sevenZipPath)) { throw "7-Zip executable was not found at '$sevenZipPath'." } + + # 通过 Gitea Release API 读取 Release body 中内嵌的 SHA-256 + $apiBase = "$baseUrl/api/v1" + $releaseResp = Invoke-RestMethod ` + -Uri "$apiBase/repos/$releaseOwner/$releaseRepo/releases/tags/$releaseTag" ` + -Headers @{ Accept = 'application/json' } ` + -ErrorAction Stop + $expectedHash = $null + if ($releaseResp.body -match 'SHA256:\s*([A-Fa-f0-9]{64})') { + $expectedHash = $Matches[1] + } + if ([string]::IsNullOrWhiteSpace($expectedHash)) { + throw "Could not parse SHA-256 from Release body for tag '$releaseTag'." + } + Write-Host "Expected SHA256 from Release body: $expectedHash" + + Write-Host 'Ensuring deploy directories...' + if (-not (Test-Path -Path $deployRoot)) { + New-Item -ItemType Directory -Path $deployRoot -Force | Out-Null + } + if (-not (Test-Path -Path $tmpDir)) { + New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null + } + + Write-Host "Downloading asset: $downloadUrl" + if (Test-Path -Path $encryptedZipPath) { + Remove-Item -Path $encryptedZipPath -Force + } + $ProgressPreference = 'SilentlyContinue' + Invoke-WebRequest -Uri $downloadUrl -OutFile $encryptedZipPath -SkipCertificateCheck -ErrorAction Stop + + if (-not (Test-Path -Path $encryptedZipPath)) { throw "Downloaded file was not created: '$encryptedZipPath'." } + $downloadedFile = Get-Item -Path $encryptedZipPath + if ($downloadedFile.Length -le 0) { throw "Downloaded file is empty: '$encryptedZipPath'." } + Write-Host "Downloaded file size: $($downloadedFile.Length) bytes" + + $actualHash = (Get-FileHash -Path $encryptedZipPath -Algorithm SHA256).Hash + Write-Host "Downloaded SHA256: $actualHash" + if (-not [string]::Equals($actualHash, $expectedHash, [System.StringComparison]::OrdinalIgnoreCase)) { + throw "Downloaded package hash mismatch. Expected '$expectedHash' but got '$actualHash'." + } + + # 解压外层 7z -> 内层 zip + if (-not (Test-Path -Path $targetDir)) { + New-Item -ItemType Directory -Path $targetDir -Force | Out-Null + } + $innerZipPath = Join-Path -Path $targetDir -ChildPath "HighErpAgent-v$version-deploy.zip" + Write-Host "Extracting $assetName -> $targetDir" + & $sevenZipPath x "$encryptedZipPath" -p"$env:DEPLOY_ZIP_PASSWORD" -o"$targetDir" -aoa + + if (-not (Test-Path -Path $innerZipPath)) { throw "Inner deploy zip not found after extracting '$assetName': '$innerZipPath'." } + Write-Host "Expanding inner zip -> $targetDir" + Expand-Archive -LiteralPath $innerZipPath -DestinationPath $targetDir -Force + Remove-Item -Path $innerZipPath -Force + Remove-Item -Path $encryptedZipPath -Force + + Write-Host 'Deployed files:' + Get-ChildItem -Path $targetDir | ForEach-Object { Write-Host " $($_.Name)" } diff --git a/deploy-server.yml b/deploy-server.yml new file mode 100644 index 0000000..6f5b861 --- /dev/null +++ b/deploy-server.yml @@ -0,0 +1,120 @@ +name: deploy-server + +# 此文件放在公开仓库 HighErpAgent-Release 的 .gitea/workflows/ 目录下 +# 由私有仓库构建完成后推送 deploy-sv*.*.* 标签触发 + +on: + push: + tags: + - 'deploy-sv*.*.*' + +jobs: + deploy: + runs-on: hea + steps: + - name: Deploy server from public release + shell: pwsh + env: + DEPLOY_ZIP_PASSWORD: ${{ secrets.DEPLOY_ZIP_PASSWORD }} + run: | + Set-StrictMode -Version Latest + $ErrorActionPreference = 'Stop' + + # 从触发标签解析版本号: deploy-sv1.2.3 -> 1.2.3 + $deployTag = '${{ github.ref_name }}' + if (-not ($deployTag -match '^deploy-sv(\d+\.\d+\.\d+)$')) { + throw "Trigger tag '$deployTag' must match deploy-svx.x.x." + } + $version = $Matches[1] + + $baseUrl = '${{ github.server_url }}' + $releaseOwner = '${{ github.repository_owner }}' + $releaseRepo = 'HighErpAgent-Release' + $releaseTag = "sv$version" + $assetName = "HighErpAgent-server-sv$version-deploy.7z" + $serviceName = 'HighErpAgent' + $deployRoot = 'D:\HighErpAgent' + $tmpDir = Join-Path -Path $deployRoot -ChildPath 'temp' + $sevenZipPath = Join-Path -Path $env:ProgramFiles -ChildPath '7-Zip\7z.exe' + $downloadUrl = "$baseUrl/$releaseOwner/$releaseRepo/releases/download/$releaseTag/$assetName" + $encryptedZipPath = Join-Path -Path $tmpDir -ChildPath $assetName + + Write-Host 'Server deploy configuration:' + Write-Host " - Base URL: $baseUrl" + Write-Host " - Release Repo: $releaseOwner/$releaseRepo" + Write-Host " - Version: $version" + Write-Host " - Release Tag: $releaseTag" + Write-Host " - Asset Name: $assetName" + Write-Host " - Download URL: $downloadUrl" + Write-Host " - Download Path: $encryptedZipPath" + Write-Host " - Deploy Root: $deployRoot" + Write-Host " - Temp Dir: $tmpDir" + Write-Host " - Service Name: $serviceName" + Write-Host " - 7-Zip Path: $sevenZipPath" + Write-Host " - PowerShell: $($PSVersionTable.PSVersion)" + + if ([string]::IsNullOrWhiteSpace($version)) { throw 'Version could not be parsed from trigger tag.' } + if ([string]::IsNullOrWhiteSpace($env:ProgramFiles)) { throw 'ProgramFiles environment variable is missing.' } + if (-not (Test-Path -Path $sevenZipPath)) { throw "7-Zip executable was not found at '$sevenZipPath'." } + + # 通过 Gitea Release API 读取 Release body 中内嵌的 SHA-256 + $apiBase = "$baseUrl/api/v1" + $releaseResp = Invoke-RestMethod ` + -Uri "$apiBase/repos/$releaseOwner/$releaseRepo/releases/tags/$releaseTag" ` + -Headers @{ Accept = 'application/json' } ` + -ErrorAction Stop + $expectedHash = $null + if ($releaseResp.body -match 'SHA256:\s*([A-Fa-f0-9]{64})') { + $expectedHash = $Matches[1] + } + if ([string]::IsNullOrWhiteSpace($expectedHash)) { + throw "Could not parse SHA-256 from Release body for tag '$releaseTag'." + } + Write-Host "Expected SHA256 from Release body: $expectedHash" + + Write-Host 'Ensuring deploy directories...' + if (-not (Test-Path -Path $deployRoot)) { + New-Item -ItemType Directory -Path $deployRoot -Force | Out-Null + } + if (-not (Test-Path -Path $tmpDir)) { + New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null + } + + Write-Host "Downloading asset: $downloadUrl" + if (Test-Path -Path $encryptedZipPath) { + Remove-Item -Path $encryptedZipPath -Force + } + $ProgressPreference = 'SilentlyContinue' + Invoke-WebRequest -Uri $downloadUrl -OutFile $encryptedZipPath -SkipCertificateCheck -ErrorAction Stop + + if (-not (Test-Path -Path $encryptedZipPath)) { throw "Downloaded file was not created: '$encryptedZipPath'." } + $downloadedFile = Get-Item -Path $encryptedZipPath + if ($downloadedFile.Length -le 0) { throw "Downloaded file is empty: '$encryptedZipPath'." } + Write-Host "Downloaded file size: $($downloadedFile.Length) bytes" + + $actualHash = (Get-FileHash -Path $encryptedZipPath -Algorithm SHA256).Hash + Write-Host "Downloaded SHA256: $actualHash" + if (-not [string]::Equals($actualHash, $expectedHash, [System.StringComparison]::OrdinalIgnoreCase)) { + throw "Downloaded package hash mismatch. Expected '$expectedHash' but got '$actualHash'." + } + + $service = Get-Service -Name $serviceName -ErrorAction Stop + Write-Host "Current service status: $($service.Status)" + if ($service.Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped) { + Write-Host "Stopping service $serviceName" + Stop-Service -Name $serviceName -Force -ErrorAction Stop + $service.WaitForStatus([System.ServiceProcess.ServiceControllerStatus]::Stopped, [TimeSpan]::FromMinutes(1)) + } + + Write-Host "Extracting $assetName -> $deployRoot" + & $sevenZipPath x "$encryptedZipPath" -p"$env:DEPLOY_ZIP_PASSWORD" -o"$deployRoot" -aoa + Remove-Item -Path $encryptedZipPath -Force + + Write-Host "Starting service $serviceName" + Start-Service -Name $serviceName -ErrorAction Stop + $service = Get-Service -Name $serviceName -ErrorAction Stop + $service.WaitForStatus([System.ServiceProcess.ServiceControllerStatus]::Running, [TimeSpan]::FromMinutes(1)) + Write-Host "Service status: $($service.Status)" + + Write-Host 'Deployed server binaries:' + Get-ChildItem -Path $deployRoot -File | Where-Object { $_.Extension -in '.dll', '.exe' } | Sort-Object Name | ForEach-Object { Write-Host " $($_.Name)" }