From cf3d868f353c4a5a9ecf4fbc2a44960671ba59cb Mon Sep 17 00:00:00 2001 From: Jiang Xin Date: Wed, 11 Nov 2020 19:32:00 +0800 Subject: t5411: new helper filter_out_user_friendly_and_stable_output New helper `filter_out_user_friendly_and_stable_output` will call common helpr function `make_user_friendly_and_stable_output` and use additional arguments to filter out messages for specific test cases. Suggested-by: Junio C Hamano Signed-off-by: Jiang Xin Signed-off-by: Junio C Hamano diff --git a/t/t5411/common-functions.sh b/t/t5411/common-functions.sh index 521a347..344d13f 100644 --- a/t/t5411/common-functions.sh +++ b/t/t5411/common-functions.sh @@ -42,7 +42,7 @@ create_commits_in () { make_user_friendly_and_stable_output () { sed \ -e "s/ *\$//" \ - -e "s/ */ /g" \ + -e "s/ */ /g" \ -e "s/'/\"/g" \ -e "s/ / /g" \ -e "s/$A//g" \ @@ -54,3 +54,8 @@ make_user_friendly_and_stable_output () { -e "s#To $URL_PREFIX/upstream.git#To #" \ -e "/^error: / d" } + +filter_out_user_friendly_and_stable_output () { + make_user_friendly_and_stable_output | + sed -n ${1+"$@"} +} diff --git a/t/t5411/test-0000-standard-git-push.sh b/t/t5411/test-0000-standard-git-push.sh index 2b04b49..47b058a 100644 --- a/t/t5411/test-0000-standard-git-push.sh +++ b/t/t5411/test-0000-standard-git-push.sh @@ -36,11 +36,10 @@ test_expect_success "git-push --atomic ($PROTOCOL)" ' main \ $B:refs/heads/next \ >out 2>&1 && - make_user_friendly_and_stable_output actual && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; }" \ + -e "/^ ! / { p; }" \ + actual && cat >expect <<-EOF && To ! [rejected] main -> main (non-fast-forward) diff --git a/t/t5411/test-0001-standard-git-push--porcelain.sh b/t/t5411/test-0001-standard-git-push--porcelain.sh index 747307f..bbead12 100644 --- a/t/t5411/test-0001-standard-git-push--porcelain.sh +++ b/t/t5411/test-0001-standard-git-push--porcelain.sh @@ -37,16 +37,15 @@ test_expect_success "git-push --atomic ($PROTOCOL/porcelain)" ' main \ $B:refs/heads/next \ >out 2>&1 && - make_user_friendly_and_stable_output actual && + filter_out_user_friendly_and_stable_output \ + -e "s/^# GETTEXT POISON #//" \ + -e "/^To / { p; }" \ + -e "/^! / { p; }" \ + actual && cat >expect <<-EOF && To - ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) - ! :refs/heads/next [rejected] (atomic push failed) + ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) + ! :refs/heads/next [rejected] (atomic push failed) EOF test_cmp expect actual && git -C "$upstream" show-ref >out && -- cgit v0.10.2-6-g49f6 From f65003b4c4abea49a00cc9f3d87b9f37db6b48f1 Mon Sep 17 00:00:00 2001 From: Jiang Xin Date: Wed, 11 Nov 2020 19:32:01 +0800 Subject: receive-pack: gently write messages to proc-receive Johannes found a flaky hang in `t5411/test-0013-bad-protocol.sh` in the osx-clang job of the CI/PR builds, and ran into an issue when using the `--stress` option with the following error messages: fatal: unable to write flush packet: Broken pipe send-pack: unexpected disconnect while reading sideband packet fatal: the remote end hung up unexpectedly In this test case, the "proc-receive" hook sends an error message and dies earlier. While "receive-pack" on the other side of the pipe should forward the error message of the "proc-receive" hook to the client side, but it fails to do so. This is because "receive-pack" uses `packet_write_fmt()` and `packet_flush()` to write pkt-line message to "proc-receive" hook, and these functions die immediately when pipe is broken. Using "gently" forms for these functions will get more predicable output. Add more "--die-*" options to test helper to test different stages of the protocol between "receive-pack" and "proc-receive" hook. Reported-by: Johannes Schindelin Suggested-by: Jeff King Signed-off-by: Jiang Xin Signed-off-by: Junio C Hamano diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index bb9909c..2bd7365 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -977,15 +977,25 @@ static int read_proc_receive_report(struct packet_reader *reader, int new_report = 0; int code = 0; int once = 0; + int response = 0; for (;;) { struct object_id old_oid, new_oid; const char *head; const char *refname; char *p; - - if (packet_reader_read(reader) != PACKET_READ_NORMAL) + enum packet_read_status status; + + status = packet_reader_read(reader); + if (status != PACKET_READ_NORMAL) { + /* Check whether proc-receive exited abnormally */ + if (status == PACKET_READ_EOF && !response) { + strbuf_addstr(errmsg, "proc-receive exited abnormally"); + return -1; + } break; + } + response++; head = reader->line; p = strchr(head, ' '); @@ -1145,28 +1155,41 @@ static int run_proc_receive_hook(struct command *commands, if (use_push_options) strbuf_addstr(&cap, " push-options"); if (cap.len) { - packet_write_fmt(proc.in, "version=1%c%s\n", '\0', cap.buf + 1); + code = packet_write_fmt_gently(proc.in, "version=1%c%s\n", '\0', cap.buf + 1); strbuf_release(&cap); } else { - packet_write_fmt(proc.in, "version=1\n"); + code = packet_write_fmt_gently(proc.in, "version=1\n"); } - packet_flush(proc.in); + if (!code) + code = packet_flush_gently(proc.in); - for (;;) { - int linelen; + if (!code) + for (;;) { + int linelen; + enum packet_read_status status; - if (packet_reader_read(&reader) != PACKET_READ_NORMAL) - break; + status = packet_reader_read(&reader); + if (status != PACKET_READ_NORMAL) { + /* Check whether proc-receive exited abnormally */ + if (status == PACKET_READ_EOF) + code = -1; + break; + } - if (reader.pktlen > 8 && starts_with(reader.line, "version=")) { - version = atoi(reader.line + 8); - linelen = strlen(reader.line); - if (linelen < reader.pktlen) { - const char *feature_list = reader.line + linelen + 1; - if (parse_feature_request(feature_list, "push-options")) - hook_use_push_options = 1; + if (reader.pktlen > 8 && starts_with(reader.line, "version=")) { + version = atoi(reader.line + 8); + linelen = strlen(reader.line); + if (linelen < reader.pktlen) { + const char *feature_list = reader.line + linelen + 1; + if (parse_feature_request(feature_list, "push-options")) + hook_use_push_options = 1; + } } } + + if (code) { + strbuf_addstr(&errmsg, "fail to negotiate version with proc-receive hook"); + goto cleanup; } if (version != 1) { @@ -1180,20 +1203,36 @@ static int run_proc_receive_hook(struct command *commands, for (cmd = commands; cmd; cmd = cmd->next) { if (!cmd->run_proc_receive || cmd->skip_update || cmd->error_string) continue; - packet_write_fmt(proc.in, "%s %s %s", - oid_to_hex(&cmd->old_oid), - oid_to_hex(&cmd->new_oid), - cmd->ref_name); + code = packet_write_fmt_gently(proc.in, "%s %s %s", + oid_to_hex(&cmd->old_oid), + oid_to_hex(&cmd->new_oid), + cmd->ref_name); + if (code) + break; + } + if (!code) + code = packet_flush_gently(proc.in); + if (code) { + strbuf_addstr(&errmsg, "fail to write commands to proc-receive hook"); + goto cleanup; } - packet_flush(proc.in); /* Send push options */ if (hook_use_push_options) { struct string_list_item *item; - for_each_string_list_item(item, push_options) - packet_write_fmt(proc.in, "%s", item->string); - packet_flush(proc.in); + for_each_string_list_item(item, push_options) { + code = packet_write_fmt_gently(proc.in, "%s", item->string); + if (code) + break; + } + if (!code) + code = packet_flush_gently(proc.in); + if (code) { + strbuf_addstr(&errmsg, + "fail to write push-options to proc-receive hook"); + goto cleanup; + } } /* Read result from proc-receive */ diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c index 42164d9..6652ced 100644 --- a/t/helper/test-proc-receive.c +++ b/t/helper/test-proc-receive.c @@ -10,8 +10,11 @@ static const char *proc_receive_usage[] = { NULL }; -static int die_version; -static int die_readline; +static int die_read_version; +static int die_write_version; +static int die_read_commands; +static int die_read_push_options; +static int die_write_report; static int no_push_options; static int use_atomic; static int use_push_options; @@ -33,6 +36,9 @@ struct command { static void proc_receive_verison(struct packet_reader *reader) { int server_version = 0; + if (die_read_version) + die("die with the --die-read-version option"); + for (;;) { int linelen; @@ -52,9 +58,12 @@ static void proc_receive_verison(struct packet_reader *reader) { } } - if (server_version != 1 || die_version) + if (server_version != 1) die("bad protocol version: %d", server_version); + if (die_write_version) + die("die with the --die-write-version option"); + packet_write_fmt(1, "version=%d%c%s\n", version, '\0', use_push_options && !no_push_options ? "push-options": ""); @@ -75,11 +84,13 @@ static void proc_receive_read_commands(struct packet_reader *reader, if (packet_reader_read(reader) != PACKET_READ_NORMAL) break; + if (die_read_commands) + die("die with the --die-read-commands option"); + if (parse_oid_hex(reader->line, &old_oid, &p) || *p++ != ' ' || parse_oid_hex(p, &new_oid, &p) || - *p++ != ' ' || - die_readline) + *p++ != ' ') die("protocol error: expected 'old new ref', got '%s'", reader->line); refname = p; @@ -99,6 +110,9 @@ static void proc_receive_read_push_options(struct packet_reader *reader, if (no_push_options || !use_push_options) return; + if (die_read_push_options) + die("die with the --die-read-push-options option"); + while (1) { if (packet_reader_read(reader) != PACKET_READ_NORMAL) break; @@ -117,10 +131,16 @@ int cmd__proc_receive(int argc, const char **argv) struct option options[] = { OPT_BOOL(0, "no-push-options", &no_push_options, "disable push options"), - OPT_BOOL(0, "die-version", &die_version, - "die during version negotiation"), - OPT_BOOL(0, "die-readline", &die_readline, - "die when readline"), + OPT_BOOL(0, "die-read-version", &die_read_version, + "die when reading version"), + OPT_BOOL(0, "die-write-version", &die_write_version, + "die when writing version"), + OPT_BOOL(0, "die-read-commands", &die_read_commands, + "die when reading commands"), + OPT_BOOL(0, "die-read-push-options", &die_read_push_options, + "die when reading push-options"), + OPT_BOOL(0, "die-write-report", &die_write_report, + "die when writing report"), OPT_STRING_LIST('r', "return", &returns, "old/new/ref/status/msg", "return of results"), OPT__VERBOSE(&verbose, "be verbose"), @@ -136,7 +156,7 @@ int cmd__proc_receive(int argc, const char **argv) usage_msg_opt("Too many arguments.", proc_receive_usage, options); packet_reader_init(&reader, 0, NULL, 0, PACKET_READ_CHOMP_NEWLINE | - PACKET_READ_DIE_ON_ERR_PACKET); + PACKET_READ_GENTLE_ON_EOF); sigchain_push(SIGPIPE, SIG_IGN); proc_receive_verison(&reader); @@ -166,6 +186,8 @@ int cmd__proc_receive(int argc, const char **argv) fprintf(stderr, "proc-receive> %s\n", item->string); } + if (die_write_report) + die("die with the --die-write-report option"); if (returns.nr) for_each_string_list_item(item, &returns) packet_write_fmt(1, "%s\n", item->string); diff --git a/t/t5411/test-0013-bad-protocol.sh b/t/t5411/test-0013-bad-protocol.sh index 854c3e8..b9be12b 100644 --- a/t/t5411/test-0013-bad-protocol.sh +++ b/t/t5411/test-0013-bad-protocol.sh @@ -16,7 +16,8 @@ test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL)" ' # Check status report for git-push sed -n \ - -e "/^To / { p; n; p; }" \ + -e "/^To / { p; }" \ + -e "/^ ! / { p; }" \ actual-report && cat >expect <<-EOF && To @@ -41,32 +42,98 @@ test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL)" ' test_cmp expect actual ' -test_expect_success "setup proc-receive hook (hook --die-version, $PROTOCOL)" ' +test_expect_success "setup proc-receive hook (hook --die-read-version, $PROTOCOL)" ' write_script "$upstream/hooks/proc-receive" <<-EOF printf >&2 "# proc-receive hook\n" - test-tool proc-receive -v --die-version + test-tool proc-receive -v --die-read-version EOF ' # Refs of upstream : main(A) # Refs of workbench: main(A) tags/v123 # git push : refs/for/main/topic(A) -test_expect_success "proc-receive: bad protocol (hook --die-version, $PROTOCOL)" ' +test_expect_success "proc-receive: bad protocol (hook --die-read-version, $PROTOCOL)" ' test_must_fail git -C workbench push origin \ HEAD:refs/for/main/topic \ >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; }" \ + -e "/^ ! / { p; }" \ + actual && + cat >expect <<-EOF && + To + ! [remote rejected] HEAD -> refs/for/main/topic (fail to run proc-receive hook) + EOF + test_cmp expect actual && + grep "remote: fatal: die with the --die-read-version option" out && + grep "remote: error: fail to negotiate version with proc-receive hook" out && + + git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (hook --die-write-version, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-write-version + EOF +' +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push : refs/for/main/topic(A) +test_expect_success "proc-receive: bad protocol (hook --die-write-version, $PROTOCOL)" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; }" \ + -e "/^ ! / { p; }" \ + actual && + cat >expect <<-EOF && + To + ! [remote rejected] HEAD -> refs/for/main/topic (fail to run proc-receive hook) + EOF + test_cmp expect actual && + grep "remote: fatal: die with the --die-write-version option" out && + grep "remote: error: fail to negotiate version with proc-receive hook" out && + + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (hook --die-read-commands, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-read-commands + EOF +' + +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push : refs/for/main/topic(A) +test_expect_success "proc-receive: bad protocol (hook --die-read-commands, $PROTOCOL)" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; }" \ + -e "/^ ! / { p; }" \ + actual && cat >expect <<-EOF && - remote: # pre-receive hook - remote: pre-receive< refs/for/main/topic - remote: # proc-receive hook - remote: fatal: bad protocol version: 1 - remote: error: proc-receive version "0" is not supported To ! [remote rejected] HEAD -> refs/for/main/topic (fail to run proc-receive hook) EOF test_cmp expect actual && + grep "remote: fatal: die with the --die-read-commands option" out && git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && @@ -76,23 +143,65 @@ test_expect_success "proc-receive: bad protocol (hook --die-version, $PROTOCOL)" test_cmp expect actual ' -test_expect_success "setup proc-receive hook (hook --die-readline, $PROTOCOL)" ' +test_expect_success "setup proc-receive hook (hook --die-read-push-options, $PROTOCOL)" ' write_script "$upstream/hooks/proc-receive" <<-EOF printf >&2 "# proc-receive hook\n" - test-tool proc-receive -v --die-readline + test-tool proc-receive -v --die-read-push-options EOF ' # Refs of upstream : main(A) # Refs of workbench: main(A) tags/v123 # git push : refs/for/main/topic(A) -test_expect_success "proc-receive: bad protocol (hook --die-readline, $PROTOCOL)" ' +test_expect_success "proc-receive: bad protocol (hook --die-read-push-options, $PROTOCOL)" ' + git -C "$upstream" config receive.advertisePushOptions true && test_must_fail git -C workbench push origin \ + -o reviewers=user1,user2 \ HEAD:refs/for/main/topic \ >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; }" \ + -e "/^ ! / { p; }" \ + actual && + cat >expect <<-EOF && + To + ! [remote rejected] HEAD -> refs/for/main/topic (fail to run proc-receive hook) + EOF + test_cmp expect actual && + grep "remote: fatal: die with the --die-read-push-options option" out && + + git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (hook --die-write-report, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-write-report + EOF +' - grep "remote: fatal: protocol error: expected \"old new ref\", got \" refs/for/main/topic\"" actual && +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push : refs/for/main/topic(A) +test_expect_success "proc-receive: bad protocol (hook --die-write-report, $PROTOCOL)" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; }" \ + -e "/^ ! / { p; }" \ + actual && + cat >expect <<-EOF && + To + ! [remote rejected] HEAD -> refs/for/main/topic (fail to run proc-receive hook) + EOF + test_cmp expect actual && + grep "remote: fatal: die with the --die-write-report option" out && git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && @@ -130,6 +239,7 @@ test_expect_success "proc-receive: bad protocol (no report, $PROTOCOL)" ' ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status) EOF test_cmp expect actual && + git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && cat >expect <<-EOF && @@ -173,6 +283,7 @@ test_expect_success "proc-receive: bad protocol (no ref, $PROTOCOL)" ' ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status) EOF test_cmp expect actual && + git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && cat >expect <<-EOF && @@ -208,6 +319,7 @@ test_expect_success "proc-receive: bad protocol (unknown status, $PROTOCOL)" ' ! [remote rejected] HEAD -> refs/for/main/topic (proc-receive failed to report status) EOF test_cmp expect actual && + git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && cat >expect <<-EOF && diff --git a/t/t5411/test-0014-bad-protocol--porcelain.sh b/t/t5411/test-0014-bad-protocol--porcelain.sh index 88c5631..fdb4569 100644 --- a/t/t5411/test-0014-bad-protocol--porcelain.sh +++ b/t/t5411/test-0014-bad-protocol--porcelain.sh @@ -42,6 +42,175 @@ test_expect_success "proc-receive: bad protocol (unknown version, $PROTOCOL/porc test_cmp expect actual ' +test_expect_success "setup proc-receive hook (hook --die-read-version, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-read-version + EOF +' + +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push : refs/for/main/topic(A) +test_expect_success "proc-receive: bad protocol (hook --die-read-version, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain origin \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; n; p; n; p; }" \ + actual && + cat >expect <<-EOF && + To + ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook) + Done + EOF + test_cmp expect actual && + grep "remote: fatal: die with the --die-read-version option" out && + grep "remote: error: fail to negotiate version with proc-receive hook" out && + + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (hook --die-write-version, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-write-version + EOF +' + +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push : refs/for/main/topic(A) +test_expect_success "proc-receive: bad protocol (hook --die-write-version, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain origin \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; n; p; n; p; }" \ + actual && + cat >expect <<-EOF && + To + ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook) + Done + EOF + test_cmp expect actual && + grep "remote: fatal: die with the --die-write-version option" out && + grep "remote: error: fail to negotiate version with proc-receive hook" out && + + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (hook --die-read-commands, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-read-commands + EOF +' + +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push : refs/for/main/topic(A) +test_expect_success "proc-receive: bad protocol (hook --die-read-commands, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain origin \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; n; p; n; p; }" \ + actual && + cat >expect <<-EOF && + To + ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook) + Done + EOF + test_cmp expect actual && + grep "remote: fatal: die with the --die-read-commands option" out && + + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (hook --die-read-push-options, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-read-push-options + EOF +' + +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push : refs/for/main/topic(A) +test_expect_success "proc-receive: bad protocol (hook --die-read-push-options, $PROTOCOL/porcelain)" ' + git -C "$upstream" config receive.advertisePushOptions true && + test_must_fail git -C workbench push --porcelain origin \ + -o reviewers=user1,user2 \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; n; p; n; p; }" \ + actual && + cat >expect <<-EOF && + To + ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook) + Done + EOF + test_cmp expect actual && + grep "remote: fatal: die with the --die-read-push-options option" out && + + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (hook --die-write-report, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-write-report + EOF +' + +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push : refs/for/main/topic(A) +test_expect_success "proc-receive: bad protocol (hook --die-write-report, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain origin \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + filter_out_user_friendly_and_stable_output \ + -e "/^To / { p; n; p; n; p; }" \ + actual && + cat >expect <<-EOF && + To + ! HEAD:refs/for/main/topic [remote rejected] (fail to run proc-receive hook) + Done + EOF + test_cmp expect actual && + grep "remote: fatal: die with the --die-write-report option" out && + + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + EOF + test_cmp expect actual +' + test_expect_success "setup proc-receive hook (no report, $PROTOCOL/porcelain)" ' write_script "$upstream/hooks/proc-receive" <<-EOF printf >&2 "# proc-receive hook\n" @@ -71,6 +240,7 @@ test_expect_success "proc-receive: bad protocol (no report, $PROTOCOL/porcelain) Done EOF test_cmp expect actual && + git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && cat >expect <<-EOF && @@ -84,7 +254,6 @@ test_expect_success "proc-receive: bad protocol (no report, $PROTOCOL/porcelain) # Refs of workbench: main(A) tags/v123 test_expect_success "cleanup ($PROTOCOL/porcelain)" ' git -C "$upstream" update-ref -d refs/heads/next - ' test_expect_success "setup proc-receive hook (no ref, $PROTOCOL/porcelain)" ' @@ -115,6 +284,7 @@ test_expect_success "proc-receive: bad protocol (no ref, $PROTOCOL/porcelain)" ' Done EOF test_cmp expect actual && + git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && cat >expect <<-EOF && @@ -151,6 +321,7 @@ test_expect_success "proc-receive: bad protocol (unknown status, $PROTOCOL/porce Done EOF test_cmp expect actual && + git -C "$upstream" show-ref >out && make_user_friendly_and_stable_output actual && cat >expect <<-EOF && -- cgit v0.10.2-6-g49f6 From 80ffeb94f4c9eae4e099fec47e39105fc1e19132 Mon Sep 17 00:00:00 2001 From: Jiang Xin Date: Wed, 11 Nov 2020 19:32:02 +0800 Subject: receive-pack: use default version 0 for proc-receive In the verison negotiation phase between "receive-pack" and "proc-receive", "proc-receive" can send an empty flush-pkt to end the negotiation and use default version 0. Capabilities (such as "push-options") are not supported in version 0. Signed-off-by: Jiang Xin Signed-off-by: Junio C Hamano diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 2bd7365..f1f0f7b 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -1192,7 +1192,12 @@ static int run_proc_receive_hook(struct command *commands, goto cleanup; } - if (version != 1) { + switch (version) { + case 0: + /* fallthrough */ + case 1: + break; + default: strbuf_addf(&errmsg, "proc-receive version '%d' is not supported", version); code = -1; diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c index 6652ced..cc08506 100644 --- a/t/helper/test-proc-receive.c +++ b/t/helper/test-proc-receive.c @@ -45,8 +45,14 @@ static void proc_receive_verison(struct packet_reader *reader) { if (packet_reader_read(reader) != PACKET_READ_NORMAL) break; + /* Ignore version negotiation for version 0 */ + if (version == 0) + continue; + if (reader->pktlen > 8 && starts_with(reader->line, "version=")) { server_version = atoi(reader->line+8); + if (server_version != 1) + die("bad protocol version: %d", server_version); linelen = strlen(reader->line); if (linelen < reader->pktlen) { const char *feature_list = reader->line + linelen + 1; @@ -58,15 +64,13 @@ static void proc_receive_verison(struct packet_reader *reader) { } } - if (server_version != 1) - die("bad protocol version: %d", server_version); - if (die_write_version) die("die with the --die-write-version option"); - packet_write_fmt(1, "version=%d%c%s\n", - version, '\0', - use_push_options && !no_push_options ? "push-options": ""); + if (version != 0) + packet_write_fmt(1, "version=%d%c%s\n", + version, '\0', + use_push_options && !no_push_options ? "push-options": ""); packet_flush(1); } diff --git a/t/t5411/test-0026-push-options.sh b/t/t5411/test-0026-push-options.sh index d414be8..e88edb1 100644 --- a/t/t5411/test-0026-push-options.sh +++ b/t/t5411/test-0026-push-options.sh @@ -32,6 +32,66 @@ test_expect_success "enable push options ($PROTOCOL)" ' git -C "$upstream" config receive.advertisePushOptions true ' +test_expect_success "setup version=0 for proc-receive hook ($PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + --version 0 \ + -r "ok refs/for/main/topic" + EOF +' + +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push -o ... : next(A) refs/for/main/topic +test_expect_success "proc-receive: ignore push-options for version 0 ($PROTOCOL)" ' + git -C workbench push \ + --atomic \ + -o issue=123 \ + -o reviewer=user1 \ + origin \ + HEAD:refs/heads/next \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/heads/next + remote: pre-receive< refs/for/main/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/main/topic + remote: proc-receive> ok refs/for/main/topic + remote: # post-receive hook + remote: post-receive< refs/heads/next + remote: post-receive< refs/for/main/topic + To + * [new branch] HEAD -> next + * [new reference] HEAD -> refs/for/main/topic + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + refs/heads/next + EOF + test_cmp expect actual +' + +test_expect_success "restore proc-receive hook ($PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/main/topic" + EOF +' + +# Refs of upstream : main(A) next(A) +# Refs of workbench: main(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL)" ' + git -C "$upstream" update-ref -d refs/heads/next +' + # Refs of upstream : main(A) # Refs of workbench: main(A) tags/v123 # git push -o ... : next(A) refs/for/main/topic diff --git a/t/t5411/test-0027-push-options--porcelain.sh b/t/t5411/test-0027-push-options--porcelain.sh index d5d0dcb..3a6561b 100644 --- a/t/t5411/test-0027-push-options--porcelain.sh +++ b/t/t5411/test-0027-push-options--porcelain.sh @@ -33,6 +33,68 @@ test_expect_success "enable push options ($PROTOCOL/porcelain)" ' git -C "$upstream" config receive.advertisePushOptions true ' +test_expect_success "setup version=0 for proc-receive hook ($PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + --version 0 \ + -r "ok refs/for/main/topic" + EOF +' + +# Refs of upstream : main(A) +# Refs of workbench: main(A) tags/v123 +# git push -o ... : next(A) refs/for/main/topic +test_expect_success "proc-receive: ignore push-options for version 0 ($PROTOCOL/porcelain)" ' + git -C workbench push \ + --porcelain \ + --atomic \ + -o issue=123 \ + -o reviewer=user1 \ + origin \ + HEAD:refs/heads/next \ + HEAD:refs/for/main/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/heads/next + remote: pre-receive< refs/for/main/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/main/topic + remote: proc-receive> ok refs/for/main/topic + remote: # post-receive hook + remote: post-receive< refs/heads/next + remote: post-receive< refs/for/main/topic + To + * HEAD:refs/heads/next [new branch] + * HEAD:refs/for/main/topic [new reference] + Done + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/main + refs/heads/next + EOF + test_cmp expect actual +' + +test_expect_success "restore proc-receive hook ($PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/main/topic" + EOF +' + +# Refs of upstream : main(A) next(A) +# Refs of workbench: main(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL/porcelain)" ' + git -C "$upstream" update-ref -d refs/heads/next +' + # Refs of upstream : main(A) # Refs of workbench: main(A) tags/v123 # git push -o ... : next(A) refs/for/main/topic -- cgit v0.10.2-6-g49f6