Deploymentcenter-Integration (Schritte 0-8 des Konzepts)
Bindet Lizenz, Watchdog, Fehler-Stream, UpdateService und Erstinstallation an
das Deploymentcenter 2.5.1 an. Einbauort ist IBKRTrader.Hosting - den Host
teilen sich Shell und Daemon.
Projekt-Befunde aus dem Konzept vorab bereinigt:
P1 Echte DB-Zugangsdaten als Vorgabewerte in AppSettings -> Platzhalter.
Das alte Passwort steht weiterhin in der Git-Historie und ist als
kompromittiert zu behandeln (Rotation ist Nutzer-Aktion).
P2 AppPaths fiel unter Windows auf /etc/ibkrtrader zurueck, was .NET zu
C:\etc\ibkrtrader aufloest. Jetzt %ProgramData%\IBKRTrader.
P3 Globale Ausnahmebehandler (AppDomain / TaskScheduler) - vorher gab es
keinen Logeintrag, wenn der Prozess unbehandelt wegbrach.
P4 Version einmal zentral in Directory.Build.props statt zweimal hartkodiert.
Bewusste Abweichungen vom DC-Leitfaden, beide fuer ein handelndes System:
- Lizenz-Urteil fuehrt zum Sperrbetrieb (TradingEnabled=false) statt zu
Environment.Exit(1). Keine neuen Einstiege, aber Risiko-, Exit- und
Buchhaltungslogik laufen weiter.
- exitCurrentApp bleibt immer false; der Aufrufer beendet geordnet.
Das SDK haengt als Cross-Repo-ProjectReference am Schwester-Repo
Deploymentcenter (Interim, siehe Konzept 2.2). Damit ist P5 offen: die
Gitea-CI checkt das Schwester-Repo nicht aus und wird rot, bis der Bezug auf
ein NuGet-Paket umgestellt ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"_comment": "Kopie als scripts/release.config.json angelegt und ausgefuellt. Diese Datei enthaelt KEINE Zugangsdaten - die kommen aus Umgebungsvariablen (DC_FTP_HOST, DC_FTP_USER, DC_FTP_PASS, DC_TOKEN) oder aus einer packager.config.json neben dem Werkzeug. release.config.json darf deshalb versioniert werden.",
|
||||
|
||||
"_project_comment": "IBKRTrader.Daemon ist der Release-Kandidat: plattformneutral (net10.0 ohne Plattformbindung, siehe README), laeuft kopflos auf beiden Zielsystemen. IBKRTrader.App (Avalonia-Shell) ist bewusst NICHT Teil dieser automatisierten Pipeline - das Vorlagenskript nimmt genau eine csproj fuer alle Runtimes, und das Skript bleibt laut Anleitung unveraendert. Eine Desktop-Distribution der Shell ist ein separater, spaeterer Schritt.",
|
||||
"project": "ibkrtrader",
|
||||
|
||||
"csproj": "src/IBKRTrader.Daemon/IBKRTrader.Daemon.csproj",
|
||||
|
||||
"_runtimes_comment": "Je Eintrag entsteht ein eigenes Release - ohne Plattformangabe wuerden sie sich gegenseitig ueberschreiben.",
|
||||
"runtimes": ["win-x64", "linux-x64"],
|
||||
|
||||
"_selfContained_comment": "true nimmt die .NET-Laufzeit ins Paket, damit ein frisch aufgesetztes System kein vorinstalliertes .NET braucht (siehe deploy/README.md zur ICU-Warnung).",
|
||||
"selfContained": true,
|
||||
|
||||
"publishSingleFile": false,
|
||||
|
||||
"setupJson": "setup.json",
|
||||
|
||||
"mainAssembly": "",
|
||||
|
||||
"baseUrl": "https://dc.mhdf.de"
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Veroeffentlicht dieses Projekt im Deploymentcenter.
|
||||
|
||||
.DESCRIPTION
|
||||
Vorlage zum Kopieren nach scripts/release.ps1 des eigenen Projekts.
|
||||
Anzupassen ist nur der Kopf von release.config.json - dieses Skript
|
||||
selbst bleibt unveraendert.
|
||||
|
||||
Der Ablauf je Zielplattform:
|
||||
dotnet publish -r <rid> -> pack-and-deploy --platform <rid>
|
||||
|
||||
pack-and-deploy uebernimmt dabei Pruefsummen, Dateimanifest, das
|
||||
Fortschreiben der latest.json und die Anmeldung beim Deploymentcenter.
|
||||
Das hier nachzubauen waere ein zweiter Ort fuer dieselben Fehler; das
|
||||
Skript orchestriert nur.
|
||||
|
||||
Fehlt das Werkzeug, wird es geholt und die Pruefsumme geprueft.
|
||||
|
||||
.EXAMPLE
|
||||
.\scripts\release.ps1 -Version 1.4.3 -Changelog "Behebt den Login-Fehler."
|
||||
|
||||
.EXAMPLE
|
||||
.\scripts\release.ps1 -Version 1.5.0 -Channel beta -WhatIf
|
||||
#>
|
||||
|
||||
[CmdletBinding(SupportsShouldProcess = $true)]
|
||||
param(
|
||||
# Ohne Angabe wird die Version aus Directory.Build.props bzw. der csproj gelesen.
|
||||
[string] $Version,
|
||||
|
||||
[ValidateSet('prod', 'beta', 'dev')]
|
||||
[string] $Channel = 'prod',
|
||||
|
||||
[string] $Changelog,
|
||||
|
||||
# Als kritisches Update kennzeichnen (Rollout priorisieren).
|
||||
[switch] $Critical,
|
||||
|
||||
[string] $ConfigFile = (Join-Path $PSScriptRoot 'release.config.json')
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# ---------------------------------------------------------------- Konfiguration
|
||||
if (-not (Test-Path $ConfigFile)) {
|
||||
throw "Konfiguration fehlt: $ConfigFile`nVorlage kopieren: release.config.example.json -> release.config.json"
|
||||
}
|
||||
|
||||
$config = Get-Content $ConfigFile -Raw | ConvertFrom-Json
|
||||
|
||||
foreach ($required in @('project', 'csproj', 'runtimes')) {
|
||||
if (-not $config.$required) {
|
||||
throw "In $ConfigFile fehlt der Eintrag '$required'."
|
||||
}
|
||||
}
|
||||
|
||||
$repoRoot = Resolve-Path (Join-Path $PSScriptRoot '..')
|
||||
$csprojRel = $config.csproj
|
||||
$csproj = Join-Path $repoRoot $csprojRel
|
||||
|
||||
if (-not (Test-Path $csproj)) {
|
||||
throw "Projektdatei nicht gefunden: $csproj"
|
||||
}
|
||||
|
||||
$baseUrl = if ($config.baseUrl) { $config.baseUrl.TrimEnd('/') } else { 'https://dc.mhdf.de' }
|
||||
$toolDir = Join-Path $repoRoot '.dc-tools'
|
||||
|
||||
# ---------------------------------------------------------------------- Version
|
||||
function Get-ProjectVersion {
|
||||
# Directory.Build.props zuerst: Steht <Version> nur in einem von mehreren
|
||||
# Projekten, laufen die Angaben frueher oder spaeter auseinander - und
|
||||
# pack-and-deploy bricht dann zu Recht mit einem Versionskonflikt ab.
|
||||
foreach ($candidate in @(
|
||||
(Join-Path $repoRoot 'Directory.Build.props'),
|
||||
$csproj
|
||||
)) {
|
||||
if (-not (Test-Path $candidate)) { continue }
|
||||
|
||||
$match = [regex]::Match((Get-Content $candidate -Raw), '<Version>\s*([^<]+?)\s*</Version>')
|
||||
if ($match.Success) {
|
||||
return $match.Groups[1].Value.Trim()
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
if (-not $Version) {
|
||||
$Version = Get-ProjectVersion
|
||||
if (-not $Version) {
|
||||
throw "Keine <Version> in Directory.Build.props oder $csprojRel gefunden. Bitte -Version angeben."
|
||||
}
|
||||
Write-Host "Version aus dem Projekt gelesen: $Version" -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
if (-not $Changelog) {
|
||||
$Changelog = "Release v$Version"
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------- Werkzeug
|
||||
function Get-PackAndDeploy {
|
||||
$exe = Join-Path $toolDir 'pack-and-deploy.exe'
|
||||
if (Test-Path $exe) { return $exe }
|
||||
|
||||
Write-Host "pack-and-deploy wird geholt ..." -ForegroundColor Cyan
|
||||
New-Item -ItemType Directory -Force -Path $toolDir | Out-Null
|
||||
|
||||
$name = 'pack-and-deploy-win-x64.exe'
|
||||
$temp = Join-Path $toolDir 'download.tmp'
|
||||
|
||||
Invoke-WebRequest -Uri "$baseUrl/installer/$name" -OutFile $temp -UseBasicParsing
|
||||
|
||||
$expectedRaw = (Invoke-WebRequest -Uri "$baseUrl/installer/$name.sha256" -UseBasicParsing).Content
|
||||
$expected = if ($expectedRaw -is [byte[]]) {
|
||||
[System.Text.Encoding]::ASCII.GetString($expectedRaw)
|
||||
} else { [string]$expectedRaw }
|
||||
$expected = $expected.Trim().ToLower()
|
||||
|
||||
$actual = (Get-FileHash $temp -Algorithm SHA256).Hash.ToLower()
|
||||
|
||||
if ($actual -ne $expected) {
|
||||
Remove-Item $temp -Force
|
||||
throw "Pruefsumme von $name stimmt nicht.`n erwartet: $expected`n erhalten: $actual"
|
||||
}
|
||||
|
||||
Move-Item $temp $exe -Force
|
||||
try { Unblock-File $exe -ErrorAction SilentlyContinue } catch { }
|
||||
|
||||
Write-Host " Pruefsumme in Ordnung." -ForegroundColor DarkGray
|
||||
return $exe
|
||||
}
|
||||
|
||||
$packAndDeploy = Get-PackAndDeploy
|
||||
|
||||
# --------------------------------------------------------------------- Ablauf
|
||||
Write-Host ''
|
||||
Write-Host "Projekt : $($config.project)" -ForegroundColor White
|
||||
Write-Host "Version : $Version"
|
||||
Write-Host "Kanal : $Channel"
|
||||
Write-Host "Plattform : $($config.runtimes -join ', ')"
|
||||
Write-Host ''
|
||||
|
||||
$results = @()
|
||||
|
||||
foreach ($rid in $config.runtimes) {
|
||||
Write-Host "=== $rid ===" -ForegroundColor Cyan
|
||||
|
||||
$publishDir = Join-Path $repoRoot "artifacts/publish/$rid"
|
||||
|
||||
if ($PSCmdlet.ShouldProcess("$($config.project) $Version ($rid)", 'dotnet publish')) {
|
||||
# Sauber neu bauen: Reste einer vorherigen Laufzeitkennung wuerden
|
||||
# sonst mit ins Paket wandern.
|
||||
if (Test-Path $publishDir) { Remove-Item $publishDir -Recurse -Force }
|
||||
|
||||
$publishArgs = @(
|
||||
'publish', $csproj,
|
||||
'-c', 'Release',
|
||||
'-r', $rid,
|
||||
'-o', $publishDir,
|
||||
'--nologo'
|
||||
)
|
||||
|
||||
if ($config.selfContained) { $publishArgs += '--self-contained', 'true' }
|
||||
else { $publishArgs += '--self-contained', 'false' }
|
||||
|
||||
if ($config.publishSingleFile) { $publishArgs += '-p:PublishSingleFile=true' }
|
||||
|
||||
& dotnet @publishArgs
|
||||
if ($LASTEXITCODE -ne 0) { throw "dotnet publish fuer $rid ist fehlgeschlagen." }
|
||||
}
|
||||
|
||||
# setup.json mitliefern, damit der Installer weiss, was einzurichten ist.
|
||||
# Bewusst kein Ternary-Operator: den gibt es erst ab PowerShell 7, und
|
||||
# diese Vorlage soll auch mit dem mitgelieferten 5.1 laufen.
|
||||
$setupRel = if ($config.setupJson) { $config.setupJson } else { 'setup.json' }
|
||||
$setupJson = Join-Path $repoRoot $setupRel
|
||||
if (Test-Path $setupJson) {
|
||||
Copy-Item $setupJson (Join-Path $publishDir 'setup.json') -Force
|
||||
Write-Host " setup.json mitgenommen" -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
if ($PSCmdlet.ShouldProcess("$($config.project) $Version ($rid)", 'pack-and-deploy')) {
|
||||
$packArgs = @(
|
||||
'--project', $config.project,
|
||||
'--version', $Version,
|
||||
'--channel', $Channel,
|
||||
'--platform', $rid,
|
||||
'--publish-dir', $publishDir,
|
||||
'--changelog', $Changelog
|
||||
)
|
||||
|
||||
if ($Critical) { $packArgs += '--critical' }
|
||||
if ($config.mainAssembly) { $packArgs += '--main-assembly', $config.mainAssembly }
|
||||
|
||||
& $packAndDeploy @packArgs
|
||||
$code = $LASTEXITCODE
|
||||
|
||||
$results += [pscustomobject]@{ Runtime = $rid; ExitCode = $code }
|
||||
|
||||
# 1 = Konfigurationsfehler oder Versionskonflikt: dann stimmt etwas
|
||||
# Grundsaetzliches, und die weiteren Plattformen wuerden genauso
|
||||
# scheitern.
|
||||
if ($code -eq 1) { throw "pack-and-deploy meldet einen Konfigurations- oder Versionsfehler." }
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------ Ergebnis
|
||||
Write-Host '=== Ergebnis ===' -ForegroundColor White
|
||||
|
||||
foreach ($r in $results) {
|
||||
$text = switch ($r.ExitCode) {
|
||||
0 { 'vollstaendig veroeffentlicht' }
|
||||
2 { 'TEILWEISE - Upload oder Registrierung fehlgeschlagen' }
|
||||
default { "unerwarteter Rueckgabewert $($r.ExitCode)" }
|
||||
}
|
||||
$color = if ($r.ExitCode -eq 0) { 'Green' } else { 'Yellow' }
|
||||
Write-Host (" {0,-16} {1}" -f $r.Runtime, $text) -ForegroundColor $color
|
||||
}
|
||||
|
||||
$failed = @($results | Where-Object { $_.ExitCode -ne 0 })
|
||||
|
||||
if ($failed.Count -gt 0) {
|
||||
Write-Host ''
|
||||
Write-Host 'Nicht alle Plattformen sind durchgelaufen. Vor einem erneuten Versuch pruefen,' -ForegroundColor Yellow
|
||||
Write-Host 'ob die bereits hochgeladenen Dateien konsistent sind.' -ForegroundColor Yellow
|
||||
exit 2
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host "Fertig. $($config.project) $Version ist im Kanal $Channel verfuegbar." -ForegroundColor Green
|
||||
@@ -0,0 +1,280 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Veroeffentlicht dieses Projekt im Deploymentcenter.
|
||||
#
|
||||
# Vorlage zum Kopieren nach scripts/release.sh des eigenen Projekts.
|
||||
# Anzupassen ist nur scripts/release.config.json - dieses Skript selbst
|
||||
# bleibt unveraendert.
|
||||
#
|
||||
# Der Ablauf je Zielplattform:
|
||||
# dotnet publish -r <rid> -> pack-and-deploy --platform <rid>
|
||||
#
|
||||
# pack-and-deploy uebernimmt Pruefsummen, Dateimanifest, das Fortschreiben der
|
||||
# latest.json und die Anmeldung beim Deploymentcenter. Das hier nachzubauen
|
||||
# waere ein zweiter Ort fuer dieselben Fehler; das Skript orchestriert nur.
|
||||
#
|
||||
# ./scripts/release.sh --version 1.4.3 --changelog "Behebt den Login-Fehler."
|
||||
# ./scripts/release.sh --version 1.5.0 --channel beta --dry-run
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
CONFIG_FILE="${DC_RELEASE_CONFIG:-$SCRIPT_DIR/release.config.json}"
|
||||
|
||||
VERSION=""
|
||||
CHANNEL="prod"
|
||||
CHANGELOG=""
|
||||
CRITICAL=0
|
||||
DRY_RUN=0
|
||||
|
||||
usage() {
|
||||
sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'
|
||||
exit 0
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--version) VERSION="$2"; shift 2 ;;
|
||||
--channel) CHANNEL="$2"; shift 2 ;;
|
||||
--changelog) CHANGELOG="$2"; shift 2 ;;
|
||||
--critical) CRITICAL=1; shift ;;
|
||||
--dry-run|-n) DRY_RUN=1; shift ;;
|
||||
--help|-h) usage ;;
|
||||
*) echo "Unbekannte Option: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# ------------------------------------------------------------- Voraussetzungen
|
||||
command -v dotnet >/dev/null 2>&1 || {
|
||||
echo "FEHLER: dotnet wird gebraucht, ist aber nicht installiert." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ -f "$CONFIG_FILE" ] || {
|
||||
echo "FEHLER: Konfiguration fehlt: $CONFIG_FILE" >&2
|
||||
echo " Vorlage kopieren: release.config.example.json -> release.config.json" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# JSON lesen - mit jq, sonst mit Python.
|
||||
#
|
||||
# Bewusst nicht nur jq: Es ist auf den wenigsten Systemen vorinstalliert, und
|
||||
# an einer fehlenden Abhaengigkeit soll die Vorlage nicht scheitern. Python
|
||||
# liegt auf den meisten Entwickler- und CI-Systemen ohnehin bereit.
|
||||
JSON_READER=""
|
||||
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
JSON_READER="jq"
|
||||
else
|
||||
# Nicht nur pruefen, ob der Befehl existiert, sondern ob er laeuft:
|
||||
# Windows legt unter WindowsApps einen python3-Platzhalter ab, der
|
||||
# gefunden wird, beim Aufruf aber nur auf den Store verweist.
|
||||
for candidate in python3 python; do
|
||||
if command -v "$candidate" >/dev/null 2>&1 \
|
||||
&& "$candidate" -c "import json" >/dev/null 2>&1; then
|
||||
JSON_READER="$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$JSON_READER" ]; then
|
||||
echo "FEHLER: Zum Lesen von $CONFIG_FILE wird jq oder ein lauffaehiges Python gebraucht." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Liest einen Skalar. Pfad in jq-Schreibweise, z. B. .project
|
||||
cfg() {
|
||||
if [ "$JSON_READER" = "jq" ]; then
|
||||
jq -r "$1 // empty" "$CONFIG_FILE"
|
||||
else
|
||||
"$JSON_READER" -c "
|
||||
import json,sys
|
||||
d=json.load(open(sys.argv[1], encoding='utf-8'))
|
||||
for part in sys.argv[2].lstrip('.').split('.'):
|
||||
if not isinstance(d, dict): d=None; break
|
||||
d=d.get(part)
|
||||
if d is None: print('')
|
||||
elif isinstance(d, bool): print('true' if d else 'false')
|
||||
else: print(d)
|
||||
" "$CONFIG_FILE" "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
# Liest ein Feld mit Zeichenketten, eine je Zeile.
|
||||
cfg_list() {
|
||||
if [ "$JSON_READER" = "jq" ]; then
|
||||
jq -r "$1[]?" "$CONFIG_FILE"
|
||||
else
|
||||
"$JSON_READER" -c "
|
||||
import json,sys
|
||||
d=json.load(open(sys.argv[1], encoding='utf-8'))
|
||||
for part in sys.argv[2].lstrip('.').split('.'):
|
||||
d = d.get(part) if isinstance(d, dict) else None
|
||||
for item in (d or []): print(item)
|
||||
" "$CONFIG_FILE" "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
PROJECT="$(cfg .project)"
|
||||
CSPROJ_REL="$(cfg .csproj)"
|
||||
BASE_URL="$(cfg .baseUrl)"
|
||||
BASE_URL="${BASE_URL:-https://dc.mhdf.de}"
|
||||
BASE_URL="${BASE_URL%/}"
|
||||
SETUP_REL="$(cfg .setupJson)"
|
||||
SETUP_REL="${SETUP_REL:-setup.json}"
|
||||
MAIN_ASSEMBLY="$(cfg .mainAssembly)"
|
||||
|
||||
[ -n "$PROJECT" ] || { echo "FEHLER: 'project' fehlt in $CONFIG_FILE" >&2; exit 1; }
|
||||
[ -n "$CSPROJ_REL" ] || { echo "FEHLER: 'csproj' fehlt in $CONFIG_FILE" >&2; exit 1; }
|
||||
|
||||
CSPROJ="$REPO_ROOT/$CSPROJ_REL"
|
||||
[ -f "$CSPROJ" ] || { echo "FEHLER: Projektdatei nicht gefunden: $CSPROJ" >&2; exit 1; }
|
||||
|
||||
mapfile -t RUNTIMES < <(cfg_list .runtimes)
|
||||
[ "${#RUNTIMES[@]}" -gt 0 ] || { echo "FEHLER: 'runtimes' ist leer." >&2; exit 1; }
|
||||
|
||||
SELF_CONTAINED="$(cfg .selfContained)"
|
||||
SINGLE_FILE="$(cfg .publishSingleFile)"
|
||||
|
||||
# -------------------------------------------------------------------- Version
|
||||
if [ -z "$VERSION" ]; then
|
||||
# Directory.Build.props zuerst: Steht <Version> nur in einem von mehreren
|
||||
# Projekten, laufen die Angaben auseinander - und pack-and-deploy bricht
|
||||
# dann zu Recht mit einem Versionskonflikt ab.
|
||||
for candidate in "$REPO_ROOT/Directory.Build.props" "$CSPROJ"; do
|
||||
[ -f "$candidate" ] || continue
|
||||
VERSION="$(sed -n 's:.*<Version>\s*\([^<]*\)\s*</Version>.*:\1:p' "$candidate" | head -1 | tr -d '[:space:]')"
|
||||
[ -n "$VERSION" ] && break
|
||||
done
|
||||
|
||||
[ -n "$VERSION" ] || {
|
||||
echo "FEHLER: Keine <Version> gefunden. Bitte --version angeben." >&2
|
||||
exit 1
|
||||
}
|
||||
echo "Version aus dem Projekt gelesen: $VERSION"
|
||||
fi
|
||||
|
||||
CHANGELOG="${CHANGELOG:-Release v$VERSION}"
|
||||
|
||||
# ------------------------------------------------------------------- Werkzeug
|
||||
TOOL_DIR="$REPO_ROOT/.dc-tools"
|
||||
PACK="$TOOL_DIR/pack-and-deploy"
|
||||
|
||||
fetch_tool() {
|
||||
[ -x "$PACK" ] && return 0
|
||||
|
||||
case "$(uname -m)" in
|
||||
x86_64|amd64) rid="linux-x64" ;;
|
||||
aarch64|arm64) rid="linux-arm64" ;;
|
||||
*) echo "FEHLER: Nicht unterstuetzte Architektur $(uname -m)" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
echo "pack-and-deploy wird geholt ($rid) ..."
|
||||
mkdir -p "$TOOL_DIR"
|
||||
|
||||
tmp="$(mktemp)"
|
||||
curl -fsSL "$BASE_URL/installer/pack-and-deploy-$rid" -o "$tmp"
|
||||
expected="$(curl -fsSL "$BASE_URL/installer/pack-and-deploy-$rid.sha256" | tr -d ' \t\r\n')"
|
||||
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
actual="$(sha256sum "$tmp" | cut -d' ' -f1)"
|
||||
else
|
||||
actual="$(shasum -a 256 "$tmp" | cut -d' ' -f1)"
|
||||
fi
|
||||
|
||||
if [ "$actual" != "$expected" ]; then
|
||||
rm -f "$tmp"
|
||||
echo "FEHLER: Pruefsumme stimmt nicht." >&2
|
||||
echo " erwartet: $expected" >&2
|
||||
echo " erhalten: $actual" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod +x "$tmp"
|
||||
mv "$tmp" "$PACK"
|
||||
echo " Pruefsumme in Ordnung."
|
||||
}
|
||||
|
||||
fetch_tool
|
||||
|
||||
# --------------------------------------------------------------------- Ablauf
|
||||
echo
|
||||
echo "Projekt : $PROJECT"
|
||||
echo "Version : $VERSION"
|
||||
echo "Kanal : $CHANNEL"
|
||||
echo "Plattform : ${RUNTIMES[*]}"
|
||||
[ "$DRY_RUN" -eq 1 ] && echo "(Probelauf - es wird nichts hochgeladen)"
|
||||
echo
|
||||
|
||||
FAILED=0
|
||||
|
||||
for rid in "${RUNTIMES[@]}"; do
|
||||
echo "=== $rid ==="
|
||||
|
||||
PUBLISH_DIR="$REPO_ROOT/artifacts/publish/$rid"
|
||||
|
||||
if [ "$DRY_RUN" -eq 0 ]; then
|
||||
# Sauber neu bauen: Reste einer vorherigen Laufzeitkennung wuerden
|
||||
# sonst mit ins Paket wandern.
|
||||
rm -rf "$PUBLISH_DIR"
|
||||
|
||||
publish_args=(publish "$CSPROJ" -c Release -r "$rid" -o "$PUBLISH_DIR" --nologo)
|
||||
|
||||
if [ "$SELF_CONTAINED" = "true" ]; then
|
||||
publish_args+=(--self-contained true)
|
||||
else
|
||||
publish_args+=(--self-contained false)
|
||||
fi
|
||||
|
||||
[ "$SINGLE_FILE" = "true" ] && publish_args+=(-p:PublishSingleFile=true)
|
||||
|
||||
dotnet "${publish_args[@]}"
|
||||
|
||||
# setup.json mitliefern, damit der Installer weiss, was einzurichten ist.
|
||||
if [ -f "$REPO_ROOT/$SETUP_REL" ]; then
|
||||
cp "$REPO_ROOT/$SETUP_REL" "$PUBLISH_DIR/setup.json"
|
||||
echo " setup.json mitgenommen"
|
||||
fi
|
||||
|
||||
pack_args=(
|
||||
--project "$PROJECT"
|
||||
--version "$VERSION"
|
||||
--channel "$CHANNEL"
|
||||
--platform "$rid"
|
||||
--publish-dir "$PUBLISH_DIR"
|
||||
--changelog "$CHANGELOG"
|
||||
)
|
||||
|
||||
[ "$CRITICAL" -eq 1 ] && pack_args+=(--critical)
|
||||
[ -n "$MAIN_ASSEMBLY" ] && pack_args+=(--main-assembly "$MAIN_ASSEMBLY")
|
||||
|
||||
set +e
|
||||
"$PACK" "${pack_args[@]}"
|
||||
code=$?
|
||||
set -e
|
||||
|
||||
case "$code" in
|
||||
0) echo " -> vollstaendig veroeffentlicht" ;;
|
||||
1)
|
||||
# Konfigurationsfehler oder Versionskonflikt: die weiteren
|
||||
# Plattformen wuerden genauso scheitern.
|
||||
echo "FEHLER: Konfigurations- oder Versionsfehler - Abbruch." >&2
|
||||
exit 1
|
||||
;;
|
||||
2) echo " -> TEILWEISE: Upload oder Registrierung fehlgeschlagen"; FAILED=1 ;;
|
||||
*) echo " -> unerwarteter Rueckgabewert $code"; FAILED=1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo
|
||||
done
|
||||
|
||||
if [ "$FAILED" -ne 0 ]; then
|
||||
echo "Nicht alle Plattformen sind durchgelaufen. Vor einem erneuten Versuch pruefen," >&2
|
||||
echo "ob die bereits hochgeladenen Dateien konsistent sind." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "Fertig. $PROJECT $VERSION ist im Kanal $CHANNEL verfuegbar."
|
||||
Reference in New Issue
Block a user