Web lists-archives.com

[PATCH 1/2] praise: a culturally sensitive wrapper for 'blame'




Add a wrapper for "blame" for use in blameless cultural
settings. Users in such cultures have hitherto had to fall back on the
legacy "annotate" command and its inferior output if they wanted to
avoid culturally inappropriate behavior.

Now such users have the option of using this wrapper. Organizations
that wish to engage in cultural enforcement can set
"blame.culture=blameless" in their configuration to make any direct
use of the "blame" command an error. Those wishing to centrally report
such transgressions can do so with the trace2 logging facility[1].

1. See Documentation/technical/api-trace2.txt --
   https://github.com/git/git/blob/master/Documentation/technical/api-trace2.txt

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx>
---
 Documentation/config/blame.txt | 10 ++++++++++
 Documentation/git-blame.txt    |  3 ++-
 Documentation/git-praise.txt   | 20 ++++++++++++++++++++
 builtin/blame.c                |  9 +++++++++
 git.c                          |  1 +
 t/t8002-blame.sh               | 15 +++++++++++++++
 6 files changed, 57 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/git-praise.txt

diff --git a/Documentation/config/blame.txt b/Documentation/config/blame.txt
index 67b5c1d1e0..c85b35de17 100644
--- a/Documentation/config/blame.txt
+++ b/Documentation/config/blame.txt
@@ -1,3 +1,13 @@
+blame.culture::
+	Set to 'blameless' to enforce the use of the functionality of
+	linkgit:git-blame[1] in blameless cultural settings. This will
+	make invocations of linkgit:git-blame[1] an error, forcing the
+	use of linkgit:git-praise[1]. Defaults to 'blameful', which is
+	the default.
++
+Note that the `--porcelain` format for machine consumption is exempt
+from this enforcement to avoid breaking existing scripts.
+
 blame.blankBoundary::
 	Show blank commit object name for boundary commits in
 	linkgit:git-blame[1]. This option defaults to false.
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index 16323eb80e..9c1bff7389 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -228,7 +228,8 @@ include::mailmap.txt[]
 
 SEE ALSO
 --------
-linkgit:git-annotate[1]
+linkgit:git-annotate[1],
+linkgit:git-praise[1]
 
 GIT
 ---
diff --git a/Documentation/git-praise.txt b/Documentation/git-praise.txt
new file mode 100644
index 0000000000..d34b9dbc61
--- /dev/null
+++ b/Documentation/git-praise.txt
@@ -0,0 +1,20 @@
+git-praise(1)
+============
+
+NAME
+----
+git-praise - A culturally sensitive alias for git-blame
+
+DESCRIPTION
+-----------
+
+Annotates each line in the given file without compromising the
+cultural integrity of blameless cultures.
+
+The functionality of this command is equivalent to
+linkgit:git-blame[1]. Its use can be enforced by setting
+`blame.culture=blameless` in the config. See linkgit:git-config[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/builtin/blame.c b/builtin/blame.c
index 177c1022a0..238b19db48 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -37,6 +37,7 @@ static const char *blame_opt_usage[] = {
 	NULL
 };
 
+static int blameless_culture;
 static int longest_file;
 static int longest_author;
 static int max_orig_digits;
@@ -681,6 +682,10 @@ static int git_blame_config(const char *var, const char *value, void *cb)
 		blank_boundary = git_config_bool(var, value);
 		return 0;
 	}
+	if (!strcmp(var, "blame.culture")) {
+		blameless_culture = !strcmp(value, "blameless");
+		return 0;
+	}
 	if (!strcmp(var, "blame.showemail")) {
 		int *output_option = cb;
 		if (git_config_bool(var, value))
@@ -828,6 +833,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 
 	struct parse_opt_ctx_t ctx;
 	int cmd_is_annotate = !strcmp(argv[0], "annotate");
+	int cmd_is_praise = !strcmp(argv[0], "praise");
 	struct range_set ranges;
 	unsigned int range_i;
 	long anchor;
@@ -889,6 +895,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 	if (cmd_is_annotate) {
 		output_option |= OUTPUT_ANNOTATE_COMPAT;
 		blame_date_mode.type = DATE_ISO8601;
+	} else if (!cmd_is_praise && blameless_culture &&
+		   !(output_option & OUTPUT_PORCELAIN)) {
+		die(_("must be invoked as 'git praise' with 'blame.culture=blameless' set!"));
 	} else {
 		blame_date_mode = revs.date_mode;
 	}
diff --git a/git.c b/git.c
index 2014aab6b8..77640f8cd9 100644
--- a/git.c
+++ b/git.c
@@ -536,6 +536,7 @@ static struct cmd_struct commands[] = {
 	{ "pack-refs", cmd_pack_refs, RUN_SETUP },
 	{ "patch-id", cmd_patch_id, RUN_SETUP_GENTLY | NO_PARSEOPT },
 	{ "pickaxe", cmd_blame, RUN_SETUP },
+	{ "praise", cmd_blame, RUN_SETUP },
 	{ "prune", cmd_prune, RUN_SETUP },
 	{ "prune-packed", cmd_prune_packed, RUN_SETUP },
 	{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh
index eea048e52c..2d59b856d1 100755
--- a/t/t8002-blame.sh
+++ b/t/t8002-blame.sh
@@ -48,6 +48,21 @@ test_expect_success 'blame with no options and no config' '
 	test_cmp expected_n result
 '
 
+test_expect_success 'praise' '
+	git praise --show-email one >praise1 &&
+	find_blame <praise1 >result &&
+	test_cmp expected_e result &&
+
+	git praise --no-show-email one >praise2 &&
+	find_blame <praise2 >result &&
+	test_cmp expected_n result
+'
+
+test_expect_success 'enforced praise' '
+	test_must_fail git -c blame.culture=blameless blame one 2>err &&
+	test_i18ngrep "must be.*git praise" err
+'
+
 test_expect_success 'blame with showemail options' '
 	git blame --show-email one >blame1 &&
 	find_blame <blame1 >result &&
-- 
2.21.0.392.gf8f6787159e