Add Windows deploy script

This commit is contained in:
2026-05-18 19:11:31 +02:00
parent 20c8868744
commit ff28f70b51

167
scripts/deploy.ps1 Normal file
View File

@@ -0,0 +1,167 @@
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Require-Tool {
param(
[Parameter(Mandatory = $true)][string]$Name
)
if ($null -eq (Get-Command $Name -ErrorAction SilentlyContinue)) {
throw "Required tool not found: $Name"
}
}
function Invoke-NativeCommand {
param(
[Parameter(Mandatory = $true)][string]$Name,
[Parameter(Mandatory = $true)][scriptblock]$Action
)
Write-Host $Name
& $Action
if ($LASTEXITCODE -ne 0) {
throw "Step failed: $Name"
}
}
function Get-RemoteScript {
param(
[Parameter(Mandatory = $true)][string]$RemoteReleaseDir,
[Parameter(Mandatory = $true)][string]$RemoteCurrentLink,
[Parameter(Mandatory = $true)][string]$ContainerName,
[Parameter(Mandatory = $true)][string]$ImageName,
[Parameter(Mandatory = $true)][string]$ReleaseTimestamp,
[Parameter(Mandatory = $true)][string]$RemoteDataDir,
[Parameter(Mandatory = $true)][string]$ContainerPort,
[Parameter(Mandatory = $true)][string]$HostPort
)
$script = @'
set -euo pipefail
remote_release_dir='__REMOTE_RELEASE_DIR__'
remote_current_link='__REMOTE_CURRENT_LINK__'
container_name='__CONTAINER_NAME__'
image_name='__IMAGE_NAME__'
release_timestamp='__RELEASE_TIMESTAMP__'
remote_data_dir='__REMOTE_DATA_DIR__'
container_port='__CONTAINER_PORT__'
host_port='__HOST_PORT__'
previous_current_target=''
if [ -L "${remote_current_link}" ]; then
previous_current_target="$(readlink -f "${remote_current_link}")"
fi
docker build -t "${image_name}:${release_timestamp}" -t "${image_name}:latest" "${remote_release_dir}"
ln -sfn "${remote_release_dir}" "${remote_current_link}"
if docker ps -aq --filter "name=^/${container_name}$" | grep -q .; then
docker rm -f "${container_name}" >/dev/null
fi
if ! docker run -d \
--name "${container_name}" \
--restart unless-stopped \
-p "127.0.0.1:${host_port}:${container_port}" \
-e ASPNETCORE_ENVIRONMENT=Production \
-e ASPNETCORE_URLS="http://+:${container_port}" \
-e ConnectionStrings__RpgRoller="Data Source=/app/data/rpgroller.db" \
-v "${remote_data_dir}:/app/data" \
"${image_name}:${release_timestamp}" >/dev/null; then
if [ -n "${previous_current_target}" ]; then
ln -sfn "${previous_current_target}" "${remote_current_link}"
fi
exit 1
fi
'@
return $script.
Replace("__REMOTE_RELEASE_DIR__", $RemoteReleaseDir).
Replace("__REMOTE_CURRENT_LINK__", $RemoteCurrentLink).
Replace("__CONTAINER_NAME__", $ContainerName).
Replace("__IMAGE_NAME__", $ImageName).
Replace("__RELEASE_TIMESTAMP__", $ReleaseTimestamp).
Replace("__REMOTE_DATA_DIR__", $RemoteDataDir).
Replace("__CONTAINER_PORT__", $ContainerPort).
Replace("__HOST_PORT__", $HostPort)
}
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = Split-Path -Parent $scriptDir
$projectPath = Join-Path $repoRoot "RpgRoller\RpgRoller.csproj"
$remoteHost = "myvserver"
$remoteRoot = "/root/docker/rpgroller"
$remoteReleasesDir = "$remoteRoot/releases"
$remoteCurrentLink = "$remoteRoot/current"
$remoteDataDir = "$remoteRoot/data"
$containerName = "rpgroller"
$imageName = "rpgroller"
$containerPort = "8080"
$hostPort = "8082"
$releaseTimestamp = (Get-Date).ToUniversalTime().ToString("yyyyMMddHHmmss")
$localStageDir = Join-Path $repoRoot "artifacts\deploy\$releaseTimestamp"
$localPublishDir = Join-Path $localStageDir "publish"
$remoteReleaseDir = "$remoteReleasesDir/$releaseTimestamp"
Write-Host "Deploying release $releaseTimestamp"
Require-Tool -Name "dotnet"
Require-Tool -Name "ssh"
Require-Tool -Name "scp"
try {
New-Item -ItemType Directory -Path $localPublishDir -Force | Out-Null
Invoke-NativeCommand -Name "1) Publishing app locally..." -Action {
dotnet publish $projectPath -c Release -o $localPublishDir
}
@'
FROM mcr.microsoft.com/dotnet/aspnet:10.0
WORKDIR /app
ENV ASPNETCORE_URLS=http://+:8080
ENV DOTNET_EnableDiagnostics=0
EXPOSE 8080
COPY publish/ ./
RUN mkdir -p /app/data
ENTRYPOINT ["dotnet", "RpgRoller.dll"]
'@ | Set-Content -Path (Join-Path $localStageDir "Dockerfile") -NoNewline
Invoke-NativeCommand -Name "2) Preparing remote release directory..." -Action {
ssh $remoteHost "mkdir -p '$remoteReleasesDir' '$remoteDataDir' && test ! -e '$remoteReleaseDir' && mkdir -p '$remoteReleaseDir'"
}
Invoke-NativeCommand -Name "3) Uploading release payload..." -Action {
Push-Location $localStageDir
try {
scp -r "Dockerfile" "publish" "${remoteHost}:$remoteReleaseDir/"
}
finally {
Pop-Location
}
}
$remoteScript = Get-RemoteScript `
-RemoteReleaseDir $remoteReleaseDir `
-RemoteCurrentLink $remoteCurrentLink `
-ContainerName $containerName `
-ImageName $imageName `
-ReleaseTimestamp $releaseTimestamp `
-RemoteDataDir $remoteDataDir `
-ContainerPort $containerPort `
-HostPort $hostPort
Invoke-NativeCommand -Name "4) Building image and restarting container on remote host..." -Action {
$remoteScript | ssh $remoteHost "bash -se"
}
Write-Host "5) Deployment complete."
}
finally {
if (Test-Path $localStageDir) {
Remove-Item -Path $localStageDir -Recurse -Force -ErrorAction SilentlyContinue
}
}