diff --git a/include/vcpkg/base/downloads.h b/include/vcpkg/base/downloads.h index e996024570..b161bd2d4c 100644 --- a/include/vcpkg/base/downloads.h +++ b/include/vcpkg/base/downloads.h @@ -37,6 +37,10 @@ namespace vcpkg const std::string& github_repository, const Json::Object& snapshot); + // Builds the dependency graph snapshots endpoint used for GitHub submission. + std::string github_dependency_graph_snapshots_uri(const Optional& maybe_github_server_url, + StringView github_repository); + std::vector url_heads(DiagnosticContext& context, View urls, View headers); struct AssetCachingSettings diff --git a/src/vcpkg-test/downloads.cpp b/src/vcpkg-test/downloads.cpp index dba4b05005..4b66480c1b 100644 --- a/src/vcpkg-test/downloads.cpp +++ b/src/vcpkg-test/downloads.cpp @@ -53,6 +53,32 @@ TEST_CASE ("url_encode_spaces", "[downloads]") "https://example.com/a%20%20space/b?query=value&query2=value2"); } +TEST_CASE ("github_dependency_graph_snapshots_uri", "[downloads]") +{ + REQUIRE(github_dependency_graph_snapshots_uri(nullopt, "owner/repo") == + "https://api.github.com/repos/owner/repo/dependency-graph/snapshots"); + + REQUIRE(github_dependency_graph_snapshots_uri(Optional{"https://github.com"}, "owner/repo") == + "https://api.github.com/repos/owner/repo/dependency-graph/snapshots"); + + REQUIRE(github_dependency_graph_snapshots_uri(Optional{"https://github.com/"}, "owner/repo") == + "https://api.github.com/repos/owner/repo/dependency-graph/snapshots"); + + REQUIRE(github_dependency_graph_snapshots_uri(Optional{"https://github.example.com"}, "owner/repo") == + "https://github.example.com/api/v3/repos/owner/repo/dependency-graph/snapshots"); + + REQUIRE(github_dependency_graph_snapshots_uri(Optional{"https://github.example.com/"}, "owner/repo") == + "https://github.example.com/api/v3/repos/owner/repo/dependency-graph/snapshots"); + + REQUIRE(github_dependency_graph_snapshots_uri(Optional{"https://user:pass@github.example.com:443"}, + "owner/repo") == + "https://user:pass@github.example.com:443/api/v3/repos/owner/repo/dependency-graph/snapshots"); + + REQUIRE( + github_dependency_graph_snapshots_uri(Optional{"https://github.com"}, "owner/repo with space") == + "https://api.github.com/repos/owner/repo%20with%20space/dependency-graph/snapshots"); +} + /* * To run this test: * - Set environment variables VCPKG_TEST_AZBLOB_URL and VCPKG_TEST_AZBLOB_SAS. diff --git a/src/vcpkg/base/downloads.cpp b/src/vcpkg/base/downloads.cpp index 22f1bb9b3f..ac1580e6b4 100644 --- a/src/vcpkg/base/downloads.cpp +++ b/src/vcpkg/base/downloads.cpp @@ -287,19 +287,7 @@ namespace vcpkg const std::string& github_repository, const Json::Object& snapshot) { - std::string uri; - if (auto github_server_url = maybe_github_server_url.get()) - { - uri = *github_server_url; - uri.append("/api/v3"); - } - else - { - uri = "https://api.github.com"; - } - - fmt::format_to( - std::back_inserter(uri), "/repos/{}/dependency-graph/snapshots", url_encode_spaces(github_repository)); + const auto uri = github_dependency_graph_snapshots_uri(maybe_github_server_url, github_repository); CurlEasyHandle handle; CURL* curl = handle.get(); @@ -334,6 +322,40 @@ namespace vcpkg return response_code >= 200 && response_code < 300; } + std::string github_dependency_graph_snapshots_uri(const Optional& maybe_github_server_url, + StringView github_repository) + { + std::string uri; + constexpr StringLiteral github_com_url = "https://github.com"; + constexpr StringLiteral api_github_com_url = "https://api.github.com"; + if (auto github_server_url = maybe_github_server_url.get()) + { + StringView normalized_server_url = *github_server_url; + if (!normalized_server_url.empty() && normalized_server_url[normalized_server_url.size() - 1] == '/') + { + normalized_server_url = normalized_server_url.substr(0, normalized_server_url.size() - 1); + } + + if (normalized_server_url == github_com_url) + { + uri.assign(api_github_com_url.data(), api_github_com_url.size()); + } + else + { + uri.assign(normalized_server_url.data(), normalized_server_url.size()); + uri.append("/api/v3"); + } + } + else + { + uri.assign(api_github_com_url.data(), api_github_com_url.size()); + } + + fmt::format_to( + std::back_inserter(uri), "/repos/{}/dependency-graph/snapshots", url_encode_spaces(github_repository)); + return uri; + } + static size_t read_file_callback(char* buffer, size_t size, size_t nitems, void* param) { auto* file = static_cast(param);