Files

139 lines
4.0 KiB
PowerShell

# Deploy prebuilt MyOffice artifacts to a Proxmox CT (or any Linux host).
# Usage:
# .\proxmox\publish.ps1
# .\proxmox\deploy.ps1 -TargetHost 192.168.1.120
# .\proxmox\deploy.ps1 -TargetHost 192.168.1.120 -User root -RemotePath /opt/myoffice/api
#
# Requires OpenSSH client (ssh/scp). Prefers rsync if available (Git Bash / WSL / cwRsync).
# Preserves CT-owned appsettings.Production.json / appsettings.shared.Production.json.
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[Alias('ComputerName', 'Host')]
[string]$TargetHost,
[string]$User = 'root',
[Alias('Path')]
[string]$RemotePath = '/opt/myoffice/api',
[string]$Service = 'myoffice-api',
[string]$PublishDir = '',
[int]$Port = 22
)
$ErrorActionPreference = 'Stop'
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = Resolve-Path (Join-Path $scriptDir '..')
if (-not $PublishDir) {
$PublishDir = Join-Path $repoRoot '_Published'
}
if (-not (Test-Path $PublishDir)) {
throw "Publish folder not found: $PublishDir — run .\proxmox\publish.ps1 first."
}
if (-not (Test-Path (Join-Path $PublishDir 'MyOffice.Web.dll'))) {
throw "MyOffice.Web.dll missing in $PublishDir — run .\proxmox\publish.ps1 first."
}
$ctOwnedSettings = @(
'appsettings.Production.json',
'appsettings.shared.Production.json'
)
$remote = "${User}@${TargetHost}"
$sshTarget = @('-p', "$Port", $remote)
$scpTarget = @('-P', "$Port")
function Invoke-Remote {
param([Parameter(Mandatory = $true)][string]$Command)
& ssh @sshTarget $Command
if ($LASTEXITCODE -ne 0) {
throw "ssh failed (exit $LASTEXITCODE): $Command"
}
}
function Test-Rsync {
return [bool](Get-Command rsync -ErrorAction SilentlyContinue)
}
function ConvertTo-RsyncPath([string]$WindowsPath) {
$p = ($WindowsPath.TrimEnd('\', '/') + '/') -replace '\\', '/'
if ($p -match '^[A-Za-z]:') {
$drive = $p.Substring(0, 1).ToLower()
$p = "/$drive" + $p.Substring(2)
}
return $p
}
Write-Host "-----------------------------------------------"
Write-Host "Deploy $PublishDir -> ${remote}:${RemotePath}"
Write-Host "-----------------------------------------------"
Write-Host "Stopping $Service..."
Invoke-Remote "systemctl stop $Service || true"
Invoke-Remote "mkdir -p '$RemotePath'"
$rsync = Test-Rsync
if ($rsync) {
Write-Host "Copying with rsync (preserve CT Production appsettings)..."
$rsyncSrc = ConvertTo-RsyncPath $PublishDir
$rsyncArgs = @(
'-r', '--info=progress2',
'--exclude', 'appsettings.Production.json',
'--exclude', 'appsettings.shared.Production.json',
'-e', "ssh -p $Port",
$rsyncSrc,
"${remote}:${RemotePath}/"
)
& rsync @rsyncArgs
if ($LASTEXITCODE -ne 0) {
throw "rsync failed with exit code $LASTEXITCODE"
}
}
else {
Write-Host "rsync not found — using tar+scp fallback..."
$staging = Join-Path $env:TEMP ("myoffice-deploy-" + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $staging | Out-Null
try {
Get-ChildItem -Path $PublishDir -Force | Where-Object {
$_.Name -notin $ctOwnedSettings
} | ForEach-Object {
Copy-Item $_.FullName -Destination $staging -Recurse -Force
}
$tarLocal = Join-Path $env:TEMP 'myoffice-deploy.tar.gz'
if (Test-Path $tarLocal) { Remove-Item -Force $tarLocal }
Push-Location $staging
try {
tar -czf $tarLocal *
if ($LASTEXITCODE -ne 0) { throw "tar create failed" }
}
finally {
Pop-Location
}
& scp @scpTarget $tarLocal "${remote}:/tmp/myoffice-deploy.tar.gz"
if ($LASTEXITCODE -ne 0) { throw "scp failed" }
Invoke-Remote "tar -xzf /tmp/myoffice-deploy.tar.gz -C '$RemotePath' && rm -f /tmp/myoffice-deploy.tar.gz"
}
finally {
Remove-Item -Recurse -Force $staging -ErrorAction SilentlyContinue
Remove-Item -Force (Join-Path $env:TEMP 'myoffice-deploy.tar.gz') -ErrorAction SilentlyContinue
}
}
Write-Host "Starting $Service..."
Invoke-Remote "systemctl start $Service"
Invoke-Remote "systemctl --no-pager --full status $Service || true"
Write-Host ""
Write-Host "Deployed to http://${TargetHost}:9100 (or your nginx public URL)"
Write-Host ""