|
| 1 | +# Guía de estilo y operaciones generales |
| 2 | + |
| 3 | +Guía operativa y de estilo para trabajar con este repositorio usando agentes. |
| 4 | + |
| 5 | +Precedencia de reglas |
| 6 | +- Las reglas se aplican en orden de precedencia creciente: las que aparecen más tarde prevalecen sobre las anteriores. |
| 7 | +- Las reglas de proyecto (asociadas a rutas concretas) tienen prioridad sobre reglas personales. |
| 8 | +- Entre reglas de proyecto, las de subdirectorios prevalecen sobre las del directorio padre. |
| 9 | + |
| 10 | +## Comunicación y formato |
| 11 | +- Conversaciones y asistencia: en español. |
| 12 | +- Código, mensajes de commit, comentarios de código y resúmenes de PR: en inglés. |
| 13 | +- PR: usar texto sin escapar en asunto y cuerpo. |
| 14 | + |
| 15 | +## Terminal y ejecución |
| 16 | +- No cerrar la terminal ni ejecutar comandos que finalicen la sesión. |
| 17 | +- Evitar comandos interactivos salvo que sea estrictamente necesario. |
| 18 | +- Extremar cuidado con comillas simples y dobles en los comandos. |
| 19 | + |
| 20 | +## Despliegue y CI |
| 21 | + |
| 22 | +- Se realiza mediante azure-pipelines.yml. |
| 23 | +- La build debe pasar correctamente antes de fusionar una PR. |
| 24 | + |
| 25 | +## Lineamientos de diseño y estilo (C# / Reactive) |
| 26 | + |
| 27 | +- Preferir programación funcional y reactiva cuando no complique en exceso. |
| 28 | +- Validación: preferir ReactiveUI.Validations. |
| 29 | +- Result handling: usar CSharpFunctionalExtensions cuando sea posible. |
| 30 | +- Convenciones: |
| 31 | + - No usar sufijo “Async” en métodos que devuelven Task. |
| 32 | + - No usar guiones bajos para campos privados. |
| 33 | + - Evitar eventos (salvo indicación explícita). |
| 34 | + - Favorecer inmutabilidad; mutar solo lo estrictamente necesario. |
| 35 | + - Evitar poner lógica en Observable.Subscribe; preferir encadenar operadores y proyecciones. |
| 36 | + |
| 37 | +# Errores y notificaciones |
| 38 | + |
| 39 | +- Para flujos de Result<T> usar el operador Successes. |
| 40 | +- Para fallos, HandleErrorsWith() empleando INotificationService para notificar al usuario. |
| 41 | + |
| 42 | +# Toolkit Zafiro |
| 43 | + |
| 44 | +Es mi propio toolkit. Disponible en https://github.com/SuperJMN/Zafiro. Muchos de los métodos que no conozcas pueden formar parte de este toolkit. Tenlo en consideración. |
| 45 | + |
| 46 | +# Manejo de bytes (sin Streams imperativos) |
| 47 | + |
| 48 | +- Usar Zafiro.DivineBytes para flujos de bytes evitables con Stream. |
| 49 | +- ByteSource es la abstracción observable y componible equivalente a un stream de lectura. |
| 50 | + |
| 51 | +# Refactorización guiada por responsabilidades |
| 52 | + |
| 53 | +1. Leer el código y describir primero sus responsabilidades. |
| 54 | +2. Enumerar cada responsabilidad como una frase nominal clara. |
| 55 | +3. Para cada responsabilidad, crear una clase o método con nombre específico y semántico. |
| 56 | +4. Extraer campos y dependencias según cada responsabilidad. |
| 57 | +5. Evitar variables compartidas entre responsabilidades; si aparecen, replantear los límites. |
| 58 | +6. No introducir patrones arbitrarios; mantener la interfaz pública estable. |
| 59 | +7. No eliminar logs ni validaciones existentes. |
| 60 | + |
| 61 | + |
| 62 | +# General guidelines about this repo |
| 63 | + |
| 64 | +This file guides Warp (and future contributors) on how CI/CD and packaging work in this repository. |
| 65 | + |
| 66 | +Scope: whole repository (DotnetPackaging). |
| 67 | + |
| 68 | +CI pipeline (Azure Pipelines) |
| 69 | +- Definition: azure-pipelines.yml at repo root. |
| 70 | +- Agent: windows-latest. |
| 71 | +- Versioning: computed with GitVersion.Tool; packages use MajorMinorPatch as Version; GitHub Release tag uses v{SemVer}. |
| 72 | +- Behavior on master: |
| 73 | + - Restore, build and pack all projects; push .nupkg (non-symbol) to NuGet (skip-duplicate) with $(NuGetApiKey). |
| 74 | + - Publish Windows EXE stubs (DotnetPackaging.Exe.Installer) for win-x64 and win-arm64 as single-file self-extract apps (IncludeNativeLibrariesForSelfExtract/IncludeAllContentForSelfExtract, no trimming). |
| 75 | + - Produce .sha256 for each stub and upload both .exe and .sha256 to a GitHub Release tagged v{SemVer} using gh CLI. |
| 76 | +- Other branches/PRs: build and pack only (no push, no release). |
| 77 | +- Packable projects: every project with IsPackable/PackAsTool set. The CLI tool lives in src/DotnetPackaging.Tool (PackAsTool=true). |
| 78 | + |
| 79 | +Versioning (GitVersion) |
| 80 | +- GitVersion.Tool runs in CI to produce: |
| 81 | + - Version: MajorMinorPatch (used for dotnet build/pack). |
| 82 | + - TagName: v{SemVer} (used to create/update the GitHub Release). |
| 83 | +- Practical effect: merging to master triggers package publish to NuGet and stub upload to a GitHub Release for the computed tag. |
| 84 | + |
| 85 | +Secrets |
| 86 | +- The pipeline expects a variable group named api-keys providing: |
| 87 | + - NuGetApiKey: API key used to push packages to NuGet. |
| 88 | + - GitHubApiKey: token exposed as GITHUB_TOKEN to create/update releases and upload stub assets via gh. |
| 89 | +- Do not hardcode secrets. Locally, export environment variables and pass them to the CLI tools. |
| 90 | + |
| 91 | +Local replication |
| 92 | +- Pack locally: |
| 93 | + - dotnet restore |
| 94 | + - dotnet build -c Release -p:ContinuousIntegrationBuild=true -p:Version=1.2.3 --no-restore |
| 95 | + - dotnet pack -c Release --no-build -p:IncludeSymbols=false -p:SymbolPackageFormat=snupkg -p:Version=1.2.3 -o ./artifacts/nuget |
| 96 | +- Push to NuGet: |
| 97 | + - For each .nupkg (non-symbol): dotnet nuget push ./artifacts/nuget/<pkg>.nupkg --api-key "$env:NUGET_API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate |
| 98 | +- Build Windows stubs (on Windows): |
| 99 | + - dotnet publish src/DotnetPackaging.Exe.Installer/DotnetPackaging.Exe.Installer.csproj -c Release -r win-x64 -p:PublishSingleFile=true -p:SelfContained=true -p:IncludeNativeLibrariesForSelfExtract=true -p:IncludeAllContentForSelfExtract=true -p:PublishTrimmed=false -o ./artifacts/stubs/win-x64 |
| 100 | + - Repeat for win-arm64 by changing -r. |
| 101 | +- Release (optional): |
| 102 | + - gh release create v1.2.3 --title "DotnetPackaging 1.2.3" --notes "Local release" |
| 103 | + - gh release upload v1.2.3 ./artifacts/stubs/win-*/DotnetPackaging.Exe.Installer*.exe ./artifacts/stubs/win-*/DotnetPackaging.Exe.Installer*.exe.sha256 -R <owner>/<repo> |
| 104 | + |
| 105 | +Notes |
| 106 | +- Because the CLI is a dotnet tool (PackAsTool=true) and is included in the solution, CI will pack and publish it to NuGet alongside the libraries when running on master. |
| 107 | +- The pipeline performs a shallow fetch depth override (full history) to ensure GitVersion/describe work correctly. |
| 108 | + |
| 109 | +Packaging formats: status and details |
| 110 | +- AppImage (Linux) |
| 111 | + - Status: supported and used. Library: src/DotnetPackaging.AppImage (net8.0). |
| 112 | + - How it works: builds an AppDir from a published app directory, generates AppRun, .desktop and AppStream files, discovers icons, then creates a SquashFS and concatenates the official AppImage runtime. |
| 113 | + - Runtime retrieval: downloads AppImageKit runtime per architecture (x86_64/armhf/aarch64) via RuntimeFactory. No external tools required (no linuxdeploy, no appimagetool). |
| 114 | + - Icon strategy: automatic discovery under the provided directory; if none, falls back to common names (icon.svg, icon-256.png, icon.png). Optionally writes .DirIcon. |
| 115 | + - Debugging: set DOTNETPACKAGING_DEBUG=1 to dump intermediate Runtime*.runtime and Image*-Container.sqfs in the temp folder. |
| 116 | +- Debian .deb (Linux) |
| 117 | + - Status: supported and used. Library: src/DotnetPackaging.Deb. |
| 118 | + - How it works: lays out files under /opt/<package>, generates .desktop under /usr/local/share/applications and a wrapper under /usr/local/bin/<package>. |
| 119 | + - Packaging: fully managed (no external dpkg-deb required). Icons are optionally embedded under hicolor/<size>/apps/<package>.png. |
| 120 | +- RPM .rpm (Linux) |
| 121 | + - Status: supported and used. Library: src/DotnetPackaging.Rpm; exposed via CLI. |
| 122 | + - How it works: stages files under /opt/<package>, writes a .desktop in /usr/share/applications and a wrapper in /usr/bin/<package>. |
| 123 | + - Packaging: uses system rpmbuild to assemble the package. Requires rpm-build to be installed locally. |
| 124 | + - Portability: auto-generated dependency/provides under /opt/<package> are excluded (using %global __requires_exclude_from/__provides_exclude_from), preventing hard Requires like liblttng-ust.so.0 and making self-contained .NET apps install across RPM-based distros. |
| 125 | + - Ownership: the package only owns directories under /opt/<package>; system directories (/usr, /usr/bin, etc.) are not owned to avoid conflicts with filesystem packages. |
| 126 | +- MSIX (Windows) |
| 127 | + - Status: experimental/preview. Library: src/DotnetPackaging.Msix with tests in src/DotnetPackaging.Msix.Tests. |
| 128 | + - CLI: exposed via msix pack (from directory) and msix from-project (publishes then packs). Assumes a valid AppxManifest.xml and assets are present; metadata generation can be added. |
| 129 | + - Validation: tests unpack resulting MSIX using makeappx tooling in CI-like conditions. |
| 130 | +- Flatpak (Linux) |
| 131 | + - Status: supported (bundle via system `flatpak`) with internal OSTree bundler fallback. |
| 132 | + - Libraries: src/DotnetPackaging.Flatpak (Factory, Packer, OSTree scaffolding). |
| 133 | + - How it works: builds a Flatpak layout (metadata at root, files/ subtree) from a publish directory; icons auto-detected and installed under files/share/icons/.../apps/<appId>.(svg/png). Desktop Icon is forced to <appId>. |
| 134 | + - Bundling: prefers system `flatpak build-export/build-bundle`; if not available or fails, uses internal bundler to emit a single-file `.flatpak` (unsigned, for testing). |
| 135 | + - Defaults: freedesktop runtime 24.08 (runtime/sdk), branch=stable, common permissions (network/ipc, wayland/x11/pulseaudio, dri, filesystem=home). Command defaults to AppId. |
| 136 | +- DMG .dmg (macOS) |
| 137 | + - Status: experimental cross-platform builder. Library: src/DotnetPackaging.Dmg. |
| 138 | + - How it works: emits an ISO9660/Joliet image (UDTO) with optional .app scaffolding if none exists. Special adornments like .VolumeIcon.icns and .background are hoisted to the image root when present. |
| 139 | + - Notes: intended for simple drag-and-drop installs. Not a full UDIF/UDZO implementation; signing and advanced Finder layouts are out of scope for now. |
| 140 | +- Windows EXE (.exe) — preview |
| 141 | + - Status: preview. Dotnet-only SFX builder. Library: src/DotnetPackaging.Exe. Stub Avalonia: src/DotnetPackaging.Exe.Installer (esqueleto WIP). |
| 142 | + - How it works: produces a self-extracting installer by concatenating [stub.exe][payload.zip][Int64 length]["DPACKEXE1"]. The payload contains metadata.json and Content/ (publish output). The stub leerá metadata y realizará la instalación. |
| 143 | + - CLI: exe (desde carpeta publish) y exe from-project (publica y empaqueta). Si omites --stub, el packer descargará automáticamente el stub que corresponda desde GitHub Releases; puedes pasar --stub para forzar uno concreto. |
| 144 | + - Cross-platform build: el empaquetado (concatenación) funciona desde cualquier SO. El stub se publica por RID (win-x64/win-arm64). |
| 145 | + - Defaults: self-contained=true al generar desde proyecto; en hosts no Windows, especifica --rid (win-x64/win-arm64) para elegir el stub/target correcto. |
| 146 | + |
| 147 | +CLI tool (dotnet tool) |
| 148 | +- Project: src/DotnetPackaging.Tool (PackAsTool=true, ToolCommandName=dotnetpackaging). |
| 149 | +- Commands available: |
| 150 | + - appimage: create an AppImage from a directory (typically dotnet publish output). Autodetects executable + architecture; generates metadata and icons. |
| 151 | + - appimage from-project: publish a .NET project and build an AppImage. |
| 152 | + - deb: create a .deb from a directory (dotnet publish output). Detects executable; generates metadata, .desktop and wrapper. |
| 153 | + - deb from-project: publish a .NET project and build a .deb. |
| 154 | + - rpm: create an .rpm from a directory (dotnet publish output). Uses rpmbuild; excludes auto-deps under /opt/<package> and avoids owning system dirs. |
| 155 | + - rpm from-project: publish a .NET project and build an .rpm. |
| 156 | + - flatpak: layout, bundle (system or internal), repo, and pack (minimal UX). |
| 157 | + - flatpak from-project: publish a .NET project and build a .flatpak bundle. |
| 158 | + - msix (experimental): msix pack (from directory) and msix from-project. |
| 159 | + - dmg (experimental): dmg (from directory) and dmg from-project (publishes then builds a .dmg). |
| 160 | + - exe (preview): Windows self-extracting installer (.exe) from directory; and exe from-project (publica y empaqueta). Si omites --stub, se descargará el stub apropiado automáticamente. |
| 161 | +- Common options (all commands share a metadata set): |
| 162 | + - --directory <dir> (required): input directory to package from. |
| 163 | + - --output <file> (required): output file (.AppImage, .deb, .rpm, .msix, .flatpak, .dmg). |
| 164 | + - --application-name, --wm-class, --main-category, --additional-categories, --keywords, --comment, --version, |
| 165 | + --homepage, --license, --screenshot-urls, --summary, --appId, --executable-name, --is-terminal, --icon <path>. |
| 166 | +- Examples (from a published folder): |
| 167 | + - AppImage (dir): dotnetpackaging appimage --directory /path/to/publish --output /path/out/MyApp.AppImage --application-name "MyApp" |
| 168 | + - AppImage (project): dotnetpackaging appimage from-project --project /path/to/MyApp.csproj --output /path/out/MyApp.AppImage --application-name "MyApp" |
| 169 | + - Deb (dir): dotnetpackaging deb --directory /path/to/publish --output /path/out/myapp_1.0.0_amd64.deb --application-name "MyApp" |
| 170 | + - Deb (project): dotnetpackaging deb from-project --project /path/to/MyApp.csproj --output /path/out/myapp_1.0.0_amd64.deb --application-name "MyApp" |
| 171 | + - RPM (dir): dotnetpackaging rpm --directory /path/to/publish --output /path/out/myapp-1.0.0-1.x86_64.rpm --application-name "MyApp" |
| 172 | + - RPM (project): dotnetpackaging rpm from-project --project /path/to/MyApp.csproj --output /path/out/myapp-1.0.0-1.x86_64.rpm --application-name "MyApp" |
| 173 | + - Flatpak (minimal): dotnetpackaging flatpak pack --directory /path/to/publish --output-dir /path/out |
| 174 | + - Flatpak (bundle): dotnetpackaging flatpak bundle --directory /path/to/publish --output /path/out/MyApp.flatpak --system |
| 175 | + - Flatpak (project): dotnetpackaging flatpak from-project --project /path/to/MyApp.csproj --output /path/out/MyApp.flatpak --system |
| 176 | + - MSIX (dir, experimental): dotnetpackaging msix pack --directory /path/to/publish --output /path/out/MyApp.msix |
| 177 | + - MSIX (project, experimental): dotnetpackaging msix from-project --project /path/to/MyApp.csproj --output /path/out/MyApp.msix |
| 178 | + - DMG (dir, experimental): dotnetpackaging dmg --directory /path/to/publish --output /path/out/MyApp.dmg --application-name "MyApp" |
| 179 | + - DMG (project, experimental): dotnetpackaging dmg from-project --project /path/to/MyApp.csproj --output /path/out/MyApp.dmg --application-name "MyApp" |
| 180 | + - EXE (preview, dir): dotnetpackaging exe --directory /path/to/win-x64/publish --output /path/out/Setup.exe --rid win-x64 --application-name "MyApp" --appId com.example.myapp --version 1.0.0 --vendor "Vendor" |
| 181 | + - EXE (preview, project): dotnetpackaging exe from-project --project /path/to/MyApp.csproj --rid win-x64 --output /path/out/Setup.exe --application-name "MyApp" --appId com.example.myapp --version 1.0.0 --vendor "Vendor" |
| 182 | + |
| 183 | +Tests |
| 184 | +- AppImage tests (test/DotnetPackaging.AppImage.Tests): |
| 185 | + - CreateAppImage validates building from containers and saving bytes. |
| 186 | + - SquashFS tests ensure filesystem construction integrity. |
| 187 | +- Deb tests (test/DotnetPackaging.Deb.Tests): |
| 188 | + - Integration tests covering metadata and tar entries layout. |
| 189 | +- MSIX tests (src/DotnetPackaging.Msix.Tests): |
| 190 | + - Validate building MSIX and unpacking with makeappx to assert structure. |
| 191 | +- EXE tests (test/DotnetPackaging.Exe.Tests): |
| 192 | + - Validate metadata zip creation and concatenation format; basic install path resolution. |
| 193 | +- Gaps / TODOs: |
| 194 | + - Add CLI end-to-end tests (invocation of dotnetpackaging appimage/deb/rpm/exe on temp publishes and validating outputs). |
| 195 | + - Integrate dotnet test into azure-pipelines.yml. |
| 196 | + - Improve EXE installer UI and add Windows E2E tests. |
| 197 | + |
| 198 | +Developer workflow tips |
| 199 | +- Publish input |
| 200 | + - AppImage/Deb/RPM/Flatpak/MSIX consume a folder produced by dotnet publish. from-project subcommands invoke a minimal publisher and reuse the same pipelines. |
| 201 | + - For AppImage, ensure an ELF executable is present (self-contained single-file publish is acceptable). If not specified, the first eligible ELF is chosen. |
| 202 | +- RID/self-contained |
| 203 | + - from-project defaults: |
| 204 | + - rpm/deb/appimage: self-contained=true by default. RID is optional; if you need to cross-publish (target a different OS/arch than the host), pass --rid (e.g., linux-x64/linux-arm64). |
| 205 | + - msix: self-contained=false by default. RID is optional; pass --rid when cross-publishing (e.g., win-x64/win-arm64). |
| 206 | + - dmg: requires --rid (osx-x64 or osx-arm64). Host RID inference is intentionally not used to avoid producing non-mac binaries when running on Linux/Windows. |
| 207 | + - flatpak: framework-dependent by default; uses its own runtime. You can still publish self-contained by passing --self-contained and --rid if needed. |
| 208 | +- RPM prerequisites |
| 209 | + - Install rpmbuild tooling: dnf install -y rpm-build (or the equivalent on your distro). |
| 210 | + - The RPM builder excludes auto-deps/provides under /opt/<package> to keep self-contained .NET apps portable and avoid liblttng-ust.so.N issues across distros. |
| 211 | + - The package does not own system directories; only /opt/<package> and files explicitly installed (wrapper under /usr/bin and .desktop in /usr/share/applications). |
| 212 | +- Icon handling |
| 213 | + - The CLI and libraries attempt to discover icons automatically. You can override via --icon or supply common names in the root (icon.svg, icon-256.png, icon.png). |
| 214 | +- Debug |
| 215 | + - Set DOTNETPACKAGING_DEBUG=1 to dump AppImage intermediate artifacts (runtime + squashfs). |
| 216 | + |
| 217 | +Repository map (relevant) |
| 218 | +- src/DotnetPackaging.AppImage: AppImage core (AppImageFactory, RuntimeFactory, SquashFS). |
| 219 | +- src/DotnetPackaging.Deb: Debian packaging (Tar entries, DebFile). |
| 220 | +- src/DotnetPackaging.Rpm: RPM packaging (layout builder and rpmbuild spec generation). |
| 221 | +- src/DotnetPackaging.Msix: MSIX packaging (builder and helpers). |
| 222 | +- src/DotnetPackaging.Exe: Windows SFX packer (concatenation and metadata). |
| 223 | +- src/DotnetPackaging.Exe.Installer: Avalonia stub installer. |
| 224 | +- src/DotnetPackaging.Tool: CLI (dotnet tool) with commands appimage, deb, rpm, flatpak, msix, exe. |
| 225 | +- test/*: AppImage and Deb tests; src/DotnetPackaging.Msix.Tests for MSIX; test/DotnetPackaging.Exe.Tests for EXE packaging. |
| 226 | + |
| 227 | +Backlog / Future work |
| 228 | +- Add CLI E2E tests (including rpm/exe) and hook dotnet test in CI. |
| 229 | +- Optional: enrich icon detection strategies and metadata mapping (e.g., auto-appId from name + reverse DNS). |
| 230 | + |
| 231 | +Windows EXE (.exe) – progress log (snapshot) |
| 232 | +- Done: |
| 233 | + - Librería DotnetPackaging.Exe con SimpleExePacker (concatena stub + zip + footer). |
| 234 | + - Comandos CLI: exe (desde carpeta) y exe from-project (publica y empaqueta). --stub es opcional; si se omite, el packer descarga el stub que corresponda desde GitHub Releases. |
| 235 | + - Stub Avalonia creado (esqueleto) en src/DotnetPackaging.Exe.Installer con lector de payload. |
| 236 | + - Instalador: opción de crear acceso directo en Escritorio en el paso Finish; acceso directo en Start Menu se mantiene. |
| 237 | + - CI: publica stubs win-x64 y win-arm64 como single-file self-extract con hashes y los sube a un GitHub Release (tag v{SemVer}). |
| 238 | + - Packer: logging antes de descargar el stub para informar del tiempo de espera. |
| 239 | +- Next: |
| 240 | + - UI: Integrar SlimWizard de Zafiro en el stub (ahora hay UI mínima). Navegación con WizardNavigator y páginas. |
| 241 | + - Lógica: Elevación UAC y carpeta por defecto en Program Files según arquitectura. |
| 242 | + - Packer: caché local de stubs y reintentos/validación de hashes. |
| 243 | + - Detección avanzada de ejecutable e icono (paridad con .deb/.appimage). |
| 244 | + - Modo silencioso. |
| 245 | + - Pruebas E2E en Windows. |
0 commit comments