winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 565344c92d7b4732cce026ca076bd973897bce60
parent bec3c8b347b9fa782130ef559c85c2ae4576e4bd
Author: JohnMcPMS <johnmcp@microsoft.com>
Date:   Tue,  6 May 2025 16:35:44 -0700

Place DSCv3 resource manifests in the package (#5433)

## Change
Adds a method to write all manifests to a directory with one command.
Uses that to write all DSCv3 resource manifests and add them to the
package files.

Also changes the "module" name for the dev package to add ".Dev" and
updated export to use the shared definition of the module name. This
involved a minor refactor to remove static globals and unnecessary
string constructions.

Finally, moves to using the DSC v3 `UserSettingsFile` resource rather
than the v2 version.
Diffstat:
Msrc/AppInstallerCLI.sln | 1+
Msrc/AppInstallerCLICore/Command.h | 2++
Msrc/AppInstallerCLICore/Commands/DscCommand.cpp | 54+++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/AppInstallerCLICore/Commands/DscCommand.h | 4+++-
Msrc/AppInstallerCLICore/Commands/DscCommandBase.cpp | 22+++++++++++++++-------
Msrc/AppInstallerCLICore/Commands/DscCommandBase.h | 17+++++++++++++++++
Msrc/AppInstallerCLICore/Resources.h | 1+
Msrc/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp | 44+++++++++++++++++++++++++++++++-------------
Msrc/AppInstallerCLIE2ETests/ConfigureCommand.cs | 7+++----
Msrc/AppInstallerCLIE2ETests/ConfigureExportCommand.cs | 19++++++++++---------
Msrc/AppInstallerCLIE2ETests/ConfigureShowCommand.cs | 4++--
Msrc/AppInstallerCLIE2ETests/DSCv3PackageResourceCommand.cs | 2+-
Msrc/AppInstallerCLIE2ETests/DSCv3ResourceTestBase.cs | 7+++----
Msrc/AppInstallerCLIE2ETests/DSCv3SourceResourceCommand.cs | 2+-
Msrc/AppInstallerCLIE2ETests/DSCv3UserSettingsFileResourceCommand.cs | 2+-
Msrc/AppInstallerCLIE2ETests/TestData/Configuration/ShowDetails_DSCv3.yml | 2+-
Msrc/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj | 10++++++++++
Msrc/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw | 6+++++-
18 files changed, 160 insertions(+), 46 deletions(-)

diff --git a/src/AppInstallerCLI.sln b/src/AppInstallerCLI.sln @@ -1165,6 +1165,7 @@ Global CertificateResources\CertificateResources.vcxitems*{5890d6ed-7c3b-40f3-b436-b54f640d9e65}*SharedItemsImports = 4 COMServer\COMServer.vcxitems*{5890d6ed-7c3b-40f3-b436-b54f640d9e65}*SharedItemsImports = 4 ManifestSchema\ManifestSchema.vcxitems*{5890d6ed-7c3b-40f3-b436-b54f640d9e65}*SharedItemsImports = 4 + PureLib\PureLib.vcxitems*{5890d6ed-7c3b-40f3-b436-b54f640d9e65}*SharedItemsImports = 4 binver\binver.vcxitems*{5b6f90df-fd19-4bae-83d9-24dad128e777}*SharedItemsImports = 4 CertificateResources\CertificateResources.vcxitems*{5eb88068-5fb9-4e69-89b2-72dbc5e068f9}*SharedItemsImports = 4 binver\binver.vcxitems*{6e36ddd7-1602-474e-b1d7-d0a7e1d5ad86}*SharedItemsImports = 9 diff --git a/src/AppInstallerCLICore/Command.h b/src/AppInstallerCLICore/Command.h @@ -59,6 +59,8 @@ namespace AppInstaller::CLI Command(name, aliases, parent, visibility, Settings::ExperimentalFeature::Feature::None) {} Command(std::string_view name, std::string_view parent, Settings::ExperimentalFeature::Feature feature) : Command(name, {}, parent, Command::Visibility::Show, feature) {} + Command(std::string_view name, std::string_view parent, Settings::ExperimentalFeature::Feature feature, CommandOutputFlags outputFlags) : + Command(name, {}, parent, Command::Visibility::Show, feature, Settings::TogglePolicy::Policy::None, outputFlags) {} Command(std::string_view name, std::vector<std::string_view> aliases, std::string_view parent, Settings::ExperimentalFeature::Feature feature) : Command(name, aliases, parent, Command::Visibility::Show, feature) {} Command(std::string_view name, std::vector<std::string_view> aliases, std::string_view parent, Settings::TogglePolicy::Policy groupPolicy) : diff --git a/src/AppInstallerCLICore/Commands/DscCommand.cpp b/src/AppInstallerCLICore/Commands/DscCommand.cpp @@ -13,8 +13,22 @@ namespace AppInstaller::CLI { + namespace + { + Argument GetOutputFileArgument() + { + return { Execution::Args::Type::OutputFile, Resource::String::OutputDirectoryArgumentDescription, ArgumentType::Standard }; + } + } + + DscCommand::DscCommand(std::string_view parent) : + Command(StaticName(), parent) + { + } + std::vector<std::unique_ptr<Command>> DscCommand::GetCommands() const { + // These should all derive from DscCommandBase return InitializeFromMoveOnly<std::vector<std::unique_ptr<Command>>>({ std::make_unique<DscPackageResource>(FullName()), std::make_unique<DscSourceResource>(FullName()), @@ -26,6 +40,16 @@ namespace AppInstaller::CLI }); } + std::vector<Argument> DscCommand::GetArguments() const + { + std::vector<Argument> result; + + result.emplace_back(Execution::Args::Type::DscResourceFunctionManifest, Resource::String::DscResourceFunctionDescriptionManifest, ArgumentType::Flag); + result.emplace_back(GetOutputFileArgument()); + + return result; + } + Resource::LocString DscCommand::ShortDescription() const { return { Resource::String::DscCommandShortDescription }; @@ -43,6 +67,34 @@ namespace AppInstaller::CLI void DscCommand::ExecuteInternal(Execution::Context& context) const { - OutputHelp(context.Reporter); + if (context.Args.Contains(Execution::Args::Type::DscResourceFunctionManifest)) + { + std::filesystem::path outputDirectory{ Utility::ConvertToUTF16(context.Args.GetArg(Execution::Args::Type::OutputFile)) }; + std::filesystem::create_directories(outputDirectory); + + std::string filePrefix = Utility::ToLower(DscCommandBase::ModuleName()); + + for (const auto& command : GetCommands()) + { + DscCommandBase* commandBase = static_cast<DscCommandBase*>(command.get()); + + std::filesystem::path outputPath = outputDirectory; + outputPath /= std::string{ filePrefix }.append(".").append(commandBase->Name()).append(".dsc.resource.json"); + commandBase->WriteManifest(context, outputPath); + } + } + else + { + OutputHelp(context.Reporter); + } + } + + void DscCommand::ValidateArgumentsInternal(Execution::Args& args) const + { + if (args.Contains(Execution::Args::Type::DscResourceFunctionManifest) && + !args.Contains(Execution::Args::Type::OutputFile)) + { + throw CommandException(Resource::String::RequiredArgError(GetOutputFileArgument().Name())); + } } } diff --git a/src/AppInstallerCLICore/Commands/DscCommand.h b/src/AppInstallerCLICore/Commands/DscCommand.h @@ -8,11 +8,12 @@ namespace AppInstaller::CLI { struct DscCommand final : public Command { - DscCommand(std::string_view parent) : Command(StaticName(), parent, Settings::ExperimentalFeature::Feature::ConfigurationDSCv3) {} + DscCommand(std::string_view parent); static constexpr std::string_view StaticName() { return "dscv3"sv; }; std::vector<std::unique_ptr<Command>> GetCommands() const override; + std::vector<Argument> GetArguments() const override; Resource::LocString ShortDescription() const override; Resource::LocString LongDescription() const override; @@ -21,5 +22,6 @@ namespace AppInstaller::CLI protected: void ExecuteInternal(Execution::Context& context) const override; + void ValidateArgumentsInternal(Execution::Args& args) const override; }; } diff --git a/src/AppInstallerCLICore/Commands/DscCommandBase.cpp b/src/AppInstallerCLICore/Commands/DscCommandBase.cpp @@ -22,8 +22,6 @@ namespace AppInstaller::CLI { namespace { - constexpr std::string_view s_WingetModuleName = "Microsoft.WinGet"sv; - std::string GetFunctionManifestString(DscFunctions function) { THROW_HR_IF(E_INVALIDARG, !WI_IsSingleFlagSet(function)); @@ -167,7 +165,7 @@ namespace AppInstaller::CLI } DscCommandBase::DscCommandBase(std::string_view parent, std::string_view resourceName, DscResourceKind kind, DscFunctions functions, DscFunctionModifiers modifiers) : - Command(resourceName, parent, CommandOutputFlags::IgnoreSettingsWarnings), m_kind(kind), m_functions(functions), m_modifiers(modifiers) + Command(resourceName, parent, Settings::ExperimentalFeature::Feature::ConfigurationDSCv3, CommandOutputFlags::IgnoreSettingsWarnings), m_kind(kind), m_functions(functions), m_modifiers(modifiers) { // Limits on current implementation THROW_HR_IF(E_NOTIMPL, kind != DscResourceKind::Resource); @@ -224,14 +222,14 @@ namespace AppInstaller::CLI WINGET_DSC_FUNCTION_FOREACH(WINGET_DSC_FUNCTION_METHOD); - void DscCommandBase::ResourceFunctionManifest(Execution::Context& context) const + void DscCommandBase::WriteManifest(Execution::Context& context, const std::filesystem::path& filePath) const { Json::Value json{ Json::ValueType::objectValue }; // TODO: Move to release schema when released (there should be an aka.ms link as well, but it wasn't active yet) //json["$schema"] = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/bundled/resource/manifest.json"; json["$schema"] = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/bundled/resource/manifest.json"; - json["type"] = std::string{ s_WingetModuleName } + '/' + ResourceType(); + json["type"] = std::string{ ModuleName() } + '/' + ResourceType(); json["description"] = LongDescription().get(); json["version"] = Runtime::GetClientVersion().get(); @@ -253,9 +251,9 @@ namespace AppInstaller::CLI writerBuilder.settings_["indentation"] = " "; std::string jsonString = Json::writeString(writerBuilder, json); - if (context.Args.Contains(Execution::Args::Type::OutputFile)) + if (!filePath.empty()) { - std::ofstream stream{ Utility::ConvertToUTF16(context.Args.GetArg(Execution::Args::Type::OutputFile)), std::ios::binary }; + std::ofstream stream{ filePath, std::ios::binary }; stream.write(jsonString.c_str(), jsonString.length()); } else @@ -264,6 +262,16 @@ namespace AppInstaller::CLI } } + void DscCommandBase::ResourceFunctionManifest(Execution::Context& context) const + { + std::filesystem::path path; + if (context.Args.Contains(Execution::Args::Type::OutputFile)) + { + path = std::filesystem::path{ Utility::ConvertToUTF16(context.Args.GetArg(Execution::Args::Type::OutputFile)) }; + } + WriteManifest(context, path); + } + #undef WINGET_DSC_FUNCTION_METHOD std::optional<Json::Value> DscCommandBase::GetJsonFromInput(Execution::Context& context, bool terminateContextOnError) const diff --git a/src/AppInstallerCLICore/Commands/DscCommandBase.h b/src/AppInstallerCLICore/Commands/DscCommandBase.h @@ -5,6 +5,14 @@ #include <json/json.h> #include <optional> +#ifndef AICLI_DISABLE_TEST_HOOKS +#define WINGET_DSCV3_MODULE_NAME "Microsoft.WinGet.Dev" +#define WINGET_DSCV3_MODULE_NAME_WIDE L"Microsoft.WinGet.Dev" +#else +#define WINGET_DSCV3_MODULE_NAME "Microsoft.WinGet" +#define WINGET_DSCV3_MODULE_NAME_WIDE L"Microsoft.WinGet" +#endif + namespace AppInstaller::CLI { // The kind of resource that this command is implementing. @@ -75,6 +83,15 @@ namespace AppInstaller::CLI Utility::LocIndView HelpLink() const override; + static constexpr std::string_view ModuleName() + { + return WINGET_DSCV3_MODULE_NAME; + } + + // Writes the manifest for the command to the file path. + // If the path is empty, writes the manifest to the output stream. + void WriteManifest(Execution::Context& context, const std::filesystem::path& filePath) const; + protected: void ExecuteInternal(Execution::Context& context) const override; diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h @@ -483,6 +483,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(OpenSourceFailedNoMatchHelp); WINGET_DEFINE_RESOURCE_STRINGID(OpenSourceFailedNoSourceDefined); WINGET_DEFINE_RESOURCE_STRINGID(Options); + WINGET_DEFINE_RESOURCE_STRINGID(OutputDirectoryArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(OutputFileArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(OverrideArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(OverwritingExistingFileAtMessage); diff --git a/src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp b/src/AppInstallerCLICore/Workflows/ConfigurationFlow.cpp @@ -8,6 +8,7 @@ #include "Public/ConfigurationSetProcessorFactoryRemoting.h" #include "ConfigurationCommon.h" #include "ConfigurationWingetDscModuleUnitValidation.h" +#include "Commands/DscCommandBase.h" #include <AppInstallerDateTime.h> #include <AppInstallerDownloader.h> #include <AppInstallerErrors.h> @@ -47,8 +48,9 @@ namespace AppInstaller::CLI::Workflow constexpr std::wstring_view s_Unit_WinGetPackage = L"WinGetPackage"; constexpr std::wstring_view s_Unit_WinGetSource = L"WinGetSource"; - constexpr std::wstring_view s_UnitType_WinGetPackage_DSCv3 = L"Microsoft.WinGet/Package"; - constexpr std::wstring_view s_UnitType_WinGetSource_DSCv3 = L"Microsoft.WinGet/Source"; + constexpr std::wstring_view s_UnitType_WinGetPackage_DSCv3 = WINGET_DSCV3_MODULE_NAME_WIDE L"/Package"; + constexpr std::wstring_view s_UnitType_WinGetSource_DSCv3 = WINGET_DSCV3_MODULE_NAME_WIDE L"/Source"; + constexpr std::wstring_view s_UnitType_WinGetUserSettingsFile_DSCv3 = WINGET_DSCV3_MODULE_NAME_WIDE L"/UserSettingsFile"; constexpr std::wstring_view s_UnitType_PowerShellModuleGet = L"PowerShellGet/PSModule"; constexpr std::wstring_view s_Module_WinGetClient = L"Microsoft.WinGet.DSC"; @@ -66,19 +68,33 @@ namespace AppInstaller::CLI::Workflow struct PredefinedResource { // RequiredModule could be empty, meaning no required modules needed. - std::wstring RequiredModule; + std::wstring_view RequiredModule; - std::vector<std::wstring> UnitTypes; + std::vector<std::wstring_view> UnitTypes; }; - static const PredefinedResource s_PredefinedResourcesForExport[] = { - { std::wstring{ s_Module_WinGetClient }, { L"Microsoft.WinGet.DSC/WinGetUserSettings" } }, - { L"Microsoft.Windows.Developer", { L"Microsoft.Windows.Developer/DeveloperMode", L"Microsoft.Windows.Developer/EnableDarkMode", L"Microsoft.Windows.Developer/ShowSecondsInClock", L"Microsoft.Windows.Developer/Taskbar", L"Microsoft.Windows.Developer/WindowsExplorer" }}, - }; + std::vector<PredefinedResource> PredefinedResourcesForExport() + { + return { + { {}, { s_UnitType_WinGetUserSettingsFile_DSCv3 } }, + { L"Microsoft.Windows.Developer", { L"Microsoft.Windows.Developer/DeveloperMode", L"Microsoft.Windows.Developer/EnableDarkMode", L"Microsoft.Windows.Developer/ShowSecondsInClock", L"Microsoft.Windows.Developer/Taskbar", L"Microsoft.Windows.Developer/WindowsExplorer" } }, + }; + } - static const std::wstring s_PackageSettingsExclusionList[] = { - L"Microsoft.WinGet/", L"Microsoft.DSC.Debug/", L"Microsoft.DSC/", L"Microsoft.DSC.Transitional/", L"Microsoft.Windows/RebootPending", - L"Microsoft.Windows/Registry", L"Microsoft.Windows/WMI", L"Microsoft.Windows/WindowsPowerShell", L"Microsoft/OSInfo" + std::vector<std::wstring_view> PackageSettingsExclusionList() + { + return { + L"Microsoft.WinGet/", + L"Microsoft.WinGet.Dev/", + L"Microsoft.DSC.Debug/", + L"Microsoft.DSC/", + L"Microsoft.DSC.Transitional/", + L"Microsoft.Windows/RebootPending", + L"Microsoft.Windows/Registry", + L"Microsoft.Windows/WMI", + L"Microsoft.Windows/WindowsPowerShell", + L"Microsoft/OSInfo" + }; }; Logging::Level ConvertLevel(DiagnosticLevel level) @@ -1475,7 +1491,7 @@ namespace AppInstaller::CLI::Workflow { ConfigurationContext& configContext = context.Get<Data::ConfigurationContext>(); - for (const auto& resources : s_PredefinedResourcesForExport) + for (const auto& resources : PredefinedResourcesForExport()) { std::optional<ConfigurationUnit> requiredModuleUnit; @@ -1538,11 +1554,13 @@ namespace AppInstaller::CLI::Workflow context.Reporter.Warn() << Resource::String::ConfigurationExportFailedToGetUnitProcessors << std::endl; } + auto exclusionList = PackageSettingsExclusionList(); + // Filter out processors in exclusion list. for (auto itr = unitProcessors.begin(); itr != unitProcessors.end(); /* itr incremented in the logic */) { bool processorRemoved = false; - for (const auto& exclusionItem : anon::s_PackageSettingsExclusionList) + for (const auto& exclusionItem : exclusionList) { if (Utility::CaseInsensitiveStartsWith(itr->UnitType(), exclusionItem)) { diff --git a/src/AppInstallerCLIE2ETests/ConfigureCommand.cs b/src/AppInstallerCLIE2ETests/ConfigureCommand.cs @@ -23,8 +23,7 @@ namespace AppInstallerCLIE2ETests /// </summary> public static void EnsureTestResourcePresence() { - DSCv3ResourceTestBase.EnsureTestResourcePresence("test-file"); - DSCv3ResourceTestBase.EnsureTestResourcePresence("test-json"); + DSCv3ResourceTestBase.EnsureTestResourcePresence(); } /// <summary> @@ -330,12 +329,12 @@ namespace AppInstallerCLIE2ETests var exportDir = TestCommon.GetRandomTestDir(); var exportFile = Path.Combine(exportDir, "exported.yml"); - result = TestCommon.RunAICLICommand("test config-export-units", $"-o {exportFile} --resource Microsoft.WinGet/TestJSON --verbose"); + result = TestCommon.RunAICLICommand("test config-export-units", $"-o {exportFile} --resource Microsoft.WinGet.Dev/TestJSON --verbose"); Assert.AreEqual(0, result.ExitCode); Assert.True(File.Exists(exportFile)); string exportText = File.ReadAllText(exportFile); - Assert.True(exportText.Contains("Microsoft.WinGet/TestJSON")); + Assert.True(exportText.Contains("Microsoft.WinGet.Dev/TestJSON")); Assert.True(exportText.Contains(propertyName1)); Assert.True(exportText.Contains(propertyName2)); Assert.True(exportText.Contains(propertyValue1)); diff --git a/src/AppInstallerCLIE2ETests/ConfigureExportCommand.cs b/src/AppInstallerCLIE2ETests/ConfigureExportCommand.cs @@ -34,6 +34,7 @@ namespace AppInstallerCLIE2ETests TestCommon.RunAICLICommand("install", $"AppInstallerTest.TestPackageExport -v 1.0.0.0 --silent -l {installDir}"); this.previousPathValue = System.Environment.GetEnvironmentVariable("PATH"); System.Environment.SetEnvironmentVariable("PATH", this.previousPathValue + ";" + installDir); + DSCv3ResourceTestBase.EnsureTestResourcePresence(); } /// <summary> @@ -67,13 +68,13 @@ namespace AppInstallerCLIE2ETests // Check exported file is readable and validate content var showResult = TestCommon.RunAICLICommand(ShowCommand, $"-f {exportFile}"); Assert.AreEqual(Constants.ErrorCode.S_OK, showResult.ExitCode); - Assert.True(showResult.StdOut.Contains("Microsoft.WinGet/Source")); + Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/Source")); Assert.True(showResult.StdOut.Contains($"[{Constants.TestSourceName}_{Constants.TestSourceType}]")); Assert.True(showResult.StdOut.Contains($"type: {Constants.TestSourceType}")); Assert.True(showResult.StdOut.Contains($"argument: {Constants.TestSourceUrl}")); Assert.True(showResult.StdOut.Contains($"name: {Constants.TestSourceName}")); - Assert.True(showResult.StdOut.Contains("Microsoft.WinGet/Package")); + Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/Package")); Assert.True(showResult.StdOut.Contains($"[{Constants.TestSourceName}_AppInstallerTest.TestPackageExport]")); Assert.True(showResult.StdOut.Contains($"Dependencies: {Constants.TestSourceName}_{Constants.TestSourceType}")); Assert.True(showResult.StdOut.Contains("id: AppInstallerTest.TestPackageExport")); @@ -95,13 +96,13 @@ namespace AppInstallerCLIE2ETests // Check exported file is readable and validate content var showResult = TestCommon.RunAICLICommand(ShowCommand, $"-f {exportFile}"); Assert.AreEqual(Constants.ErrorCode.S_OK, showResult.ExitCode); - Assert.True(showResult.StdOut.Contains("Microsoft.WinGet/Source")); + Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/Source")); Assert.True(showResult.StdOut.Contains($"[{Constants.TestSourceName}_{Constants.TestSourceType}]")); Assert.True(showResult.StdOut.Contains($"type: {Constants.TestSourceType}")); Assert.True(showResult.StdOut.Contains($"argument: {Constants.TestSourceUrl}")); Assert.True(showResult.StdOut.Contains($"name: {Constants.TestSourceName}")); - Assert.True(showResult.StdOut.Contains("Microsoft.WinGet/Package")); + Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/Package")); Assert.True(showResult.StdOut.Contains($"[{Constants.TestSourceName}_AppInstallerTest.TestPackageExport]")); Assert.True(showResult.StdOut.Contains($"Dependencies: {Constants.TestSourceName}_{Constants.TestSourceType}")); Assert.True(showResult.StdOut.Contains("id: AppInstallerTest.TestPackageExport")); @@ -127,13 +128,13 @@ namespace AppInstallerCLIE2ETests // Check exported file is readable and validate content var showResult = TestCommon.RunAICLICommand(ShowCommand, $"-f {exportFile}"); Assert.AreEqual(Constants.ErrorCode.S_OK, showResult.ExitCode); - Assert.True(showResult.StdOut.Contains("Microsoft.WinGet/Source")); + Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/Source")); Assert.True(showResult.StdOut.Contains($"[{Constants.TestSourceName}_{Constants.TestSourceType}]")); Assert.True(showResult.StdOut.Contains($"type: {Constants.TestSourceType}")); Assert.True(showResult.StdOut.Contains($"argument: {Constants.TestSourceUrl}")); Assert.True(showResult.StdOut.Contains($"name: {Constants.TestSourceName}")); - Assert.True(showResult.StdOut.Contains("Microsoft.WinGet/Package")); + Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/Package")); Assert.True(showResult.StdOut.Contains($"[{Constants.TestSourceName}_AppInstallerTest.TestPackageExport]")); Assert.True(showResult.StdOut.Contains($"Dependencies: {Constants.TestSourceName}_{Constants.TestSourceType}")); Assert.True(showResult.StdOut.Contains("id: AppInstallerTest.TestPackageExport")); @@ -157,17 +158,17 @@ namespace AppInstallerCLIE2ETests var showResult = TestCommon.RunAICLICommand(ShowCommand, $"-f {exportFile}", timeOut: 1200000); Assert.AreEqual(Constants.ErrorCode.S_OK, showResult.ExitCode); - Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.DSC/WinGetUserSettings")); + Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/UserSettingsFile")); Assert.True(showResult.StdOut.Contains("Microsoft.Windows.Developer/DeveloperMode")); Assert.True(showResult.StdOut.Contains("Microsoft.Windows.Developer/EnableDarkMode")); - Assert.True(showResult.StdOut.Contains("Microsoft.WinGet/Source")); + Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/Source")); Assert.True(showResult.StdOut.Contains($"[{Constants.TestSourceName}_{Constants.TestSourceType}]")); Assert.True(showResult.StdOut.Contains($"type: {Constants.TestSourceType}")); Assert.True(showResult.StdOut.Contains($"argument: {Constants.TestSourceUrl}")); Assert.True(showResult.StdOut.Contains($"name: {Constants.TestSourceName}")); - Assert.True(showResult.StdOut.Contains("Microsoft.WinGet/Package")); + Assert.True(showResult.StdOut.Contains("Microsoft.WinGet.Dev/Package")); Assert.True(showResult.StdOut.Contains($"[{Constants.TestSourceName}_AppInstallerTest.TestPackageExport]")); Assert.True(showResult.StdOut.Contains($"Dependencies: {Constants.TestSourceName}_{Constants.TestSourceType}")); Assert.True(showResult.StdOut.Contains("id: AppInstallerTest.TestPackageExport")); diff --git a/src/AppInstallerCLIE2ETests/ConfigureShowCommand.cs b/src/AppInstallerCLIE2ETests/ConfigureShowCommand.cs @@ -172,7 +172,7 @@ namespace AppInstallerCLIE2ETests int startLine = -1; for (int i = 0; i < outputLines.Length; ++i) { - if (outputLines[i].Trim() == "Microsoft.WinGet/TestFile [Test File]") + if (outputLines[i].Trim() == "Microsoft.WinGet.Dev/TestFile [Test File]") { startLine = i; } @@ -202,7 +202,7 @@ namespace AppInstallerCLIE2ETests int startLine = -1; for (int i = 0; i < outputLines.Length; ++i) { - if (outputLines[i].Trim() == "Microsoft.WinGet/TestFile [Test File]") + if (outputLines[i].Trim() == "Microsoft.WinGet.Dev/TestFile [Test File]") { startLine = i; } diff --git a/src/AppInstallerCLIE2ETests/DSCv3PackageResourceCommand.cs b/src/AppInstallerCLIE2ETests/DSCv3PackageResourceCommand.cs @@ -35,7 +35,7 @@ namespace AppInstallerCLIE2ETests TestCommon.SetupTestSource(); WinGetSettingsHelper.ConfigureFeature("dsc3", true); WinGetSettingsHelper.ConfigureLoggingLevel("verbose"); - EnsureTestResourcePresence(PackageResource); + EnsureTestResourcePresence(); } /// <summary> diff --git a/src/AppInstallerCLIE2ETests/DSCv3ResourceTestBase.cs b/src/AppInstallerCLIE2ETests/DSCv3ResourceTestBase.cs @@ -50,15 +50,14 @@ namespace AppInstallerCLIE2ETests public const string InDesiredStatePropertyName = "_inDesiredState"; /// <summary> - /// Write the resource manifest out to the WindowsApps alias directory. + /// Write the resource manifests out to the WindowsApps alias directory. /// </summary> - /// <param name="resource">The resource manifest to write.</param> - public static void EnsureTestResourcePresence(string resource) + public static void EnsureTestResourcePresence() { string outputDirectory = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\WindowsApps"); Assert.IsNotEmpty(outputDirectory); - var result = TestCommon.RunAICLICommand($"dscv3 {resource}", $"--manifest -o {outputDirectory}\\microsoft.winget.{resource}.dsc.resource.json"); + var result = TestCommon.RunAICLICommand($"dscv3", $"--manifest -o {outputDirectory}"); Assert.AreEqual(0, result.ExitCode); } diff --git a/src/AppInstallerCLIE2ETests/DSCv3SourceResourceCommand.cs b/src/AppInstallerCLIE2ETests/DSCv3SourceResourceCommand.cs @@ -57,7 +57,7 @@ namespace AppInstallerCLIE2ETests { TestCommon.SetupTestSource(); WinGetSettingsHelper.ConfigureFeature("dsc3", true); - EnsureTestResourcePresence(SourceResource); + EnsureTestResourcePresence(); } /// <summary> diff --git a/src/AppInstallerCLIE2ETests/DSCv3UserSettingsFileResourceCommand.cs b/src/AppInstallerCLIE2ETests/DSCv3UserSettingsFileResourceCommand.cs @@ -36,7 +36,7 @@ public class DSCv3UserSettingsFileResourceCommand : DSCv3ResourceTestBase { TestCommon.SetupTestSource(); WinGetSettingsHelper.ConfigureFeature("dsc3", true); - EnsureTestResourcePresence(UserSettingsFileResource); + EnsureTestResourcePresence(); } /// <summary> diff --git a/src/AppInstallerCLIE2ETests/TestData/Configuration/ShowDetails_DSCv3.yml b/src/AppInstallerCLIE2ETests/TestData/Configuration/ShowDetails_DSCv3.yml @@ -4,7 +4,7 @@ metadata: processor: dscv3 resources: - name: Test File - type: Microsoft.WinGet/TestFile + type: Microsoft.WinGet.Dev/TestFile metadata: description: Description 1. properties: diff --git a/src/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj b/src/AppInstallerCLIPackage/AppInstallerCLIPackage.wapproj @@ -218,6 +218,12 @@ <PropertyGroup Condition="'$(Platform)'=='x86'"> <ConfigServerRid>win-x86</ConfigServerRid> </PropertyGroup> + <Target Name="WinGetGenerateDSCv3Manifests" BeforeTargets="WinGetIncludeAdditionalFilesInPackage"> + <Message Importance="normal" Text="Generating DSCv3 manifests..." /> + <Copy SourceFiles="$(SolutionDir)\$(PlatformTarget)\$(Configuration)\WindowsPackageManager\WindowsPackageManager.dll" DestinationFolder="$(SolutionDir)\$(PlatformTarget)\$(Configuration)\AppInstallerCLI" SkipUnchangedFiles="true" /> + <Exec Command="$(SolutionDir)\$(PlatformTarget)\$(Configuration)\AppInstallerCLI\winget.exe dscv3 --manifest -o $(SolutionDir)\$(PlatformTarget)\$(Configuration)\AppInstallerCLI\DSCv3Manifests" /> + <Message Importance="normal" Text="DSCv3 manifests generated." /> + </Target> <Target Name="WinGetIncludeAdditionalFilesInPackage" AfterTargets="_ComputeAppxPackagePayload"> <PropertyGroup> <WinGetAdditionalPackageFileRoot>$(SolutionDir)</WinGetAdditionalPackageFileRoot> @@ -244,6 +250,10 @@ <PackagePath>ExternalModules</PackagePath> <Recurse>true</Recurse> </WinGetAdditionalPackageFile> + <WinGetAdditionalPackageFile Include="$(SolutionDir)\$(PlatformTarget)\$(Configuration)\AppInstallerCLI\DSCv3Manifests\*"> + <PackagePath>.</PackagePath> + <Recurse>true</Recurse> + </WinGetAdditionalPackageFile> </ItemGroup> <Error Condition="!Exists('%(WinGetAdditionalPackageFile.Identity)')" Text="%(WinGetAdditionalPackageFile.Identity) was not found" /> <!-- Single (non-recursive) file items --> diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -3345,4 +3345,7 @@ Please specify one of them using the --source option to proceed.</value> <data name="ConfigurationExportFailedToGetUnitProcessors" xml:space="preserve"> <value>Failed to get unit processors. Individual package settings will not be exported.</value> </data> -</root> + <data name="OutputDirectoryArgumentDescription" xml:space="preserve"> + <value>Directory where the results are to be written</value> + </data> +</root>+ \ No newline at end of file