@@ -207,7 +207,7 @@ namespace vcpkg
207
207
msg::print (Color::warning, warnings);
208
208
}
209
209
msg::println_error (create_error_message (result, spec));
210
- msg::print (create_user_troubleshooting_message (*action, paths, nullopt));
210
+ msg::print (create_user_troubleshooting_message (*action, args. detected_ci (), paths, {} , nullopt));
211
211
return 1 ;
212
212
}
213
213
case BuildResult::Excluded:
@@ -1694,43 +1694,144 @@ namespace vcpkg
1694
1694
return " https://github.com/microsoft/vcpkg/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+" + spec_name;
1695
1695
}
1696
1696
1697
- static std::string make_gh_issue_open_url (StringView spec_name, StringView triplet, StringView path )
1697
+ static std::string make_gh_issue_open_url (StringView spec_name, StringView triplet, StringView body )
1698
1698
{
1699
1699
return Strings::concat (" https://github.com/microsoft/vcpkg/issues/new?title=[" ,
1700
1700
spec_name,
1701
1701
" ]+Build+error+on+" ,
1702
1702
triplet,
1703
- " &body=Copy+issue+body+from+" ,
1704
- Strings::percent_encode (path));
1703
+ " &body=" ,
1704
+ Strings::percent_encode (body));
1705
+ }
1706
+
1707
+ static bool is_collapsible_ci_kind (CIKind kind)
1708
+ {
1709
+ switch (kind)
1710
+ {
1711
+ case CIKind::GithubActions:
1712
+ case CIKind::GitLabCI:
1713
+ case CIKind::AzurePipelines: return true ;
1714
+ case CIKind::None:
1715
+ case CIKind::AppVeyor:
1716
+ case CIKind::AwsCodeBuild:
1717
+ case CIKind::CircleCI:
1718
+ case CIKind::HerokuCI:
1719
+ case CIKind::JenkinsCI:
1720
+ case CIKind::TeamCityCI:
1721
+ case CIKind::TravisCI:
1722
+ case CIKind::Generic: return false ;
1723
+ default : Checks::unreachable (VCPKG_LINE_INFO);
1724
+ }
1725
+ }
1726
+
1727
+ static void append_file_collapsible (LocalizedString& output,
1728
+ CIKind kind,
1729
+ const ReadOnlyFilesystem& fs,
1730
+ const Path& file)
1731
+ {
1732
+ auto title = file.filename ();
1733
+ auto contents = fs.read_contents (file, VCPKG_LINE_INFO);
1734
+ switch (kind)
1735
+ {
1736
+ case CIKind::GithubActions:
1737
+ // https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#grouping-log-lines
1738
+ output.append_raw (" ::group::" )
1739
+ .append_raw (title)
1740
+ .append_raw (' \n ' )
1741
+ .append_raw (contents)
1742
+ .append_raw (" ::endgroup::\n " );
1743
+ break ;
1744
+ case CIKind::GitLabCI:
1745
+ {
1746
+ // https://docs.gitlab.com/ee/ci/jobs/job_logs.html#custom-collapsible-sections
1747
+ using namespace std ::chrono;
1748
+ std::string section_name;
1749
+ std::copy_if (title.begin (), title.end (), std::back_inserter (section_name), [](char c) {
1750
+ return c == ' .' || ParserBase::is_alphanum (c);
1751
+ });
1752
+ const auto timestamp = duration_cast<seconds>(system_clock::now ().time_since_epoch ()).count ();
1753
+ output
1754
+ .append_raw (
1755
+ fmt::format (" \\ e[0Ksection_start:{}:{}[collapsed=true]\r\\ e[0K" , timestamp, section_name))
1756
+ .append_raw (title)
1757
+ .append_raw (' \n ' )
1758
+ .append_raw (contents)
1759
+ .append_raw (fmt::format (" \\ e[0Ksection_end:{}:{}\r\\ e[0K\n " , timestamp, section_name));
1760
+ }
1761
+ break ;
1762
+ case CIKind::AzurePipelines:
1763
+ // https://learn.microsoft.com/en-us/azure/devops/pipelines/scripts/logging-commands?view=azure-devops&tabs=bash#formatting-commands
1764
+ output.append_raw (" ##vso[task.uploadfile]" )
1765
+ .append_raw (file)
1766
+ .append_raw (' \n ' )
1767
+ .append_raw (" ##[group]" )
1768
+ .append_raw (title)
1769
+ .append_raw (' \n ' )
1770
+ .append_raw (contents)
1771
+ .append_raw (" ##[endgroup]\n " );
1772
+ break ;
1773
+ case CIKind::None:
1774
+ case CIKind::AppVeyor:
1775
+ case CIKind::AwsCodeBuild:
1776
+ case CIKind::CircleCI:
1777
+ case CIKind::HerokuCI:
1778
+ case CIKind::JenkinsCI:
1779
+ case CIKind::TeamCityCI:
1780
+ case CIKind::TravisCI:
1781
+ case CIKind::Generic: Checks::unreachable (VCPKG_LINE_INFO, " CIKind not collapsible" );
1782
+ default : Checks::unreachable (VCPKG_LINE_INFO);
1783
+ }
1705
1784
}
1706
1785
1707
1786
LocalizedString create_user_troubleshooting_message (const InstallPlanAction& action,
1787
+ CIKind detected_ci,
1708
1788
const VcpkgPaths& paths,
1709
- const Optional<Path>& issue_body)
1789
+ const std::vector<std::string>& error_logs,
1790
+ const Optional<Path>& maybe_issue_body)
1710
1791
{
1711
1792
const auto & spec_name = action.spec .name ();
1712
1793
const auto & triplet_name = action.spec .triplet ().to_string ();
1713
1794
LocalizedString result = msg::format (msgBuildTroubleshootingMessage1).append_raw (' \n ' );
1714
1795
result.append_indent ().append_raw (make_gh_issue_search_url (spec_name)).append_raw (' \n ' );
1715
- result.append (msgBuildTroubleshootingMessage2).append_raw (' \n ' );
1716
- if (issue_body.has_value ())
1796
+ result.append (msgBuildTroubleshootingMessage2).append_raw (' \n ' ).append_indent ();
1797
+
1798
+ if (auto issue_body = maybe_issue_body.get ())
1717
1799
{
1718
- const auto path = issue_body.get ()->generic_u8string ();
1719
- result.append_indent ().append_raw (make_gh_issue_open_url (spec_name, triplet_name, path)).append_raw (' \n ' );
1720
- if (!paths.get_filesystem ().find_from_PATH (" gh" ).empty ())
1800
+ auto & fs = paths.get_filesystem ();
1801
+ // The 'body' content is not localized because it becomes part of the posted GitHub issue
1802
+ // rather than instructions for the current user of vcpkg.
1803
+ if (is_collapsible_ci_kind (detected_ci))
1721
1804
{
1722
- Command gh (" gh" );
1723
- gh.string_arg (" issue" ).string_arg (" create" ).string_arg (" -R" ).string_arg (" microsoft/vcpkg" );
1724
- gh.string_arg (" --title" ).string_arg (fmt::format (" [{}] Build failure on {}" , spec_name, triplet_name));
1725
- gh.string_arg (" --body-file" ).string_arg (path);
1726
-
1727
- result.append (msgBuildTroubleshootingMessageGH).append_raw (' \n ' );
1728
- result.append_indent ().append_raw (gh.command_line ());
1805
+ auto body = fmt::format (" Copy issue body from collapsed section \" {}\" in the ci log output" ,
1806
+ issue_body->filename ());
1807
+ result.append_raw (make_gh_issue_open_url (spec_name, triplet_name, body)).append_raw (' \n ' );
1808
+ append_file_collapsible (result, detected_ci, fs, *issue_body);
1809
+ for (Path error_log_path : error_logs)
1810
+ {
1811
+ append_file_collapsible (result, detected_ci, fs, error_log_path);
1812
+ }
1813
+ }
1814
+ else
1815
+ {
1816
+ const auto path = issue_body->generic_u8string ();
1817
+ auto body = fmt::format (" Copy issue body from {}" , path);
1818
+ result.append_raw (make_gh_issue_open_url (spec_name, triplet_name, body)).append_raw (' \n ' );
1819
+ auto gh_path = fs.find_from_PATH (" gh" );
1820
+ if (!gh_path.empty ())
1821
+ {
1822
+ Command gh (gh_path[0 ]);
1823
+ gh.string_arg (" issue" ).string_arg (" create" ).string_arg (" -R" ).string_arg (" microsoft/vcpkg" );
1824
+ gh.string_arg (" --title" ).string_arg (
1825
+ fmt::format (" [{}] Build failure on {}" , spec_name, triplet_name));
1826
+ gh.string_arg (" --body-file" ).string_arg (path);
1827
+ result.append (msgBuildTroubleshootingMessageGH).append_raw (' \n ' );
1828
+ result.append_indent ().append_raw (gh.command_line ());
1829
+ }
1729
1830
}
1730
1831
}
1731
1832
else
1732
1833
{
1733
- result. append_indent ()
1834
+ result
1734
1835
.append_raw (" https://github.com/microsoft/vcpkg/issues/"
1735
1836
" new?template=report-package-build-failure.md&title=[" )
1736
1837
.append_raw (spec_name)
0 commit comments