aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2019-01-25 11:42:02 +0200
committerKaren Arutyunov <karen@codesynthesis.com>2019-01-26 15:38:46 +0300
commit698bbc675764f3aec648aa242a99e89859065454 (patch)
treed0ced970ae3dd9b9b490e5d6c05ec312e46752e4
parent782e978d23f0fa0d7d01b924f84caa82284e8520 (diff)
Add --show-push option to bdep-release
-rw-r--r--bdep/release.cli7
-rw-r--r--bdep/release.cxx128
-rw-r--r--tests/release.testscript113
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 <bdep/release.hxx>
+#include <iostream> // cout
+
#include <libbutl/manifest-types.mxx> // manifest_name_value
#include <libbutl/manifest-rewriter.mxx>
@@ -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<bool> 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 <remote>/<branch> 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 <src>:<dst> to just <src> 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 <remote>/<branch> 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
}