From 698bbc675764f3aec648aa242a99e89859065454 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 25 Jan 2019 11:42:02 +0200 Subject: Add --show-push option to bdep-release --- bdep/release.cli | 7 +++ bdep/release.cxx | 128 ++++++++++++++++++++++++++++++++++++++--------- tests/release.testscript | 113 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 215 insertions(+), 33 deletions(-) diff --git a/bdep/release.cli b/bdep/release.cli index c90ec29..12210d1 100644 --- a/bdep/release.cli +++ b/bdep/release.cli @@ -99,6 +99,13 @@ namespace bdep "Push the committed changes and tags to the remote." } + bool --show-push + { + "Print the push command instead of executing it. This allows examining + the committed changes and tags before pushing them to the remote. Note + that the command is printed to \cb{stdout}." + } + bool --no-open { "Don't open the next development cycle. Opening can be performed later diff --git a/bdep/release.cxx b/bdep/release.cxx index 22f2d91..232df64 100644 --- a/bdep/release.cxx +++ b/bdep/release.cxx @@ -4,6 +4,8 @@ #include +#include // cout + #include // manifest_name_value #include @@ -483,10 +485,12 @@ namespace bdep verify ("--no-open", o.no_open ()); // Releasing only (see above). // There is no sense to push without committing the version change first. + // Meaningful for all modes. // gopt = nullptr; - verify ("--push", o.push ()); // Meaningful for all modes. - verify ("--no-commit", o.no_commit ()); // See above for modes. + verify ("--push", o.push ()); + verify ("--show-push", o.show_push ()); + verify ("--no-commit", o.no_commit ()); // Not for tagging (see above). } // Fully parse package manifest verifying it is valid and returning the @@ -656,7 +660,12 @@ namespace bdep const package& pkg (prj.packages.front ()); // Exemplar package. bool commit (!o.no_commit () && (pkg.release_version || prj.open_version)); - bool push (o.push ()); + + // true - push, false - show push, nullopt - none of the above + // + optional push; + if (o.push () || o.show_push ()) + push = o.push (); if (push && st.upstream.empty ()) fail << "no upstream branch set for local branch '" << st.branch << "'"; @@ -694,6 +703,9 @@ namespace bdep dr << " push: " << (push ? st.upstream.c_str () : "no"); + if (push && !*push) + dr << " (show)"; + dr.flush (); if (!yn_prompt ("continue? [y/n]")) @@ -860,6 +872,40 @@ namespace bdep // replace the tag in the remote repository. Thus, we specify the // repository and refspecs explicitly. // + // Upstream is normally in the / form, for example + // 'origin/master'. + // + string remote; + string brspec; + { + size_t p (path::traits::rfind_separator (st.upstream)); + + if (p == string::npos) + fail << "unable to extract remote from '" << st.upstream << "'"; + + remote = string (st.upstream, 0, p); + + // Push the branch if the mode is other than tagging (and so the + // version change is committed) or the local branch is ahead (probably + // due to the previous command run without --push). + // + if (!o.tag () || st.ahead) + { + // Since we may print the push command, let's tidy it up a bit by + // reducing : to just if the source and destination + // branches are the same. + // + brspec = st.branch; + + string b (st.upstream, p + 1); + if (b != st.branch) + { + brspec += ':'; + brspec += b; + } + } + } + string tagspec; if (prj.tag) @@ -873,35 +919,69 @@ namespace bdep tagspec += *prj.tag; } - // Upstream is normally in the / form, for example - // 'origin/master'. + // There should always be something to push, since we are either tagging + // or committing the version change (or both). // - string remote; - string brspec; + assert (!brspec.empty () || !tagspec.empty ()); + + if (*push) { - size_t p (path::traits::rfind_separator (st.upstream)); + if (verb && !o.no_progress ()) + { + diag_record dr (text); + dr << "pushing"; - if (p == string::npos) - fail << "unable to extract remote from '" << st.upstream << "'"; + if (!brspec.empty ()) + dr << " branch " << st.branch; - remote = string (st.upstream, 0, p); - brspec = st.branch + ':' + string (st.upstream, p + 1); - } + if (prj.tag) + { + if (!brspec.empty ()) + dr << ','; - if (verb && !o.no_progress ()) - { - diag_record dr (text); - dr << "pushing branch " << st.branch; + dr << " tag " << *prj.tag; + } + } - if (prj.tag) - dr << ", tag " << *prj.tag; + git_push (o, + prj.path, + remote, + !brspec.empty () ? brspec.c_str () : nullptr, + !tagspec.empty () ? tagspec.c_str () : nullptr); } + else + { + // While normally the command will be run by the user, it's possible + // this will be scripted in some way and the script may want to + // extract the push command to run later. So, for generality and + // consistency with other similar situations, we print the command + // to stdout. + // + cout << "git "; - git_push (o, - prj.path, - remote, - brspec, - !tagspec.empty () ? tagspec.c_str () : nullptr); + // Check if CWD is the project root and add -C if it's not. + // + if (prj.path != path::current_directory()) + { + // Quote the directory if it contains spaces. + // + const string& s (prj.path.string ()); + const string& d (s.find (' ') == string::npos ? s : '"' + s + '"'); + cout << "-C " << d << ' '; + } + + // Note: none of the remote, branch, or tag may contain spaces. + // + cout << "push " << remote; + + if (!brspec.empty ()) + cout << ' ' << brspec; + + if (!tagspec.empty ()) + cout << ' ' << tagspec; + + cout << endl; + } } return 0; diff --git a/tests/release.testscript b/tests/release.testscript index 9b77674..fe32b85 100644 --- a/tests/release.testscript +++ b/tests/release.testscript @@ -349,7 +349,7 @@ log2 = $gp2 log '--pretty=format:"%d %s"' EOE $* --tag --force=snapshot 2>>~%EOE%; - %pushing branch master, tag v0.2.0-a.0.\.+%d + %pushing tag v0.2.0-a.0.\.+%d EOE $pull2; @@ -377,7 +377,7 @@ log2 = $gp2 log '--pretty=format:"%d %s"' EOO $* --tag 2>>EOE; - pushing branch master, tag v0.1.0 + pushing tag v0.1.0 EOE $pull2; @@ -469,7 +469,10 @@ log2 = $gp2 log '--pretty=format:"%d %s"' $* --no-commit; $gp commit -a -m 'Release version'; - $* --tag --push -q; + + $* --tag --push 2>>EOE; + pushing branch master, tag v0.1.0 + EOE $clone2; $log2 >>:~%EOO% @@ -718,14 +721,13 @@ log2 = $gp2 log '--pretty=format:"%d %s"' +$gp push --set-upstream origin master test.options += -q - test.arguments += --push : patch : { $clone_repos; - $* --yes; + $* --push --yes; $clone2; $log2 >>:~%EOO%; @@ -754,7 +756,7 @@ log2 = $gp2 log '--pretty=format:"%d %s"' : multiple-revisions : { - test.arguments += --yes + test.arguments += --push --yes $clone_repos; $* --no-open; @@ -808,6 +810,35 @@ log2 = $gp2 log '--pretty=format:"%d %s"' commit: yes tag: v0.1.0 + push: no + continue? [y/n]$sp + EOE + + $clone2; + $log2 >>:~%EOO% + % \(HEAD -> master, \.*\) Create%d + EOO + } + + : push + : + { + $clone_repos; + + $* --push <'y' 2>>:"EOE"; + releasing: + package: prj + current: 0.1.0-a.0.z + release: 0.1.0 + open: 0.2.0-a.0.z + + package: libprj + current: 0.1.0-a.0.z + release: 0.1.0 + open: 0.2.0-a.0.z + + commit: yes + tag: v0.1.0 push: origin/master continue? [y/n]$sp EOE @@ -820,6 +851,69 @@ log2 = $gp2 log '--pretty=format:"%d %s"' EOO } + : show-push + : + { + $clone_repos; + + $* --show-push <'y' 2>>:"EOE" >>~%EOO%; + releasing: + package: prj + current: 0.1.0-a.0.z + release: 0.1.0 + open: 0.2.0-a.0.z + + package: libprj + current: 0.1.0-a.0.z + release: 0.1.0 + open: 0.2.0-a.0.z + + commit: yes + tag: v0.1.0 + push: origin/master \(show\) + continue? [y/n]$sp + EOE + %git -C \.+prj push origin master refs/tags/v0.1.0%d + EOO + + $gp push origin master refs/tags/v0.1.0; + + $clone2; + $log2 >>:~%EOO%; + % \(HEAD -> master, \.*\) Change version to 0.2.0-a.0.z%d + (tag: v0.1.0) Release version 0.1.0 + Create + EOO + + $* --no-tag --no-open --show-push --yes >>~%EOO%; + %git -C .+prj push origin master% + EOO + + $gp push origin master; + + $pull2 --tags; # Updates the existing local tag. + $log2 >>:~%EOO%; + % \(HEAD -> master, \.*\) Release version 0.2.0%d + Change version to 0.2.0-a.0.z + (tag: v0.1.0) Release version 0.1.0 + Create + EOO + + $* --tag --show-push --yes >>~%EOO%; + %git -C \.+prj push origin refs/tags/v0.2.0%d + EOO + + $gp push origin refs/tags/v0.2.0; + + $pull2 --tags; # Updates the existing local tag. + $log2 >>:~%EOO% + % \(HEAD -> master, tag: v0.2.0, \.*\) Release version 0.2.0%d + Change version to 0.2.0-a.0.z + (tag: v0.1.0) Release version 0.1.0 + Create + EOO + } + : no-tag : { @@ -839,7 +933,7 @@ log2 = $gp2 log '--pretty=format:"%d %s"' commit: yes tag: no - push: origin/master + push: no continue? [y/n]$sp EOE } @@ -861,7 +955,7 @@ log2 = $gp2 log '--pretty=format:"%d %s"' commit: yes tag: v0.1.0 - push: origin/master + push: no continue? [y/n]$sp EOE } @@ -879,5 +973,6 @@ log2 = $gp2 log '--pretty=format:"%d %s"' $* --revision --open-beta 2>'error: both --revision and --open-beta specified' != 0; $* --open --no-tag 2>'error: both --open and --no-tag specified' != 0; $* --tag --no-commit 2>'error: both --tag and --no-commit specified' != 0; - $* --push --no-commit 2>'error: both --push and --no-commit specified' != 0 + $* --push --no-commit 2>'error: both --push and --no-commit specified' != 0; + $* --push --show-push 2>'error: both --push and --show-push specified' != 0 } -- cgit v1.1