Skip to content

Commit 81a1ff5

Browse files
jiangxingitster
authored andcommitted
receive-pack: extension for server-side report
Each command for the "proc-receive" hook may point to a pseudo-reference and always has a zero-old as its old-oid. But the "proc-receive" hook may update an alternate reference and the reference may exist already (has a non-zero old-oid). And we may want certain commands to bypass the "proc-receive" hook and let "receive-pack" handle them. In order to report proper reference name, old-oid, and let certain commands fall through, an extensible reporting method for "proc-receive" and "receive-pack" is introduced. The "proc-receive" hook can report its results in the following format: # OK, run this command successfully. PKT-LINE(<old-oid> <new-oid> <ref> ok) # NO, I reject it. PKT-LINE(<old-oid> <new-oid> <ref> ng <reason>) # Fall through, let "receive-pack" to execute it. PKT-LINE(<old-oid> <new-oid> <ref> ft) # OK, but has an alternate reference. The alternate reference name # and other status are given in key=value pairs after the null # character. PKT-LINE(<old-oid> <new-oid> <ref> ok\0ref=refs/pull/123/head forced-update) The reporting function for "receive-pack" is also extended using a backward compatible way by adding key-value pairs after an null character, like: # OK, run this command successfully with optional extended-status. ok <reference>\0ref=refs/pull/123/head old-oid=... # NO, I reject it. ng <reference> <error message> This commit only includes changes on the server side, so we can make a compatible test on old version of a Git client. Suggested-by: Junio C Hamano <[email protected]> Signed-off-by: Jiang Xin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2df8de1 commit 81a1ff5

File tree

3 files changed

+137
-16
lines changed

3 files changed

+137
-16
lines changed

builtin/receive-pack.c

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ static void write_head_info(void)
328328
struct command {
329329
struct command *next;
330330
const char *error_string;
331+
const char *extended_status;
331332
unsigned int skip_update:1,
332333
did_not_exist:1,
333334
run_proc_receive:2;
@@ -850,6 +851,7 @@ static int read_proc_receive_report(struct packet_reader *reader,
850851
{
851852
struct command *cmd;
852853
struct command *hint = NULL;
854+
struct strbuf extended_status = STRBUF_INIT;
853855
int code = 0;
854856

855857
for (;;) {
@@ -858,9 +860,11 @@ static int read_proc_receive_report(struct packet_reader *reader,
858860
const char *p;
859861
char *status;
860862
char *msg = NULL;
863+
int len;
861864

862865
if (packet_reader_read(reader) != PACKET_READ_NORMAL)
863866
break;
867+
len = strlen(reader->line);
864868
if (parse_oid_hex(reader->line, &old_oid, &p) ||
865869
*p++ != ' ' ||
866870
parse_oid_hex(p, &new_oid, &p) ||
@@ -912,16 +916,34 @@ static int read_proc_receive_report(struct packet_reader *reader,
912916
else
913917
hint->error_string = "failed";
914918
code = -1;
919+
} else if (!strcmp("ft", status)) {
920+
/* Reset "run_proc_receive" field, and continue to run in "receive-pack" */
921+
hint->run_proc_receive = 0;
915922
} else if (strcmp("ok", status)) {
916923
strbuf_addf(errmsg, "proc-receive has bad status '%s' for '%s'\n",
917924
status, reader->line);
918925
code = -1;
919926
/* Skip marking it as RUN_PROC_RECEIVE_RETURNED */
920927
continue;
921928
}
922-
oidcpy(&hint->old_oid, &old_oid);
923-
oidcpy(&hint->new_oid, &new_oid);
924-
hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED;
929+
if (reader->pktlen > len)
930+
strbuf_addstr(&extended_status, (char *)reader->line + len + 1);
931+
if (oidcmp(&hint->old_oid, &old_oid)) {
932+
oidcpy(&hint->old_oid, &old_oid);
933+
strbuf_addf(&extended_status, "%sold-oid=%s",
934+
extended_status.len > 0 ? " ": "",
935+
oid_to_hex(&old_oid));
936+
}
937+
if (oidcmp(&hint->new_oid, &new_oid)) {
938+
oidcpy(&hint->new_oid, &new_oid);
939+
strbuf_addf(&extended_status, "%snew-oid=%s",
940+
extended_status.len > 0 ? " ": "",
941+
oid_to_hex(&new_oid));
942+
}
943+
if (extended_status.len > 0)
944+
hint->extended_status = strbuf_detach(&extended_status, NULL);
945+
if (hint->run_proc_receive)
946+
hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED;
925947
}
926948

927949
for (cmd = commands; cmd; cmd = cmd->next)
@@ -2179,12 +2201,23 @@ static void report(struct command *commands, const char *unpack_status)
21792201
packet_buf_write(&buf, "unpack %s\n",
21802202
unpack_status ? unpack_status : "ok");
21812203
for (cmd = commands; cmd; cmd = cmd->next) {
2182-
if (!cmd->error_string)
2183-
packet_buf_write(&buf, "ok %s\n",
2184-
cmd->ref_name);
2185-
else
2186-
packet_buf_write(&buf, "ng %s %s\n",
2187-
cmd->ref_name, cmd->error_string);
2204+
if (!cmd->error_string) {
2205+
if (cmd->extended_status)
2206+
packet_buf_write(&buf, "ok %s%c%s\n",
2207+
cmd->ref_name, '\0',
2208+
cmd->extended_status);
2209+
else
2210+
packet_buf_write(&buf, "ok %s\n",
2211+
cmd->ref_name);
2212+
} else {
2213+
if (cmd->extended_status)
2214+
packet_buf_write(&buf, "ng %s %s%c%s\n",
2215+
cmd->ref_name, cmd->error_string,
2216+
'\0', cmd->extended_status);
2217+
else
2218+
packet_buf_write(&buf, "ng %s %s\n",
2219+
cmd->ref_name, cmd->error_string);
2220+
}
21882221
}
21892222
packet_buf_flush(&buf);
21902223

t/helper/test-proc-receive.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,18 @@ int cmd__proc_receive(int argc, const char **argv)
159159
}
160160

161161
if (returns.nr)
162-
for_each_string_list_item(item, &returns)
163-
packet_write_fmt(1, "%s\n", item->string);
162+
for_each_string_list_item(item, &returns) {
163+
char *p;
164+
165+
p = strstr(item->string, "\\0");
166+
if (p) {
167+
*p = '\0';
168+
p += 2;
169+
packet_write_fmt(1, "%s%c%s\n", item->string, '\0', p);
170+
} else {
171+
packet_write_fmt(1, "%s\n", item->string);
172+
}
173+
}
164174
packet_flush(1);
165175
sigchain_pop(SIGPIPE);
166176

t/t5411/common-test-cases.sh

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -640,8 +640,8 @@ test_expect_success "setup proc-receive hook" '
640640
641641
test-tool proc-receive -v \
642642
-r "$ZERO_OID $A refs/review/a/b/c/topic ok" \
643-
-r "$ZERO_OID $A refs/for/next/topic ok" \
644-
-r "$B $A refs/for/master/topic ok"
643+
-r "$ZERO_OID $A refs/for/next/topic ok\0ref=refs/pull/123/head" \
644+
-r "$B $A refs/for/master/topic ok\0ref=refs/pull/124/head forced-update"
645645
EOF
646646
chmod a+x "$upstream/hooks/proc-receive"
647647
'
@@ -666,8 +666,8 @@ test_expect_success "report update of all special refs" '
666666
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/review/a/b/c/topic
667667
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
668668
remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/review/a/b/c/topic ok
669-
remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/for/next/topic ok
670-
remote: proc-receive> <COMMIT-B> <COMMIT-A> refs/for/master/topic ok
669+
remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/for/next/topic ok\0ref=refs/pull/123/head
670+
remote: proc-receive> <COMMIT-B> <COMMIT-A> refs/for/master/topic ok\0ref=refs/pull/124/head forced-update
671671
remote: # post-receive hook
672672
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
673673
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/review/a/b/c/topic
@@ -701,9 +701,10 @@ test_expect_success "setup proc-receive hook" '
701701

702702
# Refs of upstream : master(A)
703703
# Refs of workbench: master(A) tags/v123
704-
# git push : bar(A) baz(A) refs/for/next/topic(A) foo(A) refs/for/master/topic(A)
704+
# git push : (B) bar(A) baz(A) refs/for/next/topic(A) foo(A) refs/for/master/topic(A)
705705
test_expect_success "report mixed refs update" '
706706
git -C workbench push origin \
707+
$B:refs/heads/master \
707708
HEAD:refs/heads/bar \
708709
HEAD:refs/heads/baz \
709710
HEAD:refs/for/next/topic \
@@ -713,6 +714,7 @@ test_expect_success "report mixed refs update" '
713714
make_user_friendly_and_stable_output <out >actual &&
714715
cat >expect <<-EOF &&
715716
remote: # pre-receive hook
717+
remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
716718
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
717719
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
718720
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
@@ -724,12 +726,14 @@ test_expect_success "report mixed refs update" '
724726
remote: proc-receive> <ZERO-OID> <COMMIT-A> refs/for/next/topic ok
725727
remote: proc-receive> <COMMIT-A> <COMMIT-B> refs/for/master/topic ok
726728
remote: # post-receive hook
729+
remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/master
727730
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/bar
728731
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/baz
729732
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
730733
remote: post-receive< <ZERO-OID> <COMMIT-A> refs/heads/foo
731734
remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
732735
To <URL/of/upstream.git>
736+
<OID-A>..<OID-B> <COMMIT-B> -> master
733737
* [new branch] HEAD -> bar
734738
* [new branch] HEAD -> baz
735739
* [new reference] HEAD -> refs/for/next/topic
@@ -743,6 +747,80 @@ test_expect_success "report mixed refs update" '
743747
<COMMIT-A> refs/heads/bar
744748
<COMMIT-A> refs/heads/baz
745749
<COMMIT-A> refs/heads/foo
750+
<COMMIT-B> refs/heads/master
751+
EOF
752+
test_cmp expect actual
753+
'
754+
755+
test_expect_success "config receive.procReceiveRefs for all refs" '
756+
git -C "$upstream" config --add receive.procReceiveRefs refs
757+
'
758+
759+
test_expect_success "setup proc-receive hook" '
760+
cat >"$upstream/hooks/proc-receive" <<-EOF &&
761+
#!/bin/sh
762+
763+
printf >&2 "# proc-receive hook\n"
764+
765+
test-tool proc-receive -v \
766+
-r "$B $A refs/heads/master ft" \
767+
-r "$A $ZERO_OID refs/heads/foo ft" \
768+
-r "$A $B refs/heads/bar ft" \
769+
-r "$A $B refs/for/master/topic ok\0ref=refs/pull/123/head" \
770+
-r "$B $A refs/for/next/topic ok\0ref=refs/pull/124/head forced-update"
771+
EOF
772+
chmod a+x "$upstream/hooks/proc-receive"
773+
'
774+
775+
# Refs of upstream : master(B) foo(A) bar(A)) baz(A)
776+
# Refs of workbench: master(A) tags/v123
777+
# git push -f : master(A) (NULL) (B) refs/for/master/topic(A) refs/for/next/topic(A)
778+
test_expect_success "report test: fallthrough" '
779+
git -C workbench push -f origin \
780+
HEAD:refs/heads/master \
781+
:refs/heads/foo \
782+
$B:refs/heads/bar \
783+
HEAD:refs/for/master/topic \
784+
HEAD:refs/for/next/topic \
785+
>out 2>&1 &&
786+
make_user_friendly_and_stable_output <out >actual &&
787+
cat >expect <<-EOF &&
788+
remote: # pre-receive hook
789+
remote: pre-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
790+
remote: pre-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
791+
remote: pre-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
792+
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
793+
remote: pre-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
794+
remote: # proc-receive hook
795+
remote: proc-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
796+
remote: proc-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
797+
remote: proc-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
798+
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/master/topic
799+
remote: proc-receive< <ZERO-OID> <COMMIT-A> refs/for/next/topic
800+
remote: proc-receive> <COMMIT-B> <COMMIT-A> refs/heads/master ft
801+
remote: proc-receive> <COMMIT-A> <ZERO-OID> refs/heads/foo ft
802+
remote: proc-receive> <COMMIT-A> <COMMIT-B> refs/heads/bar ft
803+
remote: proc-receive> <COMMIT-A> <COMMIT-B> refs/for/master/topic ok\0ref=refs/pull/123/head
804+
remote: proc-receive> <COMMIT-B> <COMMIT-A> refs/for/next/topic ok\0ref=refs/pull/124/head forced-update
805+
remote: # post-receive hook
806+
remote: post-receive< <COMMIT-A> <COMMIT-B> refs/heads/bar
807+
remote: post-receive< <COMMIT-A> <ZERO-OID> refs/heads/foo
808+
remote: post-receive< <COMMIT-B> <COMMIT-A> refs/heads/master
809+
remote: post-receive< <COMMIT-A> <COMMIT-B> refs/for/master/topic
810+
remote: post-receive< <COMMIT-B> <COMMIT-A> refs/for/next/topic
811+
To <URL/of/upstream.git>
812+
<OID-A>..<OID-B> <COMMIT-B> -> bar
813+
- [deleted] foo
814+
+ <OID-B>...<OID-A> HEAD -> master (forced update)
815+
* [new reference] HEAD -> refs/for/master/topic
816+
* [new reference] HEAD -> refs/for/next/topic
817+
EOF
818+
test_cmp expect actual &&
819+
git -C "$upstream" show-ref >out &&
820+
make_user_friendly_and_stable_output <out >actual &&
821+
cat >expect <<-EOF &&
822+
<COMMIT-B> refs/heads/bar
823+
<COMMIT-A> refs/heads/baz
746824
<COMMIT-A> refs/heads/master
747825
EOF
748826
test_cmp expect actual

0 commit comments

Comments
 (0)