@@ -25,6 +25,7 @@
/git-bisect--helper
/git-blame
/git-branch
+/git-bugreport
/git-bundle
/git-cat-file
/git-check-attr
new file mode 100644
@@ -0,0 +1,43 @@
+git-bugreport(1)
+================
+
+NAME
+----
+git-bugreport - Collect information for user to file a bug report
+
+SYNOPSIS
+--------
+[verse]
+'git bugreport' [-o | --output <path>]
+
+DESCRIPTION
+-----------
+Captures information about the user's machine, Git client, and repository state,
+as well as a form requesting information about the behavior the user observed,
+into a single text file which the user can then share, for example to the Git
+mailing list, in order to report an observed bug.
+
+The following information is requested from the user:
+
+ - Reproduction steps
+ - Expected behavior
+ - Actual behavior
+
+The following information is captured automatically:
+
+ - Git version (`git version --build-options`)
+ - Machine information (`uname -a`)
+ - Versions of various dependencies
+ - Git config contents (`git config --show-origin --list`)
+ - The names of all configured git-hooks in `.git/hooks/`
+
+OPTIONS
+-------
+-o [<path>]::
+--output [<path>]::
+ Place the resulting bug report file in <path> instead of the root of the
+ Git repository.
+
+GIT
+---
+Part of the linkgit:git[1] suite
@@ -681,6 +681,7 @@ EXTRA_PROGRAMS =
# ... and all the rest that could be moved out of bindir to gitexecdir
PROGRAMS += $(EXTRA_PROGRAMS)
+PROGRAM_OBJS += bugreport.o
PROGRAM_OBJS += credential-store.o
PROGRAM_OBJS += daemon.o
PROGRAM_OBJS += fast-import.o
@@ -2448,6 +2449,10 @@ endif
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
+ $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+ $(LIBS)
+
git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
$(IMAP_SEND_LDFLAGS) $(LIBS)
new file mode 100644
@@ -0,0 +1,69 @@
+#include "builtin.h"
+#include "parse-options.h"
+#include "stdio.h"
+#include "strbuf.h"
+#include "time.h"
+
+static const char * const bugreport_usage[] = {
+ N_("git bugreport [-o|--output <file>]"),
+ NULL
+};
+
+static int get_bug_template(struct strbuf *template)
+{
+ const char template_text[] = N_(
+"Thank you for filling out a Git bug report!\n"
+"Please answer the following questions to help us understand your issue.\n"
+"\n"
+"What did you do before the bug happened? (Steps to reproduce your issue)\n"
+"\n"
+"What did you expect to happen? (Expected behavior)\n"
+"\n"
+"What happened instead? (Actual behavior)\n"
+"\n"
+"What's different between what you expected and what actually happened?\n"
+"\n"
+"Anything else you want to add:\n"
+"\n"
+"Please review the rest of the bug report below.\n"
+"You can delete any lines you don't wish to send.\n");
+
+ strbuf_addstr(template, template_text);
+ return 0;
+}
+
+int cmd_main(int argc, const char **argv)
+{
+ struct strbuf buffer = STRBUF_INIT;
+ struct strbuf report_path = STRBUF_INIT;
+ FILE *report;
+ time_t now = time(NULL);
+ char *option_output = NULL;
+
+ const struct option bugreport_options[] = {
+ OPT_STRING('o', "output", &option_output, N_("path"),
+ N_("specify a destination for the bugreport file")),
+ OPT_END()
+ };
+ argc = parse_options(argc, argv, "", bugreport_options,
+ bugreport_usage, 0);
+
+ if (option_output) {
+ strbuf_addstr(&report_path, option_output);
+ strbuf_complete(&report_path, '/');
+ }
+
+ strbuf_addstr(&report_path, "git-bugreport-");
+ strbuf_addftime(&report_path, "%F", gmtime(&now), 0, 0);
+ strbuf_addstr(&report_path, ".txt");
+
+
+ get_bug_template(&buffer);
+
+ report = fopen_for_writing(report_path.buf);
+ strbuf_write(&buffer, report);
+ fclose(report);
+
+ launch_editor(report_path.buf, NULL, NULL);
+ return 0;
+}
new file mode 100755
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+test_description='git bugreport'
+
+. ./test-lib.sh
+
+# Headers "[System Info]" will be followed by a non-empty line if we put some
+# information there; we can make sure all our headers were followed by some
+# information to check if the command was successful.
+HEADER_PATTERN="^\[.*\]$"
+check_all_headers_populated() {
+ while read -r line; do
+ if [$(grep $HEADER_PATTERN $line)]; then
+ read -r nextline
+ if [-z $nextline]; then
+ return 1;
+ fi
+ fi
+ done
+}
+
+test_expect_success 'creates a report with content in the right places' '
+ git bugreport &&
+ check_all_headers_populated <git-bugreport-* &&
+ rm git-bugreport-*
+'
+
+test_expect_success '--output puts the report in the provided dir' '
+ mkdir foo/ &&
+ git bugreport -o foo/ &&
+ test -f foo/git-bugreport-* &&
+ rm -fr foo/
+'
+
+test_expect_success 'incorrect arguments abort with usage' '
+ test_must_fail git bugreport --false 2>output &&
+ grep usage output &&
+ test ! -f git-bugreport-*
+'
+
+test_done
Teach Git how to prompt the user for a good bug report: reproduction steps, expected behavior, and actual behavior. Later, Git can learn how to collect some diagnostic information from the repository. If users can send us a well-written bug report which contains diagnostic information we would otherwise need to ask the user for, we can reduce the number of question-and-answer round trips between the reporter and the Git contributor. Users may also wish to send a report like this to their local "Git expert" if they have put their repository into a state they are confused by. Signed-off-by: Emily Shaffer <emilyshaffer@google.com> --- .gitignore | 1 + Documentation/git-bugreport.txt | 43 ++++++++++++++++++++ Makefile | 5 +++ bugreport.c | 69 +++++++++++++++++++++++++++++++++ t/t0091-bugreport.sh | 41 ++++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 Documentation/git-bugreport.txt create mode 100644 bugreport.c create mode 100755 t/t0091-bugreport.sh