Files
Deploymentcenter/client-dotnet/Deploymentcenter.Client/Deploymentcenter.BuildInfo.targets
T
Deploymentcenter BotandClaude Opus 5 2388b5abe1 feat(updateservice): Plattform-Dimension, signierte Releases, Update mit Rollback
Behebt eine Reihe zusammenhaengender Fehler im Update-Weg, die zusammen
verhindert haben, fuer mehr als eine Plattform auszuliefern - und die im
Fehlerfall halb aktualisierte Installationen hinterliessen.

Server
- Migration 009: Spalte platform samt neuem Unique-Key. Zuvor verdraengte das
  zuletzt veroeffentlichte Paket alle anderen Plattformen derselben Version,
  weil ON DUPLICATE KEY auf (slug, version, channel) griff. Ein Linux-System
  zog sich damit das Windows-Paket.
- Aufloesungsregel: je Version das plattformgenaue Paket, sonst das
  plattformunabhaengige. Ein Client ohne Plattformangabe sieht ausschliesslich
  'any' - lieber kein Update als das falsche.
- manifest_json wird endlich befuellt; die Spalte blieb bisher immer leer,
  wodurch die API nie der Rueckfall sein konnte, als der sie gedacht war.
- Releases werden serverseitig mit RSA-SHA256 signiert, neuer Endpunkt
  /api/updateservice/v1/pubkey. Bewusst kein HMAC: der Pruefende laeuft auf
  fremden Systemen und darf den Signierschluessel nicht besitzen.

Packager
- Bricht ab, statt die Versionshistorie zu verlieren. Schlug das Lesen der
  bestehenden latest.json fehl, ersetzte ein leeres catch die komplette
  Historie durch einen einzigen Eintrag - ohne jede Meldung.
- Echte Glob-Muster. Zuvor trafen "logs/**" und "scratch/**" aus der
  mitgelieferten Beispielkonfiguration nie zu.
- preservePatterns: Konfigurationsvorlagen werden ausgeliefert, ersetzen am
  Ziel aber keine vorhandene Datei. Eine settings.json mit Zugangsdaten
  ueberschrieb bisher beim Update die Konfiguration jedes Zielsystems.
- Warnt vor Dateien, die nach Zugangsdaten aussehen und auf keiner Liste stehen.
- Prueft --version gegen die Hauptassembly. Eine Abweichung fuehrte zu einer
  Endlosschleife: Clients aktualisieren, melden weiter die alte Version,
  halten das Release erneut fuer neu.
- --platform mit Ableitung aus dem Publish-Pfad.

Agent
- Anwenden mit Plan, Backup und vollstaendigem Rollback. Die Stelle war als
  "Atomic Replace with Backup" kommentiert und war eine Kopierschleife.
- Verwaiste Dateien werden entfernt, aber nur solche aus dem Manifest der
  Vorversion. Was nicht aus einem Release stammt, bleibt liegen.
- Das laufende Agent-Binary wird zur Seite gelegt statt ueberschrieben.
- API-Rueckfall in FetchManifestAsync; bisher nur im SDK vorhanden, weshalb
  die Anwendung "Update verfuegbar" und der Agent "kein Release" sagen konnte.
- Installierte Version aus --current-version oder manifest.json statt des
  Textes "Unbekannt", der als 0 gelesen wurde und jede Version neuer erscheinen
  liess. Reparatur funktioniert damit auch ohne manifest.json.
- Setzt das Ausfuehrungsbit fuer Linux-Pakete, die unter Windows gebaut wurden.

SDK
- ResolveAgentPath() liefert den plattformrichtigen Namen; ein fest verdrahtetes
  "update-agent.exe" wird unter Linux nie gefunden.
- LaunchUpdateAgent uebergibt jetzt --restart (wurde nie uebergeben, die
  Anwendung blieb nach dem Update zu), --wait-for-pid (kein Wettlauf mehr mit
  dem Herunterfahren) und --platform.

Enthaelt ausserdem die bislang nicht committete Arbeit an Watchdog, Lizenz-
Client und cli/tick.php samt Migration 008; die betroffenen Dateien liessen
sich nicht getrennt stagen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 19:56:35 +02:00

118 lines
6.0 KiB
XML

<Project>
<!--
Erzeugt vor jeder Uebersetzung eine BuildInfo-Klasse mit Version,
UTC-Build-Datum und Git-Commit.
Einbindung in der .csproj des Consumers:
<Import Project="..\Deploymentcenter.Client\Deploymentcenter.BuildInfo.targets" />
Die Klasse entsteht im Namensraum des einbindenden Projekts
($(RootNamespace)), nicht in dem des SDK.
Die vorherige Fassung erzeugte "public static partial class BuildInfo" im
Namensraum Deploymentcenter.Client.Models. Dort liefert das SDK aber bereits
eine gleichnamige, nicht partielle Klasse aus: im Consumer entstand ein
zweiter Typ mit demselben vollen Namen in einer zweiten Assembly (CS0433),
und der generierte statische Konstruktor setzte Eigenschaften, die in seiner
Teilklasse gar nicht deklariert waren (CS0103). Einbinden war damit
unmoeglich - obwohl der UpdateService-Leitfaden genau dazu riet. Der
generierte Code deklariert seine Werte jetzt selbst und braucht keine
Gegenstelle im SDK.
Ueberschreibbare Eigenschaften:
DeploymentcenterBuildInfoNamespace Zielnamensraum (Vorgabe: RootNamespace)
DeploymentcenterBuildInfoClass Klassenname (Vorgabe: BuildInfo)
BuildChannel prod, beta, ... (Vorgabe: prod)
GenerateDeploymentcenterBuildInfo auf false setzen, um abzuschalten
-->
<PropertyGroup>
<GenerateDeploymentcenterBuildInfo Condition="'$(GenerateDeploymentcenterBuildInfo)' == ''">true</GenerateDeploymentcenterBuildInfo>
<DeploymentcenterBuildInfoClass Condition="'$(DeploymentcenterBuildInfoClass)' == ''">BuildInfo</DeploymentcenterBuildInfoClass>
</PropertyGroup>
<Target Name="GenerateDeploymentcenterBuildInfo"
BeforeTargets="CoreCompile"
Condition="'$(GenerateDeploymentcenterBuildInfo)' == 'true'">
<PropertyGroup>
<!-- Zielnamensraum: ausdrueckliche Angabe, sonst RootNamespace, sonst Projektname. -->
<DeploymentcenterBuildInfoNamespace Condition="'$(DeploymentcenterBuildInfoNamespace)' == ''">$(RootNamespace)</DeploymentcenterBuildInfoNamespace>
<DeploymentcenterBuildInfoNamespace Condition="'$(DeploymentcenterBuildInfoNamespace)' == ''">$(MSBuildProjectName)</DeploymentcenterBuildInfoNamespace>
<BuildInfoFile>$(IntermediateOutputPath)DeploymentcenterBuildInfo.g.cs</BuildInfoFile>
<BuildDateUtc>$([System.DateTime]::UtcNow.ToString("o"))</BuildDateUtc>
<!-- Version aus <Version>, ersatzweise <AssemblyVersion>, sonst 0.0.0. -->
<BuildVersion Condition="'$(BuildVersion)' == ''">$(Version)</BuildVersion>
<BuildVersion Condition="'$(BuildVersion)' == ''">$(AssemblyVersion)</BuildVersion>
<BuildVersion Condition="'$(BuildVersion)' == ''">0.0.0</BuildVersion>
<BuildChannel Condition="'$(BuildChannel)' == ''">prod</BuildChannel>
</PropertyGroup>
<!--
ContinueOnError, damit ein Build ohne Git-Arbeitskopie oder ohne
installiertes Git nicht scheitert. IgnoreExitCode allein genuegte nicht:
fehlt die ausfuehrbare Datei, bricht Exec selbst ab.
-->
<Exec Command="git rev-parse HEAD"
ConsoleToMSBuild="true"
IgnoreExitCode="true"
ContinueOnError="true"
StandardErrorImportance="low">
<Output TaskParameter="ConsoleOutput" PropertyName="DcGitCommitLong" />
</Exec>
<Exec Command="git rev-parse --short HEAD"
ConsoleToMSBuild="true"
IgnoreExitCode="true"
ContinueOnError="true"
StandardErrorImportance="low">
<Output TaskParameter="ConsoleOutput" PropertyName="DcGitCommitShort" />
</Exec>
<PropertyGroup>
<DcGitCommitLong Condition="'$(DcGitCommitLong)' == ''">UNKNOWN_COMMIT</DcGitCommitLong>
<DcGitCommitShort Condition="'$(DcGitCommitShort)' == ''">UNKNOWN</DcGitCommitShort>
<!-- Zeilenumbrueche aus der Git-Ausgabe entfernen, sie wuerden das Literal sprengen. -->
<DcGitCommitLong>$(DcGitCommitLong.Trim())</DcGitCommitLong>
<DcGitCommitShort>$(DcGitCommitShort.Trim())</DcGitCommitShort>
</PropertyGroup>
<ItemGroup>
<BuildInfoLine Include="// &lt;auto-generated /&gt;" />
<BuildInfoLine Include="// Erzeugt von Deploymentcenter.BuildInfo.targets - nicht von Hand aendern." />
<BuildInfoLine Include="namespace $(DeploymentcenterBuildInfoNamespace)" />
<BuildInfoLine Include="{" />
<BuildInfoLine Include=" /// &lt;summary&gt;Zur Uebersetzungszeit eingebettete Build-Daten.&lt;/summary&gt;" />
<BuildInfoLine Include=" public static class $(DeploymentcenterBuildInfoClass)" />
<BuildInfoLine Include=" {" />
<BuildInfoLine Include=" public const string Version = &quot;$(BuildVersion)&quot;%3B" />
<BuildInfoLine Include=" public const string GitCommit = &quot;$(DcGitCommitLong)&quot;%3B" />
<BuildInfoLine Include=" public const string GitCommitShort = &quot;$(DcGitCommitShort)&quot;%3B" />
<BuildInfoLine Include=" public const string BuildDateUtc = &quot;$(BuildDateUtc)&quot;%3B" />
<BuildInfoLine Include=" public const string Channel = &quot;$(BuildChannel)&quot;%3B" />
<!-- Include darf nicht leer sein, daher ein Leerzeichen statt einer Leerzeile. -->
<BuildInfoLine Include=" " />
<BuildInfoLine Include=" public static string Summary" />
<BuildInfoLine Include=" {" />
<BuildInfoLine Include=" get { return &quot;v&quot; + Version + &quot; (&quot; + GitCommitShort + &quot;) built on &quot; + BuildDateUtc + &quot; [&quot; + Channel + &quot;]&quot;%3B }" />
<BuildInfoLine Include=" }" />
<BuildInfoLine Include=" }" />
<BuildInfoLine Include="}" />
</ItemGroup>
<WriteLinesToFile File="$(BuildInfoFile)"
Lines="@(BuildInfoLine)"
Overwrite="true"
WriteOnlyWhenDifferent="true" />
<ItemGroup>
<Compile Include="$(BuildInfoFile)" />
<FileWrites Include="$(BuildInfoFile)" />
</ItemGroup>
</Target>
</Project>