Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1690,30 +1690,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 @@ -1723,6 +1803,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