189 lines
4.6 KiB
PowerShell
189 lines
4.6 KiB
PowerShell
param(
|
|
[string]$RepoRoot = $(Split-Path -Parent $PSScriptRoot),
|
|
[string]$Ref = "origin/main",
|
|
[string]$RemoteBase = "/opt/furniture-3d-system-prod",
|
|
[string]$ServerHost = "ltai5tdb2ogyj59fquyedh.yydd.ai",
|
|
[int]$SshPort = 60022,
|
|
[string]$ServerUser = "root",
|
|
[string]$ServerPassword = "",
|
|
[string]$HostKeyFingerprint = "SHA256:JPHcomdjuUZOTM7sNdBYg0/xRkQSXzbXe7FEfNtIFAU",
|
|
[int]$AppPort = 3001,
|
|
[string]$Pm2Name = "furniture-3d-system-prod",
|
|
[int]$KeepReleases = 5,
|
|
[switch]$KeepArtifacts
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$createScript = Join-Path $RepoRoot 'scripts\create-yydd-prod-deploy.ps1'
|
|
$plinkPath = 'C:\Program Files\PuTTY\plink.exe'
|
|
$pscpPath = 'C:\Program Files\PuTTY\pscp.exe'
|
|
|
|
if (-not (Test-Path -LiteralPath $createScript)) {
|
|
throw "缺少打包脚本: $createScript"
|
|
}
|
|
if (-not (Test-Path -LiteralPath $plinkPath)) {
|
|
throw "缺少 plink.exe: $plinkPath"
|
|
}
|
|
if (-not (Test-Path -LiteralPath $pscpPath)) {
|
|
throw "缺少 pscp.exe: $pscpPath"
|
|
}
|
|
|
|
function Invoke-NativeCommand {
|
|
param(
|
|
[string]$FilePath,
|
|
[string[]]$Arguments,
|
|
[string]$WorkingDirectory = $RepoRoot
|
|
)
|
|
|
|
$previousErrorActionPreference = $ErrorActionPreference
|
|
|
|
try {
|
|
$ErrorActionPreference = 'Continue'
|
|
Push-Location -LiteralPath $WorkingDirectory
|
|
try {
|
|
$output = & $FilePath @Arguments 2>&1
|
|
$exitCode = $LASTEXITCODE
|
|
}
|
|
finally {
|
|
Pop-Location
|
|
}
|
|
|
|
$lines = @(
|
|
$output |
|
|
ForEach-Object {
|
|
if ($_ -is [System.Management.Automation.ErrorRecord]) {
|
|
$_.ToString()
|
|
}
|
|
else {
|
|
[string]$_
|
|
}
|
|
} |
|
|
Where-Object { $_.Length -gt 0 }
|
|
)
|
|
|
|
if ($exitCode -ne 0) {
|
|
throw (($lines -join [Environment]::NewLine).Trim())
|
|
}
|
|
|
|
return $lines
|
|
}
|
|
finally {
|
|
$ErrorActionPreference = $previousErrorActionPreference
|
|
}
|
|
}
|
|
|
|
function Invoke-Plink {
|
|
param(
|
|
[string]$Command
|
|
)
|
|
|
|
$arguments = @(
|
|
'-ssh'
|
|
'-batch'
|
|
'-hostkey'
|
|
$HostKeyFingerprint
|
|
'-P'
|
|
[string]$SshPort
|
|
)
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($ServerPassword)) {
|
|
$arguments += @('-pw', $ServerPassword)
|
|
}
|
|
|
|
$arguments += @(
|
|
('{0}@{1}' -f $ServerUser, $ServerHost)
|
|
$Command
|
|
)
|
|
|
|
return Invoke-NativeCommand -FilePath $plinkPath -Arguments $arguments -WorkingDirectory $RepoRoot
|
|
}
|
|
|
|
function Copy-WithPscp {
|
|
param(
|
|
[string]$LocalPath,
|
|
[string]$RemotePath
|
|
)
|
|
|
|
if (-not (Test-Path -LiteralPath $LocalPath)) {
|
|
throw "上传文件不存在: $LocalPath"
|
|
}
|
|
|
|
$arguments = @(
|
|
'-batch'
|
|
'-hostkey'
|
|
$HostKeyFingerprint
|
|
'-P'
|
|
[string]$SshPort
|
|
)
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($ServerPassword)) {
|
|
$arguments += @('-pw', $ServerPassword)
|
|
}
|
|
|
|
$arguments += @(
|
|
$LocalPath
|
|
('{0}@{1}:{2}' -f $ServerUser, $ServerHost, $RemotePath)
|
|
)
|
|
|
|
return Invoke-NativeCommand -FilePath $pscpPath -Arguments $arguments -WorkingDirectory $RepoRoot
|
|
}
|
|
|
|
$package = & $createScript `
|
|
-RepoRoot $RepoRoot `
|
|
-Ref $Ref `
|
|
-RemoteBase $RemoteBase `
|
|
-ServerHost $ServerHost `
|
|
-AppPort $AppPort `
|
|
-Pm2Name $Pm2Name `
|
|
-KeepReleases $KeepReleases
|
|
|
|
if (-not $package) {
|
|
throw '打包脚本未返回结果'
|
|
}
|
|
|
|
$archivePath = [string]$package.Archive
|
|
$scriptPath = [string]$package.Script
|
|
$remoteArchivePath = [string]$package.RemoteArchivePath
|
|
$remoteScriptPath = [string]$package.RemoteScriptPath
|
|
$remoteIncoming = ('{0}/incoming' -f $RemoteBase)
|
|
$mkdirIncomingCommand = "mkdir -p '{0}'" -f $remoteIncoming
|
|
$runDeployCommand = "chmod +x '{0}' && bash '{0}'" -f $remoteScriptPath
|
|
|
|
try {
|
|
Invoke-Plink $mkdirIncomingCommand | Out-Null
|
|
Copy-WithPscp -LocalPath $archivePath -RemotePath $remoteArchivePath | Out-Null
|
|
Copy-WithPscp -LocalPath $scriptPath -RemotePath $remoteScriptPath | Out-Null
|
|
$deployOutput = Invoke-Plink $runDeployCommand
|
|
}
|
|
finally {
|
|
if (-not $KeepArtifacts) {
|
|
try {
|
|
Invoke-Plink ("rm -f '{0}' '{1}'" -f $remoteArchivePath, $remoteScriptPath) | Out-Null
|
|
}
|
|
catch {
|
|
Write-Warning ("远端部署临时文件清理失败: {0}" -f $_.Exception.Message)
|
|
}
|
|
|
|
if (Test-Path -LiteralPath $archivePath) {
|
|
Remove-Item -LiteralPath $archivePath -Force
|
|
}
|
|
if (Test-Path -LiteralPath $scriptPath) {
|
|
Remove-Item -LiteralPath $scriptPath -Force
|
|
}
|
|
}
|
|
}
|
|
|
|
[PSCustomObject]@{
|
|
Mode = 'safe-git-release-deploy'
|
|
Ref = [string]$package.Ref
|
|
Commit = [string]$package.Commit
|
|
RemoteBase = $RemoteBase
|
|
RemoteArchivePath = $remoteArchivePath
|
|
RemoteScriptPath = $remoteScriptPath
|
|
ServerHost = $ServerHost
|
|
SshPort = $SshPort
|
|
Pm2Name = $Pm2Name
|
|
Output = ($deployOutput -join [Environment]::NewLine)
|
|
}
|