diff --git a/README.md b/README.md index f8f504d..49fda15 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,32 @@ cd /opt/equipment-management 部署脚本默认会先备份,再重建固定资产系统容器,最后检查健康状态和另一套系统状态。 +## 标准发布命令 + +在当前这台 Windows 开发机上,推荐直接使用: + +```powershell +$env:DEPLOY_PASSWORD="jsjj8888" +.\scripts\publish-to-server.ps1 +``` + +这个脚本会自动完成: + +- 打包当前仓库源码 +- 上传到 `/opt/equipment-management` +- 只覆盖固定资产系统源码 +- 调用服务器上的安全部署脚本 + +常用参数: + +```powershell +.\scripts\publish-to-server.ps1 -SkipDeploy +.\scripts\publish-to-server.ps1 -SkipBackup +``` + +- `-SkipDeploy`:只同步代码,不执行服务器部署 +- `-SkipBackup`:执行部署,但跳过备份,不建议常用 + ## 备份与回滚 执行备份: diff --git a/scripts/publish-to-server.ps1 b/scripts/publish-to-server.ps1 new file mode 100644 index 0000000..a2ccc14 --- /dev/null +++ b/scripts/publish-to-server.ps1 @@ -0,0 +1,103 @@ +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 "未找到命令: $name" + } + return $cmd.Source +} + +function Invoke-External { + param( + [string]$FilePath, + [string[]]$Arguments, + [switch]$IgnoreExitCode + ) + + & $FilePath @Arguments + if (-not $IgnoreExitCode -and $LASTEXITCODE -ne 0) { + throw "命令执行失败: $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 "未找到可发布文件。" +} + +$files | Set-Content -Path $fileListPath -Encoding utf8 + +if (Test-Path $archivePath) { + Remove-Item $archivePath -Force +} + +Write-Host ">>> 打包当前仓库源码..." +Invoke-External -FilePath $tarExe -Arguments @("-czf", $archivePath, "-T", $fileListPath) + +$remoteTarget = "$User@$HostName" +$sshBaseArgs = @("-o", "StrictHostKeyChecking=no") +$scpBaseArgs = @("-o", "StrictHostKeyChecking=no") + +if ($password) { + Write-Host ">>> 使用 DEPLOY_PASSWORD 进行上传和远程执行..." + Invoke-External -FilePath $sshpassExe -Arguments @("-p", $password, $scpExe) + $scpBaseArgs + @($archivePath, "${remoteTarget}:$RemoteArchive") +} else { + Write-Host ">>> 使用 SSH 密钥或交互密码进行上传和远程执行..." + Invoke-External -FilePath $scpExe -Arguments $scpBaseArgs + @($archivePath, "${remoteTarget}:$RemoteArchive") +} + +$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) { + Invoke-External -FilePath $sshpassExe -Arguments @("-p", $password, $sshExe) + $sshBaseArgs + @($remoteTarget, $deployCommand) +} else { + Invoke-External -FilePath $sshExe -Arguments $sshBaseArgs + @($remoteTarget, $deployCommand) +} + +Write-Host ">>> 发布流程完成"