diff options
-rw-r--r-- | src/buildtool/serve_api/remote/configuration_client.cpp | 86 | ||||
-rw-r--r-- | src/buildtool/serve_api/remote/configuration_client.hpp | 4 | ||||
-rw-r--r-- | src/buildtool/serve_api/remote/serve_api.hpp | 31 | ||||
-rw-r--r-- | src/buildtool/serve_api/remote/source_tree_client.cpp | 18 | ||||
-rw-r--r-- | src/buildtool/serve_api/remote/source_tree_client.hpp | 16 | ||||
-rw-r--r-- | src/buildtool/serve_api/remote/target_client.cpp | 45 | ||||
-rw-r--r-- | src/buildtool/serve_api/remote/target_client.hpp | 12 | ||||
-rw-r--r-- | src/other_tools/git_operations/git_config_settings.cpp | 4 | ||||
-rw-r--r-- | src/other_tools/just_mr/setup_utils.cpp | 6 | ||||
-rw-r--r-- | src/other_tools/just_mr/setup_utils.hpp | 4 |
10 files changed, 129 insertions, 97 deletions
diff --git a/src/buildtool/serve_api/remote/configuration_client.cpp b/src/buildtool/serve_api/remote/configuration_client.cpp index 032e548f..dcc7d31a 100644 --- a/src/buildtool/serve_api/remote/configuration_client.cpp +++ b/src/buildtool/serve_api/remote/configuration_client.cpp @@ -14,13 +14,14 @@ #include "src/buildtool/serve_api/remote/configuration_client.hpp" +#include <exception> #include <optional> #include "nlohmann/json.hpp" #include "src/buildtool/execution_api/remote/config.hpp" #include "src/buildtool/serve_api/remote/config.hpp" -auto ConfigurationClient::CheckServeRemoteExecution() -> bool { +auto ConfigurationClient::CheckServeRemoteExecution() noexcept -> bool { auto client_remote_address = RemoteExecutionConfig::RemoteAddress(); if (!client_remote_address) { logger_.Emit(LogLevel::Error, @@ -46,49 +47,60 @@ auto ConfigurationClient::CheckServeRemoteExecution() -> bool { LogStatus(&logger_, LogLevel::Error, status); return false; } - auto client_msg = client_remote_address->ToJson().dump(); - std::string serve_msg{}; - if (response.address().empty()) { - // just serve acts as just execute, so from the server's perspective - // there is nothing to be checked and it's the client's job to ensure - // that its remote execution and serve endpoints match - // - // NOTE: This check might make sense to be removed altogether in the - // future, or updated to (at most) a warning. - if (client_remote_address->ToJson() == client_serve_address->ToJson()) { - return true; - } - serve_msg = client_serve_address->ToJson().dump(); - } - else { - nlohmann::json serve_remote_endpoint{}; - try { - serve_remote_endpoint = nlohmann::json::parse(response.address()); - } catch (std::exception const& ex) { - logger_.Emit( - LogLevel::Error, - "Parsing configured address from response failed with:\n{}", - ex.what()); + try { + auto client_msg = client_remote_address->ToJson().dump(); + std::string serve_msg{}; + + if (response.address().empty()) { + // just serve acts as just execute, so from the server's perspective + // there is nothing to be checked and it's the client's job to + // ensure that its remote execution and serve endpoints match + // + // NOTE: This check might make sense to be removed altogether in the + // future, or updated to (at most) a warning. + if (client_remote_address->ToJson() == + client_serve_address->ToJson()) { + return true; + } + serve_msg = client_serve_address->ToJson().dump(); } - if (serve_remote_endpoint == client_remote_address->ToJson()) { - return true; + else { + nlohmann::json serve_remote_endpoint{}; + try { + serve_remote_endpoint = + nlohmann::json::parse(response.address()); + } catch (std::exception const& ex) { + logger_.Emit( + LogLevel::Error, + "Parsing configured address from response failed with:\n{}", + ex.what()); + } + if (serve_remote_endpoint == client_remote_address->ToJson()) { + return true; + } + serve_msg = serve_remote_endpoint.dump(); } - serve_msg = serve_remote_endpoint.dump(); + // log any mismatch found + logger_.Emit( + LogLevel::Error, + "Different execution endpoint detected!\nIn order to correctly use " + "the serve service, its remote execution endpoint must be the same " + "used by the client.\nserve remote endpoint: {}\nclient remote " + "endpoint: {}", + serve_msg, + client_msg); + + } catch (std::exception const& ex) { + logger_.Emit( + LogLevel::Error, + "parsing response for remote endpoint request failed with:\n{}", + ex.what()); } - // log any mismatch found - logger_.Emit( - LogLevel::Error, - "Different execution endpoint detected!\nIn order to correctly use " - "the serve service, its remote execution endpoint must be the same " - "used by the client.\nserve remote endpoint: {}\nclient remote " - "endpoint: {}", - serve_msg, - client_msg); return false; } -auto ConfigurationClient::IsCompatible() -> std::optional<bool> { +auto ConfigurationClient::IsCompatible() noexcept -> std::optional<bool> { grpc::ClientContext context; justbuild::just_serve::CompatibilityRequest request{}; justbuild::just_serve::CompatibilityResponse response{}; diff --git a/src/buildtool/serve_api/remote/configuration_client.hpp b/src/buildtool/serve_api/remote/configuration_client.hpp index f4346a4e..45053c5e 100644 --- a/src/buildtool/serve_api/remote/configuration_client.hpp +++ b/src/buildtool/serve_api/remote/configuration_client.hpp @@ -34,9 +34,9 @@ class ConfigurationClient { : stub_{justbuild::just_serve::Configuration::NewStub( CreateChannelWithCredentials(server, port))} {} - auto CheckServeRemoteExecution() -> bool; + [[nodiscard]] auto CheckServeRemoteExecution() noexcept -> bool; - [[nodiscard]] auto IsCompatible() -> std::optional<bool>; + [[nodiscard]] auto IsCompatible() noexcept -> std::optional<bool>; private: std::unique_ptr<justbuild::just_serve::Configuration::Stub> stub_; diff --git a/src/buildtool/serve_api/remote/serve_api.hpp b/src/buildtool/serve_api/remote/serve_api.hpp index 45a74c33..c2ad5353 100644 --- a/src/buildtool/serve_api/remote/serve_api.hpp +++ b/src/buildtool/serve_api/remote/serve_api.hpp @@ -44,7 +44,7 @@ class ServeApi final { [[nodiscard]] static auto RetrieveTreeFromCommit( std::string const& commit, std::string const& subdir = ".", - bool sync_tree = false) -> std::variant<bool, std::string> { + bool sync_tree = false) noexcept -> std::variant<bool, std::string> { return Instance().stc_->ServeCommitTree(commit, subdir, sync_tree); } @@ -53,7 +53,7 @@ class ServeApi final { std::string const& archive_type = "archive", std::string const& subdir = ".", std::optional<PragmaSpecial> const& resolve_symlinks = std::nullopt, - bool sync_tree = false) -> std::variant<bool, std::string> { + bool sync_tree = false) noexcept -> std::variant<bool, std::string> { return Instance().stc_->ServeArchiveTree( content, archive_type, subdir, resolve_symlinks, sync_tree); } @@ -61,34 +61,35 @@ class ServeApi final { [[nodiscard]] static auto RetrieveTreeFromDistdir( std::shared_ptr<std::unordered_map<std::string, std::string>> const& distfiles, - bool sync_tree = false) -> std::variant<bool, std::string> { + bool sync_tree = false) noexcept -> std::variant<bool, std::string> { return Instance().stc_->ServeDistdirTree(distfiles, sync_tree); } - [[nodiscard]] static auto ContentInRemoteCAS(std::string const& content) - -> bool { + [[nodiscard]] static auto ContentInRemoteCAS( + std::string const& content) noexcept -> bool { return Instance().stc_->ServeContent(content); } - [[nodiscard]] static auto TreeInRemoteCAS(std::string const& tree_id) - -> bool { + [[nodiscard]] static auto TreeInRemoteCAS( + std::string const& tree_id) noexcept -> bool { return Instance().stc_->ServeTree(tree_id); } - [[nodiscard]] static auto CheckRootTree(std::string const& tree_id) + [[nodiscard]] static auto CheckRootTree(std::string const& tree_id) noexcept -> std::optional<bool> { return Instance().stc_->CheckRootTree(tree_id); } - [[nodiscard]] static auto GetTreeFromRemote(std::string const& tree_id) - -> bool { + [[nodiscard]] static auto GetTreeFromRemote( + std::string const& tree_id) noexcept -> bool { return Instance().stc_->GetRemoteTree(tree_id); } [[nodiscard]] static auto ServeTargetVariables( std::string const& target_root_id, std::string const& target_file, - std::string const& target) -> std::optional<std::vector<std::string>> { + std::string const& target) noexcept + -> std::optional<std::vector<std::string>> { return Instance().tc_->ServeTargetVariables( target_root_id, target_file, target); } @@ -96,22 +97,22 @@ class ServeApi final { [[nodiscard]] static auto ServeTargetDescription( std::string const& target_root_id, std::string const& target_file, - std::string const& target) -> std::optional<ArtifactDigest> { + std::string const& target) noexcept -> std::optional<ArtifactDigest> { return Instance().tc_->ServeTargetDescription( target_root_id, target_file, target); } [[nodiscard]] static auto ServeTarget(const TargetCacheKey& key, - const std::string& repo_key) + const std::string& repo_key) noexcept -> std::optional<std::pair<TargetCacheEntry, Artifact::ObjectInfo>> { return Instance().tc_->ServeTarget(key, repo_key); } - [[nodiscard]] static auto CheckServeRemoteExecution() -> bool { + [[nodiscard]] static auto CheckServeRemoteExecution() noexcept -> bool { return Instance().cc_->CheckServeRemoteExecution(); } - [[nodiscard]] static auto IsCompatible() -> std::optional<bool> { + [[nodiscard]] static auto IsCompatible() noexcept -> std::optional<bool> { return Instance().cc_->IsCompatible(); } diff --git a/src/buildtool/serve_api/remote/source_tree_client.cpp b/src/buildtool/serve_api/remote/source_tree_client.cpp index 8267df7f..a998e1a1 100644 --- a/src/buildtool/serve_api/remote/source_tree_client.cpp +++ b/src/buildtool/serve_api/remote/source_tree_client.cpp @@ -18,7 +18,7 @@ namespace { -auto StringToArchiveType(std::string const& type) +auto StringToArchiveType(std::string const& type) noexcept -> justbuild::just_serve::ServeArchiveTreeRequest_ArchiveType { using ServeArchiveType = justbuild::just_serve::ServeArchiveTreeRequest_ArchiveType; @@ -64,7 +64,7 @@ SourceTreeClient::SourceTreeClient(std::string const& server, auto SourceTreeClient::ServeCommitTree(std::string const& commit_id, std::string const& subdir, - bool sync_tree) -> result_t { + bool sync_tree) noexcept -> result_t { justbuild::just_serve::ServeCommitTreeRequest request{}; request.set_commit(commit_id); request.set_subdir(subdir); @@ -95,7 +95,7 @@ auto SourceTreeClient::ServeArchiveTree( std::string const& archive_type, std::string const& subdir, std::optional<PragmaSpecial> const& resolve_symlinks, - bool sync_tree) -> result_t { + bool sync_tree) noexcept -> result_t { justbuild::just_serve::ServeArchiveTreeRequest request{}; request.set_content(content); request.set_archive_type(StringToArchiveType(archive_type)); @@ -127,7 +127,7 @@ auto SourceTreeClient::ServeArchiveTree( auto SourceTreeClient::ServeDistdirTree( std::shared_ptr<std::unordered_map<std::string, std::string>> const& distfiles, - bool sync_tree) -> result_t { + bool sync_tree) noexcept -> result_t { justbuild::just_serve::ServeDistdirTreeRequest request{}; for (auto const& [k, v] : *distfiles) { auto* distfile = request.add_distfiles(); @@ -156,7 +156,8 @@ auto SourceTreeClient::ServeDistdirTree( return response.tree(); // success } -auto SourceTreeClient::ServeContent(std::string const& content) -> bool { +auto SourceTreeClient::ServeContent(std::string const& content) noexcept + -> bool { justbuild::just_serve::ServeContentRequest request{}; request.set_content(content); @@ -178,7 +179,7 @@ auto SourceTreeClient::ServeContent(std::string const& content) -> bool { return true; } -auto SourceTreeClient::ServeTree(std::string const& tree_id) -> bool { +auto SourceTreeClient::ServeTree(std::string const& tree_id) noexcept -> bool { justbuild::just_serve::ServeTreeRequest request{}; request.set_tree(tree_id); @@ -199,7 +200,7 @@ auto SourceTreeClient::ServeTree(std::string const& tree_id) -> bool { return true; } -auto SourceTreeClient::CheckRootTree(std::string const& tree_id) +auto SourceTreeClient::CheckRootTree(std::string const& tree_id) noexcept -> std::optional<bool> { justbuild::just_serve::CheckRootTreeRequest request{}; request.set_tree(tree_id); @@ -226,7 +227,8 @@ auto SourceTreeClient::CheckRootTree(std::string const& tree_id) return true; // tree found } -auto SourceTreeClient::GetRemoteTree(std::string const& tree_id) -> bool { +auto SourceTreeClient::GetRemoteTree(std::string const& tree_id) noexcept + -> bool { justbuild::just_serve::GetRemoteTreeRequest request{}; request.set_tree(tree_id); diff --git a/src/buildtool/serve_api/remote/source_tree_client.hpp b/src/buildtool/serve_api/remote/source_tree_client.hpp index 24b2654a..46b17081 100644 --- a/src/buildtool/serve_api/remote/source_tree_client.hpp +++ b/src/buildtool/serve_api/remote/source_tree_client.hpp @@ -44,7 +44,7 @@ class SourceTreeClient { /// at index 1 the tree identifier on success. [[nodiscard]] auto ServeCommitTree(std::string const& commit_id, std::string const& subdir, - bool sync_tree) -> result_t; + bool sync_tree) noexcept -> result_t; /// \brief Retrieve the Git tree of an archive content, if known by the /// endpoint. It is a fatal error if the content blob is known to the @@ -63,7 +63,7 @@ class SourceTreeClient { std::string const& archive_type, std::string const& subdir, std::optional<PragmaSpecial> const& resolve_symlinks, - bool sync_tree) -> result_t; + bool sync_tree) noexcept -> result_t; /// \brief Retrieve the Git tree of a directory of distfiles, if all the /// content blobs are known by the endpoint. It is a fatal error if all @@ -77,26 +77,27 @@ class SourceTreeClient { [[nodiscard]] auto ServeDistdirTree( std::shared_ptr<std::unordered_map<std::string, std::string>> const& distfiles, - bool sync_tree) -> result_t; + bool sync_tree) noexcept -> result_t; /// \brief Make a given content blob available in remote CAS, if known by /// serve remote. /// \param[in] content Hash of the archive content to look up. /// \returns Flag to state whether content is in remote CAS. - [[nodiscard]] auto ServeContent(std::string const& content) -> bool; + [[nodiscard]] auto ServeContent(std::string const& content) noexcept + -> bool; /// \brief Make a given tree available in remote CAS, if known by serve /// remote. /// \param[in] tree_id Identifier of the Git tree to look up. /// \returns Flag to state whether tree is in remote CAS. - [[nodiscard]] auto ServeTree(std::string const& tree_id) -> bool; + [[nodiscard]] auto ServeTree(std::string const& tree_id) noexcept -> bool; /// \brief Checks if the serve endpoint has a given tree locally available /// and makes it available for a serve-orchestrated build. /// \param[in] tree_id Identifier of the Git tree to look up. /// \returns Flag to state whether tree is known or not, or nullopt on /// errors. - [[nodiscard]] auto CheckRootTree(std::string const& tree_id) + [[nodiscard]] auto CheckRootTree(std::string const& tree_id) noexcept -> std::optional<bool>; /// \brief Retrieve tree from the CAS of the associated remote-execution @@ -104,7 +105,8 @@ class SourceTreeClient { /// \param[in] tree_id Identifier of the Git tree to retrieve. /// \returns Flag to state whether tree was successfully imported into the /// local Git storage or not. - [[nodiscard]] auto GetRemoteTree(std::string const& tree_id) -> bool; + [[nodiscard]] auto GetRemoteTree(std::string const& tree_id) noexcept + -> bool; private: std::unique_ptr<justbuild::just_serve::SourceTree::Stub> stub_; diff --git a/src/buildtool/serve_api/remote/target_client.cpp b/src/buildtool/serve_api/remote/target_client.cpp index d30d4541..3c84e43d 100644 --- a/src/buildtool/serve_api/remote/target_client.cpp +++ b/src/buildtool/serve_api/remote/target_client.cpp @@ -14,6 +14,7 @@ #include "src/buildtool/serve_api/remote/target_client.hpp" +#include <exception> #include <utility> #include "nlohmann/json.hpp" @@ -26,7 +27,7 @@ TargetClient::TargetClient(std::string const& server, Port port) noexcept { } auto TargetClient::ServeTarget(const TargetCacheKey& key, - const std::string& repo_key) + const std::string& repo_key) noexcept -> std::optional<std::pair<TargetCacheEntry, Artifact::ObjectInfo>> { // make sure the blob containing the key is in the remote cas if (!local_api_->RetrieveToCas({key.Id()}, &*remote_api_)) { @@ -58,15 +59,22 @@ auto TargetClient::ServeTarget(const TargetCacheKey& key, prop->set_value(v); } - // add dispatch information to request, while ensuring blob is uploaded to - // remote cas + // add dispatch information to request, while ensuring blob is uploaded + // to remote cas auto dispatch_list = nlohmann::json::array(); - for (auto const& [props, endpoint] : - RemoteExecutionConfig::DispatchList()) { - auto entry = nlohmann::json::array(); - entry.push_back(nlohmann::json(props)); - entry.push_back(endpoint.ToJson()); - dispatch_list.push_back(entry); + try { + for (auto const& [props, endpoint] : + RemoteExecutionConfig::DispatchList()) { + auto entry = nlohmann::json::array(); + entry.push_back(nlohmann::json(props)); + entry.push_back(endpoint.ToJson()); + dispatch_list.push_back(entry); + } + } catch (std::exception const& ex) { + logger_.Emit(LogLevel::Performance, + "populating dispatch JSON array failed with:\n{}", + ex.what()); + return std::nullopt; } auto dispatch_dgst = @@ -95,6 +103,7 @@ auto TargetClient::ServeTarget(const TargetCacheKey& key, LogStatus(&logger_, LogLevel::Performance, status); return std::nullopt; } + auto const& target_value_dgst = ArtifactDigest{response.target_value()}; auto const& obj_info = Artifact::ObjectInfo{.digest = target_value_dgst, .type = ObjectType::File}; @@ -114,15 +123,21 @@ auto TargetClient::ServeTarget(const TargetCacheKey& key, obj_info.ToString()); return std::nullopt; } - auto const& result = - TargetCacheEntry::FromJson(nlohmann::json::parse(*target_value_str)); - - return std::make_pair(result, obj_info); + try { + auto const& result = TargetCacheEntry::FromJson( + nlohmann::json::parse(*target_value_str)); + return std::make_pair(result, obj_info); + } catch (std::exception const& ex) { + logger_.Emit(LogLevel::Performance, + "parsing target cache value failed with:\n{}", + ex.what()); + return std::nullopt; + } } auto TargetClient::ServeTargetVariables(std::string const& target_root_id, std::string const& target_file, - std::string const& target) + std::string const& target) noexcept -> std::optional<std::vector<std::string>> { justbuild::just_serve::ServeTargetVariablesRequest request{}; request.set_root_tree(target_root_id); @@ -152,7 +167,7 @@ auto TargetClient::ServeTargetVariables(std::string const& target_root_id, auto TargetClient::ServeTargetDescription(std::string const& target_root_id, std::string const& target_file, - std::string const& target) + std::string const& target) noexcept -> std::optional<ArtifactDigest> { justbuild::just_serve::ServeTargetDescriptionRequest request{}; request.set_root_tree(target_root_id); diff --git a/src/buildtool/serve_api/remote/target_client.hpp b/src/buildtool/serve_api/remote/target_client.hpp index 66c6dcf2..5b21208e 100644 --- a/src/buildtool/serve_api/remote/target_client.hpp +++ b/src/buildtool/serve_api/remote/target_client.hpp @@ -42,7 +42,7 @@ class TargetClient { /// \param[in] repo_key The RepositoryKey to upload as precondition /// \returns Pair of cache entry and its object info on success or nullopt. [[nodiscard]] auto ServeTarget(const TargetCacheKey& key, - const std::string& repo_key) + const std::string& repo_key) noexcept -> std::optional<std::pair<TargetCacheEntry, Artifact::ObjectInfo>>; /// \brief Retrieve the flexible config variables of an export target. @@ -52,7 +52,7 @@ class TargetClient { /// \returns The list of flexible config variables, or nullopt on errors. [[nodiscard]] auto ServeTargetVariables(std::string const& target_root_id, std::string const& target_file, - std::string const& target) + std::string const& target) noexcept -> std::optional<std::vector<std::string>>; /// \brief Retrieve the artifact digest of the blob containing the export @@ -61,10 +61,10 @@ class TargetClient { /// \param[in] target_file Relative path of the target file. /// \param[in] target Name of the target to interrogate. /// \returns The artifact digest, or nullopt on errors. - [[nodiscard]] auto ServeTargetDescription(std::string const& target_root_id, - std::string const& target_file, - std::string const& target) - -> std::optional<ArtifactDigest>; + [[nodiscard]] auto ServeTargetDescription( + std::string const& target_root_id, + std::string const& target_file, + std::string const& target) noexcept -> std::optional<ArtifactDigest>; private: std::unique_ptr<justbuild::just_serve::Target::Stub> stub_; diff --git a/src/other_tools/git_operations/git_config_settings.cpp b/src/other_tools/git_operations/git_config_settings.cpp index a6291c4b..c820aa32 100644 --- a/src/other_tools/git_operations/git_config_settings.cpp +++ b/src/other_tools/git_operations/git_config_settings.cpp @@ -67,8 +67,8 @@ struct ConfigKeyMatchCompare { /// in a more permissive way, mirroring what git and curl internally do, then /// returns the reconstructed URL if parsing succeeded, or a nullopt ProxyInfo. /// Returns nullopt on unexpected errors. -[[nodiscard]] auto GetProxyAsPermissiveUrl(std::string const& proxy_url) - -> std::optional<ProxyInfo> { +[[nodiscard]] auto GetProxyAsPermissiveUrl( + std::string const& proxy_url) noexcept -> std::optional<ProxyInfo> { // parse proxy string with permissive options: // use_non_support_scheme allows for non-standard schemes to be parsed; // use_guess_scheme tries to figure out the scheme from the hostname if none diff --git a/src/other_tools/just_mr/setup_utils.cpp b/src/other_tools/just_mr/setup_utils.cpp index c6805e07..43d19709 100644 --- a/src/other_tools/just_mr/setup_utils.cpp +++ b/src/other_tools/just_mr/setup_utils.cpp @@ -32,7 +32,7 @@ namespace { -void SetupAuthConfig(MultiRepoRemoteAuthArguments const& authargs) { +void SetupAuthConfig(MultiRepoRemoteAuthArguments const& authargs) noexcept { bool use_tls{false}; if (authargs.tls_ca_cert) { use_tls = true; @@ -237,7 +237,7 @@ auto ReadConfiguration( auto GetRemoteApi(std::optional<std::string> const& remote_exec_addr, std::optional<std::string> const& remote_serve_addr, - MultiRepoRemoteAuthArguments const& auth) + MultiRepoRemoteAuthArguments const& auth) noexcept -> IExecutionApi::Ptr { // if only a serve endpoint address is given, we assume it is one that acts // also as remote-execution @@ -262,7 +262,7 @@ auto GetRemoteApi(std::optional<std::string> const& remote_exec_addr, } auto SetupServeApi(std::optional<std::string> const& remote_serve_addr, - MultiRepoRemoteAuthArguments const& auth) -> bool { + MultiRepoRemoteAuthArguments const& auth) noexcept -> bool { if (remote_serve_addr) { // setup authentication SetupAuthConfig(auth); diff --git a/src/other_tools/just_mr/setup_utils.hpp b/src/other_tools/just_mr/setup_utils.hpp index 11d4af45..278658c1 100644 --- a/src/other_tools/just_mr/setup_utils.hpp +++ b/src/other_tools/just_mr/setup_utils.hpp @@ -66,13 +66,13 @@ void DefaultReachableRepositories( [[nodiscard]] auto GetRemoteApi( std::optional<std::string> const& remote_exec_addr, std::optional<std::string> const& remote_serve_addr, - MultiRepoRemoteAuthArguments const& auth) -> IExecutionApi::Ptr; + MultiRepoRemoteAuthArguments const& auth) noexcept -> IExecutionApi::Ptr; /// \brief Setup of a 'just serve' remote API based on just-mr arguments. /// \returns Flag stating whether a serve API is available or not. [[nodiscard]] auto SetupServeApi( std::optional<std::string> const& remote_serve_addr, - MultiRepoRemoteAuthArguments const& auth) -> bool; + MultiRepoRemoteAuthArguments const& auth) noexcept -> bool; } // namespace Utils |