|
|
@@ -20,6 +20,15 @@ private const string BUMP_REBUILD_DEPENDANTS_FLAG = "rebuildDependants";
|
|
|
* pending so the tag captures the release state. `--push` pushes branch and
|
|
|
* tag, implying `--git`.
|
|
|
*
|
|
|
+ * When the manifest's `execs` object declares a `bump` executable and the
|
|
|
+ * version actually changes, the hook runs before anything is rewritten —
|
|
|
+ * invoked as `<bump> <old-version> <new-version>` from the current (source)
|
|
|
+ * directory — so it can update version strings elsewhere in the tree
|
|
|
+ * (source files, meson.build, …). A non-zero exit or a failure to spawn the
|
|
|
+ * hook aborts the whole bump, leaving the manifest and tree untouched. A
|
|
|
+ * `--git` release after a hook run stages the whole working tree, since what
|
|
|
+ * the hook edited cannot be known.
|
|
|
+ *
|
|
|
* The manifest is parsed and rewritten as raw JSON rather than through
|
|
|
* {@link Usm.Manifest}'s mapper, so a bump neither depends on manifest
|
|
|
* validation nor rewrites flags the lib's flag enum has to know about.
|
|
|
@@ -122,7 +131,19 @@ public int manifest_bump(string[] args) {
|
|
|
}
|
|
|
|
|
|
bool changed = false;
|
|
|
+ bool hook_ran = false;
|
|
|
if(new_version != null && new_version != current_version) {
|
|
|
+ // The bump hook runs after the new version is computed but before any
|
|
|
+ // file is touched, so a failing hook leaves the tree exactly as it was
|
|
|
+ string? bump_hook = bump_executable(root);
|
|
|
+ if(bump_hook != null) {
|
|
|
+ printerr(@"Running bump hook \"$bump_hook\" \"$current_version\" \"$new_version\"\n");
|
|
|
+ if(!bump_hook_run(bump_hook, current_version, new_version)) {
|
|
|
+ printerr(@"Error running bump exec: the bump hook \"$bump_hook\" failed, aborting the bump of \"$current_version\" → \"$new_version\"\n");
|
|
|
+ return 251;
|
|
|
+ }
|
|
|
+ hook_ran = true;
|
|
|
+ }
|
|
|
try {
|
|
|
root.set_native("version", new_version);
|
|
|
}
|
|
|
@@ -208,8 +229,11 @@ public int manifest_bump(string[] args) {
|
|
|
}
|
|
|
|
|
|
// A version bump commits the manifest alone; a bare --git releases the
|
|
|
- // current version, so every pending change belongs in the release commit
|
|
|
- if(!bump_git_run(new string[] { "git", "add", spec != null ? "MANIFEST.usm" : "-A" })) {
|
|
|
+ // current version, so every pending change belongs in the release commit.
|
|
|
+ // A bump hook that ran may have edited anything in the tree, so its
|
|
|
+ // release commit stages the whole working tree too.
|
|
|
+ bool stage_everything = spec == null || hook_ran;
|
|
|
+ if(!bump_git_run(new string[] { "git", "add", stage_everything ? "-A" : "MANIFEST.usm" })) {
|
|
|
printerr("Could not stage the release changes\n");
|
|
|
return 250;
|
|
|
}
|
|
|
@@ -249,6 +273,7 @@ public int manifest_bump(string[] args) {
|
|
|
|
|
|
private int bump_usage() {
|
|
|
printerr("USAGE:\n\tusm manifest bump [major|minor|patch|<version>] [--git] [--push] [--rebuild-dependants] [--no-rebuild-dependants]\n");
|
|
|
+ printerr("\n\tWhen the manifest's execs object declares a bump executable it runs as\n\t<bump> <old-version> <new-version> before MANIFEST.usm is rewritten; a\n\tnon-zero exit aborts the bump and leaves the tree untouched.\n");
|
|
|
return 255;
|
|
|
}
|
|
|
|
|
|
@@ -305,3 +330,40 @@ private bool bump_git_run(string[] command) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Reads the manifest's `execs.bump` executable from the raw JSON tree, or
|
|
|
+ * null when the manifest declares none. The path is relative to the source
|
|
|
+ * directory, which is the current directory like acquire's.
|
|
|
+ */
|
|
|
+private string? bump_executable(InvercargillJson.JsonObject root) {
|
|
|
+ if(!root.has("execs")) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ var execs = root.get_object("execs");
|
|
|
+ if(execs == null || !execs.has("bump")) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return execs.get_string("bump");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Runs the bump hook {@link hook} in the current (source) directory with the
|
|
|
+ * old and new version as arguments; its output flows to the terminal
|
|
|
+ * unchanged. Returns false — diagnostics already printed — when it fails to
|
|
|
+ * spawn or exits non-zero.
|
|
|
+ */
|
|
|
+private bool bump_hook_run(string hook, string old_version, string new_version) {
|
|
|
+ try {
|
|
|
+ return new Subprocess.newv(
|
|
|
+ { hook, old_version, new_version },
|
|
|
+ SubprocessFlags.INHERIT_FDS
|
|
|
+ ).wait_check();
|
|
|
+ }
|
|
|
+ catch(Error e) {
|
|
|
+ printerr(@"Could not run the bump hook \"$hook\": $(e.message)\n");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|