From 58f5db85973a82010cd08a32b5cd1ca9c779d563 Mon Sep 17 00:00:00 2001 From: autoantwort Date: Sat, 28 Dec 2024 18:23:59 +0100 Subject: [PATCH 1/6] Output log files as collapsed sections in ci --- include/vcpkg/commands.build.h | 4 +- src/vcpkg/commands.build.cpp | 87 +++++++++++++++++++++++++++++++++- src/vcpkg/commands.install.cpp | 17 +++---- 3 files changed, 97 insertions(+), 11 deletions(-) diff --git a/include/vcpkg/commands.build.h b/include/vcpkg/commands.build.h index 7dd6481a0c..c0ca0ffd29 100644 --- a/include/vcpkg/commands.build.h +++ b/include/vcpkg/commands.build.h @@ -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& error_logs, const Optional& issue_body); inline void print_user_troubleshooting_message(const InstallPlanAction& action, const VcpkgPaths& paths, + const std::vector& error_logs, Optional&& 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)); } /// diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index 16029b5612..7ea8b925de 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -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: @@ -1700,8 +1700,81 @@ namespace vcpkg Strings::percent_encode(path)); } + enum class CIType + { + GithubActions, + GitlabCi, + Azure, + }; + + static Optional detectCi() + { + 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 appendFileCollapsible(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(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(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& error_logs, const Optional& issue_body) { const auto& spec_name = action.spec.name(); @@ -1709,11 +1782,13 @@ namespace vcpkg 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 = detectCi(); 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()) + 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"); @@ -1723,6 +1798,14 @@ namespace vcpkg result.append(msgBuildTroubleshootingMessageGH).append_raw('\n'); result.append_indent().append_raw(gh.command_line()); } + if (ci) + { + appendFileCollapsible(result, *ci.get(), paths.get_filesystem(), *issue_body.get()); + for (Path error_log_path : error_logs) + { + appendFileCollapsible(result, *ci.get(), paths.get_filesystem(), error_log_path); + } + } } else { diff --git a/src/vcpkg/commands.install.cpp b/src/vcpkg/commands.install.cpp index 5c1abf9c30..e3ab1b7521 100644 --- a/src/vcpkg/commands.install.cpp +++ b/src/vcpkg/commands.install.cpp @@ -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 { - 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 { + 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); } From 78dceec70ea97b6ab741c5feee4f13fdacdf7f20 Mon Sep 17 00:00:00 2001 From: autoantwort Date: Sat, 28 Dec 2024 18:55:03 +0100 Subject: [PATCH 2/6] snake_case + adapt issue body mannage --- src/vcpkg/commands.build.cpp | 37 ++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index 7ea8b925de..049878fc50 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -1690,24 +1690,24 @@ 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, + GitLabCi, Azure, }; - static Optional detectCi() + static Optional detect_ci_type() { if (get_environment_variable(EnvironmentVariableGitHubActions).has_value()) { @@ -1715,7 +1715,7 @@ namespace vcpkg } if (get_environment_variable(EnvironmentVariableGitLabCI).has_value()) { - return CIType::GitlabCi; + return CIType::GitLabCi; } if (get_environment_variable(EnvironmentVariableTfBuild).has_value()) { @@ -1724,10 +1724,10 @@ namespace vcpkg return {}; } - static void appendFileCollapsible(LocalizedString& output, - CIType type, - const ReadOnlyFilesystem& fs, - const Path& file) + static void append_file_collapsible(LocalizedString& output, + CIType type, + const ReadOnlyFilesystem& fs, + const Path& file) { auto title = file.filename(); // starting tag @@ -1736,7 +1736,7 @@ namespace vcpkg // 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) + else if (type == CIType::GitLabCi) { // https://docs.gitlab.com/ee/ci/jobs/job_logs.html#custom-collapsible-sections using namespace std::chrono; @@ -1760,7 +1760,7 @@ namespace vcpkg { output.append_raw("::endgroup::\n"); } - else if (type == CIType::GitlabCi) + else if (type == CIType::GitLabCi) { using namespace std::chrono; const auto timestamp = duration_cast(system_clock::now().time_since_epoch()).count(); @@ -1785,9 +1785,14 @@ namespace vcpkg if (issue_body.has_value()) { - auto ci = detectCi(); + 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'); + 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"); @@ -1800,10 +1805,10 @@ namespace vcpkg } if (ci) { - appendFileCollapsible(result, *ci.get(), paths.get_filesystem(), *issue_body.get()); + append_file_collapsible(result, *ci.get(), paths.get_filesystem(), *issue_body.get()); for (Path error_log_path : error_logs) { - appendFileCollapsible(result, *ci.get(), paths.get_filesystem(), error_log_path); + append_file_collapsible(result, *ci.get(), paths.get_filesystem(), error_log_path); } } } From 21166e72d7b7f2f7dd3ad71f7f1fb1431d7a604b Mon Sep 17 00:00:00 2001 From: autoantwort Date: Thu, 2 Jan 2025 21:42:13 +0100 Subject: [PATCH 3/6] unused param --- src/vcpkg/commands.build.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index 049878fc50..63dbb8a8f1 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -1788,7 +1788,7 @@ namespace vcpkg auto ci = detect_ci_type(); const auto path = issue_body.get()->generic_u8string(); const auto body = - ci.map([&](auto _) { + 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)); From 6e7a1aa21c6e496c0d85e752ff065e7b2f2a6387 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 16 Jan 2025 01:53:57 -0800 Subject: [PATCH 4/6] * Reuse CI detection from the telemetry part in vcpkgcmdarguments. * Set SECTION_NAME for GitLabCI to the alphaumericdots of the filename. * Deduplicate some CI detection tests. * Fix a *foo.get() pattern in create_user_troubleshooting_message. --- include/vcpkg/base/contractual-constants.h | 1 + include/vcpkg/base/message-data.inc.h | 5 + include/vcpkg/commands.build.h | 9 +- include/vcpkg/fwd/vcpkgcmdarguments.h | 16 +++ include/vcpkg/vcpkgcmdarguments.h | 6 +- locales/messages.json | 4 + src/vcpkg/commands.build.cpp | 154 ++++++++++----------- src/vcpkg/commands.install.cpp | 8 +- src/vcpkg/commands.z-print-config.cpp | 2 +- src/vcpkg/vcpkgcmdarguments.cpp | 46 +++--- 10 files changed, 146 insertions(+), 105 deletions(-) diff --git a/include/vcpkg/base/contractual-constants.h b/include/vcpkg/base/contractual-constants.h index fdb5c6cbba..d50eeba365 100644 --- a/include/vcpkg/base/contractual-constants.h +++ b/include/vcpkg/base/contractual-constants.h @@ -347,6 +347,7 @@ namespace vcpkg inline constexpr StringLiteral FileInclude = "include"; inline constexpr StringLiteral FileIncomplete = "incomplete"; inline constexpr StringLiteral FileInfo = "info"; + inline constexpr StringLiteral FileIssueBodyMD = "issue_body.md"; inline constexpr StringLiteral FileLicense = "LICENSE"; inline constexpr StringLiteral FileLicenseDotTxt = "LICENSE.txt"; inline constexpr StringLiteral FilePortfileDotCMake = "portfile.cmake"; diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index c216b38f25..282d15d419 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -945,6 +945,11 @@ DECLARE_MESSAGE(ConstraintViolation, (), "", "Found a constraint violation:") DECLARE_MESSAGE(ContinueCodeUnitInStart, (), "", "found continue code unit in start position") DECLARE_MESSAGE(ControlCharacterInString, (), "", "Control character in string") DECLARE_MESSAGE(ControlSupportsMustBeAPlatformExpression, (), "", "\"Supports\" must be a platform expression") +DECLARE_MESSAGE(CopyIssueBodyFromFile, (msg::path), "", "Copy issue body from {path}") +DECLARE_MESSAGE(CopyIssueBodyFromCollapsibleSection, + (msg::path), + "", + "Copy issue body from collapsed section \"{path}\" in the ci log output") DECLARE_MESSAGE(CopyrightIsDir, (), "", diff --git a/include/vcpkg/commands.build.h b/include/vcpkg/commands.build.h index c0ca0ffd29..d62c4f538a 100644 --- a/include/vcpkg/commands.build.h +++ b/include/vcpkg/commands.build.h @@ -94,15 +94,18 @@ namespace vcpkg StringLiteral to_string_locale_invariant(const BuildResult build_result); LocalizedString to_string(const BuildResult build_result); LocalizedString create_user_troubleshooting_message(const InstallPlanAction& action, + CIKind detected_ci, const VcpkgPaths& paths, const std::vector& error_logs, - const Optional& issue_body); + const Optional& maybe_issue_body); inline void print_user_troubleshooting_message(const InstallPlanAction& action, + CIKind detected_ci, const VcpkgPaths& paths, const std::vector& error_logs, - Optional&& issue_body) + Optional&& maybe_issue_body) { - msg::println(Color::error, create_user_troubleshooting_message(action, paths, error_logs, issue_body)); + msg::println(Color::error, + create_user_troubleshooting_message(action, detected_ci, paths, error_logs, maybe_issue_body)); } /// diff --git a/include/vcpkg/fwd/vcpkgcmdarguments.h b/include/vcpkg/fwd/vcpkgcmdarguments.h index 1c827c6f74..bbf195ae56 100644 --- a/include/vcpkg/fwd/vcpkgcmdarguments.h +++ b/include/vcpkg/fwd/vcpkgcmdarguments.h @@ -20,4 +20,20 @@ namespace vcpkg struct VcpkgCmdArguments; struct FeatureFlagSettings; struct PortApplicableSetting; + + enum class CIKind + { + None, + GithubActions, + GitLabCI, + AzurePipelines, + AppVeyor, + AwsCodeBuild, + CircleCI, + HerokuCI, + JenkinsCI, + TeamCityCI, + TravisCI, + Generic + }; } diff --git a/include/vcpkg/vcpkgcmdarguments.h b/include/vcpkg/vcpkgcmdarguments.h index 12b2452dd1..cb505d234d 100644 --- a/include/vcpkg/vcpkgcmdarguments.h +++ b/include/vcpkg/vcpkgcmdarguments.h @@ -298,7 +298,8 @@ namespace vcpkg f.dependency_graph = dependency_graph_enabled(); return f; } - const Optional& detected_ci_environment() const { return m_detected_ci_environment; } + const Optional& detected_ci_environment_name() const { return m_detected_ci_environment_name; } + CIKind detected_ci() const { return m_detected_ci_environment_type; } const std::string& get_command() const noexcept { return command; } @@ -333,7 +334,8 @@ namespace vcpkg std::string command; - Optional m_detected_ci_environment; + Optional m_detected_ci_environment_name; + CIKind m_detected_ci_environment_type; friend LocalizedString usage_for_command(const CommandMetadata& command_metadata); CmdParser parser; diff --git a/locales/messages.json b/locales/messages.json index fc195de5f8..8b592c8778 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -546,6 +546,10 @@ "ContinueCodeUnitInStart": "found continue code unit in start position", "ControlCharacterInString": "Control character in string", "ControlSupportsMustBeAPlatformExpression": "\"Supports\" must be a platform expression", + "CopyIssueBodyFromCollapsibleSection": "Copy issue body from collapsed section \"{path}\" in the ci log output", + "_CopyIssueBodyFromCollapsibleSection.comment": "An example of {path} is /foo/bar.", + "CopyIssueBodyFromFile": "Copy issue body from {path}", + "_CopyIssueBodyFromFile.comment": "An example of {path} is /foo/bar.", "CopyrightIsDir": "this port sets ${{CURRENT_PACKAGES_DIR}}/share/${{PORT}}/copyright to a directory, but it should be a file. Consider combining separate copyright files into one using vcpkg_install_copyright. To suppress this message, add set(VCPKG_POLICY_SKIP_COPYRIGHT_CHECK enabled)", "CorruptedDatabase": "vcpkg's installation database corrupted. This is either a bug in vcpkg or something else has modified the contents of the 'installed' directory in an unexpected way. You may be able to fix this by deleting the 'installed' directory and reinstalling what you want to use. If this problem happens consistently, please file a bug at https://github.com/microsoft/vcpkg .", "CorruptedInstallTree": "Your vcpkg 'installed' tree is corrupted.", diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index eb4316a8e2..b93f7783f6 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -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, args.detected_ci(), paths, {}, nullopt)); return 1; } case BuildResult::Excluded: @@ -1702,82 +1702,76 @@ namespace vcpkg Strings::percent_encode(body)); } - enum class CIType + static bool is_collapsible_ci_kind(CIKind kind) { - GithubActions, - GitLabCi, - Azure, - }; - - static Optional 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()) + switch (kind) { - return CIType::Azure; + case CIKind::GithubActions: + case CIKind::GitLabCI: + case CIKind::AzurePipelines: return true; + default: return false; } - return {}; } static void append_file_collapsible(LocalizedString& output, - CIType type, + CIKind kind, const ReadOnlyFilesystem& fs, const Path& file) { - auto title = file.filename(); - // starting tag - if (type == CIType::GithubActions) + if (!is_collapsible_ci_kind(kind)) { - // 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'); + Checks::unreachable(VCPKG_LINE_INFO); } - 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(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(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"); + auto title = file.filename(); + auto contents = fs.read_contents(file, VCPKG_LINE_INFO); + switch (kind) + { + case CIKind::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') + .append_raw(contents) + .append_raw("::endgroup::\n"); + break; + case CIKind::GitLabCI: + { + // https://docs.gitlab.com/ee/ci/jobs/job_logs.html#custom-collapsible-sections + using namespace std::chrono; + std::string section_name; + std::copy_if(title.begin(), title.end(), std::back_inserter(section_name), [](char c) { + return c == '.' || ParserBase::is_alphanum(c); + }); + const auto timestamp = duration_cast(system_clock::now().time_since_epoch()).count(); + output + .append_raw( + fmt::format("\\e[0Ksection_start:{}:{}[collapsed=true]\r\\e[0K", timestamp, section_name)) + .append_raw(title) + .append_raw('\n') + .append_raw(contents) + .append_raw(fmt::format("\\e[0Ksection_end:{}:{}\r\\e[0K\n", timestamp, section_name)); + } + break; + case CIKind::AzurePipelines: + // https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#formatting-commands + output.append_raw("##vso[task.uploadfile]") + .append_raw(file) + .append_raw('\n') + .append_raw("##[group]") + .append_raw(title) + .append_raw('\n') + .append_raw(contents) + .append_raw("##[endgroup]\n"); + break; } } LocalizedString create_user_troubleshooting_message(const InstallPlanAction& action, + CIKind detected_ci, const VcpkgPaths& paths, const std::vector& error_logs, - const Optional& issue_body) + const Optional& maybe_issue_body) { const auto& spec_name = action.spec.name(); const auto& triplet_name = action.spec.triplet().to_string(); @@ -1785,32 +1779,36 @@ namespace vcpkg 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()) + if (auto issue_body = maybe_issue_body.get()) { - auto ci = detect_ci_type(); - const auto path = issue_body.get()->generic_u8string(); + auto& fs = paths.get_filesystem(); + const auto path = issue_body->generic_u8string(); + const bool collapsible = is_collapsible_ci_kind(detected_ci); 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)); + collapsible ? msg::format(msgCopyIssueBodyFromCollapsibleSection, msg::path = issue_body->filename()) + : msg::format(msgCopyIssueBodyFromFile, msg::path = 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()) + if (collapsible) { - Command gh("gh"); - gh.string_arg("issue").string_arg("create").string_arg("-R").string_arg("microsoft/vcpkg"); - gh.string_arg("--title").string_arg(fmt::format("[{}] Build failure on {}", spec_name, triplet_name)); - gh.string_arg("--body-file").string_arg(path); - - result.append(msgBuildTroubleshootingMessageGH).append_raw('\n'); - result.append_indent().append_raw(gh.command_line()); + append_file_collapsible(result, detected_ci, fs, *issue_body); + for (Path error_log_path : error_logs) + { + append_file_collapsible(result, detected_ci, fs, error_log_path); + } } - if (ci) + else { - append_file_collapsible(result, *ci.get(), paths.get_filesystem(), *issue_body.get()); - for (Path error_log_path : error_logs) + auto gh_path = fs.find_from_PATH("gh"); + if (!gh_path.empty()) { - append_file_collapsible(result, *ci.get(), paths.get_filesystem(), error_log_path); + Command gh(gh_path[0]); + gh.string_arg("issue").string_arg("create").string_arg("-R").string_arg("microsoft/vcpkg"); + gh.string_arg("--title").string_arg( + fmt::format("[{}] Build failure on {}", spec_name, triplet_name)); + gh.string_arg("--body-file").string_arg(path); + result.append(msgBuildTroubleshootingMessageGH).append_raw('\n'); + result.append_indent().append_raw(gh.command_line()); } } } diff --git a/src/vcpkg/commands.install.cpp b/src/vcpkg/commands.install.cpp index 17730980ff..b7eb7ec8e0 100644 --- a/src/vcpkg/commands.install.cpp +++ b/src/vcpkg/commands.install.cpp @@ -604,8 +604,12 @@ namespace vcpkg { this_install.print_elapsed_time(); print_user_troubleshooting_message( - action, paths, result.error_logs, result.stdoutlog.then([&](auto&) -> Optional { - auto issue_body_path = paths.installed().root() / "vcpkg" / "issue_body.md"; + action, + args.detected_ci(), + paths, + result.error_logs, + result.stdoutlog.then([&](auto&) -> Optional { + auto issue_body_path = paths.installed().root() / FileVcpkg / FileIssueBodyMD; paths.get_filesystem().write_contents( issue_body_path, create_github_issue(args, result, paths, action, include_manifest_in_github_issue), diff --git a/src/vcpkg/commands.z-print-config.cpp b/src/vcpkg/commands.z-print-config.cpp index d5ad761209..9cbb7b9db7 100644 --- a/src/vcpkg/commands.z-print-config.cpp +++ b/src/vcpkg/commands.z-print-config.cpp @@ -48,7 +48,7 @@ namespace vcpkg obj.insert(JsonIdHostTriplet, host_triplet.canonical_name()); obj.insert(JsonIdVcpkgRoot, paths.root.native()); obj.insert(JsonIdTools, paths.tools.native()); - if (auto ci_env = args.detected_ci_environment().get()) + if (auto ci_env = args.detected_ci_environment_name().get()) { obj.insert(JsonIdDetectedCIEnvironment, *ci_env); } diff --git a/src/vcpkg/vcpkgcmdarguments.cpp b/src/vcpkg/vcpkgcmdarguments.cpp index 3f5edcdb9a..ffd8667bee 100644 --- a/src/vcpkg/vcpkgcmdarguments.cpp +++ b/src/vcpkg/vcpkgcmdarguments.cpp @@ -15,55 +15,62 @@ namespace { using namespace vcpkg; - constexpr std::pair KNOWN_CI_VARIABLES[]{ + struct CIRecord + { + StringLiteral env_var; + StringLiteral name; + CIKind type; + }; + + constexpr CIRecord KNOWN_CI_VARIABLES[]{ // Opt-out from CI detection - {EnvironmentVariableVcpkgNoCi, "VCPKG_NO_CI"}, + {EnvironmentVariableVcpkgNoCi, "VCPKG_NO_CI", CIKind::None}, // Azure Pipelines // https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables#system-variables - {EnvironmentVariableTfBuild, "Azure_Pipelines"}, + {EnvironmentVariableTfBuild, "Azure_Pipelines", CIKind::AzurePipelines}, // AppVeyor // https://www.appveyor.com/docs/environment-variables/ - {EnvironmentVariableAppveyor, "AppVeyor"}, + {EnvironmentVariableAppveyor, "AppVeyor", CIKind::AppVeyor}, // AWS Code Build // https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html - {EnvironmentVariableCodebuildBuildId, "AWS_CodeBuild"}, + {EnvironmentVariableCodebuildBuildId, "AWS_CodeBuild", CIKind::AwsCodeBuild}, // CircleCI // https://circleci.com/docs/env-vars#built-in-environment-variables - {EnvironmentVariableCircleCI, "Circle_CI"}, + {EnvironmentVariableCircleCI, "Circle_CI", CIKind::CircleCI}, // GitHub Actions // https://docs.github.com/en/actions/learn-github-actions/ - {EnvironmentVariableGitHubActions, "GitHub_Actions"}, + {EnvironmentVariableGitHubActions, "GitHub_Actions", CIKind::GithubActions}, // GitLab // https://docs.gitlab.com/ee/ci/variables/predefined_variables.html - {EnvironmentVariableGitLabCI, "GitLab_CI"}, + {EnvironmentVariableGitLabCI, "GitLab_CI", CIKind::GitLabCI}, // Heroku // https://devcenter.heroku.com/articles/heroku-ci#immutable-environment-variables - {EnvironmentVariableHerokuTestRunId, "Heroku_CI"}, + {EnvironmentVariableHerokuTestRunId, "Heroku_CI", CIKind::HerokuCI}, // Jenkins // https://wiki.jenkins.io/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-belowJenkinsSetEnvironmentVariables - {EnvironmentVariableJenkinsHome, "Jenkins_CI"}, - {EnvironmentVariableJenkinsUrl, "Jenkins_CI"}, + {EnvironmentVariableJenkinsHome, "Jenkins_CI", CIKind::JenkinsCI}, + {EnvironmentVariableJenkinsUrl, "Jenkins_CI", CIKind::JenkinsCI}, // TeamCity // https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html#Predefined+Server+Build+Parameters - {EnvironmentVariableTeamcityVersion, "TeamCity_CI"}, + {EnvironmentVariableTeamcityVersion, "TeamCity_CI", CIKind::TeamCityCI}, // Travis CI // https://docs.travis-ci.com/user/environment-variables/#default-environment-variables - {EnvironmentVariableTravis, "Travis_CI"}, + {EnvironmentVariableTravis, "Travis_CI", CIKind::TravisCI}, // Generic CI environment variables - {EnvironmentVariableCI, "Generic"}, - {EnvironmentVariableBuildId, "Generic"}, - {EnvironmentVariableBuildNumber, "Generic"}, + {EnvironmentVariableCI, "Generic", CIKind::Generic}, + {EnvironmentVariableBuildId, "Generic", CIKind::Generic}, + {EnvironmentVariableBuildNumber, "Generic", CIKind::Generic}, }; constexpr StringLiteral KNOWN_CI_REPOSITORY_IDENTIFIERS[] = { @@ -581,9 +588,10 @@ namespace vcpkg // detect whether we are running in a CI environment for (auto&& ci_env_var : KNOWN_CI_VARIABLES) { - if (get_env(ci_env_var.first).has_value()) + if (get_env(ci_env_var.env_var).has_value()) { - m_detected_ci_environment = ci_env_var.second; + m_detected_ci_environment_name = ci_env_var.name; + m_detected_ci_environment_type = ci_env_var.type; break; } } @@ -790,7 +798,7 @@ namespace vcpkg void VcpkgCmdArguments::track_environment_metrics() const { MetricsSubmission submission; - if (auto ci_env = m_detected_ci_environment.get()) + if (auto ci_env = m_detected_ci_environment_name.get()) { Debug::println("Detected CI environment: ", *ci_env); submission.track_string(StringMetric::DetectedCiEnvironment, *ci_env); From 9c37d8b4e0288eeb3c0dc85b6c5315aeed77e918 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 16 Jan 2025 01:59:42 -0800 Subject: [PATCH 5/6] Fix build warning on non-Windows. --- src/vcpkg/commands.build.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index b93f7783f6..3f6a451ec4 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -1709,7 +1709,16 @@ namespace vcpkg case CIKind::GithubActions: case CIKind::GitLabCI: case CIKind::AzurePipelines: return true; - default: return false; + case CIKind::None: + case CIKind::AppVeyor: + case CIKind::AwsCodeBuild: + case CIKind::CircleCI: + case CIKind::HerokuCI: + case CIKind::JenkinsCI: + case CIKind::TeamCityCI: + case CIKind::TravisCI: + case CIKind::Generic: return false; + default: Checks::unreachable(VCPKG_LINE_INFO); } } @@ -1718,11 +1727,6 @@ namespace vcpkg const ReadOnlyFilesystem& fs, const Path& file) { - if (!is_collapsible_ci_kind(kind)) - { - Checks::unreachable(VCPKG_LINE_INFO); - } - auto title = file.filename(); auto contents = fs.read_contents(file, VCPKG_LINE_INFO); switch (kind) @@ -1764,6 +1768,16 @@ namespace vcpkg .append_raw(contents) .append_raw("##[endgroup]\n"); break; + case CIKind::None: + case CIKind::AppVeyor: + case CIKind::AwsCodeBuild: + case CIKind::CircleCI: + case CIKind::HerokuCI: + case CIKind::JenkinsCI: + case CIKind::TeamCityCI: + case CIKind::TravisCI: + case CIKind::Generic: Checks::unreachable(VCPKG_LINE_INFO, "CIKind not collapsible"); + default: Checks::unreachable(VCPKG_LINE_INFO); } } From dfe1decc97e91adc80ffd1a4f76e802ea6f8465b Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Fri, 17 Jan 2025 11:56:26 -0800 Subject: [PATCH 6/6] Delocalize issue body message. --- include/vcpkg/base/message-data.inc.h | 5 ----- locales/messages.json | 4 ---- src/vcpkg/commands.build.cpp | 21 +++++++++++---------- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/include/vcpkg/base/message-data.inc.h b/include/vcpkg/base/message-data.inc.h index 282d15d419..c216b38f25 100644 --- a/include/vcpkg/base/message-data.inc.h +++ b/include/vcpkg/base/message-data.inc.h @@ -945,11 +945,6 @@ DECLARE_MESSAGE(ConstraintViolation, (), "", "Found a constraint violation:") DECLARE_MESSAGE(ContinueCodeUnitInStart, (), "", "found continue code unit in start position") DECLARE_MESSAGE(ControlCharacterInString, (), "", "Control character in string") DECLARE_MESSAGE(ControlSupportsMustBeAPlatformExpression, (), "", "\"Supports\" must be a platform expression") -DECLARE_MESSAGE(CopyIssueBodyFromFile, (msg::path), "", "Copy issue body from {path}") -DECLARE_MESSAGE(CopyIssueBodyFromCollapsibleSection, - (msg::path), - "", - "Copy issue body from collapsed section \"{path}\" in the ci log output") DECLARE_MESSAGE(CopyrightIsDir, (), "", diff --git a/locales/messages.json b/locales/messages.json index 8b592c8778..fc195de5f8 100644 --- a/locales/messages.json +++ b/locales/messages.json @@ -546,10 +546,6 @@ "ContinueCodeUnitInStart": "found continue code unit in start position", "ControlCharacterInString": "Control character in string", "ControlSupportsMustBeAPlatformExpression": "\"Supports\" must be a platform expression", - "CopyIssueBodyFromCollapsibleSection": "Copy issue body from collapsed section \"{path}\" in the ci log output", - "_CopyIssueBodyFromCollapsibleSection.comment": "An example of {path} is /foo/bar.", - "CopyIssueBodyFromFile": "Copy issue body from {path}", - "_CopyIssueBodyFromFile.comment": "An example of {path} is /foo/bar.", "CopyrightIsDir": "this port sets ${{CURRENT_PACKAGES_DIR}}/share/${{PORT}}/copyright to a directory, but it should be a file. Consider combining separate copyright files into one using vcpkg_install_copyright. To suppress this message, add set(VCPKG_POLICY_SKIP_COPYRIGHT_CHECK enabled)", "CorruptedDatabase": "vcpkg's installation database corrupted. This is either a bug in vcpkg or something else has modified the contents of the 'installed' directory in an unexpected way. You may be able to fix this by deleting the 'installed' directory and reinstalling what you want to use. If this problem happens consistently, please file a bug at https://github.com/microsoft/vcpkg .", "CorruptedInstallTree": "Your vcpkg 'installed' tree is corrupted.", diff --git a/src/vcpkg/commands.build.cpp b/src/vcpkg/commands.build.cpp index 3f6a451ec4..45a82b1726 100644 --- a/src/vcpkg/commands.build.cpp +++ b/src/vcpkg/commands.build.cpp @@ -1791,20 +1791,18 @@ namespace vcpkg 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'); + result.append(msgBuildTroubleshootingMessage2).append_raw('\n').append_indent(); if (auto issue_body = maybe_issue_body.get()) { auto& fs = paths.get_filesystem(); - const auto path = issue_body->generic_u8string(); - const bool collapsible = is_collapsible_ci_kind(detected_ci); - const auto body = - collapsible ? msg::format(msgCopyIssueBodyFromCollapsibleSection, msg::path = issue_body->filename()) - : msg::format(msgCopyIssueBodyFromFile, msg::path = path); - - result.append_indent().append_raw(make_gh_issue_open_url(spec_name, triplet_name, body)).append_raw('\n'); - if (collapsible) + // The 'body' content is not localized because it becomes part of the posted GitHub issue + // rather than instructions for the current user of vcpkg. + if (is_collapsible_ci_kind(detected_ci)) { + auto body = fmt::format("Copy issue body from collapsed section \"{}\" in the ci log output", + issue_body->filename()); + result.append_raw(make_gh_issue_open_url(spec_name, triplet_name, body)).append_raw('\n'); append_file_collapsible(result, detected_ci, fs, *issue_body); for (Path error_log_path : error_logs) { @@ -1813,6 +1811,9 @@ namespace vcpkg } else { + const auto path = issue_body->generic_u8string(); + auto body = fmt::format("Copy issue body from {}", path); + result.append_raw(make_gh_issue_open_url(spec_name, triplet_name, body)).append_raw('\n'); auto gh_path = fs.find_from_PATH("gh"); if (!gh_path.empty()) { @@ -1828,7 +1829,7 @@ namespace vcpkg } else { - result.append_indent() + result .append_raw("https://github.com/microsoft/vcpkg/issues/" "new?template=report-package-build-failure.md&title=[") .append_raw(spec_name)