Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
40 changes: 24 additions & 16 deletions .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,36 +166,47 @@ jobs:
working-directory: src
shell: pwsh
run: |
dotnet build-server shutdown
# Retry once to handle flaky tests (e.g. TaskRecyclerTests uses Random)
dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64
dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 /p:UseSharedCompilation=false /m:1
if ($LASTEXITCODE -ne 0) {
Write-Host "::warning::First test run failed, retrying..."
dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64
dotnet build-server shutdown
dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 /p:UseSharedCompilation=false /m:1
if ($LASTEXITCODE -ne 0) { exit 1 }
}

- name: Publish
shell: pwsh
run: |
$Platform = '${{ matrix.platform }}'
[xml]$BuildProps = Get-Content "src/Directory.Build.props"
$PortableTargetFramework = @($BuildProps.Project.PropertyGroup | Where-Object { $_.PortableTargetFramework } | Select-Object -First 1).PortableTargetFramework
$WindowsTargetPlatformVersion = @($BuildProps.Project.PropertyGroup | Where-Object { $_.WindowsTargetPlatformVersion } | Select-Object -First 1).WindowsTargetPlatformVersion

if ([string]::IsNullOrWhiteSpace($PortableTargetFramework) -or [string]::IsNullOrWhiteSpace($WindowsTargetPlatformVersion)) {
throw "Could not resolve the target framework from src/Directory.Build.props"
$TargetFramework = (
dotnet msbuild src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj `
/nologo `
-getProperty:TargetFramework `
/p:Configuration=Release `
/p:Platform=$Platform `
/p:RuntimeIdentifier=win-$Platform |
Select-Object -Last 1
).Trim()

if ([string]::IsNullOrWhiteSpace($TargetFramework)) {
throw "Could not resolve the Avalonia target framework from MSBuild"
}

$TargetFramework = "$PortableTargetFramework-windows$WindowsTargetPlatformVersion"
dotnet publish src/UniGetUI/UniGetUI.csproj /noLogo /p:Configuration=Release /p:Platform=$Platform -p:RuntimeIdentifier=win-$Platform -v m
if ($LASTEXITCODE -ne 0) { throw "dotnet publish WinUI failed" }
dotnet publish src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj /noLogo /p:Configuration=Release /p:Platform=$Platform -p:RuntimeIdentifier=win-$Platform -v m
if ($LASTEXITCODE -ne 0) { throw "dotnet publish Avalonia failed" }

# Stage binaries
$PublishDir = "src/UniGetUI/bin/$Platform/Release/$TargetFramework/win-$Platform/publish"
$PublishDir = "src/UniGetUI.Avalonia/bin/$Platform/Release/$TargetFramework/win-$Platform/publish"
if (Test-Path "unigetui_bin") { Remove-Item "unigetui_bin" -Recurse -Force }
New-Item "unigetui_bin" -ItemType Directory | Out-Null
Get-ChildItem $PublishDir | Move-Item -Destination "unigetui_bin" -Force

if (-not (Test-Path "unigetui_bin/UniGetUI.exe")) {
throw "Windows app host was not produced at unigetui_bin/UniGetUI.exe"
}

$MaxShippedPdbSizeBytes = 1MB
$PdbsToRemove = Get-ChildItem "unigetui_bin" -Filter "*.pdb" -File -Recurse | Where-Object {
$_.Length -gt $MaxShippedPdbSizeBytes
Expand All @@ -207,9 +218,6 @@ jobs:
Write-Host ("Removed {0} oversized PDBs above {1:N2} MiB ({2:N2} MiB total)." -f $PdbsToRemove.Count, ($MaxShippedPdbSizeBytes / 1MB), ($RemovedPdbBytes / 1MB))
}

# Backward-compat alias
Copy-Item "unigetui_bin/UniGetUI.exe" "unigetui_bin/WingetUI.exe" -Force

- name: Code-sign binaries
if: ${{ fromJSON(needs.preflight.outputs.dry-run) == false }}
shell: pwsh
Expand Down Expand Up @@ -391,7 +399,7 @@ jobs:
set -euo pipefail
VERSION='${{ needs.preflight.outputs.package-version }}'
APP_BUNDLE="UniGetUI.app"
APP_EXECUTABLE="UniGetUI.Avalonia"
APP_EXECUTABLE="UniGetUI"
DRY_RUN='${{ needs.preflight.outputs.dry-run }}'

rm -rf "${APP_BUNDLE}" output
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/cli-headless-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
fail-fast: false
matrix:
include:
- name: Windows (WinUI 3)
- name: Windows (Avalonia)
os: windows-latest
solution: UniGetUI.Windows.slnx
daemon_project: UniGetUI/UniGetUI.csproj
daemon_project: UniGetUI.Avalonia/UniGetUI.Avalonia.csproj
daemon_build_args: '-p:Platform=x64'
manifest: testing/automation/cli-e2e.manifest.windows.json
- name: Linux (Avalonia)
Expand Down Expand Up @@ -83,11 +83,14 @@ jobs:
'--configuration',
'${{ env.CONFIGURATION }}',
'--verbosity',
'minimal'
'minimal',
'/p:UseSharedCompilation=false',
'/m:1'
)
if ('${{ matrix.daemon_build_args }}') {
$args += '${{ matrix.daemon_build_args }}'
}
dotnet build-server shutdown
dotnet @args

- name: Upgrade pip tooling
Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/dotnet-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,18 @@ jobs:
- name: Check whitespace formatting
run: dotnet format whitespace src --folder --verify-no-changes --verbosity minimal

- name: Check code style formatting (Windows solution)
- name: Check code style formatting (Avalonia Windows solution)
working-directory: src
run: dotnet format style UniGetUI.Windows.slnx --no-restore --verify-no-changes --verbosity minimal

- name: Build Windows solution
- name: Build Avalonia Windows solution
working-directory: src
run: dotnet build UniGetUI.Windows.slnx --no-restore --verbosity minimal /p:Platform=x64
run: |
dotnet build-server shutdown
dotnet build UniGetUI.Windows.slnx --no-restore --verbosity minimal /p:Platform=x64 /p:UseSharedCompilation=false /m:1

- name: Run Tests
working-directory: src
env:
GITHUB_TOKEN: ${{ github.token }}
run: dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64

run: dotnet test UniGetUI.Windows.slnx --no-restore --verbosity q --nologo /p:Platform=x64 /p:UseSharedCompilation=false /m:1
19 changes: 10 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@

## Project Overview

UniGetUI is a WinUI 3 desktop app (C#/.NET 10, Windows App SDK) providing a GUI for CLI package managers (WinGet, Scoop, Chocolatey, Pip, Npm, .NET Tool, PowerShell Gallery, Cargo, Vcpkg).
UniGetUI is an Avalonia desktop app (C#/.NET 10) providing a GUI for CLI package managers (WinGet, Scoop, Chocolatey, Pip, Npm, .NET Tool, PowerShell Gallery, Cargo, Vcpkg).

Solution entry points:
- `src/UniGetUI.Windows.slnx` - official Windows solution; builds the WinUI 3 launcher/classic app and the Avalonia app
- `src/UniGetUI.Avalonia.slnx` - experimental cross-platform Avalonia port
- `src/UniGetUI.Windows.slnx` - official Windows solution; builds the Avalonia app and Windows-specific package-manager integrations
- `src/UniGetUI.Avalonia.slnx` - cross-platform Avalonia solution

## Architecture

The codebase follows a **layered, modular structure** with ~40 projects:

- **`UniGetUI/`** - WinUI 3 entry point, XAML pages, controls, and app shell (`EntryPoint.cs`, `MainWindow.xaml`)
- **`UniGetUI.Avalonia/`** - Avalonia entry point, AXAML pages, controls, and app shell (`Program.cs`, `Views/MainWindow.axaml`)
- **`SharedAssets/`** - shared app icons, symbols, splash images, and utility scripts used by packaging
- **`UniGetUI.Core.*`** - Shared infrastructure: `Logger`, `Settings`, `Tools` (includes `CoreTools.Translate()`), `IconEngine`, `LanguageEngine`
- **`UniGetUI.PackageEngine.Interfaces`** - Contracts: `IPackageManager`, `IPackage`, `IManagerSource`, `IPackageDetails`
- **`UniGetUI.PackageEngine.PackageManagerClasses`** - Base implementations: `PackageManager` (abstract), `Package`, helpers (`BasePkgDetailsHelper`, `BasePkgOperationHelper`, `BaseSourceHelper`)
Expand Down Expand Up @@ -41,15 +42,15 @@ The constructor sets `Capabilities`, `Properties`, and wires the helpers. See `s

```shell
# Restore & test (from src/)
dotnet restore
dotnet test --verbosity q --nologo
dotnet restore UniGetUI.Windows.slnx
dotnet test UniGetUI.Windows.slnx --verbosity q --nologo /p:Platform=x64

# Publish release build
dotnet publish src/UniGetUI/UniGetUI.csproj /p:Configuration=Release /p:Platform=x64
dotnet publish src/UniGetUI.Avalonia/UniGetUI.Avalonia.csproj /p:Configuration=Release /p:Platform=x64 -p:RuntimeIdentifier=win-x64
```

- Target framework: `net10.0-windows10.0.26100.0` (min `10.0.19041`)
- Build generates secrets via `src/UniGetUI/Services/generate-secrets.ps1` and integrity tree via `scripts/generate-integrity-tree.ps1`
- Build generates secrets via `src/UniGetUI.Avalonia/Infrastructure/generate-secrets.ps1` and integrity tree via `scripts/generate-integrity-tree.ps1`
- Self-contained, publish-trimmed (partial), Windows App SDK self-contained
- Tests use **xUnit** (`[Fact]`, `Assert.*`)

Expand Down Expand Up @@ -95,7 +96,7 @@ Use `CoreTools.Translate("text")` for all user-facing strings. Parameterized: `C
| Purpose | Path |
|---|---|
| Windows solution | `src/UniGetUI.Windows.slnx` |
| Experimental cross-platform solution | `src/UniGetUI.Avalonia.slnx` |
| Cross-platform solution | `src/UniGetUI.Avalonia.slnx` |
| Shared build props | `src/Directory.Build.props` |
| Version info | `src/SharedAssemblyInfo.cs` |
| Manager interface | `src/UniGetUI.PackageEngine.Interfaces/IPackageManager.cs` |
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Before reading: All of the rules below are guidelines, which means that they sho
## Formatting:
- Run `pwsh ./scripts/install-git-hooks.ps1` once after cloning to enable the repository pre-commit hook.
- The pre-commit hook runs `dotnet format whitespace src --folder` on staged files under `src` when the `dotnet` CLI is available, and stops the commit if it had to rewrite files so you can review the changes and commit again.
- CI enforces whitespace formatting with `dotnet format whitespace src --folder --verify-no-changes` and code-style verification with `dotnet format style src/UniGetUI.Windows.slnx --no-restore --verify-no-changes` in `.github/workflows/dotnet-test.yml`.
- CI enforces whitespace formatting with `dotnet format whitespace src --folder --verify-no-changes` and code-style verification with `dotnet format style src/UniGetUI.Windows.slnx --no-restore --verify-no-changes` against the Avalonia-only Windows solution in `.github/workflows/dotnet-test.yml`.
- The pre-commit hook intentionally does not run `dotnet format style` because solution loading makes it take roughly the same time for one staged C# file as for the full solution.
- If you want to check the same style rules locally before pushing, run `dotnet format style src/UniGetUI.Windows.slnx --no-restore --verify-no-changes` from the repository root.
- If you want to prepare a dedicated formatting-only commit, run `dotnet format whitespace src --folder` from the repository root.
Expand Down
13 changes: 12 additions & 1 deletion UniGetUI.iss
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ SignTool=azsign
SignedUninstaller=yes
SignedUninstallerDir=InstallerExtras\
MinVersion=10.0
SetupIconFile=src\UniGetUI\Assets\Images\icon.ico
SetupIconFile=src\SharedAssets\Assets\Images\icon.ico
UninstallDisplayIcon={app}\UniGetUI.exe
Compression=lzma
SolidCompression=yes
Expand Down Expand Up @@ -266,6 +266,17 @@ Root: HKA; Subkey: "Software\Classes\UniGetUI.PackageBundle\DefaultIcon"; ValueT
Root: HKA; Subkey: "Software\Classes\UniGetUI.PackageBundle\shell\open\command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: regularinstall;


[InstallDelete]
Type: filesandordirs; Name: "{app}\Avalonia"
Type: filesandordirs; Name: "{app}\Assets"
Type: files; Name: "{app}\WingetUI.exe"
Type: files; Name: "{app}\UniGetUI.Avalonia.exe"
Type: files; Name: "{app}\*.dll"
Type: files; Name: "{app}\*.pdb"
Type: files; Name: "{app}\*.pri"
Type: files; Name: "{app}\*.xbf"
Type: files; Name: "{app}\*.json"

[Files]
; Deploy installer for autorepair jobs (unless disabled)
Source: "{srcexe}"; DestDir: "{app}"; DestName: "UniGetUI.Installer.exe"; Flags: external ignoreversion; Tasks: regularinstall; Check: not CmdLineParamExists('/NoDeployInstaller');
Expand Down
16 changes: 9 additions & 7 deletions scripts/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ $ErrorActionPreference = 'Stop'
$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..")
$SrcDir = Join-Path $RepoRoot "src"
$WindowsSolution = Join-Path $SrcDir "UniGetUI.Windows.slnx"
$PublishProject = Join-Path $SrcDir "UniGetUI" "UniGetUI.csproj"
$PublishProject = Join-Path $SrcDir "UniGetUI.Avalonia" "UniGetUI.Avalonia.csproj"
$BinDir = Join-Path $RepoRoot "unigetui_bin"
$BuildPropsPath = Join-Path $SrcDir "Directory.Build.props"
[xml] $BuildProps = Get-Content $BuildPropsPath
Expand All @@ -50,7 +50,7 @@ if ([string]::IsNullOrWhiteSpace($PortableTargetFramework) -or [string]::IsNullO
}

$TargetFramework = "$PortableTargetFramework-windows$WindowsTargetPlatformVersion"
$PublishDir = Join-Path $SrcDir "UniGetUI" "bin" $Platform $Configuration $TargetFramework "win-$Platform" "publish"
$PublishDir = Join-Path $SrcDir "UniGetUI.Avalonia" "bin" $Platform $Configuration $TargetFramework "win-$Platform" "publish"

# --- Version stamping ---
if ($Version) {
Expand All @@ -77,9 +77,9 @@ if (-not $SkipTests) {
Write-Host "`n=== Publishing $Configuration|$Platform ===" -ForegroundColor Cyan
dotnet clean $WindowsSolution -v m --nologo /p:Platform=$Platform

dotnet publish $PublishProject /noLogo /p:Configuration=$Configuration /p:Platform=$Platform --ignore-failed-sources -v m
dotnet publish $PublishProject /noLogo /p:Configuration=$Configuration /p:Platform=$Platform -p:RuntimeIdentifier=win-$Platform --ignore-failed-sources -v m
if ($LASTEXITCODE -ne 0) {
throw "dotnet publish WinUI failed with exit code $LASTEXITCODE"
throw "dotnet publish Avalonia failed with exit code $LASTEXITCODE"
}

# --- Stage binaries ---
Expand All @@ -88,6 +88,11 @@ New-Item $BinDir -ItemType Directory | Out-Null
# Move published output into unigetui_bin
Get-ChildItem $PublishDir | Move-Item -Destination $BinDir -Force

$WindowsAppHostPath = Join-Path $BinDir "UniGetUI.exe"
if (-not (Test-Path $WindowsAppHostPath)) {
throw "Windows app host was not produced at $WindowsAppHostPath"
}

# Keep smaller symbols for useful local crash source information, and prune oversized ones.
$MaxShippedPdbSizeBytes = 1MB

Expand All @@ -101,9 +106,6 @@ if ($PdbsToRemove.Count -gt 0) {
Write-Host ("Removed {0} oversized PDBs above {1:N2} MiB ({2:N2} MiB total)." -f $PdbsToRemove.Count, ($MaxShippedPdbSizeBytes / 1MB), ($RemovedPdbBytes / 1MB))
}

# WingetUI.exe alias for backward compat
Copy-Item (Join-Path $BinDir "UniGetUI.exe") (Join-Path $BinDir "WingetUI.exe") -Force

# --- Package output ---
if (Test-Path $OutputPath) { Remove-Item $OutputPath -Recurse -Force }
New-Item $OutputPath -ItemType Directory | Out-Null
Expand Down
2 changes: 1 addition & 1 deletion scripts/macos/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<key>CFBundleDisplayName</key>
<string>UniGetUI</string>
<key>CFBundleExecutable</key>
<string>UniGetUI.Avalonia</string>
<string>UniGetUI</string>
<!-- CFBundleIconName (Assets.car, compiled from AppIcon.icon) drives the macOS 26 appearance
styling; CFBundleIconFile (UniGetUI.icns) is the static fallback for macOS < 26. -->
<key>CFBundleIconName</key>
Expand Down
2 changes: 1 addition & 1 deletion scripts/package-linux.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ param(
[string] $Url = 'https://github.com/Devolutions/UniGetUI',
[string] $AppExecutableName = 'UniGetUI.Avalonia',
[string] $LauncherName = 'unigetui',
[string] $IconSourcePath = (Join-Path $PSScriptRoot '..\src\UniGetUI\Assets\Images\icon.png')
[string] $IconSourcePath = (Join-Path $PSScriptRoot '..' 'src' 'SharedAssets' 'Assets' 'Images' 'icon.png')
)

$ErrorActionPreference = 'Stop'
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

<PropertyGroup>
<EnableAvaloniaDiagnostics>false</EnableAvaloniaDiagnostics>
<EnableAvaloniaDiagnostics Condition="'$(Configuration)' == 'Debug'">true</EnableAvaloniaDiagnostics>
<EnableAvaloniaDiagnostics Condition="'$(Configuration)' == '' or '$(Configuration)' == 'Debug'">true</EnableAvaloniaDiagnostics>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)' == 'Release'">
Expand Down
Loading
Loading