param( [string]$HostName = "1.13.22.133", [string]$User = "root", [string]$RemoteDir = "/opt/equipment-management", [string]$RemoteArchive = "/tmp/equipment-management-release.tar.gz", [switch]$SkipDeploy, [switch]$SkipBackup ) $ErrorActionPreference = "Stop" $projectRoot = Split-Path -Parent $PSScriptRoot $password = if ($env:DEPLOY_PASSWORD) { $env:DEPLOY_PASSWORD } else { "" } $archiveName = "equipment-management-release.tar.gz" $archivePath = Join-Path ([System.IO.Path]::GetTempPath()) $archiveName $fileListPath = Join-Path ([System.IO.Path]::GetTempPath()) "equipment-management-files.txt" function Get-CommandPath([string]$name) { $cmd = Get-Command $name -ErrorAction SilentlyContinue if (-not $cmd) { throw "Command not found: $name" } return $cmd.Source } function Invoke-External { param( [string]$FilePath, [string[]]$Arguments, [switch]$IgnoreExitCode ) & $FilePath @Arguments if (-not $IgnoreExitCode -and $LASTEXITCODE -ne 0) { throw "Command failed: $FilePath $($Arguments -join ' ')" } } $tarExe = Get-CommandPath "tar" $sshExe = Get-CommandPath "ssh" $scpExe = Get-CommandPath "scp" $sshpassExe = $null if ($password) { $sshpassExe = Get-CommandPath "sshpass" } Set-Location $projectRoot $files = git ls-files --cached --others --exclude-standard if (-not $files) { throw "No files to publish." } $files | Set-Content -Path $fileListPath -Encoding utf8 if (Test-Path $archivePath) { Remove-Item $archivePath -Force } Write-Host ">>> Packing repository files..." Invoke-External -FilePath $tarExe -Arguments @("-czf", $archivePath, "-T", $fileListPath) $remoteTarget = "$User@$HostName" $sshBaseArgs = @("-o", "StrictHostKeyChecking=no") $scpBaseArgs = @("-o", "StrictHostKeyChecking=no") if ($password) { Write-Host ">>> Using DEPLOY_PASSWORD for upload and remote execution..." $scpArgs = @("-p", $password, $scpExe) + $scpBaseArgs + @($archivePath, "${remoteTarget}:$RemoteArchive") Invoke-External -FilePath $sshpassExe -Arguments $scpArgs } else { Write-Host ">>> Using SSH key or interactive password..." $scpArgs = $scpBaseArgs + @($archivePath, "${remoteTarget}:$RemoteArchive") Invoke-External -FilePath $scpExe -Arguments $scpArgs } $skipBackupValue = if ($SkipBackup) { "1" } else { "0" } $deployCommand = @" set -e mkdir -p '$RemoteDir' cd '$RemoteDir' rm -rf backend frontend scripts AGENTS.md BACKUP.md README.md deploy.sh docker-compose.yml Dockerfile tar -xzf '$RemoteArchive' -C '$RemoteDir' sed -i 's/\r$//' '$RemoteDir/deploy.sh' '$RemoteDir/scripts/backup-equipment.sh' chmod +x '$RemoteDir/deploy.sh' '$RemoteDir/scripts/backup-equipment.sh' if [ '$($SkipDeploy.IsPresent)' = 'True' ]; then echo '>>> 已设置 SkipDeploy,仅同步文件,不执行部署' else if [ '$skipBackupValue' = '1' ]; then SKIP_BACKUP=1 '$RemoteDir/deploy.sh' else '$RemoteDir/deploy.sh' fi fi rm -f '$RemoteArchive' "@ if ($password) { $sshArgs = @("-p", $password, $sshExe) + $sshBaseArgs + @($remoteTarget, $deployCommand) Invoke-External -FilePath $sshpassExe -Arguments $sshArgs } else { $sshArgs = $sshBaseArgs + @($remoteTarget, $deployCommand) Invoke-External -FilePath $sshExe -Arguments $sshArgs } Write-Host ">>> Publish completed"