Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Output log files as collapsed sections in ci #1556

Merged
merged 8 commits into from
Jan 17, 2025
4 changes: 3 additions & 1 deletion include/vcpkg/commands.build.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,14 @@ namespace vcpkg
LocalizedString to_string(const BuildResult build_result);
LocalizedString create_user_troubleshooting_message(const InstallPlanAction& action,
const VcpkgPaths& paths,
const std::vector<std::string>& error_logs,
const Optional<Path>& issue_body);
inline void print_user_troubleshooting_message(const InstallPlanAction& action,
const VcpkgPaths& paths,
const std::vector<std::string>& error_logs,
Optional<Path>&& issue_body)
{
msg::println(Color::error, create_user_troubleshooting_message(action, paths, issue_body));
msg::println(Color::error, create_user_troubleshooting_message(action, paths, error_logs, issue_body));
}

/// <summary>
Expand Down
100 changes: 94 additions & 6 deletions src/vcpkg/commands.build.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ namespace vcpkg
msg::print(Color::warning, warnings);
}
msg::println_error(create_error_message(result, spec));
msg::print(create_user_troubleshooting_message(*action, paths, nullopt));
msg::print(create_user_troubleshooting_message(*action, paths, {}, nullopt));
return 1;
}
case BuildResult::Excluded:
Expand Down Expand Up @@ -1692,30 +1692,110 @@ namespace vcpkg
return "https://github.com/microsoft/vcpkg/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+" + spec_name;
}

static std::string make_gh_issue_open_url(StringView spec_name, StringView triplet, StringView path)
static std::string make_gh_issue_open_url(StringView spec_name, StringView triplet, StringView body)
{
return Strings::concat("https://github.com/microsoft/vcpkg/issues/new?title=[",
spec_name,
"]+Build+error+on+",
triplet,
"&body=Copy+issue+body+from+",
Strings::percent_encode(path));
"&body=",
Strings::percent_encode(body));
}

enum class CIType
{
GithubActions,
GitLabCi,
Azure,
};

static Optional<CIType> detect_ci_type()
{
if (get_environment_variable(EnvironmentVariableGitHubActions).has_value())
{
return CIType::GithubActions;
}
if (get_environment_variable(EnvironmentVariableGitLabCI).has_value())
{
return CIType::GitLabCi;
}
if (get_environment_variable(EnvironmentVariableTfBuild).has_value())
{
return CIType::Azure;
}
return {};
}

static void append_file_collapsible(LocalizedString& output,
CIType type,
const ReadOnlyFilesystem& fs,
const Path& file)
{
auto title = file.filename();
// starting tag
if (type == CIType::GithubActions)
{
// https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#grouping-log-lines
output.append_raw("::group::").append_raw(title).append_raw('\n');
}
else if (type == CIType::GitLabCi)
{
// https://docs.gitlab.com/ee/ci/jobs/job_logs.html#custom-collapsible-sections
using namespace std::chrono;
const auto timestamp = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
output.append_raw(fmt::format("\\e[0Ksection_start:{}:SECTION_NAME[collapsed=true]\r\\e[0K", timestamp))
.append_raw(title)
.append_raw('\n');
}
else if (type == CIType::Azure)
{
output.append_raw("##vso[task.uploadfile]").append_raw(fs.absolute(file, VCPKG_LINE_INFO)).append_raw('\n');
// https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#formatting-commands
output.append_raw("##[group]").append_raw(title).append_raw('\n');
}

// output real file
output.append_raw(fs.read_contents(file, VCPKG_LINE_INFO));

// end tag
if (type == CIType::GithubActions)
{
output.append_raw("::endgroup::\n");
}
else if (type == CIType::GitLabCi)
{
using namespace std::chrono;
const auto timestamp = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
output.append_raw(fmt::format("\\e[0Ksection_end:{}:SECTION_NAME\r\\e[0K\n", timestamp));
}
else if (type == CIType::Azure)
{
output.append_raw("##[endgroup]\n");
}
}

LocalizedString create_user_troubleshooting_message(const InstallPlanAction& action,
const VcpkgPaths& paths,
const std::vector<std::string>& error_logs,
const Optional<Path>& issue_body)
{
const auto& spec_name = action.spec.name();
const auto& triplet_name = action.spec.triplet().to_string();
LocalizedString result = msg::format(msgBuildTroubleshootingMessage1).append_raw('\n');
result.append_indent().append_raw(make_gh_issue_search_url(spec_name)).append_raw('\n');
result.append(msgBuildTroubleshootingMessage2).append_raw('\n');

if (issue_body.has_value())
{
auto ci = detect_ci_type();
const auto path = issue_body.get()->generic_u8string();
result.append_indent().append_raw(make_gh_issue_open_url(spec_name, triplet_name, path)).append_raw('\n');
if (!paths.get_filesystem().find_from_PATH("gh").empty())
const auto body =
ci.map([&](auto) {
return fmt::format("Copy issue body from collapsed section \"{}\" in the ci log output",
issue_body.get()->filename());
}).value_or(Strings::concat("Copy issue body from ", path));
result.append_indent().append_raw(make_gh_issue_open_url(spec_name, triplet_name, body)).append_raw('\n');
if (!ci && !paths.get_filesystem().find_from_PATH("gh").empty())
{
Command gh("gh");
gh.string_arg("issue").string_arg("create").string_arg("-R").string_arg("microsoft/vcpkg");
Expand All @@ -1725,6 +1805,14 @@ namespace vcpkg
result.append(msgBuildTroubleshootingMessageGH).append_raw('\n');
result.append_indent().append_raw(gh.command_line());
}
if (ci)
{
append_file_collapsible(result, *ci.get(), paths.get_filesystem(), *issue_body.get());
for (Path error_log_path : error_logs)
{
append_file_collapsible(result, *ci.get(), paths.get_filesystem(), error_log_path);
}
}
}
else
{
Expand Down
17 changes: 9 additions & 8 deletions src/vcpkg/commands.install.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,14 +603,15 @@ namespace vcpkg
if (result.code != BuildResult::Succeeded && build_options.keep_going == KeepGoing::No)
{
this_install.print_elapsed_time();
print_user_troubleshooting_message(action, paths, result.stdoutlog.then([&](auto&) -> Optional<Path> {
auto issue_body_path = paths.installed().root() / "vcpkg" / "issue_body.md";
paths.get_filesystem().write_contents(
issue_body_path,
create_github_issue(args, result, paths, action, include_manifest_in_github_issue),
VCPKG_LINE_INFO);
return issue_body_path;
}));
print_user_troubleshooting_message(
action, paths, result.error_logs, result.stdoutlog.then([&](auto&) -> Optional<Path> {
auto issue_body_path = paths.installed().root() / "vcpkg" / "issue_body.md";
paths.get_filesystem().write_contents(
issue_body_path,
create_github_issue(args, result, paths, action, include_manifest_in_github_issue),
VCPKG_LINE_INFO);
return issue_body_path;
}));
Checks::exit_fail(VCPKG_LINE_INFO);
}

Expand Down