From 663da6840187030c87f94fd69fd26623479b57fd Mon Sep 17 00:00:00 2001 From: Kaleb Luedtke Date: Tue, 28 Jul 2026 18:41:01 -0500 Subject: [PATCH 1/8] Add information about when tests should be added Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CONTRIBUTING.md | 10 +++++++++- doc/Developing.md | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index adf8758a74..520d57d108 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -118,7 +118,15 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and you ### Testing -Testing is a key component in the development workflow. +Testing is a key part of getting a change ready for review. + +If your contribution changes behavior or implementation, please add or update automated tests along with the code. For most fixes and features, that means updating unit tests in `AppInstallerCLITests`. If your change crosses command or workflow boundaries, you should also add or update end-to-end coverage in `AppInstallerCLIE2ETests`. + +Documentation-only updates and non-functional metadata changes generally do not require new tests. + +For build and test execution details, see [Running Unit Tests](./doc/Developing.md#running-unit-tests) and [Running End-to-End Tests](./doc/Developing.md#running-end-to-end-tests) in [doc/Developing.md](./doc/Developing.md). + +PRs without appropriate coverage may be asked to add tests before review completes. ### Code Review diff --git a/doc/Developing.md b/doc/Developing.md index d35e1e6878..6f5713162b 100644 --- a/doc/Developing.md +++ b/doc/Developing.md @@ -47,6 +47,20 @@ The unit tests are located inside the `AppInstallerCLITests` project. When the s > [!TIP] > If you just want to run a particular test, you can specify the test name as an argument to the executable. For example, `AppInstallerCLITests.exe EnsureSortedErrorList`. +> [!TIP] +> For local debugging, you can increase test output detail and include timing information by running `AppInstallerCLITests.exe -d yes -v high`. + +## Running End-to-End Tests + +The end-to-end tests are located in the `AppInstallerCLIE2ETests` project and are executed with NUnit. + +For setup details (including `Test.runsettings`, local test source setup, and localhost web server usage), see [`src/AppInstallerCLIE2ETests/README.md`](../src/AppInstallerCLIE2ETests/README.md). + +A typical local workflow is: +1. Build the solution. +2. Configure `src/AppInstallerCLIE2ETests/Test.runsettings` for your environment. +3. Run `AppInstallerCLIE2ETests` from Test Explorer, or run `dotnet test src\AppInstallerCLIE2ETests\AppInstallerCLIE2ETests.csproj --settings src\AppInstallerCLIE2ETests\Test.runsettings`. + ## Localization The English resource strings are the source of truth and live in: From 3d43afacaf171d1471599a16e4c72d8c423c3e15 Mon Sep 17 00:00:00 2001 From: Kaleb Luedtke Date: Tue, 28 Jul 2026 18:50:19 -0500 Subject: [PATCH 2/8] Strengthen wording to request both test types or justification Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CONTRIBUTING.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 520d57d108..abf171fa27 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -120,7 +120,11 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and you Testing is a key part of getting a change ready for review. -If your contribution changes behavior or implementation, please add or update automated tests along with the code. For most fixes and features, that means updating unit tests in `AppInstallerCLITests`. If your change crosses command or workflow boundaries, you should also add or update end-to-end coverage in `AppInstallerCLIE2ETests`. +If your contribution changes behavior or implementation, please plan to add or update automated tests alongside the code. + +As a quick rule of thumb: unit tests in `AppInstallerCLITests` focus on the code and logic, while end-to-end tests in `AppInstallerCLIE2ETests` focus on actual `winget` command behavior and the resulting system outcomes. + +For non-trivial code changes, the bar is high. Where practical, include both unit tests and end-to-end coverage. If you believe that tests aren't needed for your change, please call that out in your PR and explain why. Documentation-only updates and non-functional metadata changes generally do not require new tests. From 745b5b11029943951f43f927aab53abcf3bb65d6 Mon Sep 17 00:00:00 2001 From: Kaleb Luedtke Date: Tue, 28 Jul 2026 19:11:37 -0500 Subject: [PATCH 3/8] Add coding standards document Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CONTRIBUTING.md | 4 + doc/Developing.md | 4 + doc/Standards.md | 281 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 doc/Standards.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index abf171fa27..7e16fdcdb5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -116,6 +116,10 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and you 1. Work on your changes. 1. Build and see if it works. +### Coding Standards + +Before writing code, review [doc/Standards.md](./doc/Standards.md) for the conventions used in this codebase — naming, formatting, error handling, casts, `std::move()` usage, and resource strings. PRs that diverge from these conventions will be asked to bring their changes into line before review completes. + ### Testing Testing is a key part of getting a change ready for review. diff --git a/doc/Developing.md b/doc/Developing.md index 6f5713162b..1584ba052d 100644 --- a/doc/Developing.md +++ b/doc/Developing.md @@ -1,5 +1,9 @@ # Developer guidance +## Coding Standards + +For naming, formatting, error handling, casts, `std::move()` usage, and resource string requirements, see [doc/Standards.md](./Standards.md). + ## Prerequisites * Windows 10 1809 (17763) or later diff --git a/doc/Standards.md b/doc/Standards.md new file mode 100644 index 0000000000..f3cc5b60b1 --- /dev/null +++ b/doc/Standards.md @@ -0,0 +1,281 @@ +# Coding Standards + +This document describes the coding conventions used in the WinGet CLI codebase. It is a companion to: + +- [`CONTRIBUTING.md`](../CONTRIBUTING.md) — workflow and process guidance +- [`doc/Developing.md`](./Developing.md) — build, test, and localization instructions + +The codebase is primarily C++/WinRT. Brief notes for .NET (C#) components appear at the end. + +--- + +## File Formatting + +All source files must conform to the rules in [`.editorconfig`](../.editorconfig): + +- **Line endings**: CRLF +- **Encoding**: UTF-8 +- **Final newline**: required +- **Trailing whitespace**: must be trimmed +- **YAML files** (`.yml`/`.yaml`): 2-space indentation +- **Markdown files** (`.md`): tab indentation + +Configure your editor to apply these settings on save, or run a check before committing. + +--- + +## File Headers + +Every C++ source and header file must begin with: + +```cpp +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +``` + +Every C# source file must begin with: + +```csharp +// ----------------------------------------------------------------------------- +// +// Copyright (c) Microsoft Corporation. Licensed under the MIT License. +// +// ----------------------------------------------------------------------------- +``` + +--- + +## Brace Style + +The codebase uses **Allman style** (also known as BSD style): the opening brace of every block goes on its **own new line**, at the same indentation level as the statement that introduced it. + +```cpp +namespace AppInstaller::CLI::Workflow +{ + void SomeWorkflowTask(Execution::Context& context) + { + if (condition) + { + DoSomething(); + } + else if (otherCondition) + { + DoSomethingElse(); + } + else + { + Fallback(); + } + + for (const auto& item : items) + { + Process(item); + } + + switch (value) + { + case SomeEnum::First: + HandleFirst(); + break; + case SomeEnum::Second: + HandleSecond(); + break; + default: + THROW_HR(E_UNEXPECTED); + } + } +} +``` + +Key points: + +- `else` and `else if` go on their own line after the closing `}` — never on the same line as `}`. +- `case` labels inside a `switch` are **not** indented relative to the `switch` keyword; they sit at the same level. +- **Trivial single-expression bodies** (simple getters, forwarding constructors, one-liner lambdas) may be written inline: + ```cpp + bool IsTerminated() const { return m_isTerminated; } + SomeClass(std::string name) : m_name(std::move(name)) {} + ``` + Use judgment: if the body is anything more than a single expression, use the full Allman form. + +--- + +## Naming Conventions + +### C++ + +| Element | Convention | Example | +|---------|-----------|---------| +| Types (classes, structs, enums, type aliases) | `PascalCase` | `ExecutionContext`, `ContextFlag` | +| Functions and methods | `PascalCase` | `GetErrorCode()`, `IsTerminated()` | +| Local variables and parameters | `camelCase` | `installerType`, `packageId` | +| Non-static member variables | `m_` prefix + `camelCase` | `m_name`, `m_flags` | +| Static member variables | `s_` prefix + `camelCase` | `s_disabledReason` | +| Namespaces | `PascalCase` | `AppInstaller::CLI::Workflow` | +| Macros | `AICLI_` or `WINGET_` prefix, `ALL_CAPS` | `AICLI_TERMINATE_CONTEXT`, `WINGET_CATCH_STORE` | +| Enum members | `PascalCase` | `ContextFlag::InstallerTrusted` | + +### C\# + +Follow standard .NET naming conventions (PascalCase for public members, camelCase for local variables and private fields). StyleCop is configured in `src/stylecop.json`. + +--- + +## Error Handling + +### C++: WIL macros (preferred) + +The codebase uses the [Windows Implementation Library (WIL)](https://github.com/microsoft/wil) for HRESULT-based error handling. Prefer WIL macros over manual `if (FAILED(hr))` checks: + +```cpp +// Throw on failure — use in code where exceptions are acceptable +THROW_IF_FAILED(SomeWin32OrComApi()); +THROW_HR(E_UNEXPECTED); +THROW_HR_IF(E_POINTER, ptr == nullptr); +THROW_HR_MSG(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), "Stage %d is not valid here", stage); + +// Return the HRESULT on failure — use in COM methods or HRESULT-returning functions +RETURN_IF_FAILED(SomeWin32OrComApi()); + +// Log without propagating — use for non-fatal side effects +LOG_IF_FAILED(CleanupTempFiles()); +``` + +Prefer the most specific macro. For example, `THROW_HR_IF` is cleaner than `if (condition) { THROW_HR(...); }`. + +### C++: Workflow context termination + +Inside workflow functions (functions that take `Execution::Context& context`), use the `AICLI_*` family of macros rather than throwing: + +```cpp +void WorkflowTask(Execution::Context& context) +{ + // Guard against an already-terminated context at the top of every task + AICLI_RETURN_IF_TERMINATED(context); + + // Terminate the context and return from the current function + if (failed) + { + AICLI_TERMINATE_CONTEXT(HRESULT_VALUE); + } + + // Terminate but return a specific value (useful in non-void helpers) + // AICLI_TERMINATE_CONTEXT_RETURN(HRESULT_VALUE, returnValue); +} +``` + +`AICLI_TERMINATE_CONTEXT` records the file and line of the failure, sets the context's termination HRESULT, and returns from the current function. Do not throw exceptions out of workflow functions — use context termination instead. + +### C++: Unexpected cases must not be swallowed + +Every `switch` statement over an enum or integer must have an explicit `default` branch. That branch must either: + +1. **Terminate with `E_UNEXPECTED`** if reaching it indicates a programming error (an enum value was added but the switch was not updated, or the caller passed an invalid value): + ```cpp + switch (installerType) + { + case InstallerTypeEnum::Exe: /* ... */ break; + case InstallerTypeEnum::Msi: /* ... */ break; + default: + THROW_HR(E_UNEXPECTED); + } + ``` + +2. **Have a clearly intentional and documented fallback** when a default behavior is genuinely correct: + ```cpp + switch (result) + { + case ConfigurationTestResult::Positive: return Resource::StringId::ConfigPositive; + case ConfigurationTestResult::Negative: return Resource::StringId::ConfigNegative; + default: return Resource::StringId::Empty(); // Unknown/not yet tested + } + ``` + +The same principle applies outside of switches: use `THROW_HR_IF(E_UNEXPECTED, condition)` to assert runtime invariants that should never be violated: + +```cpp +THROW_HR_IF(E_UNEXPECTED, entries.size() != expectedCount); +``` + +**Do not leave an empty `default:` or an empty `else` branch** that silently discards an unexpected case. Silent failures are harder to debug than explicit ones. + +--- + +## Casts + +**Never use C-style casts.** C-style casts (e.g., `(int)value`) bypass the type system silently. Use the named C++ cast operators instead: + +| Situation | Use | +|-----------|-----| +| Safe numeric or enum conversions | `static_cast(value)` | +| Reinterpreting pointer/integer bytes | `reinterpret_cast(value)` | +| Removing `const` (rare; justify in a comment) | `const_cast(value)` | +| Downcasting via virtual dispatch | `dynamic_cast(value)` | +| WinRT interface conversion | `.as()` from C++/WinRT | +| Converting `ToIntegral` for enums | Use the project helper `ToIntegral(enumValue)` where available | + +--- + +## `std::move()` + +`std::move()` casts a value to an rvalue reference so its resources can be transferred rather than copied. Use it only where ownership transfer is clearly intended. + +### When to use + +- **Passing to a constructor or function that takes by value or `&&`** when you no longer need the source: + ```cpp + context.Add(std::move(manifest)); + m_items.push_back(std::move(item)); + ``` +- **Initializing members from constructor parameters**: + ```cpp + MyClass(std::string name) : m_name(std::move(name)) {} + ``` + +### When NOT to use + +- **On `return` statements.** Named Return Value Optimization (NRVO) can eliminate the copy/move entirely, but only if you return the variable directly. `std::move()` on a return statement suppresses NRVO and can result in an extra move that would not otherwise occur: + + ```cpp + // ✗ Suppresses NRVO + std::string BuildResult() { return std::move(result); } + + // ✓ Allows NRVO + std::string BuildResult() { return result; } + ``` + +- **On trivially copyable types** (`int`, `HRESULT`, raw pointers, enums, etc.). Moving these is no cheaper than copying, and `std::move()` just adds noise. + +- **On `const` objects.** The move constructor cannot be selected for a `const` object; the call silently falls back to a copy. + +- **On an object you still need after the call.** After a move, the source is in a valid but unspecified state. Accessing it without re-assignment is undefined behavior. + +--- + +## Resource Strings + +All user-visible strings must be added to the English resource file: + +``` +src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw +``` + +**Do not edit** any file under `Localization/Resources//`; those files are owned by Microsoft's localization pipeline and will be overwritten automatically. + +Every new or modified string entry must include a `` element that gives translators enough context. This is especially important for: + +- Short or single-word values (column headers, status labels) where the word has multiple meanings +- Technical jargon that may have a different colloquial meaning in other languages +- Strings with placeholders — document what each `{0}`, `{1}`, etc. represents + +See [Localization in `doc/Developing.md`](./Developing.md#localization) for an example. + +--- + +## .NET (C#) Components + +The PowerShell modules (`src/PowerShell`) and configuration tests are written in C#. In addition to the file header and naming guidance above: + +- StyleCop Analyzers are configured in `src/stylecop.json`. Build warnings from StyleCop must not be suppressed without justification. +- Follow standard .NET exception handling — avoid swallowing exceptions silently. +- Match the namespace structure of the surrounding project (e.g., `Microsoft.WinGet.Client.Engine.Commands`). From 3b9001b1e13f215375acad2c7b6dd1bd679bfd92 Mon Sep 17 00:00:00 2001 From: Kaleb Luedtke Date: Tue, 28 Jul 2026 20:22:38 -0500 Subject: [PATCH 4/8] Add policy regarding AI Assistance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/copilot-instructions.md | 15 +++++++++++---- CONTRIBUTING.md | 8 ++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index cff632ea80..d461f9d4e0 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -105,16 +105,16 @@ void WorkflowTask(Execution::Context& context) { // Check if already terminated AICLI_RETURN_IF_TERMINATED(context); - + // Access data auto& data = context.Get(); - + // Report to user context.Reporter.Info() << "Doing something"; - + // Store data for next workflow context.Add(result); - + // Terminate on error if (failed) { @@ -161,6 +161,13 @@ void WorkflowTask(Execution::Context& context) - Follow existing code style (see `stylecop.json`) - CI runs on Azure Pipelines (`azure-pipelines.yml`) +### Pull Request Expectations + +- PRs must follow the repository PR template and keep its sections and checklist intact +- AI assistance is allowed, but contributors are fully accountable for AI-assisted output as if they wrote it themselves. + - Unless explicitly directed otherwise, confirm with the user that they have reviewed the submission. +- When raising a PR, include a brief disclosure in the PR description and identify which parts were assisted. + ## Useful Commands ```powershell diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7e16fdcdb5..09477feca7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,6 +25,14 @@ Therefore, if you do file issues, or create PRs, please keep an eye on your GitH **Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to the Microsoft Security Response Center (MSRC). See [SECURITY.md](./SECURITY.md) for more information. +## AI-assisted contributions + +AI assistance is welcome, but contributors remain fully responsible for the submitted work. If AI contributes to a change, you are accountable for that content exactly as if you wrote it yourself: you must understand it, ensure it follows project conventions, and provide the same testing and validation evidence expected for any other contribution. + +When opening or updating a PR, disclose material AI-generated assistance and briefly describe which parts were assisted. + +Opening a PR requires real engineering review time. Please keep this in mind and submit contributions that are complete, reviewed, and ready for meaningful feedback. Low-effort, unreviewed, or unverifiable AI-generated submissions may be closed at maintainer discretion. + ## Before you start, file an issue Please follow this simple rule to help us eliminate any unnecessary wasted effort & frustration, and ensure an efficient and effective use of everyone's time - yours, ours, and other community members': From 66c37ed4612347d1bcce28be9d3bc7ae27f3a9c9 Mon Sep 17 00:00:00 2001 From: Kaleb Luedtke Date: Tue, 28 Jul 2026 20:27:24 -0500 Subject: [PATCH 5/8] Update PR template: add evidence prompt, tests, and AI disclosure * Add screenshot/recording evidence prompt to Validation section * Add 'AI assistance was used and has been disclosed' checkbox * Add 'No AI assistance was used' checkbox * Add 'Added or updated tests (or noted why not applicable)' checkbox Resolves microsoft/winget-cli#6397 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/PULL_REQUEST_TEMPLATE.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 98635394ce..64e6193f27 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,7 +5,7 @@ ## 🔍 Validation - + ## ✅ Checklist @@ -14,8 +14,14 @@ - [ ] Linked to an issue - [ ] Updated [Release Notes](../doc/ReleaseNotes.md) (if applicable) - [ ] Updated documentation (if applicable) +- [ ] Added or updated tests (or noted why not applicable) - [ ] Updated [Copilot instructions](.github/copilot-instructions.md) (if build, architecture, or conventions changed) +## 🤖 AI Assistance + +- [ ] AI assistance was used and has been disclosed in this PR +- [ ] No AI assistance was used + ## 📋 Issue Type - [ ] Bug fix From 9fdbc84cbd215588527624a43ce68f1c1441a5de Mon Sep 17 00:00:00 2001 From: Kaleb Luedtke Date: Tue, 28 Jul 2026 21:04:30 -0500 Subject: [PATCH 6/8] Add Allman, Downcasting, NRVO to spell check allowlist Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/actions/spelling/expect.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index d4667a1c54..3c0898e6c2 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -13,6 +13,7 @@ admx AFAIK aicli AICLIC +Allman allusers alreadyinstalled AMap @@ -148,6 +149,7 @@ DMC dnld Dns Dobbeleer +Downcasting DONOT dsc dupenv @@ -398,6 +400,7 @@ NOUPDATE nowarn npmjs nsis +NRVO NTFS objbase objidl From 71feb9ba7ee923edb70cf163959e549249d8ef4f Mon Sep 17 00:00:00 2001 From: Kaleb Luedtke Date: Mon, 21 Sep 2026 22:50:23 -0500 Subject: [PATCH 7/8] Remove note about copyright headers --- doc/Standards.md | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/doc/Standards.md b/doc/Standards.md index f3cc5b60b1..8d86e79d0c 100644 --- a/doc/Standards.md +++ b/doc/Standards.md @@ -24,26 +24,6 @@ Configure your editor to apply these settings on save, or run a check before com --- -## File Headers - -Every C++ source and header file must begin with: - -```cpp -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -``` - -Every C# source file must begin with: - -```csharp -// ----------------------------------------------------------------------------- -// -// Copyright (c) Microsoft Corporation. Licensed under the MIT License. -// -// ----------------------------------------------------------------------------- -``` - ---- ## Brace Style From f35993387e1fcdd75959601e4f70778f1d814357 Mon Sep 17 00:00:00 2001 From: Kaleb Luedtke Date: Mon, 21 Sep 2026 22:54:02 -0500 Subject: [PATCH 8/8] Fix Typo --- .github/copilot-instructions.md | 406 ++++++++++++++++---------------- 1 file changed, 203 insertions(+), 203 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index ca2f43ff4e..f19f1a7bdc 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,203 +1,203 @@ -# WinGet CLI Development Guide - -## Project Overview - -This is the Windows Package Manager (WinGet) CLI client - a native Windows application for discovering and installing packages. The codebase consists of: - -- **C++/WinRT client** (`src/AppInstallerCLI*`) - The main CLI and core logic -- **COM API** (`src/Microsoft.Management.Deployment`) - Public Windows Runtime API for programmatic access -- **PowerShell modules** (`src/PowerShell`) - Microsoft.WinGet.Client and Microsoft.WinGet.Configuration cmdlets -- **Configuration system** - DSC-based system configuration using WinGet - -## Building, Testing, and Running - -### Initial Setup - -Use a configuration file in `.config` as in `winget configure .config/configuration.winget` (alternatives provided for other VS SKUs). - -Manual steps: - -1. Install Visual Studio 2022 with required workloads (see `.vsconfig`) -2. Install Windows SDK 10.0.26100: `winget install Microsoft.WindowsSDK.10.0.26100` -3. Enable developer mode in Windows -4. Run `vcpkg integrate install` from Developer Command Prompt - -### Building - -Open `src\AppInstallerCLI.sln` in Visual Studio and build the solution (Ctrl+Shift+B) or use msbuild.exe to build from the command line. - -The solution uses: -- MSBuild -- vcpkg for C++ dependencies -- NuGet for C++ and .NET dependencies - -### Running/Debugging - -1. Deploy solution: Build > Deploy Solution -2. Run from command line: `wingetdev` -3. For debugging: - - Right-click `AppInstallerCLIPackage` > Properties > Debug tab - - Set Debugger type to "Native Only" for both Application and Background task processes - - Select "Do not launch, but debug my code when it starts" - - Press F5 and run `wingetdev` in a separate terminal - -Entry point: `src/AppInstallerCLI/main.cpp` - -### Testing - -#### C++ Unit Tests (Catch2) -Located in `AppInstallerCLITests` project. After building: - -```powershell -# Run all tests -src\\\AppInstallerCLITests\AppInstallerCLITests.exe - -# Run specific test -src\\\AppInstallerCLITests\AppInstallerCLITests.exe TestName - -# Available options -AppInstallerCLITests.exe --help -``` - -#### .NET Tests -- `Microsoft.WinGet.UnitTests` - PowerShell module tests -- `Microsoft.Management.Configuration.UnitTests` - Configuration system tests -- `WinGetUtilInterop.UnitTests` - Interop layer tests - -#### E2E Tests -`AppInstallerCLIE2ETests` project contains end-to-end integration tests. - -## Architecture - -### Core Components - -**AppInstallerCLICore** - Core CLI logic organized around: -- **ExecutionContext**: State container that flows through workflows. Contains arguments, reporter, flags, and data (ExecutionContextData.h) -- **Workflows**: Composable functions that take ExecutionContext and perform operations (e.g., InstallFlow, UpdateFlow, SearchFlow) -- **Commands**: Parse arguments and orchestrate workflows -- **Reporter**: Handles all user output (ExecutionReporter.h) - -**AppInstallerRepositoryCore** - Package source abstraction: -- Interfaces for different source types (REST, SQLite index, Microsoft Store, composite) -- Search, match, and correlation logic -- Package version selection and dependencies - -**AppInstallerCommonCore** - Shared utilities: -- Manifest parsing (YAML/JSON) -- Settings and group policy -- Telemetry and logging -- HTTP client, downloader, archive handling - -**Microsoft.Management.Deployment** - COM API surface: -- IDL definitions in `PackageManager.idl` -- WinRT projections for external consumption -- Used by PowerShell modules and third-party integrations - -**AppInstallerCLIPackage** - Dev MSIX package definition: -- Models the release package definition as closely as possible. -- Contains localized string resources at src\AppInstallerCLIPackage\Shared\Strings\en-us\winget.resw - -### Key Patterns - -**Workflow Pattern**: Functions that operate on ExecutionContext: -```cpp -void WorkflowTask(Execution::Context& context) -{ - // Check if already terminated - AICLI_RETURN_IF_TERMINATED(context); - - // Access data - auto& data = context.Get(); - - // Report to user - context.Reporter.Info() << "Doing something"; - - // Store data for next workflow - context.Add(result); - - // Terminate on error - if (failed) - { - AICLI_TERMINATE_CONTEXT(HRESULT); - } -} -``` - -**Source Composition**: Multiple package sources can be composed: -- CompositeSource combines multiple sources with conflict resolution -- Installed source tracks locally installed packages -- Available sources provide packages to install - -**Manifest Schema**: Package manifests use versioned YAML schemas: -- Schema definitions in `schemas/JSON/manifests/` -- Parsing in `AppInstallerCommonCore/Manifest/` -- Multi-file manifests: installer, locale, version, defaultLocale - -## Naming Conventions - -- **Namespace structure**: `AppInstaller::[::]` - - `AppInstaller::CLI::Execution` - CLI execution context - - `AppInstaller::CLI::Workflow` - Workflow functions - - `AppInstaller::Repository` - Repository/source logic - - `AppInstaller::Manifest` - Manifest types - - `AppInstaller::Settings` - User/admin settings - -- **Macros**: Prefixed with `AICLI_` for CLI, `WINGET_` for general -- **Data keys**: ExecutionContextData uses enum keys to type-safely store/retrieve data - -## Windows-Specific Considerations - -- Use Windows-style paths with backslashes (`\`) -- Leverage WinRT APIs via C++/WinRT projections -- COM threading models matter - client uses multi-threaded apartment (MTA) -- Package deployment uses Windows App SDK / MSIX infrastructure -- Requires Windows 10 1809+ (build 17763) - -## Contributing - -- Review `CONTRIBUTING.md` for workflow -- File/discuss issues before starting work -- Specs required for features (stored in `doc/specs/`); see `.github/instructions/specs.instructions.md` for detailed guidance -- Follow existing code style (see `stylecop.json`) -- CI runs on Azure Pipelines (`azure-pipelines.yml`) - -## Issues and Pull Requests - -- Before filing an issue, search existing open and closed issues for duplicates. -- Use the GitHub issue forms in `.github/ISSUE_TEMPLATE/`; do not file a blank issue unless a maintainer explicitly asks for one. -- Bug reports should include the form fields for relevant area, command if applicable, brief description, steps to reproduce, expected behavior, actual behavior, and environment. -- Feature requests should include the form fields for relevant area, feature or enhancement description, and proposed technical implementation details when known. -- Keep issue bodies concise and evidence-based. Do not paste large speculative patches into issue bodies; open a pull request or link a branch when code is available. -- Before opening a pull request, review `CONTRIBUTING.md`, follow the PR template, keep the change focused, and summarize validation performed. -- AI assisstance is allowed, but contributors are fully accountable for AI-assisted output as if they wrote it themselves. - - Unless explicitly directed otherwise, confirm with the user that they have reviewed the submission. - -## Useful Commands - -```powershell -# Get WinGet client info -wingetdev --info - -# Show experimental features -wingetdev features - -# Check sources -wingetdev source list -``` - -## Localization - -### Source of truth - -The English resource file `src\AppInstallerCLIPackage\Shared\Strings\en-us\winget.resw` is the only file contributors should edit for string changes. It feeds the Microsoft localization pipeline. - -The files under `Localization\Resources\\` are **automatically synced from Microsoft's internal localization system and must not be edited**. Any manual edits will be overwritten on the next sync. - -Every string that could be misunderstood without context should have a ``. - -### Triggering retranslation - -- **Changing a string's ``** automatically queues it for retranslation on the next localization sync. -- **Changing only a ``** does NOT trigger retranslation. Comments improve future translations but do not fix existing ones. - -To fix an existing bad translation, a bug has to be filed internally with the localization team. +# WinGet CLI Development Guide + +## Project Overview + +This is the Windows Package Manager (WinGet) CLI client - a native Windows application for discovering and installing packages. The codebase consists of: + +- **C++/WinRT client** (`src/AppInstallerCLI*`) - The main CLI and core logic +- **COM API** (`src/Microsoft.Management.Deployment`) - Public Windows Runtime API for programmatic access +- **PowerShell modules** (`src/PowerShell`) - Microsoft.WinGet.Client and Microsoft.WinGet.Configuration cmdlets +- **Configuration system** - DSC-based system configuration using WinGet + +## Building, Testing, and Running + +### Initial Setup + +Use a configuration file in `.config` as in `winget configure .config/configuration.winget` (alternatives provided for other VS SKUs). + +Manual steps: + +1. Install Visual Studio 2022 with required workloads (see `.vsconfig`) +2. Install Windows SDK 10.0.26100: `winget install Microsoft.WindowsSDK.10.0.26100` +3. Enable developer mode in Windows +4. Run `vcpkg integrate install` from Developer Command Prompt + +### Building + +Open `src\AppInstallerCLI.sln` in Visual Studio and build the solution (Ctrl+Shift+B) or use msbuild.exe to build from the command line. + +The solution uses: +- MSBuild +- vcpkg for C++ dependencies +- NuGet for C++ and .NET dependencies + +### Running/Debugging + +1. Deploy solution: Build > Deploy Solution +2. Run from command line: `wingetdev` +3. For debugging: + - Right-click `AppInstallerCLIPackage` > Properties > Debug tab + - Set Debugger type to "Native Only" for both Application and Background task processes + - Select "Do not launch, but debug my code when it starts" + - Press F5 and run `wingetdev` in a separate terminal + +Entry point: `src/AppInstallerCLI/main.cpp` + +### Testing + +#### C++ Unit Tests (Catch2) +Located in `AppInstallerCLITests` project. After building: + +```powershell +# Run all tests +src\\\AppInstallerCLITests\AppInstallerCLITests.exe + +# Run specific test +src\\\AppInstallerCLITests\AppInstallerCLITests.exe TestName + +# Available options +AppInstallerCLITests.exe --help +``` + +#### .NET Tests +- `Microsoft.WinGet.UnitTests` - PowerShell module tests +- `Microsoft.Management.Configuration.UnitTests` - Configuration system tests +- `WinGetUtilInterop.UnitTests` - Interop layer tests + +#### E2E Tests +`AppInstallerCLIE2ETests` project contains end-to-end integration tests. + +## Architecture + +### Core Components + +**AppInstallerCLICore** - Core CLI logic organized around: +- **ExecutionContext**: State container that flows through workflows. Contains arguments, reporter, flags, and data (ExecutionContextData.h) +- **Workflows**: Composable functions that take ExecutionContext and perform operations (e.g., InstallFlow, UpdateFlow, SearchFlow) +- **Commands**: Parse arguments and orchestrate workflows +- **Reporter**: Handles all user output (ExecutionReporter.h) + +**AppInstallerRepositoryCore** - Package source abstraction: +- Interfaces for different source types (REST, SQLite index, Microsoft Store, composite) +- Search, match, and correlation logic +- Package version selection and dependencies + +**AppInstallerCommonCore** - Shared utilities: +- Manifest parsing (YAML/JSON) +- Settings and group policy +- Telemetry and logging +- HTTP client, downloader, archive handling + +**Microsoft.Management.Deployment** - COM API surface: +- IDL definitions in `PackageManager.idl` +- WinRT projections for external consumption +- Used by PowerShell modules and third-party integrations + +**AppInstallerCLIPackage** - Dev MSIX package definition: +- Models the release package definition as closely as possible. +- Contains localized string resources at src\AppInstallerCLIPackage\Shared\Strings\en-us\winget.resw + +### Key Patterns + +**Workflow Pattern**: Functions that operate on ExecutionContext: +```cpp +void WorkflowTask(Execution::Context& context) +{ + // Check if already terminated + AICLI_RETURN_IF_TERMINATED(context); + + // Access data + auto& data = context.Get(); + + // Report to user + context.Reporter.Info() << "Doing something"; + + // Store data for next workflow + context.Add(result); + + // Terminate on error + if (failed) + { + AICLI_TERMINATE_CONTEXT(HRESULT); + } +} +``` + +**Source Composition**: Multiple package sources can be composed: +- CompositeSource combines multiple sources with conflict resolution +- Installed source tracks locally installed packages +- Available sources provide packages to install + +**Manifest Schema**: Package manifests use versioned YAML schemas: +- Schema definitions in `schemas/JSON/manifests/` +- Parsing in `AppInstallerCommonCore/Manifest/` +- Multi-file manifests: installer, locale, version, defaultLocale + +## Naming Conventions + +- **Namespace structure**: `AppInstaller::[::]` + - `AppInstaller::CLI::Execution` - CLI execution context + - `AppInstaller::CLI::Workflow` - Workflow functions + - `AppInstaller::Repository` - Repository/source logic + - `AppInstaller::Manifest` - Manifest types + - `AppInstaller::Settings` - User/admin settings + +- **Macros**: Prefixed with `AICLI_` for CLI, `WINGET_` for general +- **Data keys**: ExecutionContextData uses enum keys to type-safely store/retrieve data + +## Windows-Specific Considerations + +- Use Windows-style paths with backslashes (`\`) +- Leverage WinRT APIs via C++/WinRT projections +- COM threading models matter - client uses multi-threaded apartment (MTA) +- Package deployment uses Windows App SDK / MSIX infrastructure +- Requires Windows 10 1809+ (build 17763) + +## Contributing + +- Review `CONTRIBUTING.md` for workflow +- File/discuss issues before starting work +- Specs required for features (stored in `doc/specs/`); see `.github/instructions/specs.instructions.md` for detailed guidance +- Follow existing code style (see `stylecop.json`) +- CI runs on Azure Pipelines (`azure-pipelines.yml`) + +## Issues and Pull Requests + +- Before filing an issue, search existing open and closed issues for duplicates. +- Use the GitHub issue forms in `.github/ISSUE_TEMPLATE/`; do not file a blank issue unless a maintainer explicitly asks for one. +- Bug reports should include the form fields for relevant area, command if applicable, brief description, steps to reproduce, expected behavior, actual behavior, and environment. +- Feature requests should include the form fields for relevant area, feature or enhancement description, and proposed technical implementation details when known. +- Keep issue bodies concise and evidence-based. Do not paste large speculative patches into issue bodies; open a pull request or link a branch when code is available. +- Before opening a pull request, review `CONTRIBUTING.md`, follow the PR template, keep the change focused, and summarize validation performed. +- AI assistance is allowed, but contributors are fully accountable for AI-assisted output as if they wrote it themselves. + - Unless explicitly directed otherwise, confirm with the user that they have reviewed the submission. + +## Useful Commands + +```powershell +# Get WinGet client info +wingetdev --info + +# Show experimental features +wingetdev features + +# Check sources +wingetdev source list +``` + +## Localization + +### Source of truth + +The English resource file `src\AppInstallerCLIPackage\Shared\Strings\en-us\winget.resw` is the only file contributors should edit for string changes. It feeds the Microsoft localization pipeline. + +The files under `Localization\Resources\\` are **automatically synced from Microsoft's internal localization system and must not be edited**. Any manual edits will be overwritten on the next sync. + +Every string that could be misunderstood without context should have a ``. + +### Triggering retranslation + +- **Changing a string's ``** automatically queues it for retranslation on the next localization sync. +- **Changing only a ``** does NOT trigger retranslation. Comments improve future translations but do not fix existing ones. + +To fix an existing bad translation, a bug has to be filed internally with the localization team.