Repository navigation
nUpdate 5.0: rewrite, new formats, portable projects and a cross-platform installer - #118
Merged
Merged
Conversation
- Remove what an SDK-style build no longer needs: MigrationBackup, .nuget, packages, the git submodule and the GhostDoc and ReSharper settings. - global.json pins the .NET 10 SDK and runs tests on Microsoft.Testing.Platform. - Directory.Build.props and .targets hold the shared settings: latest C#, nullable, warnings as errors, analyzers, documentation and symbols, package metadata and the package icon in assets/. Directory.Packages.props holds the central package versions, .editorconfig the code style and .config/dotnet-tools.json ReportGenerator. - .gitignore no longer hides source folders named Packages. - nUpdate.sln starts empty; the following commits add their projects.
nUpdate (netstandard2.0) is rewritten around an asynchronous UpdateManager with injectable services (UpdateManagerServices: HttpClient, file system, logger, system information, process launcher, terminator). - API: CheckForUpdatesAsync, AvailableUpdates, DownloadAsync with progress, VerifyAsync, StartInstaller and DeleteDownloads; HttpTimeout, proxy, credentials and cancellation; failures surface as errors, never as a cancellation. - Formats: the nupdate.json feed (format marker, camelCase, string enums, one file per platform with size, SHA-512, an RSA-PSS/SHA-512 signature and the areas its operations touch), a package manifest that VerifyAsync checks against the feed entry, installer-options.json format 2 and PEM keys. - Versions: UpdateVersion has one canonical form (major.minor.patch, a fourth number when it is not 0, a SemVer pre-release label and build metadata). MinimumStability (Release, ReleaseCandidate, Beta, Any) and AcceptedPreReleaseLabels choose pre-releases; necessary updates, unsupported versions and rollout conditions choose the packages. - Platforms: a client takes the file of its runtime identifier, else of its operating system, else any. The installer comes from nUpdate.Installer/<rid>/ or InstallerPath, with ShowInstallerWindow, InstallerIcon and InstallerAccentColor. On Linux and macOS the client checks write access, sets the execute bit, finds .app bundles and never elevates. - Typed operations for files, registry, services and processes; the C# script operation is gone. AfterInstall and InstallerArgument say what happens to the application after the update. - UpdateFlow and IUpdateFlowPresenter drive the update dialogs; UpdateSummary and the formatters are shared by the built-in UIs. Texts come from UpdateTexts in six languages, Culture and TextFiles. - The installer contracts (InstallerOptions, IProgressReporter) live in nUpdate.Installer; statistics are best-effort JSON reports.
- nUpdate.UpdateInstaller (netstandard2.0) is the installer base library. InstallerHost.Run reads the options, shows a window or none (when asked, or without a display), waits for the application, runs the operations of every package and replaces its files: each one is staged next to its target and swapped in, and a locked file asks Retry, Skip or Abort. It restores Unix modes, refuses registry and service operations off Windows, swaps macOS .app bundles atomically, restarts the application with its arguments and writes install.log. Without a window it reports to the console and the Windows event log; WindowProgressReporter carries the threading protocol for windows of your own. - nUpdate.UpdateInstaller.UI.Avalonia is the built-in installer window: progress, the locked-file question inline, errors with the log path, icon and accent colour from the options, light and dark like the system. It is published self-contained, single-file and trimmed for seven runtime identifiers; the package's build targets copy the ones the app needs to nUpdate.Installer/<rid>/. - samples/CustomInstaller shows an installer of your own with a WPF window. - The .NET Framework installer, nUpdate.UpdateInstaller.UIBase and the WPF plugin installer are removed.
- nUpdate.UI.WindowsForms and nUpdate.UI.WPF target net462 and net8.0-windows. Their dialogs present UpdateFlow (search, new update with changelog and touched areas, download, errors); WPF uses constructor injection and small view models instead of a service locator. - nUpdate.UI.Avalonia (net8.0) is new: the same dialogs in the look of the installer window, modal to an owner window or on their own, with InstallerAccentColor.
begerdom
force-pushed
the
db/formats-v2-and-portable-projects
branch
2 times, most recently
from
October 8, 2026 15:20
722836d to
1e73b95
Compare
This was referenced Oct 8, 2026
Bump Newtonsoft.Json from 13.0.1 to 13.0.2 in /MigrationBackup/6aaa9608/nUpdate.UI.WindowsForms
#113
Closed
begerdom
force-pushed
the
db/formats-v2-and-portable-projects
branch
6 times, most recently
from
October 9, 2026 12:07
90598da to
3a8acc4
Compare
- nUpdate.Administration.TransferInterface: an asynchronous ITransferProvider with protocol-aware settings and trust prompts for unknown certificates and host keys (UntrustedServerException). - nUpdate.Administration.Core: project format 6 in portable project folders with project passwords, migration of every earlier project format, a package builder that writes one zip per platform with its manifest and the Unix mode of every file, RSA-PSS signing, the feed store, a compensating publish pipeline, FTP and FTPS (FluentFTP) and SFTP (SSH.NET) through an optional proxy, the statistics API v2 (nupdate-statistics.php on PHP and MySQL), and the migration of nUpdate 3 and 4 feeds and packages, which lets both versions run side by side. - nUpdate.Administration (Avalonia 12, .NET 10): main window, new-project wizard, project window with packages, overview and client snippet, statistics and history, a package editor with platforms, files and typed operations, project settings, credentials and project passwords, and the migration assistant.
- nUpdate.Tests (xUnit v3 on Microsoft.Testing.Platform, NSubstitute, Shouldly, MockFileSystem) replaces the MSTest project. It holds unit tests for every library, headless Avalonia tests of the windows and dialogs, Windows-only adapter tests, Docker-backed integration tests (FTP/FTPS, SFTP, PHP and MySQL) with end-to-end updates, scenario tests that drive each Administration dialog against those servers (trait Category=Integration), and tests of the published installer (trait PublishedInstaller, skipped without NUPDATE_INSTALLER). - tools/CoverageGate checks line and branch coverage per assembly: 100/100 for nUpdate, nUpdate.UpdateInstaller, nUpdate.Administration.Core and nUpdate.Administration.TransferInterface; 90/90 for nUpdate.Administration, nUpdate.UpdateInstaller.UI.Avalonia and nUpdate.UI.Avalonia.
- Linux: format check, build, unit and Docker integration tests, the coverage gate on the merged report and a ReportGenerator summary. - Packages: pack on Linux (the installer for all seven runtime identifiers), build an application against the packages and update it with the published linux-x64 installer. - Windows: build, unit tests including the Windows-only adapter tests, the same consumer update with the win-x64 installer, and nUpdate Administration published for win-x64. - macOS: check the signature of the osx-arm64 installer and swap a signed test bundle that must still verify and start. - Runs on pushes to every branch and on pull requests from forks; Dependabot keeps the packages and actions current.
- README: features, requirements, installation, usage with examples, the installer, nUpdate Administration, migrating from nUpdate 3 and 4 and running both side by side, and the list of changes; screenshots in docs/images and a separate NuGet readme. - BUILDING.md: building, testing, coverage and packaging. AGENTS.md lists the pitfalls for coding agents; CLAUDE.md points to it. - docs/plans: the plans for the refactoring, the formats and portable projects, and the cross-platform installer.
- StartInstaller no longer fails when an earlier installer or a virus scanner still holds a file in the application's installer folder: the installer then runs from a folder next to it, which a later update removes again. Fixes #117. - An executable path that is empty, relative or names no folder is refused where it is set, or when the installer is about to start, with a message that says to set ApplicationExecutablePath. It no longer reaches the installer as an empty application folder. Single-file builds already take the path from the process. Fixes #101.
AfterInstall.Close leaves the application closed after an update, and the example now shows how to pass the arguments of the running instance, such as a settings file from a shortcut, on to the restarted application. Closes #96.
vsftpd and ProFTPD require by default that every data connection resumes the TLS session of the control connection. The TLS of .NET, which FluentFTP uses, cannot do that, so the login works but listing and uploading fail with a bare server reply. The FTP provider now adds what to do when an FTPS data connection looks refused (reply 425, 450 or 522, a failed TLS handshake, or a reply that mentions reuse): allow fresh sessions on the server (vsftpd: require_ssl_reuse=NO, ProFTPD: TLSOptions NoSessionReuseRequired) or publish over SFTP. A failed handshake on a data connection now arrives as a TransferException instead of an unhandled AuthenticationException. The README notes the limitation. The limitation itself stays: lifting it would take FluentFTP.GnuTLS, whose LGPL-2.1 license is not an option. Refs #86.
A package can now ask to restart the application or to leave it closed after
the update, for example when the update needs a step before the next start.
The choice is stored in the feed entry ("afterInstall": "restart" or "close",
missing when the application decides) and set in the General section of the
package editor, also when editing a published package.
UpdateManager.AfterInstall becomes DefaultAfterInstall, which a package can
override; the read-only AfterInstall is the outcome for the updates found.
When several packages are installed together, leaving the application closed
wins. The update dialogs of Avalonia, WPF and Windows Forms say when the
application stays closed. "keepRunning" in a feed is rejected: whether the
application can stay open while its files are replaced only it knows.
Closes #96.
es-ES.json is built in now, from the translation by Guzzjakes in #106, adapted to the texts of nUpdate 5: the keys follow UpdateTexts, the installer messages lose their quotes, a registry subkey is a "subclave", a value is set "a" another, and a locked file no longer asks to press OK. The texts nUpdate 4 did not have are new: the application staying closed, disk space, the installer window, its log file and write access. Other Spanish regions such as es-MX get these texts too. The English typo #106 fixed no longer exists. Co-authored-by: Guzzjakes <kaxlolz@gmail.com>
begerdom
force-pushed
the
db/formats-v2-and-portable-projects
branch
from
October 10, 2026 15:48
2cca78a to
e8b55bf
Compare
begerdom
force-pushed
the
db/formats-v2-and-portable-projects
branch
3 times, most recently
from
October 10, 2026 18:22
c7bd5f8 to
36507f8
Compare
begerdom
force-pushed
the
db/formats-v2-and-portable-projects
branch
from
October 10, 2026 19:42
7c2dd41 to
a85be98
Compare
The sample application in the screenshots is Aurora now, as on the homepage, instead of Trade Updater and BuildIt. Headless rendering draws no window decorations, so WindowScreenshots adds them: the windows of nUpdate Administration in a Windows 11 frame, the installer and the Avalonia update dialog in a GNOME frame. The headless test application loads Inter like the applications do, so the screenshots no longer depend on the fonts of the machine. tools/WinFormsScreenshots renders the real update dialog of nUpdate.UI.WindowsForms on Windows, in the same Windows 11 frame; the Windows job of CI uploads it as the artifact screenshots-windows. The README shows it from docs/images instead of the BuildIt screenshot on nupdate.net.
Code clean-up across the solution. The acronyms keep the casing .NET uses (UpdaterUI, PackagePlatform.MacOS, OperatingSystem.IsMacOS), and nUpdate.sln.DotSettings declares OS and UI as abbreviations so that ReSharper keeps them.
samples/Aurora is a small Avalonia application that checks a feed with the dialogs of nUpdate.UI.Avalonia and installs what it finds. It references the nUpdate projects of the repository, so changes to the library, the dialogs or the installer are what gets tested. publish.sh <version> publishes it self-contained as a single file, with the installer for the same runtime identifier in nUpdate.Installer/<rid>/. On macOS it builds Aurora.app, signed ad hoc; every file in Contents/MacOS is Mach-O with an embedded signature, so the bundle still verifies after an update replaced it. The feed URL and the public key are entered in the window and kept outside the program folder. The README walks through an update from 1.0.0 to 1.1.0 with a local web and FTP server.
Switching from Overview to Packages sometimes did nothing for a few clicks, until another page had been opened. The pages were a Carousel bound to the rail's selection; its page transition and the items it keeps realized could leave the previous page in front. The pages are now a plain Panel, and the code-behind shows the page of the selected entry and hides the others.
nUpdate 5 is published as a release candidate first: complete and tested, but details may still change before 5.0.0. The README says so, installs 5.0.0-rc.1 and shows it in its release badge. nUpdate Administration shows its informational version, so the window title and the About dialog read 5.0.0-rc.1 instead of the numeric assembly version 5.0.0. The consumer smoke test and CI's package listing take the version from Directory.Build.props instead of naming 5.0.0.
…kage codesign keeps the signature of a file in Contents/MacOS that is not Mach-O code, such as a .NET assembly next to the executable, in extended attributes (com.apple.cs.*). A zip cannot hold them, so after an update such a bundle no longer passed codesign --verify. nUpdate Administration reads these attributes when it builds a package on a Mac and stores them, Base64 per entry, in the manifest (CodeSignatures). The installer sets them on the installed files, for a bundle on the new copy before the swap; a file it cannot set them on is a warning, as the file itself works. When the files of a published package are edited, the files that stay keep the attributes stored for them; new and replaced files are read again. The macOS published-installer test now ships a bundle with a non-Mach-O file in Contents/MacOS and checks that the swapped bundle still verifies.
Everything public in the packages is API and has to be documented, so the types that are only public because another nUpdate assembly uses them are internal now, with InternalsVisibleTo where nUpdate's own assemblies need them: - nUpdate: the default platform implementations behind UpdateManagerServices (ProcessLauncher, FilePermissions, SystemInformation, ...), the code signature attributes, PackagePlatform, PackageLayout, InstallerTexts and the JSON converters. - nUpdate.UpdateInstaller: everything except InstallerHost, InstallerSession, WindowProgressReporter and InstallerServices. Of InstallerServices only the limits HostExitTimeout and MaxLockedFileAttempts stay public; the system services in it are seams for nUpdate's own tests. - The UI packages: the view models, views and controls behind UpdaterUI. The file formats stay public (UpdateFeed, PackageManifest, PackageRoot, the operations and RegistryValue): nUpdate Administration's services expose them in their public signatures, and they are the model of the feed and the package manifest that the API page documents. The public API shrinks from 143 types to 73.
A static site in website/: plain HTML, one stylesheet and a small script, no framework and no build step. - index.html: the homepage. The installer window cycles through Windows, Linux and macOS, the platform picker follows the real rule (runtime identifier, then operating system, then any), the code samples are the real API, and nUpdate Administration's screens are rebuilt after the real windows. It says that nUpdate 5 is a release candidate and installs 5.0.0-rc.1. - api.html: the API reference, every public type and member of the packages with its signature and examples for the types and main calls, including the file formats and the transfer plugin API. Each entry names the types and members it documents in data-api, as documentation comment IDs. - imprint.html and privacy.html: the legal notice under § 5 DDG and the privacy policy, in German with an English translation. - The fonts are served from website/fonts with their licenses instead of from Google Fonts, which would send every visitor's IP address to Google; the pages load nothing from other servers. Colours are tokens with a dark variant that follows the system setting or the theme switch, and the animations stop under "reduce motion". tools/ApiDocsCheck keeps the API page complete. It reads the public types and members of the packages from their metadata (System.Reflection.Metadata, no new dependency) and compares them with the data-api IDs on api.html: it fails on a public member without an entry and on an entry whose member no longer exists, and a changed signature is both, because the IDs carry the member's type. CI runs it after the Linux build through tools/ci/api-docs-check.sh, which also runs locally after a Release build. BUILDING.md, AGENTS.md and the website README describe the process.
CI publishes nUpdate Administration for every platform it supports and starts each build once: - Linux: tools/ci/administration-linux.sh publishes it self-contained for linux-x64 and linux-arm64 and packs nUpdate-Administration-<rid>.tar.gz; a tarball keeps the executable bit, which the zip of an Actions artifact would drop. - macOS: the bundle is built for osx-x64 as well as osx-arm64. - tools/ci/check-starts.sh starts a program and fails when it exits within 15 seconds, showing its output. CI runs it for win-x64, linux-x64 under Xvfb and both macOS bundles, the Intel one under Rosetta. The builds are uploaded as administration-win-x64, administration-linux-x64, administration-linux-arm64, administration-osx-arm64 and administration-osx-x64.
begerdom
force-pushed
the
db/formats-v2-and-portable-projects
branch
from
October 10, 2026 19:57
a85be98 to
3db276b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
nUpdate 5.0. This branch contains db/refactorings-and-test-suite (a rewrite of the library, the installer and the Administration with a full test suite) and builds the 5.0 formats and the cross-platform installer on top.
What changes
nUpdate, .NET Standard 2.0): rewritten with a task-based API; a feednupdate.jsonwith one signed package file per platform (any,win,linux-arm64, …); RSA-PSS signatures with PEM keys, SHA-512 and manifest checks; canonical semantic versions;MinimumStabilityand rollout conditions.nUpdate.UpdateInstalleris the base library (engine,InstallerHost, windowless mode,WindowProgressReporterfor windows of your own);nUpdate.UpdateInstaller.UI.Avaloniais the built-in installer, self-contained for win, linux and osx on x64 and arm64, and replaces macOS app bundles atomically.UpdateFlow.Breaking changes
nUpdate 5 does not read nUpdate 4 feeds, packages or projects. The "Migrating to 5.0" section of the README and the migration assistant cover the move; both versions can run side by side.
Verification
CI is green on 12d9a30: Linux build, tests and coverage gates, the packages with the Linux installer, Windows, and macOS including the bundle swap.
Plans:
docs/plans/. Notes for coding agents:AGENTS.md.