From 7d7543ca663cdcff91016f13b01dc4e557500b2e Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Thu, 10 Sep 2020 17:51:49 +0300 Subject: Fix bdep-release failing for branch name with slash Also fix the similar bug in bdep-ci. --- bdep/ci.cxx | 39 ++++++++++++++++++++++++++++++++------- bdep/release.cxx | 28 ++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/bdep/ci.cxx b/bdep/ci.cxx index 2f07957..b7fe2cf 100644 --- a/bdep/ci.cxx +++ b/bdep/ci.cxx @@ -22,6 +22,11 @@ namespace bdep { using bpkg::repository_location; + // Note: the git_status() function, that we use, requires git 2.11.0 or + // higher. + // + static const semantic_version git_ver {2, 11, 0}; + static const url default_server ( #ifdef BDEP_STAGE "https://ci.stage.build2.org" @@ -67,15 +72,35 @@ namespace bdep info << "run 'git status' for details"; // Upstream is normally in the / form, for example - // 'origin/master'. + // 'origin/master'. Note, however, that we cannot unambiguously split it + // into the remote and branch names (see release.cxx for details). // - if (s.upstream.empty ()) - fail << "no upstream branch set for local branch '" - << s.branch << "'" << - info << "run 'git push --set-upstream' to set"; + { + if (s.upstream.empty ()) + fail << "no upstream branch set for local branch '" + << s.branch << "'" << + info << "run 'git push --set-upstream' to set"; + + optional rem (git_line (git_ver, + prj, + false /* ignore_error */, + "config", + "branch." + s.branch + ".remote")); + + if (!rem) + fail << "unable to obtain remote for '" << s.branch << "'"; + + // For good measure verify that the remote name is a prefix for the + // upstream branch. + // + size_t n (rem->size ()); + if (s.upstream.compare (0, n, *rem) != 0 || + !path::traits_type::is_separator (s.upstream[n])) + fail << "remote '" << *rem << "' is not a prefix for upstream " + << "branch '" << s.upstream << "'"; - size_t p (path::traits_type::rfind_separator (s.upstream)); - branch = p != string::npos ? string (s.upstream, p + 1) : s.upstream; + branch.assign (s.upstream, n + 1); + } // Note: not forcible (for now). While the use case is valid, the // current and committed package versions are likely to differ (in diff --git a/bdep/release.cxx b/bdep/release.cxx index 2532242..66b4a30 100644 --- a/bdep/release.cxx +++ b/bdep/release.cxx @@ -1189,17 +1189,24 @@ namespace bdep // the repository and refspecs explicitly. // // Upstream is normally in the / form, for example - // 'origin/master'. + // 'origin/master'. Note, however, that if any of these names contains + // '/', then the split is ambiguous. Thus, we retrieve the remote name + // via git-config and use it to also deduce the remote branch name from + // the upstream branch. // string remote; string brspec; { - size_t p (path::traits_type::rfind_separator (st.upstream)); + optional rem (git_line (git_ver, + prj.path, + false /* ignore_error */, + "config", + "branch." + st.branch + ".remote")); - if (p == string::npos) - fail << "unable to extract remote from '" << st.upstream << "'"; + if (!rem) + fail << "unable to obtain remote for '" << st.branch << "'"; - remote = string (st.upstream, 0, p); + remote = move (*rem); // Push the branch if the mode is other than tagging (and so the // version change is committed) or the local branch is ahead (probably @@ -1213,7 +1220,16 @@ namespace bdep // brspec = st.branch; - string b (st.upstream, p + 1); + // For good measure verify that the remote name is a prefix for the + // upstream branch. + // + size_t n (remote.size ()); + if (st.upstream.compare (0, n, remote) != 0 || + !path::traits_type::is_separator (st.upstream[n])) + fail << "remote '" << remote << "' is not a prefix for upstream " + << "branch '" << st.upstream << "'"; + + string b (st.upstream, n + 1); if (b != st.branch) { brspec += ':'; -- cgit v1.1