Skip to content

Commit 3de5ecf

Browse files
Keep JSON failures and help visible
1 parent 3e9efad commit 3de5ecf

3 files changed

Lines changed: 101 additions & 12 deletions

File tree

src/AppInstallerCLICore/Command.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1072,7 +1072,10 @@ namespace AppInstaller::CLI
10721072
{
10731073
try
10741074
{
1075-
Workflow::SetJsonOutputChannel(context);
1075+
if (!context.Args.Contains(Execution::Args::Type::Help))
1076+
{
1077+
Workflow::SetJsonOutputChannel(context);
1078+
}
10761079

10771080
if (!Settings::User().GetWarnings().empty() &&
10781081
!WI_IsFlagSet(command->GetOutputFlags(), CommandOutputFlags::IgnoreSettingsWarnings))

src/AppInstallerCLICore/Workflows/WorkflowBase.cpp

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,19 @@ namespace AppInstaller::CLI::Workflow
508508
WriteJsonOutput(context, result);
509509
}
510510

511+
Resource::LocString GetUnexpectedErrorMessage(std::string_view message)
512+
{
513+
std::string result = Resource::LocString{ Resource::String::UnexpectedErrorExecutingCommand }.get();
514+
515+
if (!message.empty())
516+
{
517+
result += ' ';
518+
result += message;
519+
}
520+
521+
return Resource::LocString{ Utility::LocIndString{ std::move(result) } };
522+
}
523+
511524
void OutputInstalledPackagesJson(
512525
Execution::Context& context,
513526
std::vector<InstalledPackagesTableLine>& lines,
@@ -790,9 +803,17 @@ namespace AppInstaller::CLI::Workflow
790803
Logging::Telemetry().LogException(Logging::FailureTypeEnum::ResultException, re.what());
791804
if (context)
792805
{
793-
context->Reporter.Error() <<
794-
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
795-
GetUserPresentableMessage(re) << std::endl;
806+
auto message = GetUserPresentableMessage(re);
807+
if (IsJsonOutputFormat(context->Args))
808+
{
809+
OutputInstalledPackagesJsonError(*context, re.GetErrorCode(), GetUnexpectedErrorMessage(message));
810+
}
811+
else
812+
{
813+
context->Reporter.Error() <<
814+
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
815+
message << std::endl;
816+
}
796817
}
797818
return re.GetErrorCode();
798819
}
@@ -802,9 +823,16 @@ namespace AppInstaller::CLI::Workflow
802823
Logging::Telemetry().LogException(Logging::FailureTypeEnum::WinrtHResultError, message);
803824
if (context)
804825
{
805-
context->Reporter.Error() <<
806-
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
807-
message << std::endl;
826+
if (IsJsonOutputFormat(context->Args))
827+
{
828+
OutputInstalledPackagesJsonError(*context, hre.code(), GetUnexpectedErrorMessage(message));
829+
}
830+
else
831+
{
832+
context->Reporter.Error() <<
833+
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
834+
message << std::endl;
835+
}
808836
}
809837
return hre.code();
810838
}
@@ -832,9 +860,17 @@ namespace AppInstaller::CLI::Workflow
832860
Logging::Telemetry().LogException(Logging::FailureTypeEnum::StdException, e.what());
833861
if (context)
834862
{
835-
context->Reporter.Error() <<
836-
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
837-
GetUserPresentableMessage(e) << std::endl;
863+
auto message = GetUserPresentableMessage(e);
864+
if (IsJsonOutputFormat(context->Args))
865+
{
866+
OutputInstalledPackagesJsonError(*context, APPINSTALLER_CLI_ERROR_COMMAND_FAILED, GetUnexpectedErrorMessage(message));
867+
}
868+
else
869+
{
870+
context->Reporter.Error() <<
871+
Resource::String::UnexpectedErrorExecutingCommand << ' ' << std::endl <<
872+
message << std::endl;
873+
}
838874
}
839875
return APPINSTALLER_CLI_ERROR_COMMAND_FAILED;
840876
}
@@ -844,8 +880,15 @@ namespace AppInstaller::CLI::Workflow
844880
Logging::Telemetry().LogException(Logging::FailureTypeEnum::Unknown, {});
845881
if (context)
846882
{
847-
context->Reporter.Error() <<
848-
Resource::String::UnexpectedErrorExecutingCommand << " ???"_liv << std::endl;
883+
if (IsJsonOutputFormat(context->Args))
884+
{
885+
OutputInstalledPackagesJsonError(*context, APPINSTALLER_CLI_ERROR_COMMAND_FAILED, GetUnexpectedErrorMessage("???"sv));
886+
}
887+
else
888+
{
889+
context->Reporter.Error() <<
890+
Resource::String::UnexpectedErrorExecutingCommand << " ???"_liv << std::endl;
891+
}
849892
}
850893
return APPINSTALLER_CLI_ERROR_COMMAND_FAILED;
851894
}

src/AppInstallerCLITests/UpdateFlow.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,23 @@ TEST_CASE("ListFlow_JsonOutputWithSettingsWarnings", "[ListFlow][workflow]")
377377
REQUIRE(json["packages"].size() == 1);
378378
}
379379

380+
TEST_CASE("ListFlow_JsonOutputHelpUsesTextOutput", "[ListFlow][workflow]")
381+
{
382+
std::ostringstream listOutput;
383+
TestContext context{ listOutput, std::cin };
384+
auto previousThreadGlobals = context.SetForCurrentThread();
385+
context.Args.AddArg(Execution::Args::Type::Help);
386+
context.Args.AddArg(Execution::Args::Type::OutputFormat, "json"sv);
387+
388+
ListCommand list({});
389+
context.SetExecutingCommand(&list);
390+
ExecuteWithoutLoggingSuccess(context, &list);
391+
INFO(listOutput.str());
392+
393+
REQUIRE(listOutput.str().find(Resource::String::Usage("winget"_liv, "list"_liv).get()) != std::string::npos);
394+
REQUIRE_FALSE(context.IsTerminated());
395+
}
396+
380397
TEST_CASE("ListFlow_JsonOutputWinGetPolicyDisabled", "[ListFlow][workflow]")
381398
{
382399
GroupPolicyTestOverride policies;
@@ -402,6 +419,32 @@ TEST_CASE("ListFlow_JsonOutputWinGetPolicyDisabled", "[ListFlow][workflow]")
402419
REQUIRE(context.GetTerminationHR() == APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY);
403420
}
404421

422+
TEST_CASE("ListFlow_JsonOutputGenericExecutionFailure", "[ListFlow][workflow]")
423+
{
424+
std::ostringstream listOutput;
425+
TestContext context{ listOutput, std::cin };
426+
auto previousThreadGlobals = context.SetForCurrentThread();
427+
context.Args.AddArg(Execution::Args::Type::OutputFormat, "json"sv);
428+
context.Override({ "OpenSource", [](TestContext&)
429+
{
430+
THROW_HR(APPINSTALLER_CLI_ERROR_SOURCE_OPEN_FAILED);
431+
} });
432+
433+
ListCommand list({});
434+
context.SetExecutingCommand(&list);
435+
ExecuteWithoutLoggingSuccess(context, &list);
436+
INFO(listOutput.str());
437+
438+
Json::Value json = ConvertToJson(listOutput.str());
439+
REQUIRE(json["packages"].isArray());
440+
REQUIRE(json["packages"].empty());
441+
REQUIRE(json["sourceFailures"].isArray());
442+
REQUIRE(json["sourceFailures"].empty());
443+
REQUIRE(json["error"]["code"].asString() == "0x8a150045");
444+
REQUIRE(json["error"]["message"].asString().empty() == false);
445+
REQUIRE(context.GetTerminationHR() == APPINSTALLER_CLI_ERROR_SOURCE_OPEN_FAILED);
446+
}
447+
405448
TEST_CASE("ListFlow_JsonOutputBadSource", "[ListFlow][workflow]")
406449
{
407450
SetSetting(Stream::UserSources, R"(

0 commit comments

Comments
 (0)