Contributing / building from source
June 18, 2026 · View on GitHub
Developer docs for building, packaging and releasing Downloader Desktop. End users don't need any of this — see the README for install instructions.
Prerequisites
- .NET 10 SDK — https://dotnet.microsoft.com/download (verify with
dotnet --version) - Git
Get the source
git clone https://github.com/bezzad/Downloader.Desktop.git
cd Downloader.Desktop/src
All commands below run from the src/ folder (where Downloader.Desktop.sln lives).
Run & test
dotnet restore
dotnet build
dotnet run --project Downloader.Desktop/Downloader.Desktop.csproj
dotnet test
Platform notes:
- Linux: needs a desktop session (X11/Wayland). Running from an IDE debugger (e.g. Rider) can group the taskbar entry under the IDE host — run the built binary directly for the real taskbar icon.
- Windows: an unsigned build may trigger SmartScreen — choose More info → Run anyway (sign builds for distribution).
Publish a self-contained build
# one command, outputs to dist/ (self-contained single file, no end-user dependencies)
./scripts/publish.sh linux-x64 win-x64 osx-arm64 osx-x64
Or per RID:
dotnet publish Downloader.Desktop/Downloader.Desktop.csproj -c Release -r linux-x64 \
--self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/linux-x64
Common RIDs: linux-x64, win-x64, osx-x64, osx-arm64.
Releasing a new version
The version is automatic: bump VersionPrefix (major.minor) in Downloader.Desktop.csproj when you want;
build/revision come from the build time. To cut a release:
git checkout main && git pull
dotnet test
git tag v1.0.0 # match major.minor to VersionPrefix
git push origin v1.0.0 # triggers .github/workflows/release.yml
release.yml builds self-contained executables for win-x64, linux-x64, osx-x64, osx-arm64,
creates the GitHub Release for the tag, and attaches the archives. dotnet-desktop.yml runs the test
suite on every push/PR. To re-run a release, delete the tag (git tag -d v1.0.0 && git push origin :refs/tags/v1.0.0)
and the GitHub Release, then re-tag.
Package listings
- winget: templates + steps in
packaging/winget/(submit viawingetcreateto microsoft/winget-pkgs). - Homebrew: cask in
Casks/downloader.rb— publish via ahomebrew-taprepo. - Linux installer:
scripts/install.sh(curl | bash) installs the latest release + a.desktopentry and icon.
macOS .app bundle + signing
The macOS release ships a proper Downloader.app bundle (Spotlight-visible, launches detached) —
both release.yml and ./scripts/publish.sh osx-arm64 produce it by wrapping the plain net10.0
self-contained binary via scripts/make-macos-app.sh. No extra workload
is required. (The native macOS TFM path — -p:IsMacBuild=true, targeting net10.0-macos — is separate
and needs dotnet workload install macos + a recent Xcode; it is not used by the release.)
# Wrap an existing publish output into Downloader.app (done automatically by publish.sh/release.yml):
scripts/make-macos-app.sh publish/osx-arm64 publish/osx-arm64-app 1.2.3
# Distribute outside the App Store: sign the bundle with a Developer ID certificate
codesign --force --options runtime --sign "Developer ID Application: Behzad Khosravifar (XXXX)" \
"publish/osx-arm64-app/Downloader.app"
Avalonia macOS packaging guide
Architecture
See CLAUDE.md and the project skill in .claude/skills/downloader-desktop/ for the full
architecture, conventions and per-feature notes.