From patchwork Tue Apr 7 12:08:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11478013 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2987D1392 for ; Tue, 7 Apr 2020 12:08:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id F2A9B2074B for ; Tue, 7 Apr 2020 12:08:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="R6GztpSv" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728478AbgDGMIX (ORCPT ); Tue, 7 Apr 2020 08:08:23 -0400 Received: from mail-pg1-f195.google.com ([209.85.215.195]:42159 "EHLO mail-pg1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728146AbgDGMIW (ORCPT ); Tue, 7 Apr 2020 08:08:22 -0400 Received: by mail-pg1-f195.google.com with SMTP id g6so1636045pgs.9 for ; Tue, 07 Apr 2020 05:08:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=IiqVaz5cJTMB/ny13GrqAqDdURHqAkS4rB+M3+MvmuU=; b=R6GztpSvvA8bIxmPsnz8hwQRgjpOr8ptbnB0ucL94qy3SW0dCPsEq5dz3QIRG+FKr4 jIoz6x2s6lRHVaamPnVUHRy07B0yJrQZRfE6Ow6jY4mBqiM5jZHXYD8lpPsPhxlu2EuI Pfpff/JxXBropH4SlE4psrBmDh27FYSTJbFW+1rTl4vzYLut9Urw31pdEho82ZkBL+T6 vwZI9YzvDzq5kMlLz8zmBbsew8+oxsnWOR/kW7C8y478NZPSwtNIdWOzehW4/NGLq1Eq pQ8zWOMSh4fAky6eiq0R3jbIToiWZlXCG7zh2fEJ6Tq0A9ZCI366xv8bZcWXF8hR2pQr AoLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=IiqVaz5cJTMB/ny13GrqAqDdURHqAkS4rB+M3+MvmuU=; b=VEM7oXHg2gYm+EwMpaRZ59DoLLNUl07CVxXALKt5YgY+CPR0oMDQAl9g+KuatVXyOf /nZUM+slxJgySH1RcrR9wp/E661jmCWPoUfh5VJ5B6+c0byGqC0io8aAWFlf4gQ1Vjov AQgxf+cGKv8sI4r449BOhK52oDzBT+/8RAPimILhBFNv1BlLZsS3zR5r5C2RdpYMx2mI ZxeQV+7TIefoUr4fMSDLju6BWTs1NtS21gdk6vWesplO3vl5M7uXp3HckB4dSUfDusEC WMpY6v8zCIB256SzYY18YmHs6/A3ka8wGfqBe1nJWuGv9aAHNzV3x4xQf082Z53eJxhx sR8w== X-Gm-Message-State: AGi0PuYQ7tmrT3reIhruKyLRM/lUh7sHkFIWB+Eg340NH4YB5lzLqpU1 63Bdeve5Qk/aVfGQDF9huZ4VHmp5n0E= X-Google-Smtp-Source: APiQypJp2ZfHlfnWvt/HJ2nZJnE8+P1jsaLfcRrwZDG/cNIx3x5eOApahd3pa26XGbkXdl+QZ8jkkQ== X-Received: by 2002:a62:e315:: with SMTP id g21mr2291550pfh.302.1586261299325; Tue, 07 Apr 2020 05:08:19 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id e26sm14061833pfj.61.2020.04.07.05.08.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Apr 2020 05:08:18 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v9 1/6] transport: not report a non-head push as a branch Date: Tue, 7 Apr 2020 08:08:08 -0400 Message-Id: <20200407120813.25025-2-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200404134345.10655-1-worldhello.net@gmail.com> References: <20200404134345.10655-1-worldhello.net@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jiang Xin When pushing a new reference (not a head or tag), report it as a new reference instead of a new branch. Signed-off-by: Jiang Xin --- t/t5411-proc-receive-hook.sh | 75 +++++++++++++++++++ t/t5411/common-functions.sh | 49 ++++++++++++ t/t5411/common-test-cases.sh | 43 +++++++++++ t/t5412-proc-receive-hook-http-protocol.sh | 86 ++++++++++++++++++++++ t/t5516-fetch-push.sh | 2 +- transport.c | 9 ++- 6 files changed, 260 insertions(+), 4 deletions(-) create mode 100755 t/t5411-proc-receive-hook.sh create mode 100644 t/t5411/common-functions.sh create mode 100644 t/t5411/common-test-cases.sh create mode 100755 t/t5412-proc-receive-hook-http-protocol.sh diff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh new file mode 100755 index 0000000000..09d516cf1b --- /dev/null +++ b/t/t5411-proc-receive-hook.sh @@ -0,0 +1,75 @@ +#!/bin/sh +# +# Copyright (c) 2020 Jiang Xin +# + +test_description='Test proc-receive hook' + +. ./test-lib.sh + +. "$TEST_DIRECTORY"/t5411/common-functions.sh + +# Format the output of git-push, git-show-ref and other commands to make a +# user-friendly and stable text. In addition to the common format method, +# we also replace URL of different protocol for the upstream repository to +# a fixed pattern. +make_user_friendly_and_stable_output () { + make_user_friendly_and_stable_output_common | sed \ + -e "s#To ../upstream.git#To #" +} + +# Refs of upstream : master(B) next(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "setup" ' + git init --bare upstream.git && + git init workbench && + create_commits_in workbench A B && + ( + cd workbench && + # Try to make a stable fixed width for abbreviated commit ID, + # this fixed-width oid will be replaced with "". + git config core.abbrev 7 && + git remote add origin ../upstream.git && + git update-ref refs/heads/master $A && + git tag -m "v123" v123 $A && + git push origin \ + $B:refs/heads/master \ + $A:refs/heads/next + ) && + TAG=$(git -C workbench rev-parse v123) && + + # setup pre-receive hook + cat >upstream.git/hooks/pre-receive <<-\EOF && + #!/bin/sh + + echo >&2 "# pre-receive hook" + + while read old new ref + do + echo >&2 "pre-receive< $old $new $ref" + done + EOF + + # setup post-receive hook + cat >upstream.git/hooks/post-receive <<-\EOF && + #!/bin/sh + + echo >&2 "# post-receive hook" + + while read old new ref + do + echo >&2 "post-receive< $old $new $ref" + done + EOF + + chmod a+x \ + upstream.git/hooks/pre-receive \ + upstream.git/hooks/post-receive && + + upstream=upstream.git +' + +# Include test cases for both file and HTTP protocol +. "$TEST_DIRECTORY"/t5411/common-test-cases.sh + +test_done diff --git a/t/t5411/common-functions.sh b/t/t5411/common-functions.sh new file mode 100644 index 0000000000..e46884f74d --- /dev/null +++ b/t/t5411/common-functions.sh @@ -0,0 +1,49 @@ +# Create commits in and assign each commit's oid to shell variables +# given in the arguments (A, B, and C). E.g.: +# +# create_commits_in A B C +# +# NOTE: Never calling this function from a subshell since variable +# assignments will disappear when subshell exits. +create_commits_in () { + repo="$1" && + if ! parent=$(git -C "$repo" rev-parse HEAD^{} --) + then + parent= + fi && + T=$(git -C "$repo" write-tree) && + shift && + while test $# -gt 0 + do + name=$1 && + test_tick && + if test -z "$parent" + then + oid=$(echo $name | git -C "$repo" commit-tree $T) + else + oid=$(echo $name | git -C "$repo" commit-tree -p $parent $T) + fi && + eval $name=$oid && + parent=$oid && + shift || + return 1 + done && + git -C "$repo" update-ref refs/heads/master $oid +} + +# Format the output of git-push, git-show-ref and other commands to make a +# user-friendly and stable text. We can easily prepare the expect text +# without having to worry about future changes of the commit ID and spaces +# of the output. We also replce single quotes with double quotes, because +# it is boring to prepare unquoted single quotes in expect txt. +make_user_friendly_and_stable_output_common () { + sed \ + -e "s/ *\$//" \ + -e "s/ */ /g" \ + -e "s/'/\"/g" \ + -e "s/$A//g" \ + -e "s/$B//g" \ + -e "s/$TAG//g" \ + -e "s/$ZERO_OID//g" \ + -e "s/[0-9a-f]\{7,\}//g" +} diff --git a/t/t5411/common-test-cases.sh b/t/t5411/common-test-cases.sh new file mode 100644 index 0000000000..33b8541f28 --- /dev/null +++ b/t/t5411/common-test-cases.sh @@ -0,0 +1,43 @@ +# Refs of upstream : master(B) next(A) +# Refs of workbench: master(A) tags/v123 +# git-push -f : master(A) NULL tags/v123 refs/review/master/topic(A) a/b/c(A) +test_expect_success "normal git-push command" ' + git -C workbench push -f origin \ + refs/tags/v123 \ + :refs/heads/next \ + HEAD:refs/heads/master \ + HEAD:refs/review/master/topic \ + HEAD:refs/heads/a/b/c \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/heads/master + remote: pre-receive< refs/heads/next + remote: pre-receive< refs/tags/v123 + remote: pre-receive< refs/review/master/topic + remote: pre-receive< refs/heads/a/b/c + remote: # post-receive hook + remote: post-receive< refs/heads/master + remote: post-receive< refs/heads/next + remote: post-receive< refs/tags/v123 + remote: post-receive< refs/review/master/topic + remote: post-receive< refs/heads/a/b/c + To + + ... HEAD -> master (forced update) + - [deleted] next + * [new tag] v123 -> v123 + * [new reference] HEAD -> refs/review/master/topic + * [new branch] HEAD -> a/b/c + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/a/b/c + refs/heads/master + refs/review/master/topic + refs/tags/v123 + EOF + test_cmp expect actual +' diff --git a/t/t5412-proc-receive-hook-http-protocol.sh b/t/t5412-proc-receive-hook-http-protocol.sh new file mode 100755 index 0000000000..4883e69299 --- /dev/null +++ b/t/t5412-proc-receive-hook-http-protocol.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# +# Copyright (c) 2020 Jiang Xin +# + +test_description='Test proc-receive hook for HTTP protocol' + +. ./test-lib.sh + +ROOT_PATH="$PWD" +. "$TEST_DIRECTORY"/lib-gpg.sh +. "$TEST_DIRECTORY"/lib-httpd.sh +. "$TEST_DIRECTORY"/lib-terminal.sh +start_httpd + +. "$TEST_DIRECTORY"/t5411/common-functions.sh + +# Format the output of git-push, git-show-ref and other commands to make a +# user-friendly and stable text. In addition to the common format method, +# we also replace URL of different protocol for the upstream repository to +# a fixed pattern. +make_user_friendly_and_stable_output () { + make_user_friendly_and_stable_output_common | sed \ + -e "s#To http:.*/upstream.git#To #" +} + +# Refs of upstream : master(B) next(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "setup" ' + git init --bare upstream.git && + git -C upstream.git config http.receivepack true && + git init workbench && + create_commits_in workbench A B && + ( + cd workbench && + # Try to make a stable fixed width for abbreviated commit ID, + # this fixed-width oid will be replaced with "". + git config core.abbrev 7 && + git remote add origin ../upstream.git && + git update-ref refs/heads/master $A && + git tag -m "v123" v123 $A && + git push origin \ + $B:refs/heads/master \ + $A:refs/heads/next + ) && + TAG=$(git -C workbench rev-parse v123) && + + # setup pre-receive hook + cat >upstream.git/hooks/pre-receive <<-\EOF && + #!/bin/sh + + echo >&2 "# pre-receive hook" + + while read old new ref + do + echo >&2 "pre-receive< $old $new $ref" + done + EOF + + # setup post-receive hook + cat >upstream.git/hooks/post-receive <<-\EOF && + #!/bin/sh + + echo >&2 "# post-receive hook" + + while read old new ref + do + echo >&2 "post-receive< $old $new $ref" + done + EOF + + chmod a+x \ + upstream.git/hooks/pre-receive \ + upstream.git/hooks/post-receive && + + upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" && + mv upstream.git "$upstream" && + git -C workbench remote set-url origin $HTTPD_URL/smart/upstream.git +' + +setup_askpass_helper + +# Include test cases for both file and HTTP protocol +. "$TEST_DIRECTORY"/t5411/common-test-cases.sh + +test_done diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 9ff041a093..9e4b9313b5 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -1039,7 +1039,7 @@ test_force_fetch_tag "annotated tag" "-f -a -m'tag message'" test_expect_success 'push --porcelain' ' mk_empty testrepo && echo >.git/foo "To testrepo" && - echo >>.git/foo "* refs/heads/master:refs/remotes/origin/master [new branch]" && + echo >>.git/foo "* refs/heads/master:refs/remotes/origin/master [new reference]" && echo >>.git/foo "Done" && git push >.git/bar --porcelain testrepo refs/heads/master:refs/remotes/origin/master && ( diff --git a/transport.c b/transport.c index 1fdc7dac1a..272c0f4046 100644 --- a/transport.c +++ b/transport.c @@ -500,9 +500,12 @@ static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_widt porcelain, summary_width); else if (is_null_oid(&ref->old_oid)) print_ref_status('*', - (starts_with(ref->name, "refs/tags/") ? "[new tag]" : - "[new branch]"), - ref, ref->peer_ref, NULL, porcelain, summary_width); + (starts_with(ref->name, "refs/tags/") + ? "[new tag]" + : (starts_with(ref->name, "refs/heads/") + ? "[new branch]" + : "[new reference]")), + ref, ref->peer_ref, NULL, porcelain, summary_width); else { struct strbuf quickref = STRBUF_INIT; char type; From patchwork Tue Apr 7 12:08:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11478019 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D695292C for ; Tue, 7 Apr 2020 12:08:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8CDD5206F7 for ; Tue, 7 Apr 2020 12:08:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="EJm0D0k1" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728578AbgDGMIZ (ORCPT ); Tue, 7 Apr 2020 08:08:25 -0400 Received: from mail-pf1-f195.google.com ([209.85.210.195]:36109 "EHLO mail-pf1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728212AbgDGMIY (ORCPT ); Tue, 7 Apr 2020 08:08:24 -0400 Received: by mail-pf1-f195.google.com with SMTP id n10so731040pff.3 for ; Tue, 07 Apr 2020 05:08:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=K4Ut4+9NEdhE6/keCrNSMawnswNQv37dMTVicn0s8pI=; b=EJm0D0k1N0ABNdBT6C0SeJ/MbJkhMhUErjeI/i3ZQ71mxn/RPm+IEvlUsyv2ZJJ7bm j86w3M25i2XykXNih/VCzaz65uoMZMKtvG+SPSR65hsseIdQ4DxNIEj6ikEL9LNfTJBe V/dQcl7Z4EV5yGlmJPulaq9BG3LyRqi43z29xuhpHTa9426cTMDIaeZnkb9YTEYxV1Bu Z9rVNSAUOHCIneHIG0gB5gSzb50FB4g5EGkqyRukhvdcLmXsjbb/oiMOPlkh9lyIq8kO wYr8QXHMGmuQrG7/IGUm29K9Uz2TlIDztsmRVa1SP05UPSidPug3Y2splQZO8Mhq/y8u mvXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=K4Ut4+9NEdhE6/keCrNSMawnswNQv37dMTVicn0s8pI=; b=mnj/o4c/xuJBKjuG2CtXQuUcFFzY00LJYV8iTx9YQleEGesyAFyXqJqpSU3NyBRvws xlyxgmuYekSGT42uIYT6eFGpdBsqFxO8IJF9qzmpRtosxrbCdkPM4sya0nI1Ka6y2eif 9QXsbEhR4/cvOiqz2/iNhCsaNTRN3MfsFmR514CX1vaeYkdEARTlgGyljgFFnn8ZPfbC QvicFGuwdZjnjozHH5TUnx8/K1s3OVktE8sUVfW6IUunxkRMngFo3JZcf1LI750jaTRi nXN1Qay+UAs1Qf5KLoRHzSh6FkIRtOK9tPFxZqjUeIukStsIxYFei/kD9OWlTVVuddz2 vIcA== X-Gm-Message-State: AGi0PuYwMHpwGEJ0hcY0sc6PKEoHYnp+LHZ4xaPXwNsNH47xdSziYEKT fij4BjSpOMVkU965GFoWx0VXQG27m60= X-Google-Smtp-Source: APiQypKlrTWL4GEUpVecveWfumWjXFeRnCJzTRGKBw/IX2jljN4+T18Qb3/cYQ5acwr11IP6GjhKUQ== X-Received: by 2002:aa7:9d0a:: with SMTP id k10mr2351495pfp.266.1586261300444; Tue, 07 Apr 2020 05:08:20 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id e26sm14061833pfj.61.2020.04.07.05.08.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Apr 2020 05:08:19 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v9 2/6] receive-pack: add new proc-receive hook Date: Tue, 7 Apr 2020 08:08:09 -0400 Message-Id: <20200407120813.25025-3-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200404134345.10655-1-worldhello.net@gmail.com> References: <20200404134345.10655-1-worldhello.net@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jiang Xin Git calls an internal `execute_commands` function to handle commands sent from client to `git-receive-pack`. Regardless of what references the user pushes, git creates or updates the corresponding references if the user has write-permission. A contributor who has no write-permission, cannot push to the repository directly. So, the contributor has to write commits to an alternate location, and sends pull request by emails or by other ways. We call this workflow as a distributed workflow. It would be more convenient to work in a centralized workflow like what Gerrit provided for some cases. For example, a read-only user who cannot push to a branch directly can run the following `git push` command to push commits to a pseudo reference (has a prefix "refs/for/", not "refs/heads/") to create a code review. git push origin \ HEAD:refs/for// The `` in the above example can be as simple as "master", or a more complicated branch name like "foo/bar". The `` in the above example command can be the local branch name of the client side, such as "my/topic". We cannot implement a centralized workflow elegantly by using "pre-receive" + "post-receive", because Git will call the internal function "execute_commands" to create references (even the special pseudo reference) between these two hooks. Even though we can delete the temporarily created pseudo reference via the "post-receive" hook, having a temporary reference is not safe for concurrent pushes. So, add a filter and a new handler to support this kind of workflow. The filter will check the prefix of the reference name, and if the command has a special reference name, the filter will turn a specific field (`run_proc_receive`) on for the command. Commands with this filed turned on will be executed by a new handler (an hook named "proc-receive") instead of the internal `execute_commands` function. We can use this "proc-receive" command to create pull requests or send emails for code review. Suggested by Junio, this "proc-receive" hook reads the commands, push-options (optional), and send result using a protocol in pkt-line format. In the following example, The letter "S" stands for "receive-pack" and letter "H" stands for the hook. # Version and capabilities negotiation. S: PKT-LINE(version=1\0push-options atomic...) S: flush-pkt H: PKT-LINE(version=1\0push-options...) H: flush-pkt # Send commands from server to the hook. S: PKT-LINE(old-oid new-oid ref) S: ... ... S: flush-pkt # Only if push-options have been negotiated. S: PKT-LINE(push-option) S: ... ... S: flush-pkt # Receive result from the hook. # OK, run this command successfully. H: PKT-LINE(old-oid new-oid ref ok) # NO, I reject it. H: PKT-LINE(old-oid new-oid ref ng reason) # OK, but use an alternate reference. (in latter commit) H: PKT-LINE(old-oid new-oid ref ok ref:alt-ref) # It will fallthrough to receive-pack to execute. (in latter commit) H: PKT-LINE(old-oid new-oid ref ft) H: ... ... H: flush-pkt After receiving a command, the hook can create/update another alternate reference. For example, a command for a reference "refs/for/master" may create a special reference, such as "refs/pull/123/head". The alternate reference can be returned from the result in an extensible format like " []". The result will be stored in a command list, and "receive-pack" will use the result to replace the commands that have specific `run_proc_receive` field turned on. Suggested-by: Junio C Hamano Signed-off-by: Jiang Xin --- Makefile | 1 + builtin/receive-pack.c | 269 +++++++++++++++- t/helper/test-proc-receive.c | 175 +++++++++++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + t/t5411/common-functions.sh | 10 +- t/t5411/common-test-cases.sh | 576 +++++++++++++++++++++++++++++++++++ 7 files changed, 1027 insertions(+), 6 deletions(-) create mode 100644 t/helper/test-proc-receive.c diff --git a/Makefile b/Makefile index ef1ff2228f..1c52c280ce 100644 --- a/Makefile +++ b/Makefile @@ -725,6 +725,7 @@ TEST_BUILTINS_OBJS += test-parse-pathspec-file.o TEST_BUILTINS_OBJS += test-path-utils.o TEST_BUILTINS_OBJS += test-pkt-line.o TEST_BUILTINS_OBJS += test-prio-queue.o +TEST_BUILTINS_OBJS += test-proc-receive.o TEST_BUILTINS_OBJS += test-progress.o TEST_BUILTINS_OBJS += test-reach.o TEST_BUILTINS_OBJS += test-read-cache.o diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 2cc18bbffd..f3a2c2612d 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -308,11 +308,14 @@ static void write_head_info(void) packet_flush(1); } +#define RUN_PROC_RECEIVE_SCHEDULED 1 +#define RUN_PROC_RECEIVE_RETURNED 2 struct command { struct command *next; const char *error_string; unsigned int skip_update:1, - did_not_exist:1; + did_not_exist:1, + run_proc_receive:2; int index; struct object_id old_oid; struct object_id new_oid; @@ -817,6 +820,239 @@ static int run_update_hook(struct command *cmd) return finish_command(&proc); } +static struct command *find_command_by_refname(const struct command *list, + const char *refname) +{ + for ( ; list; list = list->next) + if (!strcmp(list->ref_name, refname)) + return (struct command *)list; + return NULL; +} + +static int read_proc_receive_result(struct packet_reader *reader, + struct command *commands, + struct strbuf *errmsg) +{ + struct command *hint; + struct command *cmd; + int code = 0; + + hint = NULL; + for (;;) { + struct object_id old_oid, new_oid; + const char *refname; + const char *p; + char *status; + char *msg = NULL; + + if (packet_reader_read(reader) != PACKET_READ_NORMAL) + break; + if (parse_oid_hex(reader->line, &old_oid, &p) || + *p++ != ' ' || + parse_oid_hex(p, &new_oid, &p) || + *p++ != ' ') { + strbuf_addf(errmsg, "proc-receive expected 'old new ref status [msg]', got '%s'\n", + reader->line); + code = -1; + continue; + } + + refname = p; + status = strchr(p, ' '); + if (!status) { + strbuf_addf(errmsg, "proc-receive expected 'old new ref status [msg]', got '%s'\n", + reader->line); + code = -1; + continue; + } + *status++ = '\0'; + if (strlen(status) > 2 && *(status + 2) == ' ') { + msg = status + 2; + *msg++ = '\0'; + } + if (strlen(status) != 2) { + strbuf_addf(errmsg, "proc-receive has bad status '%s' for '%s'\n", + status, reader->line); + code = -1; + continue; + } + + /* first try searching at our hint, falling back to all refs */ + if (hint) + hint = find_command_by_refname(hint, refname); + if (!hint) + hint = find_command_by_refname(commands, refname); + if (!hint) { + strbuf_addf(errmsg, "proc-receive reported status on unknown ref: %s\n", + refname); + continue; + } + if (!hint->run_proc_receive) { + strbuf_addf(errmsg, "proc-receive reported status on ref of builtin command: %s\n", + refname); + continue; + } + if (!strcmp(status, "ng")) { + if (msg) + hint->error_string = xstrdup(msg); + else + hint->error_string = "failed"; + code = -1; + } else if (strcmp("ok", status)) { + strbuf_addf(errmsg, "proc-receive has bad status '%s' for '%s'\n", + status, reader->line); + code = -1; + /* Skip marking it as RUN_PROC_RECEIVE_RETURNED */ + continue; + } + oidcpy(&hint->old_oid, &old_oid); + oidcpy(&hint->new_oid, &new_oid); + hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED; + } + + for (cmd = commands; cmd; cmd = cmd->next) + if (cmd->run_proc_receive && + !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED)) { + cmd->error_string = "no report from proc-receive"; + code = -1; + } + + return code; +} + +static int run_proc_receive_hook(struct command *commands, + const struct string_list *push_options) +{ + struct child_process proc = CHILD_PROCESS_INIT; + struct async muxer; + struct command *cmd; + const char *argv[2]; + struct packet_reader reader; + struct strbuf cap = STRBUF_INIT; + struct strbuf errmsg = STRBUF_INIT; + int pr_use_push_options = 0; + int version = 0; + int code; + + argv[0] = find_hook("proc-receive"); + if (!argv[0]) { + rp_error("cannot find hook 'proc-receive'"); + return -1; + } + argv[1] = NULL; + + proc.argv = argv; + proc.in = -1; + proc.out = -1; + proc.trace2_hook_name = "proc-receive"; + + if (use_sideband) { + memset(&muxer, 0, sizeof(muxer)); + muxer.proc = copy_to_sideband; + muxer.in = -1; + code = start_async(&muxer); + if (code) + return code; + proc.err = muxer.in; + } else { + proc.err = 0; + } + + code = start_command(&proc); + if (code) { + if (use_sideband) + finish_async(&muxer); + return code; + } + + sigchain_push(SIGPIPE, SIG_IGN); + + /* Version negotiaton */ + packet_reader_init(&reader, proc.out, NULL, 0, + PACKET_READ_CHOMP_NEWLINE | + PACKET_READ_DIE_ON_ERR_PACKET); + if (use_atomic) + strbuf_addstr(&cap, " atomic"); + 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); + strbuf_release(&cap); + } else { + packet_write_fmt(proc.in, "version=1\n"); + } + packet_flush(proc.in); + + for (;;) { + int linelen; + + if (packet_reader_read(&reader) != PACKET_READ_NORMAL) + 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")) + pr_use_push_options = 1; + } + } + } + + if (version != 1) { + strbuf_addf(&errmsg, "proc-receive version '%d' is not supported", + version); + code = -1; + goto cleanup; + } + + /* Send commands */ + for (cmd = commands; cmd; cmd = cmd->next) { + char *old_hex, *new_hex; + + if (!cmd->run_proc_receive || cmd->skip_update || cmd->error_string) + continue; + old_hex = oid_to_hex(&cmd->old_oid); + new_hex = oid_to_hex(&cmd->new_oid); + packet_write_fmt(proc.in, "%s %s %s", + old_hex, new_hex, cmd->ref_name); + } + packet_flush(proc.in); + + /* Send push options */ + if (pr_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); + } + + /* Read result from proc-receive */ + code = read_proc_receive_result(&reader, commands, &errmsg); + +cleanup: + close(proc.in); + close(proc.out); + if (use_sideband) + finish_async(&muxer); + if (finish_command(&proc)) + code = -1; + if (errmsg.len >0) { + char *p = errmsg.buf; + + p += errmsg.len - 1; + if (*p == '\n') + *p = '\0'; + rp_error("%s", errmsg.buf); + strbuf_release(&errmsg); + } + sigchain_pop(SIGPIPE); + + return code; +} + static char *refuse_unconfigured_deny_msg = N_("By default, updating the current branch in a non-bare repository\n" "is denied, because it will make the index and work tree inconsistent\n" @@ -1392,7 +1628,7 @@ static void execute_commands_non_atomic(struct command *commands, struct strbuf err = STRBUF_INIT; for (cmd = commands; cmd; cmd = cmd->next) { - if (!should_process_cmd(cmd)) + if (!should_process_cmd(cmd) || cmd->run_proc_receive) continue; transaction = ref_transaction_begin(&err); @@ -1432,7 +1668,7 @@ static void execute_commands_atomic(struct command *commands, } for (cmd = commands; cmd; cmd = cmd->next) { - if (!should_process_cmd(cmd)) + if (!should_process_cmd(cmd) || cmd->run_proc_receive) continue; cmd->error_string = update(cmd, si); @@ -1468,6 +1704,7 @@ static void execute_commands(struct command *commands, struct iterate_data data; struct async muxer; int err_fd = 0; + int run_proc_receive = 0; if (unpacker_error) { for (cmd = commands; cmd; cmd = cmd->next) @@ -1497,6 +1734,20 @@ static void execute_commands(struct command *commands, reject_updates_to_hidden(commands); + /* Try to find commands that have special prefix in their reference names, + * and mark them to run an external "proc-receive" hook later. + */ + for (cmd = commands; cmd; cmd = cmd->next) { + if (!should_process_cmd(cmd)) + continue; + + /* TODO: replace the fixed prefix by looking up git config variables. */ + if (!strncmp(cmd->ref_name, "refs/for/", 9)) { + cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED; + run_proc_receive = 1; + } + } + if (run_receive_hook(commands, "pre-receive", 0, push_options)) { for (cmd = commands; cmd; cmd = cmd->next) { if (!cmd->error_string) @@ -1523,6 +1774,18 @@ static void execute_commands(struct command *commands, free(head_name_to_free); head_name = head_name_to_free = resolve_refdup("HEAD", 0, NULL, NULL); + if (run_proc_receive) { + int code; + + code = run_proc_receive_hook(commands, push_options); + if (code) { + for (cmd = commands; cmd; cmd = cmd->next) { + if (!cmd->error_string && (cmd->run_proc_receive || use_atomic)) + cmd->error_string = "fail to run proc-receive hook"; + } + } + } + if (use_atomic) execute_commands_atomic(commands, si); else diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c new file mode 100644 index 0000000000..ca44b05bd0 --- /dev/null +++ b/t/helper/test-proc-receive.c @@ -0,0 +1,175 @@ +#include "cache.h" +#include "connect.h" +#include "parse-options.h" +#include "pkt-line.h" +#include "sigchain.h" +#include "string-list.h" +#include "test-tool.h" + +static const char *proc_receive_usage[] = { + "test-tool proc-receive [...]", + NULL +}; + +static int version = 1; +static int verbose = 0; +static int no_push_options = 0; +static int use_atomic = 0; +static int use_push_options = 0; +static struct string_list returns = STRING_LIST_INIT_NODUP; + +struct command { + struct command *next; + const char *error_string; + unsigned int skip_update:1, + did_not_exist:1; + int index; + struct object_id old_oid; + struct object_id new_oid; + char ref_name[FLEX_ARRAY]; /* more */ +}; + +static void proc_receive_verison(struct packet_reader *reader) { + int server_version = 0; + + for (;;) { + int linelen; + + if (packet_reader_read(reader) != PACKET_READ_NORMAL) + break; + + if (reader->pktlen > 8 && starts_with(reader->line, "version=")) { + server_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, "atomic")) + use_atomic= 1; + if (parse_feature_request(feature_list, "push-options")) + use_push_options = 1; + } + } + } + + if (server_version != 1) + die("bad protocol version: %d", server_version); + + packet_write_fmt(1, "version=%d%c%s\n", + version, '\0', + use_push_options && !no_push_options ? "push-options": ""); + packet_flush(1); +} + +static void proc_receive_read_commands(struct packet_reader *reader, + struct command **commands) +{ + struct command **tail = commands; + + for (;;) { + struct object_id old_oid, new_oid; + struct command *cmd; + const char *refname; + const char *p; + + if (packet_reader_read(reader) != PACKET_READ_NORMAL) { + break; + } + + if (parse_oid_hex(reader->line, &old_oid, &p) || + *p++ != ' ' || + parse_oid_hex(p, &new_oid, &p) || + *p++ != ' ') + die("protocol error: expected 'old new ref', got '%s'", + reader->line); + refname = p; + FLEX_ALLOC_STR(cmd, ref_name, refname); + oidcpy(&cmd->old_oid, &old_oid); + oidcpy(&cmd->new_oid, &new_oid); + + *tail = cmd; + tail = &cmd->next; + } +} + +static void proc_receive_read_push_options(struct packet_reader *reader, + struct string_list *options) +{ + + if (no_push_options || !use_push_options) + return; + + while (1) { + if (packet_reader_read(reader) != PACKET_READ_NORMAL) + break; + + string_list_append(options, reader->line); + } +} + +int cmd__proc_receive(int argc, const char **argv) +{ + struct packet_reader reader; + struct command *commands; + struct string_list push_options = STRING_LIST_INIT_DUP; + struct string_list_item *item; + struct option options[] = { + OPT_BOOL(0, "no-push-options", &no_push_options, + "disable push options"), + OPT_STRING_LIST('r', "return", &returns, "old/new/ref/status/msg", + "return of results"), + OPT__VERBOSE(&verbose, "be verbose"), + OPT_INTEGER('V', "version", &version, + "use this protocol version number"), + OPT_END() + }; + + argc = parse_options(argc, argv, "test-tools", options, proc_receive_usage, 0); + if (argc > 0) + 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); + + sigchain_push(SIGPIPE, SIG_IGN); + proc_receive_verison(&reader); + proc_receive_read_commands(&reader, &commands); + proc_receive_read_push_options(&reader, &push_options); + + if (verbose) { + struct command *cmd; + + if (use_push_options || use_atomic) + fprintf(stderr, "proc-receive:%s%s\n", + use_atomic? " atomic": "", + use_push_options ? " push_options": ""); + + for (cmd = commands; cmd; cmd = cmd->next) { + char *old_hex, *new_hex; + + old_hex = oid_to_hex(&cmd->old_oid); + new_hex = oid_to_hex(&cmd->new_oid); + fprintf(stderr, "proc-receive< %s %s %s\n", + old_hex, new_hex, cmd->ref_name); + } + + if (push_options.nr > 0) { + for_each_string_list_item(item, &push_options) + fprintf(stderr, "proc-receive< %s\n", item->string); + } + + if (returns.nr) { + for_each_string_list_item(item, &returns) + fprintf(stderr, "proc-receive> %s\n", item->string); + } + } + + if (returns.nr) { + for_each_string_list_item(item, &returns) + packet_write_fmt(1, "%s\n", item->string); + } + packet_flush(1); + sigchain_pop(SIGPIPE); + + return 0; +} diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 31eedcd241..f865433a61 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -44,6 +44,7 @@ static struct test_cmd cmds[] = { { "path-utils", cmd__path_utils }, { "pkt-line", cmd__pkt_line }, { "prio-queue", cmd__prio_queue }, + { "proc-receive", cmd__proc_receive}, { "progress", cmd__progress }, { "reach", cmd__reach }, { "read-cache", cmd__read_cache }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 4eb5e6609e..059008cf22 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -34,6 +34,7 @@ int cmd__parse_pathspec_file(int argc, const char** argv); int cmd__path_utils(int argc, const char **argv); int cmd__pkt_line(int argc, const char **argv); int cmd__prio_queue(int argc, const char **argv); +int cmd__proc_receive(int argc, const char **argv); int cmd__progress(int argc, const char **argv); int cmd__reach(int argc, const char **argv); int cmd__read_cache(int argc, const char **argv); diff --git a/t/t5411/common-functions.sh b/t/t5411/common-functions.sh index e46884f74d..6ccab42c6c 100644 --- a/t/t5411/common-functions.sh +++ b/t/t5411/common-functions.sh @@ -34,8 +34,11 @@ create_commits_in () { # Format the output of git-push, git-show-ref and other commands to make a # user-friendly and stable text. We can easily prepare the expect text # without having to worry about future changes of the commit ID and spaces -# of the output. We also replce single quotes with double quotes, because -# it is boring to prepare unquoted single quotes in expect txt. +# of the output. Single quotes are replaced with double quotes, because +# it is boring to prepare unquoted single quotes in expect txt. We also +# remove some locale error messages, which break test if we turn on +# `GIT_TEST_GETTEXT_POISON=true` in order to test unintentional translations +# on plumbing commands. make_user_friendly_and_stable_output_common () { sed \ -e "s/ *\$//" \ @@ -45,5 +48,6 @@ make_user_friendly_and_stable_output_common () { -e "s/$B//g" \ -e "s/$TAG//g" \ -e "s/$ZERO_OID//g" \ - -e "s/[0-9a-f]\{7,\}//g" + -e "s/[0-9a-f]\{7,\}//g" \ + -e "/^error: / d" } diff --git a/t/t5411/common-test-cases.sh b/t/t5411/common-test-cases.sh index 33b8541f28..08c7abf11a 100644 --- a/t/t5411/common-test-cases.sh +++ b/t/t5411/common-test-cases.sh @@ -41,3 +41,579 @@ test_expect_success "normal git-push command" ' EOF test_cmp expect actual ' + +# Refs of upstream : master(A) tags/v123 refs/review/master/topic(A) a/b/c(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup" ' + ( + cd "$upstream" && + git update-ref -d refs/review/master/topic && + git update-ref -d refs/tags/v123 && + git update-ref -d refs/heads/a/b/c + ) +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : next(A) refs/for/master/topic(A) +test_expect_success "no proc-receive hook, fail to push special ref" ' + test_must_fail git -C workbench push origin \ + HEAD:next \ + HEAD:refs/for/master/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/master/topic + remote: error: cannot find hook "proc-receive" + remote: # post-receive hook + remote: post-receive< refs/heads/next + To + * [new branch] HEAD -> next + ! [remote rejected] HEAD -> refs/for/master/topic (fail to run proc-receive hook) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + refs/heads/next + EOF + test_cmp expect actual +' + +# Refs of upstream : master(A) next(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup" ' + git -C "$upstream" update-ref -d refs/heads/next +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push --atomic: (B) next(A) refs/for/master/topic(A) +test_expect_success "no proc-receive hook, fail all for atomic push" ' + test_must_fail git -C workbench push --atomic origin \ + $B:master \ + HEAD:next \ + HEAD:refs/for/master/topic >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/heads/master + remote: pre-receive< refs/heads/next + remote: pre-receive< refs/for/master/topic + remote: error: cannot find hook "proc-receive" + To + ! [remote rejected] -> master (fail to run proc-receive hook) + ! [remote rejected] HEAD -> next (fail to run proc-receive hook) + ! [remote rejected] HEAD -> refs/for/master/topic (fail to run proc-receive hook) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (bad version)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF && + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v --version 2 + EOF + chmod a+x "$upstream/hooks/proc-receive" +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic(A) +test_expect_success "proc-receive bad protocol: unknown version" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + + # Check status report for git-push + sed -n \ + -e "/^To / { s/ */ /g; p; }" \ + -e "/^ / { s/ */ /g; p; }" \ + actual-report && + cat >expect <<-EOF && + To + ! [remote rejected] HEAD -> refs/for/master/topic (fail to run proc-receive hook) + EOF + test_cmp expect actual-report && + + # Check error message from "receive-pack", but ignore unstable fatal error + # message ("remote: fatal: the remote end hung up unexpectedly") which + # is different from the remote HTTP server with different locale settings. + sed -n -e "/^remote: error:/ { s/ */ /g; p; }" \ + actual-error && + cat >expect <<-EOF && + remote: error: proc-receive version "2" is not supported + EOF + test_cmp expect actual-error && + + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (no report)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : next(A) refs/for/master/topic(A) +test_expect_success "proc-receive bad protocol: no report" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/heads/next \ + HEAD:refs/for/master/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/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/master/topic + remote: # post-receive hook + remote: post-receive< refs/heads/next + To + * [new branch] HEAD -> next + ! [remote rejected] HEAD -> refs/for/master/topic (no report from proc-receive) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + refs/heads/next + EOF + test_cmp expect actual +' + +# Refs of upstream : master(A) next(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup" ' + git -C "$upstream" update-ref -d refs/heads/next + +' + +test_expect_success "setup proc-receive hook (bad oid)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "bad-id new-id ref ok" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic +test_expect_success "proc-receive bad protocol: bad oid" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/master/topic\ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/master/topic + remote: proc-receive> bad-id new-id ref ok + remote: error: proc-receive expected "old new ref status [msg]", got "bad-id new-id ref ok" + To + ! [remote rejected] HEAD -> refs/for/master/topic (no report from proc-receive) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (no status)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$ZERO_OID $A refs/for/master/topic" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic +test_expect_success "proc-receive bad protocol: no status" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/master/topic + remote: proc-receive> refs/for/master/topic + remote: error: proc-receive expected "old new ref status [msg]", got " refs/for/master/topic" + To + ! [remote rejected] HEAD -> refs/for/master/topic (no report from proc-receive) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (unknown status)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$ZERO_OID $A refs/for/master/topic xx msg" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic +test_expect_success "proc-receive bad protocol: unknown status" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/master/topic + remote: proc-receive> refs/for/master/topic xx msg + remote: error: proc-receive has bad status "xx" for " refs/for/master/topic" + To + ! [remote rejected] HEAD -> refs/for/master/topic (no report from proc-receive) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (bad status)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$ZERO_OID $A refs/for/master/topic bad status" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic +test_expect_success "proc-receive bad protocol: bad status" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/master/topic + remote: proc-receive> refs/for/master/topic bad status + remote: error: proc-receive has bad status "bad status" for " refs/for/master/topic" + To + ! [remote rejected] HEAD -> refs/for/master/topic (no report from proc-receive) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (ng)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$ZERO_OID $A refs/for/master/topic ng" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic +test_expect_success "proc-receive: fail to update (no message)" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/master/topic + remote: proc-receive> refs/for/master/topic ng + To + ! [remote rejected] HEAD -> refs/for/master/topic (failed) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (ng message)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$ZERO_OID $A refs/for/master/topic ng error msg" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic +test_expect_success "proc-receive: fail to update (has message)" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/master/topic + remote: proc-receive> refs/for/master/topic ng error msg + To + ! [remote rejected] HEAD -> refs/for/master/topic (error msg) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (report status on builtin command)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$ZERO_OID $A refs/heads/master ok" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : (B) refs/for/master/topic +test_expect_success "proc-receive: warning on report for builtin command" ' + test_must_fail git -C workbench push origin \ + $B:refs/heads/master \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/heads/master + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/master/topic + remote: proc-receive> refs/heads/master ok + remote: error: proc-receive reported status on ref of builtin command: refs/heads/master + remote: # post-receive hook + remote: post-receive< refs/heads/master + To + .. -> master + ! [remote rejected] HEAD -> refs/for/master/topic (no report from proc-receive) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "cleanup" ' + git -C "$upstream" update-ref refs/heads/master $A +' + +test_expect_success "setup proc-receive hook (ok)" ' + cat >"$upstream/hooks/proc-receive" <<-EOF + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$ZERO_OID $A refs/for/master/topic ok" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic +test_expect_success "proc-receive: ok" ' + git -C workbench push origin \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/master/topic + remote: proc-receive> refs/for/master/topic ok + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * [new reference] HEAD -> refs/for/master/topic + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/a/b/c/my/topic +test_expect_success "proc-receive: no report from proc-receive" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/a/b/c/my/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/for/a/b/c/my/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/a/b/c/my/topic + remote: proc-receive> refs/for/master/topic ok + remote: error: proc-receive reported status on unknown ref: refs/for/master/topic + To + ! [remote rejected] HEAD -> refs/for/a/b/c/my/topic (no report from proc-receive) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push -o ... : refs/for/master/topic +test_expect_success "not support push options" ' + test_must_fail git -C workbench push \ + -o issue=123 \ + -o reviewer=user1 \ + origin \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + test_i18ngrep "fatal: the receiving end does not support push options" \ + actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "enable push options" ' + git -C "$upstream" config receive.advertisePushOptions true +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push -o ... : next(A) refs/for/master/topic +test_expect_success "push with options" ' + git -C workbench push \ + --atomic \ + -o issue=123 \ + -o reviewer=user1 \ + origin \ + HEAD:refs/heads/next \ + HEAD:refs/for/master/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/master/topic + remote: # proc-receive hook + remote: proc-receive: atomic push_options + remote: proc-receive< refs/for/master/topic + remote: proc-receive< issue=123 + remote: proc-receive< reviewer=user1 + remote: proc-receive> refs/for/master/topic ok + remote: # post-receive hook + remote: post-receive< refs/heads/next + remote: post-receive< refs/for/master/topic + To + * [new branch] HEAD -> next + * [new reference] HEAD -> refs/for/master/topic + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + refs/heads/next + EOF + test_cmp expect actual +' From patchwork Tue Apr 7 12:08:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11478015 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A1CD492C for ; Tue, 7 Apr 2020 12:08:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8166F2074B for ; Tue, 7 Apr 2020 12:08:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="EgiHnwXn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728434AbgDGMIW (ORCPT ); Tue, 7 Apr 2020 08:08:22 -0400 Received: from mail-pj1-f67.google.com ([209.85.216.67]:36460 "EHLO mail-pj1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728212AbgDGMIW (ORCPT ); Tue, 7 Apr 2020 08:08:22 -0400 Received: by mail-pj1-f67.google.com with SMTP id nu11so692187pjb.1 for ; Tue, 07 Apr 2020 05:08:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=k0TTErNib/oVDKYqMrFH1TE4YX/C72t6kSBmdz23lsc=; b=EgiHnwXnYOwaS3J9zlSmvvvoWcRDCpFIUrUIZ7FWpwHXtyBgc+JNn3ZrmwOzr5Ohpu frwafgrbe1p9Kbql4ogH6Fug9sCdRxnGTKTkbt8Pkz6QBo3GMAYuYm2t7COCJKp7GXeX UYZHI5dbhbeAxsByAXuriILQZBYeRNY8Hwf3bs2QsgKO1HJlruFqCw9cijSuULwBWfQ3 UzN2Vh9wHp9w6leytV3RUrsKxfS1zRiuz3COfWl4RMOF7R6VI3ZAXGM24vu37r86tyVJ GwRzlka9k8pPeVtRqnJ8Ii5hvRaJ17AH1CFS42hZeN7B1Qm/KbsW0oAJLLlACKANNd64 rgvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=k0TTErNib/oVDKYqMrFH1TE4YX/C72t6kSBmdz23lsc=; b=q32ypRlhW4+5nyHS/YwdWUdrE0qd7R06qI2LeWpwUaoHuDmpA/xd9KzRsHFQiUyF2P Tuv2wamhYZ2aDdsU7gNkCq1anYqj5FKgEaEpUX3iAKBzYjTZbln4e5a7Z7G7kKA7d6iq X/tuD2+0Ie++zrm8wSPQq9kJu4yVgE85Gu+37eTnkVulCsQcPgIQHVoCsksoK2qqLKof EnpI6I5ZKYQU3wUc1w2g+YZ1rkKX5qB/+aAsdacSX6/s4pg0M3Ib/CKsoK4Jn1wAvYCa 6dmjFZabHKIEwIBrj6w1H0g/NnLbRnp2D7Gpg6u9E3llv5VjJDqceLQ3T63f4LHBgKJN P6yQ== X-Gm-Message-State: AGi0PuaH03voi7E0+PKYMSIbYfJ+xs46K1bsw1H5YaidTbTZBBB7GBW6 QzJFfruunLe4t0DBMyaA71is9J68ENI= X-Google-Smtp-Source: APiQypKVVvKrgFGVVTvqa2fQ+vmwwzR9rnZcTDCamKQp1aCl4Ywjvvba/1g9Ru0X8A+r4PS9NcQzOg== X-Received: by 2002:a17:90a:358e:: with SMTP id r14mr2439503pjb.182.1586261301315; Tue, 07 Apr 2020 05:08:21 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id e26sm14061833pfj.61.2020.04.07.05.08.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Apr 2020 05:08:20 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v9 3/6] refs.c: refactor to reuse ref_is_hidden() Date: Tue, 7 Apr 2020 08:08:10 -0400 Message-Id: <20200407120813.25025-4-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200404134345.10655-1-worldhello.net@gmail.com> References: <20200404134345.10655-1-worldhello.net@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jiang Xin Add new function `ref_is_matched()` to reuse `ref_is_hidden()`. Will use this function for `receive-pack` to check commands with specific prefixes. Test case t5512 covered this change. Signed-off-by: Jiang Xin --- refs.c | 11 ++++++++--- refs.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/refs.c b/refs.c index 1ab0bb54d3..229159ea1a 100644 --- a/refs.c +++ b/refs.c @@ -1389,13 +1389,18 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti } int ref_is_hidden(const char *refname, const char *refname_full) +{ + return ref_is_matched(hide_refs, refname, refname_full); +} + +int ref_is_matched(struct string_list *match_refs, const char *refname, const char *refname_full) { int i; - if (!hide_refs) + if (!match_refs) return 0; - for (i = hide_refs->nr - 1; i >= 0; i--) { - const char *match = hide_refs->items[i].string; + for (i = match_refs->nr - 1; i >= 0; i--) { + const char *match = match_refs->items[i].string; const char *subject; int neg = 0; const char *p; diff --git a/refs.h b/refs.h index 545029c6d8..a2ea043f7f 100644 --- a/refs.h +++ b/refs.h @@ -739,6 +739,7 @@ int parse_hide_refs_config(const char *var, const char *value, const char *); * parameter always points to the full ref name. */ int ref_is_hidden(const char *, const char *); +int ref_is_matched(struct string_list *, const char *, const char *); enum ref_type { REF_TYPE_PER_WORKTREE, /* refs inside refs/ but not shared */ From patchwork Tue Apr 7 12:08:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11478021 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B83C0112C for ; Tue, 7 Apr 2020 12:08:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 834D020719 for ; Tue, 7 Apr 2020 12:08:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="kW3uyudd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728593AbgDGMI1 (ORCPT ); Tue, 7 Apr 2020 08:08:27 -0400 Received: from mail-pg1-f170.google.com ([209.85.215.170]:39588 "EHLO mail-pg1-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728482AbgDGMI0 (ORCPT ); Tue, 7 Apr 2020 08:08:26 -0400 Received: by mail-pg1-f170.google.com with SMTP id g32so1643609pgb.6 for ; Tue, 07 Apr 2020 05:08:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=C1BSxpcZF9BxBTcW03GzPNLANjvsQuzxRVMzeb8MHQ8=; b=kW3uyudd6GnKRPEr9sKtsYPKPcwNsvCZhHAv9CtiyPU12O+6iuX0kxi358CXCzh9fC LldhpHxYjqKflfuKFr6cxhYZTj8nAQxREliWYVWHa2FeuijTZXGPREHGORZcT5G0PGWV 6KarD86qU8S+Ca9do/93XV74kaBbEvX3RbzKAdja21AsbAM5SoBntU8wQweSuEmJVL0I csUN1e76AOQ7V52zTQcwX184Zzij37W5SdyW0YZt5lF/V3vMaXTfzTv62HG4igj63x6r 5gageSTmh44pb42DjvdJ+AgbRnnL52jBhDpfB4BhZ7RFNVsoVcTJBa/6nNucIS7WYdZl tx4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=C1BSxpcZF9BxBTcW03GzPNLANjvsQuzxRVMzeb8MHQ8=; b=b+frFxMvzbrKEY5Fh7i9b5dfPaPyjcXiP6+MHHDVdlJuQerhHY5hoqyrOoyxrX2N/w jG8GgzKKaGG6S2oox5y4IvXq0jp4OS31nQ45/DHo+6D8q45MUWPu2i6vTAX6gW1FrVMK 4bnKvVT7nXHiUAzstDmd4o38qJyso2U4W2AJ+GISVgo7q87eQJEFYaNkWyxgYBpCnFvR 37B5JMGy/fGeBdJ7MMUSpU8p4+vnKDjKMAKdDEcjhO010GC5DiW2YXUZEVRBIe0mF+Xa GbN1rg/9CPXU+pXkfoRX1g4HjQZouM7KDAIyEHjG5yWJdysK9YExG5E8EFTe6WiDqdd9 3CsA== X-Gm-Message-State: AGi0PuZq9vAro3LFdhiM3ueIO9uObyOv2Y/8/+P1+xlAkjEvpY1K76P+ u9hBNaLWME2zbylDGunDq4s= X-Google-Smtp-Source: APiQypJRADoEZQMZQSy5uwIIGGMad+qmN15jsrbyv4khRRbV7NcCQ2501UIY8gqktRYna2V6vRo2OQ== X-Received: by 2002:a63:5645:: with SMTP id g5mr1853647pgm.268.1586261302260; Tue, 07 Apr 2020 05:08:22 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id e26sm14061833pfj.61.2020.04.07.05.08.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Apr 2020 05:08:21 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v9 4/6] receive-pack: new config receive.procReceiveRefs Date: Tue, 7 Apr 2020 08:08:11 -0400 Message-Id: <20200407120813.25025-5-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200404134345.10655-1-worldhello.net@gmail.com> References: <20200404134345.10655-1-worldhello.net@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jiang Xin Add a new multi-valued config variable "receive.procReceiveRefs" for `receive-pack` command, like the follows: git config --system --add receive.procReceiveRefs refs/for/ git config --system --add receive.procReceiveRefs refs/drafts/ If the specific prefix strings match the reference names of the commands which are sent by git client to `receive-pack`, these commands will be executed by an external hook (named "proc-receive"), instead of the internal `execute_commands` function. For example, if it is set to "refs/for/", pushing to a reference such as "refs/for/master" will not create or update reference "refs/for/master", but may create or update a pull request directly by running the external hook. Signed-off-by: Jiang Xin --- Documentation/config/receive.txt | 14 ++++ builtin/receive-pack.c | 43 ++++++++-- t/t5411/common-test-cases.sh | 130 +++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 7 deletions(-) diff --git a/Documentation/config/receive.txt b/Documentation/config/receive.txt index 65f78aac37..4f993ee376 100644 --- a/Documentation/config/receive.txt +++ b/Documentation/config/receive.txt @@ -114,6 +114,20 @@ receive.hideRefs:: An attempt to update or delete a hidden ref by `git push` is rejected. +receive.procReceiveRefs:: + This is a multi-valued variable that defines reference prefixes + to match the commands in `receive-pack`. Commands matching the + prefixes will be executed by an external hooks "proc-receive", + instead of the internal `execute_commands` function. If this + variable is not defined, the "proc-receive" hook will never be + used, and all commands will be executed by the internal + `execute_commands` function. + + For example, if this variable is set to "refs/for", pushing to + reference such as "refs/for/master" will not create or update a + reference named "refs/for/master", but may create or update a + pull request directly by running an external hook. + receive.updateServerInfo:: If set to true, git-receive-pack will run git-update-server-info after receiving data from git-push and updating refs. diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index f3a2c2612d..a78daa6733 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -76,6 +76,7 @@ static struct object_id push_cert_oid; static struct signature_check sigcheck; static const char *push_cert_nonce; static const char *cert_nonce_seed; +static struct string_list proc_receive_refs; static const char *NONCE_UNSOLICITED = "UNSOLICITED"; static const char *NONCE_BAD = "BAD"; @@ -228,6 +229,20 @@ static int receive_pack_config(const char *var, const char *value, void *cb) return 0; } + if (strcmp(var, "receive.procreceiverefs") == 0) { + char *prefix; + int len; + + if (!value) + return config_error_nonbool(var); + prefix = xstrdup(value); + len = strlen(prefix); + while (len && prefix[len - 1] == '/') + prefix[--len] = '\0'; + string_list_insert(&proc_receive_refs, prefix); + return 0; + } + return git_default_config(var, value, cb); } @@ -1737,15 +1752,26 @@ static void execute_commands(struct command *commands, /* Try to find commands that have special prefix in their reference names, * and mark them to run an external "proc-receive" hook later. */ - for (cmd = commands; cmd; cmd = cmd->next) { - if (!should_process_cmd(cmd)) - continue; + if (proc_receive_refs.nr > 0) { + struct strbuf refname_full = STRBUF_INIT; + size_t prefix_len; + + strbuf_addstr(&refname_full, get_git_namespace()); + prefix_len = refname_full.len; - /* TODO: replace the fixed prefix by looking up git config variables. */ - if (!strncmp(cmd->ref_name, "refs/for/", 9)) { - cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED; - run_proc_receive = 1; + for (cmd = commands; cmd; cmd = cmd->next) { + if (!should_process_cmd(cmd)) + continue; + + strbuf_setlen(&refname_full, prefix_len); + strbuf_addstr(&refname_full, cmd->ref_name); + if (ref_is_matched(&proc_receive_refs, cmd->ref_name, refname_full.buf)) { + cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED; + run_proc_receive = 1; + } } + + strbuf_release(&refname_full); } if (run_receive_hook(commands, "pre-receive", 0, push_options)) { @@ -2205,6 +2231,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) OPT_END() }; + string_list_init(&proc_receive_refs, 0); + packet_trace_identity("receive-pack"); argc = parse_options(argc, argv, prefix, options, receive_pack_usage, 0); @@ -2320,5 +2348,6 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) oid_array_clear(&shallow); oid_array_clear(&ref); free((void *)push_cert_nonce); + string_list_clear(&proc_receive_refs, 0); return 0; } diff --git a/t/t5411/common-test-cases.sh b/t/t5411/common-test-cases.sh index 08c7abf11a..a9e80c374b 100644 --- a/t/t5411/common-test-cases.sh +++ b/t/t5411/common-test-cases.sh @@ -53,6 +53,14 @@ test_expect_success "cleanup" ' ) ' +test_expect_success "add two receive.procReceiveRefs settings" ' + ( + cd "$upstream" && + git config --add receive.procReceiveRefs refs/for && + git config --add receive.procReceiveRefs refs/review/ + ) +' + # Refs of upstream : master(A) # Refs of workbench: master(A) tags/v123 # git push : next(A) refs/for/master/topic(A) @@ -617,3 +625,125 @@ test_expect_success "push with options" ' EOF test_cmp expect actual ' + +# Refs of upstream : master(A) next(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup" ' + git -C "$upstream" update-ref -d refs/heads/next +' + +test_expect_success "setup proc-receive hook" ' + cat >"$upstream/hooks/proc-receive" <<-EOF && + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$ZERO_OID $A refs/review/a/b/c/topic ok" \ + -r "$ZERO_OID $A refs/for/next/topic ok" \ + -r "$ZERO_OID $A refs/for/master/topic ok" + EOF + chmod a+x "$upstream/hooks/proc-receive" +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/review/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "report update of all special refs" ' + git -C workbench push origin \ + HEAD:refs/for/next/topic \ + HEAD:refs/review/a/b/c/topic \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/for/next/topic + remote: pre-receive< refs/review/a/b/c/topic + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/next/topic + remote: proc-receive< refs/review/a/b/c/topic + remote: proc-receive< refs/for/master/topic + remote: proc-receive> refs/review/a/b/c/topic ok + remote: proc-receive> refs/for/next/topic ok + remote: proc-receive> refs/for/master/topic ok + remote: # post-receive hook + remote: post-receive< refs/for/next/topic + remote: post-receive< refs/review/a/b/c/topic + remote: post-receive< refs/for/master/topic + To + * [new reference] HEAD -> refs/for/next/topic + * [new reference] HEAD -> refs/review/a/b/c/topic + * [new reference] HEAD -> refs/for/master/topic + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook" ' + cat >"$upstream/hooks/proc-receive" <<-EOF && + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$ZERO_OID $A refs/for/next/topic ok" \ + -r "$ZERO_OID $A refs/for/master/topic ok" + EOF + chmod a+x "$upstream/hooks/proc-receive" +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : bar(A) baz(A) refs/for/next/topic(A) foo(A) refs/for/master/topic(A) +test_expect_success "report mixed refs update" ' + git -C workbench push origin \ + HEAD:refs/heads/bar \ + HEAD:refs/heads/baz \ + HEAD:refs/for/next/topic \ + HEAD:refs/heads/foo \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/heads/bar + remote: pre-receive< refs/heads/baz + remote: pre-receive< refs/for/next/topic + remote: pre-receive< refs/heads/foo + remote: pre-receive< refs/for/master/topic + remote: # proc-receive hook + remote: proc-receive< refs/for/next/topic + remote: proc-receive< refs/for/master/topic + remote: proc-receive> refs/for/next/topic ok + remote: proc-receive> refs/for/master/topic ok + remote: # post-receive hook + remote: post-receive< refs/heads/bar + remote: post-receive< refs/heads/baz + remote: post-receive< refs/for/next/topic + remote: post-receive< refs/heads/foo + remote: post-receive< refs/for/master/topic + To + * [new branch] HEAD -> bar + * [new branch] HEAD -> baz + * [new reference] HEAD -> refs/for/next/topic + * [new branch] HEAD -> foo + * [new reference] HEAD -> refs/for/master/topic + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/bar + refs/heads/baz + refs/heads/foo + refs/heads/master + EOF + test_cmp expect actual +' From patchwork Tue Apr 7 12:08:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11478025 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DA67492C for ; Tue, 7 Apr 2020 12:08:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A689E2078A for ; Tue, 7 Apr 2020 12:08:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="AiT9VFAA" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728558AbgDGMIZ (ORCPT ); Tue, 7 Apr 2020 08:08:25 -0400 Received: from mail-pf1-f180.google.com ([209.85.210.180]:34984 "EHLO mail-pf1-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728146AbgDGMIY (ORCPT ); Tue, 7 Apr 2020 08:08:24 -0400 Received: by mail-pf1-f180.google.com with SMTP id a13so732238pfa.2 for ; Tue, 07 Apr 2020 05:08:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=v1jJN+P+rvSSaTa0cMo/s2c7wwX384ryG7L7urnsdJ4=; b=AiT9VFAABlA1TcuhtqLJREz8+Yh01y+O4XujaVBISU3k39Yvsjs7F84MBGXz5vkIHs 22PKOkmxOLAXaogAMHWnY2O2Nd94LMlg2b/G5s850DQoKeLDp/TaiKrj7PPtKw9fWWCy 4avaQFUOskAT/aACmPjn1TpUknhM/LxFLagHVBD9JAiBok1C2IbG5g2gjznXFeIExmKd lW42sLk6MtqrhgLXTc0hfF22Vj04BhPHoU7TpIYIzinbeIjef7RHkPOzzHBR+aWBl/7I d7vJRlaFJW3JpyICYGwlsFbSaONnIngdJiOjGdy2POl0vjLjvnI2wwpOjB5BvSga0HUZ eabw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=v1jJN+P+rvSSaTa0cMo/s2c7wwX384ryG7L7urnsdJ4=; b=dltKcVHPyHYIOgh2UUTibY8C3tSKJwoAekQGYb23X5Oy5xWtDVHufYbUn2L2aL19uT eUCb5IwN/xkI7GQ106g7D48Dw4yOshrU1m9OSXGaaqEiUH3ZMXHo5Ns/IaqN+Dpu0cQ2 WX/0BI4znuw9xbc69xB+Ap8MDar5pLFUmUZcn0xjvHxhT99fqAQ3vt4nZDs3fmI5a/+A x8EbNR70We3fhx+AWiscJlXfP0MGW/hBcp2i8y6ELnpflu2XTNkt0FkHZfweoJrggp4X 8vY4AEJbbet68nXELh/hkZA4RXe0h2s5H47sZJwwblDrLDY31rh76hCQl+5Qok7+S6sD GfsA== X-Gm-Message-State: AGi0PuZLLSeXg6UQ+tt06aj1npJG3wNyqFvAfCz1F8g/NAgcGh1Ql6ki /Nl5aC8Xk/ECGPIQovLE3d0= X-Google-Smtp-Source: APiQypKmYqYioRL9std5JUImKrl/kd4SvvlS/n4oogE4gRMcElIkQ0Qf5A7JInwq+tcR0ygBKmD3pw== X-Received: by 2002:a65:68cb:: with SMTP id k11mr1728098pgt.78.1586261303213; Tue, 07 Apr 2020 05:08:23 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id e26sm14061833pfj.61.2020.04.07.05.08.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Apr 2020 05:08:22 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v9 5/6] receive-pack: refactor report for proc-receive Date: Tue, 7 Apr 2020 08:08:12 -0400 Message-Id: <20200407120813.25025-6-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200404134345.10655-1-worldhello.net@gmail.com> References: <20200404134345.10655-1-worldhello.net@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jiang Xin The "proc-receive" may update one or more references, and will send its result one by one in pkt-line format. Each line of the result has four fields and one optional message field, as " []". See the following example: # 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) # OK, but use an alternate reference. PKT-LINE(old-oid new-oid ref ok ref:alt-ref) # It will fallthrough to receive-pack to execute. PKT-LINE(old-oid new-oid ref ft) The first three fields have the same foramt as a command. The forth field has a two-letter status code. Available status code: * ok: The command runs successfully. If the optional message has a prefix "ref:", the hook has created/updated an alternate reference instead. * ng: Fail to run the command. Error message is in the optional message field. * ft: Will fallthrough to receive-pack to execute. Suggested-by: Junio C Hamano Signed-off-by: Jiang Xin --- builtin/receive-pack.c | 24 +++++++--- t/t5411/common-test-cases.sh | 90 +++++++++++++++++++++++++++++++++--- transport-helper.c | 64 ++++++++++++------------- transport.c | 25 ++++++++-- 4 files changed, 156 insertions(+), 47 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index a78daa6733..73acb1b5c8 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -328,6 +328,7 @@ static void write_head_info(void) struct command { struct command *next; const char *error_string; + const char *extra_string; unsigned int skip_update:1, did_not_exist:1, run_proc_receive:2; @@ -913,7 +914,12 @@ static int read_proc_receive_result(struct packet_reader *reader, else hint->error_string = "failed"; code = -1; - } else if (strcmp("ok", status)) { + } else if (!strcmp("ok", status)) { + hint->extra_string = xstrdup_or_null(msg); + } else if (!strcmp("ft", status)) { + /* Reset "run_proc_receive" field, and continue to run in "receive-pack" */ + hint->run_proc_receive = 0; + } else { strbuf_addf(errmsg, "proc-receive has bad status '%s' for '%s'\n", status, reader->line); code = -1; @@ -922,7 +928,8 @@ static int read_proc_receive_result(struct packet_reader *reader, } oidcpy(&hint->old_oid, &old_oid); oidcpy(&hint->new_oid, &new_oid); - hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED; + if (hint->run_proc_receive) + hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED; } for (cmd = commands; cmd; cmd = cmd->next) @@ -2188,12 +2195,17 @@ static void report(struct command *commands, const char *unpack_status) packet_buf_write(&buf, "unpack %s\n", unpack_status ? unpack_status : "ok"); for (cmd = commands; cmd; cmd = cmd->next) { - if (!cmd->error_string) - packet_buf_write(&buf, "ok %s\n", - cmd->ref_name); - else + if (!cmd->error_string) { + if (!cmd->extra_string) + packet_buf_write(&buf, "ok %s\n", + cmd->ref_name); + else + packet_buf_write(&buf, "ok %s%c%s\n", + cmd->ref_name, ' ', cmd->extra_string); + } else { packet_buf_write(&buf, "ng %s %s\n", cmd->ref_name, cmd->error_string); + } } packet_buf_flush(&buf); diff --git a/t/t5411/common-test-cases.sh b/t/t5411/common-test-cases.sh index a9e80c374b..a2a16c0ed4 100644 --- a/t/t5411/common-test-cases.sh +++ b/t/t5411/common-test-cases.sh @@ -640,8 +640,8 @@ test_expect_success "setup proc-receive hook" ' test-tool proc-receive -v \ -r "$ZERO_OID $A refs/review/a/b/c/topic ok" \ - -r "$ZERO_OID $A refs/for/next/topic ok" \ - -r "$ZERO_OID $A refs/for/master/topic ok" + -r "$ZERO_OID $A refs/for/next/topic ok ref:refs/pull/123/head" \ + -r "$ZERO_OID $A refs/for/master/topic ok ref:refs/pull/124/head" EOF chmod a+x "$upstream/hooks/proc-receive" ' @@ -666,16 +666,16 @@ test_expect_success "report update of all special refs" ' remote: proc-receive< refs/review/a/b/c/topic remote: proc-receive< refs/for/master/topic remote: proc-receive> refs/review/a/b/c/topic ok - remote: proc-receive> refs/for/next/topic ok - remote: proc-receive> refs/for/master/topic ok + remote: proc-receive> refs/for/next/topic ok ref:refs/pull/123/head + remote: proc-receive> refs/for/master/topic ok ref:refs/pull/124/head remote: # post-receive hook remote: post-receive< refs/for/next/topic remote: post-receive< refs/review/a/b/c/topic remote: post-receive< refs/for/master/topic To - * [new reference] HEAD -> refs/for/next/topic + * [new reference] HEAD -> refs/pull/123/head * [new reference] HEAD -> refs/review/a/b/c/topic - * [new reference] HEAD -> refs/for/master/topic + * [new reference] HEAD -> refs/pull/124/head EOF test_cmp expect actual && git -C "$upstream" show-ref >out && @@ -704,6 +704,7 @@ test_expect_success "setup proc-receive hook" ' # git push : bar(A) baz(A) refs/for/next/topic(A) foo(A) refs/for/master/topic(A) test_expect_success "report mixed refs update" ' git -C workbench push origin \ + $B:refs/heads/master \ HEAD:refs/heads/bar \ HEAD:refs/heads/baz \ HEAD:refs/for/next/topic \ @@ -713,6 +714,7 @@ test_expect_success "report mixed refs update" ' make_user_friendly_and_stable_output actual && cat >expect <<-EOF && remote: # pre-receive hook + remote: pre-receive< refs/heads/master remote: pre-receive< refs/heads/bar remote: pre-receive< refs/heads/baz remote: pre-receive< refs/for/next/topic @@ -724,12 +726,14 @@ test_expect_success "report mixed refs update" ' remote: proc-receive> refs/for/next/topic ok remote: proc-receive> refs/for/master/topic ok remote: # post-receive hook + remote: post-receive< refs/heads/master remote: post-receive< refs/heads/bar remote: post-receive< refs/heads/baz remote: post-receive< refs/for/next/topic remote: post-receive< refs/heads/foo remote: post-receive< refs/for/master/topic To + .. -> master * [new branch] HEAD -> bar * [new branch] HEAD -> baz * [new reference] HEAD -> refs/for/next/topic @@ -743,6 +747,80 @@ test_expect_success "report mixed refs update" ' refs/heads/bar refs/heads/baz refs/heads/foo + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "config receive.procReceiveRefs for all ref/" ' + git -C "$upstream" config --add receive.procReceiveRefs refs/ +' + +test_expect_success "setup proc-receive hook" ' + cat >"$upstream/hooks/proc-receive" <<-EOF && + #!/bin/sh + + printf >&2 "# proc-receive hook\n" + + test-tool proc-receive -v \ + -r "$B $A refs/heads/master ft" \ + -r "$A $ZERO_OID refs/heads/foo ft" \ + -r "$A $B refs/heads/bar ft" \ + -r "$A $B refs/for/master/topic ok ref:refs/pull/123/head" \ + -r "$B $A refs/for/next/topic ok ref:refs/pull/124/head" + EOF + chmod a+x "$upstream/hooks/proc-receive" +' + +# Refs of upstream : master(B) foo(A) bar(A)) baz(A) +# Refs of workbench: master(A) tags/v123 +# git push -f : (NULL) (B) refs/for/master/topic(A) refs/for/next/topic(A) +test_expect_success "report test: fallthrough" ' + git -C workbench push -f origin \ + HEAD:refs/heads/master \ + :refs/heads/foo \ + $B:refs/heads/bar \ + HEAD:refs/for/master/topic \ + HEAD:refs/for/next/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/heads/bar + remote: pre-receive< refs/heads/foo + remote: pre-receive< refs/heads/master + remote: pre-receive< refs/for/master/topic + remote: pre-receive< refs/for/next/topic + remote: # proc-receive hook + remote: proc-receive< refs/heads/bar + remote: proc-receive< refs/heads/foo + remote: proc-receive< refs/heads/master + remote: proc-receive< refs/for/master/topic + remote: proc-receive< refs/for/next/topic + remote: proc-receive> refs/heads/master ft + remote: proc-receive> refs/heads/foo ft + remote: proc-receive> refs/heads/bar ft + remote: proc-receive> refs/for/master/topic ok ref:refs/pull/123/head + remote: proc-receive> refs/for/next/topic ok ref:refs/pull/124/head + remote: # post-receive hook + remote: post-receive< refs/heads/bar + remote: post-receive< refs/heads/foo + remote: post-receive< refs/heads/master + remote: post-receive< refs/for/master/topic + remote: post-receive< refs/for/next/topic + To + .. -> bar + - [deleted] foo + + ... HEAD -> master (forced update) + * [new reference] HEAD -> refs/pull/123/head + * [new reference] HEAD -> refs/pull/124/head + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/bar + refs/heads/baz refs/heads/master EOF test_cmp expect actual diff --git a/transport-helper.c b/transport-helper.c index 20a7185ec4..cec3495d59 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -747,37 +747,39 @@ static int push_update_ref_status(struct strbuf *buf, msg = xstrdup(msg); strbuf_release(&msg_buf); - if (!strcmp(msg, "no match")) { - status = REF_STATUS_NONE; - FREE_AND_NULL(msg); - } - else if (!strcmp(msg, "up to date")) { - status = REF_STATUS_UPTODATE; - FREE_AND_NULL(msg); - } - else if (!strcmp(msg, "non-fast forward")) { - status = REF_STATUS_REJECT_NONFASTFORWARD; - FREE_AND_NULL(msg); - } - else if (!strcmp(msg, "already exists")) { - status = REF_STATUS_REJECT_ALREADY_EXISTS; - FREE_AND_NULL(msg); - } - else if (!strcmp(msg, "fetch first")) { - status = REF_STATUS_REJECT_FETCH_FIRST; - FREE_AND_NULL(msg); - } - else if (!strcmp(msg, "needs force")) { - status = REF_STATUS_REJECT_NEEDS_FORCE; - FREE_AND_NULL(msg); - } - else if (!strcmp(msg, "stale info")) { - status = REF_STATUS_REJECT_STALE; - FREE_AND_NULL(msg); - } - else if (!strcmp(msg, "forced update")) { - forced = 1; - FREE_AND_NULL(msg); + if (status != REF_STATUS_OK) { + if (!strcmp(msg, "no match")) { + status = REF_STATUS_NONE; + FREE_AND_NULL(msg); + } + else if (!strcmp(msg, "up to date")) { + status = REF_STATUS_UPTODATE; + FREE_AND_NULL(msg); + } + else if (!strcmp(msg, "non-fast forward")) { + status = REF_STATUS_REJECT_NONFASTFORWARD; + FREE_AND_NULL(msg); + } + else if (!strcmp(msg, "already exists")) { + status = REF_STATUS_REJECT_ALREADY_EXISTS; + FREE_AND_NULL(msg); + } + else if (!strcmp(msg, "fetch first")) { + status = REF_STATUS_REJECT_FETCH_FIRST; + FREE_AND_NULL(msg); + } + else if (!strcmp(msg, "needs force")) { + status = REF_STATUS_REJECT_NEEDS_FORCE; + FREE_AND_NULL(msg); + } + else if (!strcmp(msg, "stale info")) { + status = REF_STATUS_REJECT_STALE; + FREE_AND_NULL(msg); + } + else if (!strcmp(msg, "forced update")) { + forced = 1; + FREE_AND_NULL(msg); + } } } diff --git a/transport.c b/transport.c index 272c0f4046..97b7c6a442 100644 --- a/transport.c +++ b/transport.c @@ -463,11 +463,28 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain, int summary_width) { + char *from_name = NULL; + char *to_name = NULL; + + if (from) { + if (from->remote_status && !strncmp(from->remote_status, "ref:", 4)) + from_name = from->remote_status + 4; + else + from_name = from->name; + } + + if (to) { + if (to->remote_status && !strncmp(to->remote_status, "ref:", 4)) + to_name = to->remote_status + 4; + else + to_name = to->name; + } + if (porcelain) { if (from) - fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name); + fprintf(stdout, "%c\t%s:%s\t", flag, from_name, to_name); else - fprintf(stdout, "%c\t:%s\t", flag, to->name); + fprintf(stdout, "%c\t:%s\t", flag, to_name); if (msg) fprintf(stdout, "%s (%s)\n", summary, msg); else @@ -481,9 +498,9 @@ static void print_ref_status(char flag, const char *summary, fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width, summary, reset); if (from) - fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name)); + fprintf(stderr, "%s -> %s", prettify_refname(from_name), prettify_refname(to_name)); else - fputs(prettify_refname(to->name), stderr); + fputs(prettify_refname(to_name), stderr); if (msg) { fputs(" (", stderr); fputs(msg, stderr); From patchwork Tue Apr 7 12:08:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11478023 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 92B44112C for ; Tue, 7 Apr 2020 12:08:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 712322078C for ; Tue, 7 Apr 2020 12:08:30 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="iZaZPQYI" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728600AbgDGMI3 (ORCPT ); Tue, 7 Apr 2020 08:08:29 -0400 Received: from mail-pg1-f193.google.com ([209.85.215.193]:42166 "EHLO mail-pg1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728515AbgDGMIZ (ORCPT ); Tue, 7 Apr 2020 08:08:25 -0400 Received: by mail-pg1-f193.google.com with SMTP id g6so1636151pgs.9 for ; Tue, 07 Apr 2020 05:08:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=xao2PpbLEeHz8Q7brQeSrXDbuQXW7E1m7gDBH+k/EMk=; b=iZaZPQYIqABgnu344wbr2Gkrn6Okhqb+Y3dmhteB8wGUREAG+Hnm71bgjQhbwgPWpX 5GgljgxYnHCBUeWcdfQHtBelgheMkunaR8LuW+38k5JFfbzn2V/bpymJ+47yDRBWAx+p Rl8phzBe+QeOJ38nfgTigLAT6mrDajDuMshRB3WyglaH3y/2Lb3wdPjqVQUm2D4vzfOJ FeizZPnko/GTmwZEfr3YYZr3VqThlYzjqp69gptEJjy6ve6QO79V30pk+LixsAXumfN9 j5FkoGHrN/bXcv0Oo2vwiYcvGL/9g7LaKmdIrnjTdWRwXQuFleIf+ZuoOnrwXAllbK8p JhVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=xao2PpbLEeHz8Q7brQeSrXDbuQXW7E1m7gDBH+k/EMk=; b=UKSr6Q5tfnminIyAHaID7Vl4EIk7T+FtItfXLM4ibq5lGoBKPnr6tMzLVGJCWyDMb9 tboEDN3ABHQ6ggCDDJL0dCJnbasUI7DcEQNxBXkC7mz73qDVD75QvlbOVepePC0Lhfjx FjSINfpbbW2MdZ87esC18C5hDCO74d+9kWi8PD47L3wHaqE+TwkjhdJbDG3iNCU/Qsw4 3hm8ItSayj9++oMSTYxt6jjTrzP1ay7R6eZvidm6gJXjmDVvdmGA4S66RB8V3EVi74ZH ehjb/silYVAu6ldZeO/TMyR8YZ0YKFzb0yd7y9HG/ZWB3ixLnG2Tm1Y3cBQaxFqHKuug Ld5A== X-Gm-Message-State: AGi0Pua9O4Q4nPv2PLrQIClr0gkJxmHzin7q/JS75ZoFRH9uGmqpl7iZ aFZjs8I/7WdlrKpgcLvX6VE= X-Google-Smtp-Source: APiQypKdCFuUa0YO1XolTcNbiDK2oEZt4gJ1W3irPdMOXq3SvvyR2ScV3P0NnmcKfU/vVLwn7/ubgA== X-Received: by 2002:a63:4d2:: with SMTP id 201mr1728524pge.276.1586261304219; Tue, 07 Apr 2020 05:08:24 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id e26sm14061833pfj.61.2020.04.07.05.08.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Apr 2020 05:08:23 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v9 6/6] doc: add documentation for the proc-receive hook Date: Tue, 7 Apr 2020 08:08:13 -0400 Message-Id: <20200407120813.25025-7-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200404134345.10655-1-worldhello.net@gmail.com> References: <20200404134345.10655-1-worldhello.net@gmail.com> MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Jiang Xin Add documentation for the new "proc-receive" hook. Signed-off-by: Jiang Xin --- Documentation/githooks.txt | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index 3dccab5375..10ea5c1f18 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -333,6 +333,76 @@ The default 'update' hook, when enabled--and with `hooks.allowunannotated` config option unset or set to false--prevents unannotated tags to be pushed. +[[proc-receive]] +proc-receive +~~~~~~~~~~~~ +This hook is invoked by linkgit:git-receive-pack[1] when it reacts to +special `git push` command. According to refnames of the commands which +`git push` sends to 'git-receive-pack', the commands will be devided +into two groups by matching what the `receive.procReceiveRefs` +configuration variable defines. One group of the commands will execute +the internal `execute_commands` function to update the corresponding +refnames, and the other group of commands which have matching refnames +will execute this 'proc-receive' hook to create pull requests, etc. +If there is no `receive.procReceiveRefs` settings, this hook won't +execute at all, and all commands are sent to the internal +`execute_commands` function. + +Its exit status only determines the success or failure of the group of +commands with special refnames, unless atomic push is in use. + +This hook executes once for the receive operation. It takes no +arguments, but will talk a protocol in pkt-line format with the +'receive-pack' for reading commands, push-options (optional), and +sending result. In the following example, The letter "S" stands for +"receive-pack" and letter "H" stands for the hook. + + # Version and capabilities negotiation. + S: PKT-LINE(version=1\0push-options atomic...) + S: flush-pkt + H: PKT-LINE(version=1\0push-options...) + H: flush-pkt + + # Send commands from server to the hook. + S: PKT-LINE(old-oid new-oid ref) + S: ... ... + S: flush-pkt + # Only if push-options have been negotiated. + S: PKT-LINE(push-option) + S: ... ... + S: flush-pkt + + # Receive result from the hook. + # OK, run this command successfully. + H: PKT-LINE(old-oid new-oid ref ok) + # NO, I reject it. + H: PKT-LINE(old-oid new-oid ref ng reason) + # OK, but use an alternate reference. + H: PKT-LINE(old-oid new-oid ref ok ref:alt-ref) + # It will fallthrough to receive-pack to execute. + H: PKT-LINE(old-oid new-oid ref ft) + H: ... ... + H: flush-pkt + +The "proc-receive" hook may update one or more references, and will send +its result one by one in pkt-line format. Each line of the result has +four fields and one optional message field, like " + []". + +The first three fields are the same as those of the commands for +"receive-pack". + +The forth field has a two-letter status code. Available status codes: + +* ok: The command runs successfully. If the optional message has a + prefix "ref:", the hook has created/updated an alternate reference + instead. + +* ng: Fail to run the command. Error message is given in the optional + message field. + +* ft: Will fallthrough to receive-pack to execute. + [[post-receive]] post-receive ~~~~~~~~~~~~