From patchwork Mon Aug 24 17:41:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733869 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 6F7B413B1 for ; Mon, 24 Aug 2020 17:42:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 573A420702 for ; Mon, 24 Aug 2020 17:42:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fy1mHgJ+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726838AbgHXRmX (ORCPT ); Mon, 24 Aug 2020 13:42:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35730 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726026AbgHXRmN (ORCPT ); Mon, 24 Aug 2020 13:42:13 -0400 Received: from mail-pf1-x444.google.com (mail-pf1-x444.google.com [IPv6:2607:f8b0:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA55DC061574 for ; Mon, 24 Aug 2020 10:42:13 -0700 (PDT) Received: by mail-pf1-x444.google.com with SMTP id m8so5202940pfh.3 for ; Mon, 24 Aug 2020 10:42:13 -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=S48FhMYr2jbNjCOT00mWxP4FBV8JzDowh/BFwzkU2ek=; b=fy1mHgJ+KCsi8VaIXR7eerKcEXnfJBEUjD4ePPZu/RFA9i+h5NxgKQ4FgVOpIM/73z KtojmCPnYDkod3P2nDCMeHm4cI1GeGJB7HZDXMlbj2aCuqD6X3jP0Gl9UL94F2TT39HF Qek+n+C7krK41598XHW/jSFdCqCqogypG5n3jZUlHbuHuQ4N+0mCA2C5Wo357BT3X2SG v86VDf/cNGnNQ+4yDxyXg9eSaAMo7/VQYKnnxE9DHgJN1jX8LEc+g0HCWrChuHi/kMeY MUNn7RC0oQx/m0/f2DzYhbl6DTpB7xSyUZzoEt3fUQCPUR1dJQYT7b9fJdsa6JC8szqZ iAtQ== 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=S48FhMYr2jbNjCOT00mWxP4FBV8JzDowh/BFwzkU2ek=; b=JiyhS1CwGQdLuCdkVjp/DY6eztH22Gx2WxYmflqsDz8/FO8fvWZ6i9HKPk3T9urDgQ kMhvmVkfMpibjPDdcyPGfq4OP2L6mQ9FatN40jbuWPV5NYnq/RNRKSWAb9jVqIN+63hE L2Y27fm3lnP+EJNHomoGPeTO2nEgHTAfwklYqltzdjDZqC8XljrgajC7lYx+MORw1Noy kgjHUBBld0RKA6RIMqJU7eBubk7del/xQhMHSYFyN1kScbv60tMkZk+VvxGwpN6MM9sy NB6EusrGnxv4GX7+1vfazfHD8GP3Imtuv8jd5w1FChjklwWhgacp5HY+b807awigy5Cs BJQA== X-Gm-Message-State: AOAM533OOknIIJtRR68J392zZImHblsyUoGihnhxtH7jOwBpgmsWqaWo cuJx4ezGOuUETsTZUbzDBhc= X-Google-Smtp-Source: ABdhPJx6RgtYXjN+TKhuq/Q2KPP8+6uxJ1GgON+be7vJdo60PeBwMK/VaU2HBAM9nfQr0Z7XAwmPkw== X-Received: by 2002:a62:7d4c:: with SMTP id y73mr2104075pfc.137.1598290933338; Mon, 24 Aug 2020 10:42:13 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.12 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:12 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v18 01/10] transport: not report a non-head push as a branch Date: Mon, 24 Aug 2020 13:41:53 -0400 Message-Id: <20200824174202.11710-2-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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/t5516-fetch-push.sh | 2 +- transport.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 9c6218f568..77938db77f 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 15f5ba4e8f..26fefd13c1 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 Mon Aug 24 17:41:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733873 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 47E1313B1 for ; Mon, 24 Aug 2020 17:42:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 23F4E2067C for ; Mon, 24 Aug 2020 17:42:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="MZH4XOl5" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726851AbgHXRm0 (ORCPT ); Mon, 24 Aug 2020 13:42:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35738 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726429AbgHXRmP (ORCPT ); Mon, 24 Aug 2020 13:42:15 -0400 Received: from mail-pf1-x441.google.com (mail-pf1-x441.google.com [IPv6:2607:f8b0:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E9C18C061575 for ; Mon, 24 Aug 2020 10:42:14 -0700 (PDT) Received: by mail-pf1-x441.google.com with SMTP id t9so1028236pfq.8 for ; Mon, 24 Aug 2020 10:42:14 -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=CrVl7OpEZe6LziifA1qnI2NegTWHi2lWvO6hB5DMHgA=; b=MZH4XOl5ocCLztnPZnsk4Qcyp39exlBbnPPmn06sR3D+rW+OHJu9FWDGH46qIsswyR eHzYNTNXusvgMJBUNn5W0xnWo1CmeI2RzIzET47vz5jmXTemVyQ35hS7NoC89jecMath roXbSyOx7eyQXmW8oABkZfu2OqChCzbzv+TkjFH36LMML+chDllB79lsw6Qei9l3PEy0 ng5cbpXbeQcgnby5cYob3QH+x2d50Y9JJq5BTH/4QWCExqFqKkap+4JGdozKFAxzM5Qh +bbFstPXW6XYgKHBRZIMAaA5+XvTmnAjbyq4ZxBZyWdui2iGWA1ObiFxLRTWTIw0fJqn /Znw== 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=CrVl7OpEZe6LziifA1qnI2NegTWHi2lWvO6hB5DMHgA=; b=JxxwOFq3O1W8t831RRj2pY+ICLOvUmH7AV+Wjq2KBPkihAJfkAdNEl9O8d097QaITb 6sW7XyDrEbJUCn8Org1hrk1CLJ+PFZDEmNBnds60/HfkwZDQhonTEMqN/SDixn7Fb5/r bF8WJcPJnKfQg9dEpefzqtHv9PiEoPadQAVaecVXeZs7vLBbrWIvMAq6+OTLLwCXIgie EorV8ZriseVzW1LIcnYOQ+E+e009lUzQP9C4T0QqxdW9AS+ooFMve3FlquHl+P6Lyqev KhhQM1pDXqlUlyiOgSf8uq28EoshPIG/vozVfppVrCXwnySPZ5DyKonRPhZbl86WGdFs ONWw== X-Gm-Message-State: AOAM533YoiD+4gJ1g3oTIFyrcs4+E9yUvKHaf5sWfj3/KSAPshaPYgkt gN3OVLRC6StkQ8SAYWuuWuU= X-Google-Smtp-Source: ABdhPJyYC4+h70dz5lrCXeP0tf7Us4lC6zkD5pAmL09ZbSOU6v2l/YdIUrt/iwMq5iBoKtCQroDtqw== X-Received: by 2002:a63:f209:: with SMTP id v9mr3929543pgh.237.1598290934268; Mon, 24 Aug 2020 10:42:14 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.13 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:13 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v18 02/10] t5411: add basic test cases for proc-receive hook Date: Mon, 24 Aug 2020 13:41:54 -0400 Message-Id: <20200824174202.11710-3-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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 Topic "proc-receive-hook" will change the workflow and output of git-push. Add some basic test cases in t5411 before introducing the new topic. Signed-off-by: Jiang Xin --- t/t5411-proc-receive-hook.sh | 108 +++++++++++++ t/t5411/common-functions.sh | 56 +++++++ t/t5411/test-0000-standard-git-push.sh | 143 +++++++++++++++++ .../test-0001-standard-git-push--porcelain.sh | 147 ++++++++++++++++++ t/t5411/test-0002-pre-receive-declined.sh | 33 ++++ ...st-0003-pre-receive-declined--porcelain.sh | 34 ++++ 6 files changed, 521 insertions(+) create mode 100755 t/t5411-proc-receive-hook.sh create mode 100644 t/t5411/common-functions.sh create mode 100644 t/t5411/test-0000-standard-git-push.sh create mode 100644 t/t5411/test-0001-standard-git-push--porcelain.sh create mode 100644 t/t5411/test-0002-pre-receive-declined.sh create mode 100644 t/t5411/test-0003-pre-receive-declined--porcelain.sh diff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh new file mode 100755 index 0000000000..3a684353a8 --- /dev/null +++ b/t/t5411-proc-receive-hook.sh @@ -0,0 +1,108 @@ +#!/bin/sh +# +# Copyright (c) 2020 Jiang Xin +# + +test_description='Test proc-receive hook' + +. ./test-lib.sh + +. "$TEST_DIRECTORY"/t5411/common-functions.sh + +setup_upstream_and_workbench () { + # Refs of upstream : master(A) + # Refs of workbench: master(A) tags/v123 + test_expect_success "setup upstream and workbench" ' + rm -rf upstream.git && + rm -rf workbench && + 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 tag -m "v123" v123 $A && + git remote add origin ../upstream.git && + git push origin master && + git update-ref refs/heads/master $A $B && + git -C ../upstream.git update-ref \ + refs/heads/master $A $B + ) && + TAG=$(git -C workbench rev-parse v123) && + + # setup pre-receive hook + write_script upstream.git/hooks/pre-receive <<-\EOF && + exec >&2 + echo "# pre-receive hook" + while read old new ref + do + echo "pre-receive< $old $new $ref" + done + EOF + + # setup post-receive hook + write_script upstream.git/hooks/post-receive <<-\EOF && + exec >&2 + echo "# post-receive hook" + while read old new ref + do + echo "post-receive< $old $new $ref" + done + EOF + + upstream=upstream.git + ' +} + +run_proc_receive_hook_test() { + case $1 in + http) + PROTOCOL="HTTP protocol" + URL_PREFIX="http://.*" + ;; + local) + PROTOCOL="builtin protocol" + URL_PREFIX="\.\." + ;; + esac + + # Include test cases for both file and HTTP protocol + for t in "$TEST_DIRECTORY"/t5411/test-*.sh + do + . "$t" + done +} + +# Initialize the upstream repository and local workbench. +setup_upstream_and_workbench + +# Run test cases for 'proc-receive' hook on local file protocol. +run_proc_receive_hook_test local + +ROOT_PATH="$PWD" +. "$TEST_DIRECTORY"/lib-gpg.sh +. "$TEST_DIRECTORY"/lib-httpd.sh +. "$TEST_DIRECTORY"/lib-terminal.sh +start_httpd + +# Re-initialize the upstream repository and local workbench. +setup_upstream_and_workbench + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "setup for HTTP protocol" ' + git -C upstream.git config http.receivepack true && + upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" && + mv upstream.git "$upstream" && + git -C workbench remote set-url origin "$HTTPD_URL/auth-push/smart/upstream.git" && + set_askpass user@host pass@host +' + +setup_askpass_helper + +# Run test cases for 'proc-receive' hook on HTTP protocol. +run_proc_receive_hook_test http + +test_done diff --git a/t/t5411/common-functions.sh b/t/t5411/common-functions.sh new file mode 100644 index 0000000000..6580bebd8e --- /dev/null +++ b/t/t5411/common-functions.sh @@ -0,0 +1,56 @@ +# 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. Single quotes are replaced with double quotes, because +# it is boring to prepare unquoted single quotes in expect text. 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 () { + sed \ + -e "s/ *\$//" \ + -e "s/ */ /g" \ + -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/$(echo $A | cut -c1-7)[0-9a-f]*//g" \ + -e "s/$(echo $B | cut -c1-7)[0-9a-f]*//g" \ + -e "s#To $URL_PREFIX/upstream.git#To #" \ + -e "/^error: / d" +} diff --git a/t/t5411/test-0000-standard-git-push.sh b/t/t5411/test-0000-standard-git-push.sh new file mode 100644 index 0000000000..e206587348 --- /dev/null +++ b/t/t5411/test-0000-standard-git-push.sh @@ -0,0 +1,143 @@ +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git-push : master(B) next(A) +test_expect_success "git-push ($PROTOCOL)" ' + git -C workbench push origin \ + $B:refs/heads/master \ + HEAD:refs/heads/next \ + >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: # post-receive hook + remote: post-receive< refs/heads/master + remote: post-receive< refs/heads/next + To + .. -> master + * [new branch] HEAD -> next + 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(B) next(A) +# Refs of workbench: master(A) tags/v123 +# git-push --atomic: master(A) next(B) +test_expect_success "git-push --atomic ($PROTOCOL)" ' + test_must_fail git -C workbench push --atomic origin \ + master \ + $B:refs/heads/next \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + To + ! [rejected] master -> master (non-fast-forward) + ! [rejected] -> next (atomic push 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 + refs/heads/next + EOF + test_cmp expect actual +' + +# Refs of upstream : master(B) next(A) +# Refs of workbench: master(A) tags/v123 +# git-push : master(A) next(B) +test_expect_success "non-fast-forward git-push ($PROTOCOL)" ' + test_must_fail git \ + -C workbench \ + -c advice.pushUpdateRejected=false \ + push origin \ + master \ + $B:refs/heads/next \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/heads/next + remote: # post-receive hook + remote: post-receive< refs/heads/next + To + .. -> next + ! [rejected] master -> master (non-fast-forward) + 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(B) next(B) +# 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 "git-push -f ($PROTOCOL)" ' + git -C workbench push -f origin \ + refs/tags/v123 \ + :refs/heads/next \ + master \ + master: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 + + ... master -> master (forced update) + - [deleted] next + * [new tag] v123 -> v123 + * [new reference] master -> 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 +' + +# 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 ($PROTOCOL)" ' + ( + 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 + ) +' diff --git a/t/t5411/test-0001-standard-git-push--porcelain.sh b/t/t5411/test-0001-standard-git-push--porcelain.sh new file mode 100644 index 0000000000..48f6fcc846 --- /dev/null +++ b/t/t5411/test-0001-standard-git-push--porcelain.sh @@ -0,0 +1,147 @@ +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git-push : master(B) next(A) +test_expect_success "git-push ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain origin \ + $B:refs/heads/master \ + HEAD:refs/heads/next \ + >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: # post-receive hook + remote: post-receive< refs/heads/master + remote: post-receive< refs/heads/next + To + :refs/heads/master .. + * HEAD:refs/heads/next [new branch] + Done + 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(B) next(A) +# Refs of workbench: master(A) tags/v123 +# git-push --atomic: master(A) next(B) +test_expect_success "git-push --atomic ($PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --atomic --porcelain origin \ + master \ + $B:refs/heads/next \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + To + ! refs/heads/master:refs/heads/master [rejected] (non-fast-forward) + ! :refs/heads/next [rejected] (atomic push 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 + refs/heads/next + EOF + test_cmp expect actual +' + +# Refs of upstream : master(B) next(A) +# Refs of workbench: master(A) tags/v123 +# git-push : master(A) next(B) +test_expect_success "non-fast-forward git-push ($PROTOCOL/porcelain)" ' + test_must_fail git \ + -C workbench \ + -c advice.pushUpdateRejected=false \ + push --porcelain origin \ + master \ + $B:refs/heads/next \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + remote: # pre-receive hook + remote: pre-receive< refs/heads/next + remote: # post-receive hook + remote: post-receive< refs/heads/next + To + :refs/heads/next .. + ! refs/heads/master:refs/heads/master [rejected] (non-fast-forward) + Done + 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(B) next(B) +# 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 "git-push -f ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain -f origin \ + refs/tags/v123 \ + :refs/heads/next \ + master \ + master: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 + + refs/heads/master:refs/heads/master ... (forced update) + - :refs/heads/next [deleted] + * refs/tags/v123:refs/tags/v123 [new tag] + * refs/heads/master:refs/review/master/topic [new reference] + * HEAD:refs/heads/a/b/c [new branch] + Done + 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 +' + +# 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 ($PROTOCOL/porcelain)" ' + ( + 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 + ) +' diff --git a/t/t5411/test-0002-pre-receive-declined.sh b/t/t5411/test-0002-pre-receive-declined.sh new file mode 100644 index 0000000000..c246f7e68e --- /dev/null +++ b/t/t5411/test-0002-pre-receive-declined.sh @@ -0,0 +1,33 @@ +test_expect_success "setup pre-receive hook ($PROTOCOL)" ' + mv "$upstream/hooks/pre-receive" "$upstream/hooks/pre-receive.ok" && + write_script "$upstream/hooks/pre-receive" <<-EOF + exit 1 + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git-push : master(B) next(A) +test_expect_success "git-push is declined ($PROTOCOL)" ' + test_must_fail git -C workbench push origin \ + $B:refs/heads/master \ + HEAD:refs/heads/next \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + To + ! [remote rejected] -> master (pre-receive hook declined) + ! [remote rejected] HEAD -> next (pre-receive hook declined) + 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 ($PROTOCOL)" ' + mv "$upstream/hooks/pre-receive.ok" "$upstream/hooks/pre-receive" +' diff --git a/t/t5411/test-0003-pre-receive-declined--porcelain.sh b/t/t5411/test-0003-pre-receive-declined--porcelain.sh new file mode 100644 index 0000000000..b14894de81 --- /dev/null +++ b/t/t5411/test-0003-pre-receive-declined--porcelain.sh @@ -0,0 +1,34 @@ +test_expect_success "setup pre-receive hook ($PROTOCOL/porcelain)" ' + mv "$upstream/hooks/pre-receive" "$upstream/hooks/pre-receive.ok" && + write_script "$upstream/hooks/pre-receive" <<-EOF + exit 1 + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git-push : master(B) next(A) +test_expect_success "git-push is declined ($PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain origin \ + $B:refs/heads/master \ + HEAD:refs/heads/next \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + To + ! :refs/heads/master [remote rejected] (pre-receive hook declined) + ! HEAD:refs/heads/next [remote rejected] (pre-receive hook declined) + Done + 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 ($PROTOCOL/porcelain)" ' + mv "$upstream/hooks/pre-receive.ok" "$upstream/hooks/pre-receive" +' From patchwork Mon Aug 24 17:41:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733875 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 DD57313B1 for ; Mon, 24 Aug 2020 17:42:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 95A4F20702 for ; Mon, 24 Aug 2020 17:42:34 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="sRqkbrP4" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726798AbgHXRmd (ORCPT ); Mon, 24 Aug 2020 13:42:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35744 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726627AbgHXRmS (ORCPT ); Mon, 24 Aug 2020 13:42:18 -0400 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8E644C061573 for ; Mon, 24 Aug 2020 10:42:17 -0700 (PDT) Received: by mail-pl1-x643.google.com with SMTP id q3so3263777pls.11 for ; Mon, 24 Aug 2020 10:42:17 -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=Vj/tMc8DKLPGZoA9OMQmtAyMKXCoc2uP+F0e81N3Qg0=; b=sRqkbrP40LUgQxKIk2YOYjiGkBAvwxWmYKR7rCXYv7smjS4gsQl8C8tOhxTTEU+w7a nf4+SaVwdH1zxdyxq4sexgfpJgY9fTTTHnH4dNBXVtWeGXjJcl86BU6SBfNUPZTvyvOK DljrZfcxGy/lLxmv2tNw1ZnFTbgJ4yW52MShAxowDwIQJ/47Q53L0ZujlL3AMPhLTv6C T1A9fnfQYcK0DpBd5pNiar/v3tMBDQYdqcuKbUXt4gBh9bwYMX+J9xUi+a6AP4mxAHvA VPQojN7CzIGLQmiLOv8ELa0dJtqjG3i7ZKQ9V5hU95anL+ZZsTlHfJ8m/gZFsb+M26m1 hcCA== 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=Vj/tMc8DKLPGZoA9OMQmtAyMKXCoc2uP+F0e81N3Qg0=; b=SS+FNibSJGTvQSLnrzpbqCdmf8o/LBXXDpNzMKzoQVjKCUL6u8XPkjVnTimqWIjvqw NxT0ziwBndvJqZ4sgZF/X6dDU5S8pi5f7pj95Gy6ycUx7UU7ncTorJd3pCb0uwHrwZ1e cd5gGZlozcwzFOryeTU3AY/mgqsIFs4g/40zqj3zhsuJ//wDt9hSPwnraDaXHjc68IKX lCOFMe7UvGYyF9t1RO9iKkV4tpM6EpFAWLLCOUHXpZN0Iw191vjYYjGzqKQVj0HxdBwF Est4JsELawb5aV1+5OJ+RXIcRLSAHKoihx6QLAwk/dV4+vxvrZcCZU5+66744t9swwqh kSNA== X-Gm-Message-State: AOAM532ElD3a+l5TFYrI+csUwBCNt0iDUEBg8OVRmejLXDrMJAFQoT6S /416NlOUKuN9b6rIOvIWd1M= X-Google-Smtp-Source: ABdhPJyYfOEMmx6+TCAJB5MgV/4dIVRNWMLs5fo7hc/FzZ4sHJ6ERoLv+ucDDJsXWrU+4arBek0jZA== X-Received: by 2002:a17:90b:4c0f:: with SMTP id na15mr310864pjb.119.1598290935450; Mon, 24 Aug 2020 10:42:15 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.14 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:14 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v18 03/10] receive-pack: add new proc-receive hook Date: Mon, 24 Aug 2020 13:41:55 -0400 Message-Id: <20200824174202.11710-4-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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 features 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( ) S: ... ... S: flush-pkt # Send push-options only if the 'push-options' feature is enabled. S: PKT-LINE(push-option) S: ... ... S: flush-pkt # Receive result from the hook. # OK, run this command successfully. H: PKT-LINE(ok ) # NO, I reject it. H: PKT-LINE(ng ) # Fall through, let 'receive-pack' to execute it. H: PKT-LINE(ok ) H: PKT-LINE(option fall-through) # OK, but has an alternate reference. The alternate reference name # and other status can be given in options H: PKT-LINE(ok ) H: PKT-LINE(option refname ) H: PKT-LINE(option old-oid ) H: PKT-LINE(option new-oid ) H: PKT-LINE(option forced-update) H: ... ... H: flush-pkt After receiving a command, the hook will execute the command, and may create/update different reference. For example, a command for a pseudo reference "refs/for/master/topic" may create/update different reference such as "refs/pull/123/head". The alternate reference name and other status are given in option lines. The list of commands returned from "proc-receive" will replace the relevant commands that are sent from user to "receive-pack", and "receive-pack" will continue to run the "execute_commands" function and other routines. Finally, the result of the execution of these commands will be reported to end user. The reporting function from "receive-pack" to "send-pack" will be extended in latter commit just like what the "proc-receive" hook reports to "receive-pack". Signed-off-by: Jiang Xin --- Makefile | 1 + builtin/receive-pack.c | 296 +++++++++++++++++- remote.h | 8 + t/helper/test-proc-receive.c | 176 +++++++++++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + t/t5411/test-0011-no-hook-error.sh | 64 ++++ t/t5411/test-0012-no-hook-error--porcelain.sh | 66 ++++ t/t5411/test-0013-bad-protocol.sh | 217 +++++++++++++ t/t5411/test-0014-bad-protocol--porcelain.sh | 160 ++++++++++ t/t5411/test-0020-report-ng.sh | 67 ++++ t/t5411/test-0021-report-ng--porcelain.sh | 69 ++++ t/t5411/test-0022-report-unexpect-ref.sh | 45 +++ ...est-0023-report-unexpect-ref--porcelain.sh | 46 +++ t/t5411/test-0024-report-unknown-ref.sh | 34 ++ ...test-0025-report-unknown-ref--porcelain.sh | 35 +++ t/t5411/test-0026-push-options.sh | 79 +++++ t/t5411/test-0027-push-options--porcelain.sh | 82 +++++ t/t5411/test-0030-report-ok.sh | 35 +++ t/t5411/test-0031-report-ok--porcelain.sh | 36 +++ t/t5411/test-0032-report-with-options.sh | 256 +++++++++++++++ ...est-0033-report-with-options--porcelain.sh | 265 ++++++++++++++++ t/t5411/test-0034-report-ft.sh | 44 +++ t/t5411/test-0035-report-ft--porcelain.sh | 45 +++ ...t-0036-report-multi-rewrite-for-one-ref.sh | 159 ++++++++++ ...rt-multi-rewrite-for-one-ref--porcelain.sh | 162 ++++++++++ t/t5411/test-0038-report-mixed-refs.sh | 89 ++++++ .../test-0039-report-mixed-refs--porcelain.sh | 91 ++++++ 28 files changed, 2626 insertions(+), 3 deletions(-) create mode 100644 t/helper/test-proc-receive.c create mode 100644 t/t5411/test-0011-no-hook-error.sh create mode 100644 t/t5411/test-0012-no-hook-error--porcelain.sh create mode 100644 t/t5411/test-0013-bad-protocol.sh create mode 100644 t/t5411/test-0014-bad-protocol--porcelain.sh create mode 100644 t/t5411/test-0020-report-ng.sh create mode 100644 t/t5411/test-0021-report-ng--porcelain.sh create mode 100644 t/t5411/test-0022-report-unexpect-ref.sh create mode 100644 t/t5411/test-0023-report-unexpect-ref--porcelain.sh create mode 100644 t/t5411/test-0024-report-unknown-ref.sh create mode 100644 t/t5411/test-0025-report-unknown-ref--porcelain.sh create mode 100644 t/t5411/test-0026-push-options.sh create mode 100644 t/t5411/test-0027-push-options--porcelain.sh create mode 100644 t/t5411/test-0030-report-ok.sh create mode 100644 t/t5411/test-0031-report-ok--porcelain.sh create mode 100644 t/t5411/test-0032-report-with-options.sh create mode 100644 t/t5411/test-0033-report-with-options--porcelain.sh create mode 100644 t/t5411/test-0034-report-ft.sh create mode 100644 t/t5411/test-0035-report-ft--porcelain.sh create mode 100644 t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh create mode 100644 t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh create mode 100644 t/t5411/test-0038-report-mixed-refs.sh create mode 100644 t/t5411/test-0039-report-mixed-refs--porcelain.sh diff --git a/Makefile b/Makefile index 3d3a39fc19..607aeabeee 100644 --- a/Makefile +++ b/Makefile @@ -722,6 +722,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 a00f91c1a0..2b63b92545 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -308,11 +308,15 @@ 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; + struct ref_push_report *report; 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; @@ -838,6 +842,268 @@ static int run_update_hook(struct command *cmd) return finish_command(&proc); } +static struct command *find_command_by_refname(struct command *list, + const char *refname) +{ + for (; list; list = list->next) + if (!strcmp(list->ref_name, refname)) + return list; + return NULL; +} + +static int read_proc_receive_report(struct packet_reader *reader, + struct command *commands, + struct strbuf *errmsg) +{ + struct command *cmd; + struct command *hint = NULL; + struct ref_push_report *report = NULL; + int new_report = 0; + int code = 0; + int once = 0; + + for (;;) { + struct object_id old_oid, new_oid; + const char *head; + const char *refname; + char *p; + + if (packet_reader_read(reader) != PACKET_READ_NORMAL) + break; + + head = reader->line; + p = strchr(head, ' '); + if (!p) { + strbuf_addf(errmsg, "proc-receive reported incomplete status line: '%s'\n", head); + code = -1; + continue; + } + *p++ = '\0'; + if (!strcmp(head, "option")) { + const char *key, *val; + + if (!hint || !(report || new_report)) { + if (!once++) + strbuf_addstr(errmsg, "proc-receive reported 'option' without a matching 'ok/ng' directive\n"); + code = -1; + continue; + } + if (new_report) { + if (!hint->report) { + hint->report = xcalloc(1, sizeof(struct ref_push_report)); + report = hint->report; + } else { + report = hint->report; + while (report->next) + report = report->next; + report->next = xcalloc(1, sizeof(struct ref_push_report)); + report = report->next; + } + new_report = 0; + } + key = p; + p = strchr(key, ' '); + if (p) + *p++ = '\0'; + val = p; + if (!strcmp(key, "refname")) + report->ref_name = xstrdup_or_null(val); + else if (!strcmp(key, "old-oid") && val && + !parse_oid_hex(val, &old_oid, &val)) + report->old_oid = oiddup(&old_oid); + else if (!strcmp(key, "new-oid") && val && + !parse_oid_hex(val, &new_oid, &val)) + report->new_oid = oiddup(&new_oid); + else if (!strcmp(key, "forced-update")) + report->forced_update = 1; + else if (!strcmp(key, "fall-through")) + /* Fall through, let 'receive-pack' to execute it. */ + hint->run_proc_receive = 0; + continue; + } + + report = NULL; + new_report = 0; + refname = p; + p = strchr(refname, ' '); + if (p) + *p++ = '\0'; + if (strcmp(head, "ok") && strcmp(head, "ng")) { + strbuf_addf(errmsg, "proc-receive reported bad status '%s' on ref '%s'\n", + head, refname); + 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); + code = -1; + continue; + } + if (!hint->run_proc_receive) { + strbuf_addf(errmsg, "proc-receive reported status on unexpected ref: %s\n", + refname); + code = -1; + continue; + } + hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED; + if (!strcmp(head, "ng")) { + if (p) + hint->error_string = xstrdup(p); + else + hint->error_string = "failed"; + code = -1; + continue; + } + new_report = 1; + } + + for (cmd = commands; cmd; cmd = cmd->next) + if (cmd->run_proc_receive && !cmd->error_string && + !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED)) { + cmd->error_string = "proc-receive failed to report status"; + 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 hook_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_GENTLE_ON_EOF); + 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")) + hook_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) { + if (!cmd->run_proc_receive || cmd->skip_update || cmd->error_string) + continue; + packet_write_fmt(proc.in, "%s %s %s", + oid_to_hex(&cmd->old_oid), + oid_to_hex(&cmd->new_oid), + cmd->ref_name); + } + packet_flush(proc.in); + + /* Send push options */ + if (hook_use_push_options) { + struct string_list_item *item; + + for_each_string_list_item(item, push_options) + packet_write_fmt(proc.in, "%s", item->string); + packet_flush(proc.in); + } + + /* Read result from proc-receive */ + code = read_proc_receive_report(&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" @@ -1413,7 +1679,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); @@ -1453,7 +1719,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); @@ -1489,6 +1755,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) @@ -1518,6 +1785,21 @@ 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) @@ -1544,6 +1826,14 @@ 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 && + run_proc_receive_hook(commands, push_options)) + for (cmd = commands; cmd; cmd = cmd->next) + if (!cmd->error_string && + !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED) && + (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/remote.h b/remote.h index 11d8719b58..ca7735b441 100644 --- a/remote.h +++ b/remote.h @@ -93,6 +93,14 @@ int for_each_remote(each_remote_fn fn, void *priv); int remote_has_url(struct remote *remote, const char *url); +struct ref_push_report { + const char *ref_name; + struct object_id *old_oid; + struct object_id *new_oid; + unsigned int forced_update:1; + struct ref_push_report *next; +}; + struct ref { struct ref *next; struct object_id old_oid; diff --git a/t/helper/test-proc-receive.c b/t/helper/test-proc-receive.c new file mode 100644 index 0000000000..42164d9898 --- /dev/null +++ b/t/helper/test-proc-receive.c @@ -0,0 +1,176 @@ +#include "cache.h" +#include "connect.h" +#include "parse-options.h" +#include "pkt-line.h" +#include "sigchain.h" +#include "test-tool.h" + +static const char *proc_receive_usage[] = { + "test-tool proc-receive [...]", + NULL +}; + +static int die_version; +static int die_readline; +static int no_push_options; +static int use_atomic; +static int use_push_options; +static int verbose; +static int version = 1; +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_version) + 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_readline) + 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) +{ + int nongit_ok = 0; + struct packet_reader reader; + struct command *commands = NULL; + 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_BOOL(0, "die-version", &die_version, + "die during version negotiation"), + OPT_BOOL(0, "die-readline", &die_readline, + "die when readline"), + 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() + }; + + setup_git_directory_gently(&nongit_ok); + + 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) + fprintf(stderr, "proc-receive< %s %s %s\n", + oid_to_hex(&cmd->old_oid), + oid_to_hex(&cmd->new_oid), + 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 590b2efca7..a0d3966b29 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -46,6 +46,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 ddc8e990e9..07034d3f38 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -35,6 +35,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/test-0011-no-hook-error.sh b/t/t5411/test-0011-no-hook-error.sh new file mode 100644 index 0000000000..bb6ec92a92 --- /dev/null +++ b/t/t5411/test-0011-no-hook-error.sh @@ -0,0 +1,64 @@ +# 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: no hook, fail to push special ref ($PROTOCOL)" ' + 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 ($PROTOCOL)" ' + 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 "proc-receive: no hook, all failed for atomic push ($PROTOCOL)" ' + 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 +' diff --git a/t/t5411/test-0012-no-hook-error--porcelain.sh b/t/t5411/test-0012-no-hook-error--porcelain.sh new file mode 100644 index 0000000000..4814f74dc2 --- /dev/null +++ b/t/t5411/test-0012-no-hook-error--porcelain.sh @@ -0,0 +1,66 @@ +# 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: no hook, fail to push special ref ($PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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 + * HEAD:refs/heads/next [new branch] + ! HEAD:refs/for/master/topic [remote rejected] (fail to run proc-receive hook) + Done + 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 ($PROTOCOL/porcelain)" ' + 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 "proc-receive: no hook, all failed for atomic push ($PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain --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 + ! :refs/heads/master [remote rejected] (fail to run proc-receive hook) + ! HEAD:refs/heads/next [remote rejected] (fail to run proc-receive hook) + ! HEAD:refs/for/master/topic [remote rejected] (fail to run proc-receive hook) + Done + 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 +' diff --git a/t/t5411/test-0013-bad-protocol.sh b/t/t5411/test-0013-bad-protocol.sh new file mode 100644 index 0000000000..c5fe4cb37b --- /dev/null +++ b/t/t5411/test-0013-bad-protocol.sh @@ -0,0 +1,217 @@ +test_expect_success "setup proc-receive hook (unknown version, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --version 2 + EOF +' + +# 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, $PROTOCOL)" ' + 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 / { p; n; 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. + grep "^remote: error:" 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 (hook --die-version, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-version + EOF +' + +# 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 (hook --die-version, $PROTOCOL)" ' + 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: fatal: bad protocol version: 1 + remote: error: proc-receive version "0" is not supported + To + ! [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 (hook --die-readline, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --die-readline + EOF +' + +# 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 (hook --die-readline, $PROTOCOL)" ' + test_must_fail git -C workbench push origin \ + HEAD:refs/for/master/topic \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + + grep "remote: fatal: protocol error: expected \"old new ref\", got \" refs/for/master/topic\"" 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 report, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + 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, $PROTOCOL)" ' + 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 (proc-receive failed to report status) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + 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 ($PROTOCOL)" ' + git -C "$upstream" update-ref -d refs/heads/next + +' + +test_expect_success "setup proc-receive hook (no ref, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "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 (no ref, $PROTOCOL)" ' + 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> ok + remote: error: proc-receive reported incomplete status line: "ok" + To + ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (unknown status, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "xx 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 (unknown status, $PROTOCOL)" ' + 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> xx refs/for/master/topic + remote: error: proc-receive reported bad status "xx" on ref "refs/for/master/topic" + To + ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' diff --git a/t/t5411/test-0014-bad-protocol--porcelain.sh b/t/t5411/test-0014-bad-protocol--porcelain.sh new file mode 100644 index 0000000000..53b47b0185 --- /dev/null +++ b/t/t5411/test-0014-bad-protocol--porcelain.sh @@ -0,0 +1,160 @@ +test_expect_success "setup proc-receive hook (unknown version, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v --version 2 + EOF +' + +# 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, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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 / { p; n; p; n; p; }" \ + actual-report && + cat >expect <<-EOF && + To + ! HEAD:refs/for/master/topic [remote rejected] (fail to run proc-receive hook) + Done + 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. + grep "^remote: error:" 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, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + 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, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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 + * HEAD:refs/heads/next [new branch] + ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status) + Done + 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 ($PROTOCOL/porcelain)" ' + git -C "$upstream" update-ref -d refs/heads/next + +' + +test_expect_success "setup proc-receive hook (no ref, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "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 (no ref, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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> ok + remote: error: proc-receive reported incomplete status line: "ok" + To + ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status) + Done + 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, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "xx 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 (unknown status, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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> xx refs/for/master/topic + remote: error: proc-receive reported bad status "xx" on ref "refs/for/master/topic" + To + ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status) + Done + 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 +' diff --git a/t/t5411/test-0020-report-ng.sh b/t/t5411/test-0020-report-ng.sh new file mode 100644 index 0000000000..f726b7ca9c --- /dev/null +++ b/t/t5411/test-0020-report-ng.sh @@ -0,0 +1,67 @@ +test_expect_success "setup proc-receive hook (ng, no message, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ng 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: fail to update (ng, no message, $PROTOCOL)" ' + 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> ng refs/for/master/topic + 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, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ng refs/for/master/topic 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 (ng, with message, $PROTOCOL)" ' + 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> ng refs/for/master/topic 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 +' diff --git a/t/t5411/test-0021-report-ng--porcelain.sh b/t/t5411/test-0021-report-ng--porcelain.sh new file mode 100644 index 0000000000..fbf5569103 --- /dev/null +++ b/t/t5411/test-0021-report-ng--porcelain.sh @@ -0,0 +1,69 @@ +test_expect_success "setup proc-receive hook (ng, no message, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ng 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: fail to update (ng, no message, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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> ng refs/for/master/topic + To + ! HEAD:refs/for/master/topic [remote rejected] (failed) + Done + 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, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ng refs/for/master/topic 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 (ng, with message, $PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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> ng refs/for/master/topic error msg + To + ! HEAD:refs/for/master/topic [remote rejected] (error msg) + Done + 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 +' diff --git a/t/t5411/test-0022-report-unexpect-ref.sh b/t/t5411/test-0022-report-unexpect-ref.sh new file mode 100644 index 0000000000..92a415b929 --- /dev/null +++ b/t/t5411/test-0022-report-unexpect-ref.sh @@ -0,0 +1,45 @@ +test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/heads/master" + 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: report unexpected ref ($PROTOCOL)" ' + 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> ok refs/heads/master + remote: error: proc-receive reported status on unexpected ref: refs/heads/master + remote: # post-receive hook + remote: post-receive< refs/heads/master + To + .. -> master + ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +# Refs of upstream : master(B) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL)" ' + git -C "$upstream" update-ref refs/heads/master $A +' diff --git a/t/t5411/test-0023-report-unexpect-ref--porcelain.sh b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh new file mode 100644 index 0000000000..acbf93e40a --- /dev/null +++ b/t/t5411/test-0023-report-unexpect-ref--porcelain.sh @@ -0,0 +1,46 @@ +test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/heads/master" + 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: report unexpected ref ($PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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> ok refs/heads/master + remote: error: proc-receive reported status on unexpected ref: refs/heads/master + remote: # post-receive hook + remote: post-receive< refs/heads/master + To + :refs/heads/master .. + ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status) + Done + 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(B) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL/porcelain)" ' + git -C "$upstream" update-ref refs/heads/master $A +' diff --git a/t/t5411/test-0024-report-unknown-ref.sh b/t/t5411/test-0024-report-unknown-ref.sh new file mode 100644 index 0000000000..c3946f329a --- /dev/null +++ b/t/t5411/test-0024-report-unknown-ref.sh @@ -0,0 +1,34 @@ +test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" + EOF +' + +# 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: report unknown reference ($PROTOCOL)" ' + 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> ok refs/for/master/topic + remote: error: proc-receive reported status on unknown ref: refs/for/master/topic + To + ! [remote rejected] HEAD -> refs/for/a/b/c/my/topic (proc-receive failed to report status) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' diff --git a/t/t5411/test-0025-report-unknown-ref--porcelain.sh b/t/t5411/test-0025-report-unknown-ref--porcelain.sh new file mode 100644 index 0000000000..d093b1a579 --- /dev/null +++ b/t/t5411/test-0025-report-unknown-ref--porcelain.sh @@ -0,0 +1,35 @@ +test_expect_success "setup proc-receive hook (unexpected ref, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" + EOF +' + +# 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: report unknown reference ($PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: error: proc-receive reported status on unknown ref: refs/for/master/topic + To + ! HEAD:refs/for/a/b/c/my/topic [remote rejected] (proc-receive failed to report status) + Done + 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 +' diff --git a/t/t5411/test-0026-push-options.sh b/t/t5411/test-0026-push-options.sh new file mode 100644 index 0000000000..d0c4da8b23 --- /dev/null +++ b/t/t5411/test-0026-push-options.sh @@ -0,0 +1,79 @@ +test_expect_success "setup proc-receive hook and disable push-options ($PROTOCOL)" ' + git -C "$upstream" config receive.advertisePushOptions false && + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push -o ... : refs/for/master/topic +test_expect_success "proc-receive: not support push options ($PROTOCOL)" ' + 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 ($PROTOCOL)" ' + 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 "proc-receive: push with options ($PROTOCOL)" ' + 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> ok refs/for/master/topic + 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 +' + +# Refs of upstream : master(A) next(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL)" ' + git -C "$upstream" update-ref -d refs/heads/next +' diff --git a/t/t5411/test-0027-push-options--porcelain.sh b/t/t5411/test-0027-push-options--porcelain.sh new file mode 100644 index 0000000000..c89a1e7c57 --- /dev/null +++ b/t/t5411/test-0027-push-options--porcelain.sh @@ -0,0 +1,82 @@ +test_expect_success "setup proc-receive hook and disable push-options ($PROTOCOL/porcelain)" ' + git -C "$upstream" config receive.advertisePushOptions false && + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push -o ... : refs/for/master/topic +test_expect_success "proc-receive: not support push options ($PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push \ + --porcelain \ + -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 ($PROTOCOL/porcelain)" ' + 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 "proc-receive: push with options ($PROTOCOL/porcelain)" ' + git -C workbench push \ + --porcelain \ + --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> ok refs/for/master/topic + remote: # post-receive hook + remote: post-receive< refs/heads/next + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/heads/next [new branch] + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/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 ($PROTOCOL/porcelain)" ' + git -C "$upstream" update-ref -d refs/heads/next +' diff --git a/t/t5411/test-0030-report-ok.sh b/t/t5411/test-0030-report-ok.sh new file mode 100644 index 0000000000..44c99d3831 --- /dev/null +++ b/t/t5411/test-0030-report-ok.sh @@ -0,0 +1,35 @@ +test_expect_success "setup proc-receive hook (ok, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok 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: ok ($PROTOCOL)" ' + 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> ok refs/for/master/topic + 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 +' diff --git a/t/t5411/test-0031-report-ok--porcelain.sh b/t/t5411/test-0031-report-ok--porcelain.sh new file mode 100644 index 0000000000..3223b26184 --- /dev/null +++ b/t/t5411/test-0031-report-ok--porcelain.sh @@ -0,0 +1,36 @@ +test_expect_success "setup proc-receive hook (ok, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok 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: ok ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' diff --git a/t/t5411/test-0032-report-with-options.sh b/t/t5411/test-0032-report-with-options.sh new file mode 100644 index 0000000000..a743aa8018 --- /dev/null +++ b/t/t5411/test-0032-report-with-options.sh @@ -0,0 +1,256 @@ +test_expect_success "setup proc-receive hook (option without matching ok, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "option refname refs/pull/123/head" \ + -r "option old-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option without matching ok ($PROTOCOL)" ' + 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> option refname refs/pull/123/head + remote: proc-receive> option old-oid + remote: error: proc-receive reported "option" without a matching "ok/ng" directive + To + ! [remote rejected] HEAD -> refs/for/master/topic (proc-receive failed to report status) + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option refname, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/123/head" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option refname ($PROTOCOL)" ' + 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/123/head + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * [new reference] HEAD -> refs/for/master/topic + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option refname and forced-update, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/123/head" \ + -r "option forced-update" + EOF +' +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option refname and forced-update ($PROTOCOL)" ' + 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> option forced-update + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * [new reference] HEAD -> refs/for/master/topic + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option refname and old-oid, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/123/head" \ + -r "option old-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL)" ' + 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> option old-oid + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * [new reference] HEAD -> refs/for/master/topic + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option old-oid, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option old-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option old-oid ($PROTOCOL)" ' + 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> ok refs/for/master/topic + remote: proc-receive> option old-oid + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * [new reference] HEAD -> refs/for/master/topic + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option old-oid and new-oid, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option old-oid $A" \ + -r "option new-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL)" ' + 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> ok refs/for/master/topic + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * [new reference] HEAD -> refs/for/master/topic + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (report with multiple rewrites, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/a/b/c/topic" \ + -r "ok refs/for/next/topic" \ + -r "option refname refs/pull/123/head" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/124/head" \ + -r "option old-oid $B" \ + -r "option forced-update" \ + -r "option new-oid $A" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL)" ' + git -C workbench push origin \ + HEAD:refs/for/next/topic \ + HEAD:refs/for/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/for/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/for/a/b/c/topic + remote: proc-receive< refs/for/master/topic + remote: proc-receive> ok refs/for/a/b/c/topic + remote: proc-receive> ok refs/for/next/topic + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/124/head + remote: proc-receive> option old-oid + remote: proc-receive> option forced-update + remote: proc-receive> option new-oid + remote: # post-receive hook + remote: post-receive< refs/for/next/topic + remote: post-receive< refs/for/a/b/c/topic + remote: post-receive< refs/for/master/topic + To + * [new reference] HEAD -> refs/for/next/topic + * [new reference] HEAD -> refs/for/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 +' diff --git a/t/t5411/test-0033-report-with-options--porcelain.sh b/t/t5411/test-0033-report-with-options--porcelain.sh new file mode 100644 index 0000000000..439b97b06e --- /dev/null +++ b/t/t5411/test-0033-report-with-options--porcelain.sh @@ -0,0 +1,265 @@ +test_expect_success "setup proc-receive hook (option without matching ok, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "option refname refs/pull/123/head" \ + -r "option old-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option without matching ok ($PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain 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> option refname refs/pull/123/head + remote: proc-receive> option old-oid + remote: error: proc-receive reported "option" without a matching "ok/ng" directive + To + ! HEAD:refs/for/master/topic [remote rejected] (proc-receive failed to report status) + Done + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option refname, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/123/head" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option refname ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/123/head + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option refname and forced-update, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/123/head" \ + -r "option forced-update" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option refname and forced-update ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> option forced-update + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option refname and old-oid, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/123/head" \ + -r "option old-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> option old-oid + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option old-oid, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option old-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option old-oid ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: proc-receive> option old-oid + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (option old-oid and new-oid, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option old-oid $A" \ + -r "option new-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (report with multiple rewrites, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/a/b/c/topic" \ + -r "ok refs/for/next/topic" \ + -r "option refname refs/pull/123/head" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/124/head" \ + -r "option old-oid $B" \ + -r "option forced-update" \ + -r "option new-oid $A" + + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/next/topic(A) refs/for/a/b/c/topic(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain origin \ + HEAD:refs/for/next/topic \ + HEAD:refs/for/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/for/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/for/a/b/c/topic + remote: proc-receive< refs/for/master/topic + remote: proc-receive> ok refs/for/a/b/c/topic + remote: proc-receive> ok refs/for/next/topic + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/124/head + remote: proc-receive> option old-oid + remote: proc-receive> option forced-update + remote: proc-receive> option new-oid + remote: # post-receive hook + remote: post-receive< refs/for/next/topic + remote: post-receive< refs/for/a/b/c/topic + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/next/topic [new reference] + * HEAD:refs/for/a/b/c/topic [new reference] + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual && + + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' diff --git a/t/t5411/test-0034-report-ft.sh b/t/t5411/test-0034-report-ft.sh new file mode 100644 index 0000000000..aca2b0676c --- /dev/null +++ b/t/t5411/test-0034-report-ft.sh @@ -0,0 +1,44 @@ +test_expect_success "setup proc-receive hook (ft, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option fall-through" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic(B) +test_expect_success "proc-receive: fall throught, let receive-pack to execute ($PROTOCOL)" ' + git -C workbench push origin \ + $B: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> ok refs/for/master/topic + remote: proc-receive> option fall-through + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * [new reference] -> 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/for/master/topic + refs/heads/master + EOF + test_cmp expect actual +' + +# Refs of upstream : master(A) refs/for/master/topic(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL)" ' + git -C "$upstream" update-ref -d refs/for/master/topic +' diff --git a/t/t5411/test-0035-report-ft--porcelain.sh b/t/t5411/test-0035-report-ft--porcelain.sh new file mode 100644 index 0000000000..30ffffb352 --- /dev/null +++ b/t/t5411/test-0035-report-ft--porcelain.sh @@ -0,0 +1,45 @@ +test_expect_success "setup proc-receive hook (fall-through, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option fall-through" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic(B) +test_expect_success "proc-receive: fall throught, let receive-pack to execute ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain origin \ + $B: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> ok refs/for/master/topic + remote: proc-receive> option fall-through + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * :refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/for/master/topic + refs/heads/master + EOF + test_cmp expect actual +' + +# Refs of upstream : master(A) refs/for/master/topic(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL/porcelain)" ' + git -C "$upstream" update-ref -d refs/for/master/topic +' diff --git a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh new file mode 100644 index 0000000000..12acf9ea1f --- /dev/null +++ b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh @@ -0,0 +1,159 @@ +test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option old-oid $A" \ + -r "option new-oid $B" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/24/124/1" \ + -r "option old-oid $ZERO_OID" \ + -r "option new-oid $A" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/25/125/1" \ + -r "option old-oid $A" \ + -r "option new-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic(A) +test_expect_success "proc-receive: multiple rewrite for one ref, no refname for the 1st rewrite ($PROTOCOL)" ' + 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> ok refs/for/master/topic + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/24/124/1 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/25/125/1 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + 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 +' + +test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/24/124/1" \ + -r "option old-oid $ZERO_OID" \ + -r "option new-oid $A" \ + -r "ok refs/for/master/topic" \ + -r "option old-oid $A" \ + -r "option new-oid $B" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/25/125/1" \ + -r "option old-oid $B" \ + -r "option new-oid $A" \ + -r "option forced-update" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic(A) +test_expect_success "proc-receive: multiple rewrites for one ref, no refname for the 2nd rewrite ($PROTOCOL)" ' + 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/24/124/1 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/25/125/1 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> option forced-update + 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 +' + +test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/23/123/1" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/24/124/2" \ + -r "option old-oid $A" \ + -r "option new-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic(A) +test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL)" ' + 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/23/123/1 + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/24/124/2 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + 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 +' diff --git a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh new file mode 100644 index 0000000000..f4a2c56e14 --- /dev/null +++ b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh @@ -0,0 +1,162 @@ +test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option old-oid $A" \ + -r "option new-oid $B" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/24/124/1" \ + -r "option old-oid $ZERO_OID" \ + -r "option new-oid $A" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/25/125/1" \ + -r "option old-oid $A" \ + -r "option new-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic(A) +test_expect_success "proc-receive: multiple rewrite for one ref, no refname for the 1st rewrite ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/24/124/1 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/25/125/1 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/24/124/1" \ + -r "option old-oid $ZERO_OID" \ + -r "option new-oid $A" \ + -r "ok refs/for/master/topic" \ + -r "option old-oid $A" \ + -r "option new-oid $B" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/25/125/1" \ + -r "option old-oid $B" \ + -r "option new-oid $A" \ + -r "option forced-update" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic(A) +test_expect_success "proc-receive: multiple rewrites for one ref, no refname for the 2nd rewrite ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/24/124/1 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/25/125/1 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> option forced-update + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/23/123/1" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/changes/24/124/2" \ + -r "option old-oid $A" \ + -r "option new-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : refs/for/master/topic(A) +test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain 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> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/23/123/1 + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/changes/24/124/2 + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: # post-receive hook + remote: post-receive< refs/for/master/topic + To + * HEAD:refs/for/master/topic [new reference] + Done + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + EOF + test_cmp expect actual +' diff --git a/t/t5411/test-0038-report-mixed-refs.sh b/t/t5411/test-0038-report-mixed-refs.sh new file mode 100644 index 0000000000..1dd6a97a97 --- /dev/null +++ b/t/t5411/test-0038-report-mixed-refs.sh @@ -0,0 +1,89 @@ +test_expect_success "setup proc-receive hook ($PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/next/topic2" \ + -r "ng refs/for/next/topic1 fail to call Web API" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/for/master/topic" \ + -r "option old-oid $A" \ + -r "option new-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : (B) bar(A) baz(A) refs/for/next/topic(A) foo(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL)" ' + test_must_fail git -C workbench push origin \ + $B:refs/heads/master \ + HEAD:refs/heads/bar \ + HEAD:refs/heads/baz \ + HEAD:refs/for/next/topic2 \ + HEAD:refs/for/next/topic1 \ + HEAD:refs/heads/foo \ + HEAD:refs/for/master/topic \ + HEAD:refs/for/next/topic3 \ + >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/bar + remote: pre-receive< refs/heads/baz + remote: pre-receive< refs/for/next/topic2 + remote: pre-receive< refs/for/next/topic1 + remote: pre-receive< refs/heads/foo + remote: pre-receive< refs/for/master/topic + remote: pre-receive< refs/for/next/topic3 + remote: # proc-receive hook + remote: proc-receive< refs/for/next/topic2 + remote: proc-receive< refs/for/next/topic1 + remote: proc-receive< refs/for/master/topic + remote: proc-receive< refs/for/next/topic3 + remote: proc-receive> ok refs/for/next/topic2 + remote: proc-receive> ng refs/for/next/topic1 fail to call Web API + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/for/master/topic + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + 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/topic2 + 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/topic2 + * [new branch] HEAD -> foo + * [new reference] HEAD -> refs/for/master/topic + ! [remote rejected] HEAD -> refs/for/next/topic1 (fail to call Web API) + ! [remote rejected] HEAD -> refs/for/next/topic3 (proc-receive failed to report status) + EOF + test_cmp expect actual && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/bar + refs/heads/baz + refs/heads/foo + refs/heads/master + EOF + test_cmp expect actual +' + +# Refs of upstream : master(B) foo(A) bar(A)) baz(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL)" ' + ( + cd "$upstream" && + git update-ref refs/heads/master $A && + git update-ref -d refs/heads/foo && + git update-ref -d refs/heads/bar && + git update-ref -d refs/heads/baz + ) +' diff --git a/t/t5411/test-0039-report-mixed-refs--porcelain.sh b/t/t5411/test-0039-report-mixed-refs--porcelain.sh new file mode 100644 index 0000000000..32ebf63dcf --- /dev/null +++ b/t/t5411/test-0039-report-mixed-refs--porcelain.sh @@ -0,0 +1,91 @@ +test_expect_success "setup proc-receive hook ($PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/next/topic2" \ + -r "ng refs/for/next/topic1 fail to call Web API" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/for/master/topic" \ + -r "option old-oid $A" \ + -r "option new-oid $B" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : (B) bar(A) baz(A) refs/for/next/topic(A) foo(A) refs/for/master/topic(A) +test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL/porcelain)" ' + test_must_fail git -C workbench push --porcelain origin \ + $B:refs/heads/master \ + HEAD:refs/heads/bar \ + HEAD:refs/heads/baz \ + HEAD:refs/for/next/topic2 \ + HEAD:refs/for/next/topic1 \ + HEAD:refs/heads/foo \ + HEAD:refs/for/master/topic \ + HEAD:refs/for/next/topic3 \ + >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/bar + remote: pre-receive< refs/heads/baz + remote: pre-receive< refs/for/next/topic2 + remote: pre-receive< refs/for/next/topic1 + remote: pre-receive< refs/heads/foo + remote: pre-receive< refs/for/master/topic + remote: pre-receive< refs/for/next/topic3 + remote: # proc-receive hook + remote: proc-receive< refs/for/next/topic2 + remote: proc-receive< refs/for/next/topic1 + remote: proc-receive< refs/for/master/topic + remote: proc-receive< refs/for/next/topic3 + remote: proc-receive> ok refs/for/next/topic2 + remote: proc-receive> ng refs/for/next/topic1 fail to call Web API + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/for/master/topic + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + 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/topic2 + remote: post-receive< refs/heads/foo + remote: post-receive< refs/for/master/topic + To + :refs/heads/master .. + * HEAD:refs/heads/bar [new branch] + * HEAD:refs/heads/baz [new branch] + * HEAD:refs/for/next/topic2 [new reference] + * HEAD:refs/heads/foo [new branch] + * HEAD:refs/for/master/topic [new reference] + ! HEAD:refs/for/next/topic1 [remote rejected] (fail to call Web API) + ! HEAD:refs/for/next/topic3 [remote rejected] (proc-receive failed to report status) + Done + 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 +' + +# Refs of upstream : master(B) foo(A) bar(A)) baz(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL/porcelain)" ' + ( + cd "$upstream" && + git update-ref refs/heads/master $A && + git update-ref -d refs/heads/foo && + git update-ref -d refs/heads/bar && + git update-ref -d refs/heads/baz + ) + +' From patchwork Mon Aug 24 17:41:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733877 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 DB6A913A4 for ; Mon, 24 Aug 2020 17:42:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B9B032074D for ; Mon, 24 Aug 2020 17:42:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Cy6xUuHy" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726880AbgHXRme (ORCPT ); Mon, 24 Aug 2020 13:42:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35746 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726630AbgHXRmS (ORCPT ); Mon, 24 Aug 2020 13:42:18 -0400 Received: from mail-pl1-x636.google.com (mail-pl1-x636.google.com [IPv6:2607:f8b0:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 96E26C061755 for ; Mon, 24 Aug 2020 10:42:17 -0700 (PDT) Received: by mail-pl1-x636.google.com with SMTP id p15so1027416pli.6 for ; Mon, 24 Aug 2020 10:42:17 -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=oJOnLx001mlmQ3uZcYbe7M7qCAT+P1kynidn98oyJjs=; b=Cy6xUuHyJHHwljUADB2ghoYYu2cbyUJAPMZj+Hiu1irHlGxdWdcBjAF4UHEnctQKzo veOM5dH/YA/7yBfdZbdxVJmargSJAcVb8dFl8HUNDILkIkWpsBFgJvt+1ZegqMoC9ufx zPb0bRIjSCIAHwqOWv8pXjNocnW64SBHr7MddTaHyH8/xKCO+OgoLX/AbCnBl/J9SvqP S4ZS980O18gpRJLSZazLlS30DHIzgQNesRWdhkqL9u75GznbdA5ow+0Gts9OmWwzuzR8 6A2w2Xq4rNHwo2ePT5pgj2S2PZE83FY1YNPWuRAw2cNgtZ7i+cAsbT8Yt4pp1GuHpkZK TdAA== 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=oJOnLx001mlmQ3uZcYbe7M7qCAT+P1kynidn98oyJjs=; b=ry8+LaqXu4n48+nq6pDQd1NA2d2iOMr15pSEjbGdNzvj7ja1dR1JivsBy6tQRqRUa1 AId+XNOIOQUyq5+rFEaBsLHO7R/RvKu8CF5Z6WEMwV0juBqYyEFuEehiC/1AOnL3jQQP ENQ1IQkNf0LmZe8i8a0Wc3gfOBRt0nFNHt4IvNoMIw+UAnl6Fo+dizs1Np2dYrFKMjni oiXx1j7JRuHG9uOIvd7MYCd0e1Rqdo+OqZBxrD/PQ6aGLN696yZ30nntgjiz9Vp0WMyZ A+rLeNTXGILKi47ZjOTfKIx3+WHvEIo2cuOk8oLk4zFXhIlFFbidjB38Rt8K1ZU4kFl8 MJ7Q== X-Gm-Message-State: AOAM530dJDIYxUY20mpXxBJOYWSveNriwR/QVwWJDQn8hh52G641dK8r AAszfHwTBopjVAtaPir589A= X-Google-Smtp-Source: ABdhPJxrEz4GxMYEkrjt9cad0uu8sO/ApKiBU2dOKqReF6Y8u3TWO5Sc1oEjW8AMwyfwxOUcBnl6lg== X-Received: by 2002:a17:902:a982:: with SMTP id bh2mr4579021plb.182.1598290936353; Mon, 24 Aug 2020 10:42:16 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.15 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:15 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v18 04/10] receive-pack: feed report options to post-receive Date: Mon, 24 Aug 2020 13:41:56 -0400 Message-Id: <20200824174202.11710-5-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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 commands are fed to the "post-receive" hook, report options will be parsed and the real old-oid, new-oid, reference name will feed to the "post-receive" hook. Signed-off-by: Jiang Xin --- builtin/receive-pack.c | 30 ++++++++++++++++--- t/t5411/test-0032-report-with-options.sh | 14 ++++----- ...est-0033-report-with-options--porcelain.sh | 14 ++++----- ...t-0036-report-multi-rewrite-for-one-ref.sh | 11 +++++-- ...rt-multi-rewrite-for-one-ref--porcelain.sh | 11 +++++-- t/t5411/test-0038-report-mixed-refs.sh | 2 +- .../test-0039-report-mixed-refs--porcelain.sh | 2 +- 7 files changed, 58 insertions(+), 26 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 2b63b92545..38f230248d 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -694,6 +694,7 @@ static void prepare_push_cert_sha1(struct child_process *proc) struct receive_hook_feed_state { struct command *cmd; + struct ref_push_report *report; int skip_broken; struct strbuf buf; const struct string_list *push_options; @@ -781,11 +782,31 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep) cmd = cmd->next; if (!cmd) return -1; /* EOF */ + if (!bufp) + return 0; /* OK, can feed something. */ strbuf_reset(&state->buf); - strbuf_addf(&state->buf, "%s %s %s\n", - oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid), - cmd->ref_name); - state->cmd = cmd->next; + if (!state->report) + state->report = cmd->report; + if (state->report) { + struct object_id *old_oid; + struct object_id *new_oid; + const char *ref_name; + + old_oid = state->report->old_oid ? state->report->old_oid : &cmd->old_oid; + new_oid = state->report->new_oid ? state->report->new_oid : &cmd->new_oid; + ref_name = state->report->ref_name ? state->report->ref_name : cmd->ref_name; + strbuf_addf(&state->buf, "%s %s %s\n", + oid_to_hex(old_oid), oid_to_hex(new_oid), + ref_name); + state->report = state->report->next; + if (!state->report) + state->cmd = cmd->next; + } else { + strbuf_addf(&state->buf, "%s %s %s\n", + oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid), + cmd->ref_name); + state->cmd = cmd->next; + } if (bufp) { *bufp = state->buf.buf; *sizep = state->buf.len; @@ -804,6 +825,7 @@ static int run_receive_hook(struct command *commands, strbuf_init(&state.buf, 0); state.cmd = commands; state.skip_broken = skip_broken; + state.report = NULL; if (feed_receive_hook(&state, NULL, NULL)) return 0; state.cmd = commands; diff --git a/t/t5411/test-0032-report-with-options.sh b/t/t5411/test-0032-report-with-options.sh index a743aa8018..c559c207fa 100644 --- a/t/t5411/test-0032-report-with-options.sh +++ b/t/t5411/test-0032-report-with-options.sh @@ -54,7 +54,7 @@ test_expect_success "proc-receive: report option refname ($PROTOCOL)" ' remote: proc-receive> ok refs/for/master/topic remote: proc-receive> option refname refs/pull/123/head remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/pull/123/head To * [new reference] HEAD -> refs/for/master/topic EOF @@ -87,7 +87,7 @@ test_expect_success "proc-receive: report option refname and forced-update ($PRO remote: proc-receive> option refname refs/pull/123/head remote: proc-receive> option forced-update remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/pull/123/head To * [new reference] HEAD -> refs/for/master/topic EOF @@ -121,7 +121,7 @@ test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL) remote: proc-receive> option refname refs/pull/123/head remote: proc-receive> option old-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/pull/123/head To * [new reference] HEAD -> refs/for/master/topic EOF @@ -153,7 +153,7 @@ test_expect_success "proc-receive: report option old-oid ($PROTOCOL)" ' remote: proc-receive> ok refs/for/master/topic remote: proc-receive> option old-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/for/master/topic To * [new reference] HEAD -> refs/for/master/topic EOF @@ -187,7 +187,7 @@ test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL) remote: proc-receive> option old-oid remote: proc-receive> option new-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/for/master/topic To * [new reference] HEAD -> refs/for/master/topic EOF @@ -237,9 +237,9 @@ test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL)" ' remote: proc-receive> option forced-update remote: proc-receive> option new-oid remote: # post-receive hook - remote: post-receive< refs/for/next/topic + remote: post-receive< refs/pull/123/head remote: post-receive< refs/for/a/b/c/topic - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/pull/124/head To * [new reference] HEAD -> refs/for/next/topic * [new reference] HEAD -> refs/for/a/b/c/topic diff --git a/t/t5411/test-0033-report-with-options--porcelain.sh b/t/t5411/test-0033-report-with-options--porcelain.sh index 439b97b06e..ea9312234e 100644 --- a/t/t5411/test-0033-report-with-options--porcelain.sh +++ b/t/t5411/test-0033-report-with-options--porcelain.sh @@ -55,7 +55,7 @@ test_expect_success "proc-receive: report option refname ($PROTOCOL/porcelain)" remote: proc-receive> ok refs/for/master/topic remote: proc-receive> option refname refs/pull/123/head remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/pull/123/head To * HEAD:refs/for/master/topic [new reference] Done @@ -90,7 +90,7 @@ test_expect_success "proc-receive: report option refname and forced-update ($PRO remote: proc-receive> option refname refs/pull/123/head remote: proc-receive> option forced-update remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/pull/123/head To * HEAD:refs/for/master/topic [new reference] Done @@ -125,7 +125,7 @@ test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL/ remote: proc-receive> option refname refs/pull/123/head remote: proc-receive> option old-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/pull/123/head To * HEAD:refs/for/master/topic [new reference] Done @@ -158,7 +158,7 @@ test_expect_success "proc-receive: report option old-oid ($PROTOCOL/porcelain)" remote: proc-receive> ok refs/for/master/topic remote: proc-receive> option old-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/for/master/topic To * HEAD:refs/for/master/topic [new reference] Done @@ -193,7 +193,7 @@ test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL/ remote: proc-receive> option old-oid remote: proc-receive> option new-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/for/master/topic To * HEAD:refs/for/master/topic [new reference] Done @@ -245,9 +245,9 @@ test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL/porc remote: proc-receive> option forced-update remote: proc-receive> option new-oid remote: # post-receive hook - remote: post-receive< refs/for/next/topic + remote: post-receive< refs/pull/123/head remote: post-receive< refs/for/a/b/c/topic - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/pull/124/head To * HEAD:refs/for/next/topic [new reference] * HEAD:refs/for/a/b/c/topic [new reference] diff --git a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh index 12acf9ea1f..67cc4a8a4c 100644 --- a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh +++ b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh @@ -41,7 +41,9 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for remote: proc-receive> option old-oid remote: proc-receive> option new-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/for/master/topic + remote: post-receive< refs/changes/24/124/1 + remote: post-receive< refs/changes/25/125/1 To * [new reference] HEAD -> refs/for/master/topic EOF @@ -99,7 +101,9 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for remote: proc-receive> option new-oid remote: proc-receive> option forced-update remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/changes/24/124/1 + remote: post-receive< refs/for/master/topic + remote: post-receive< refs/changes/25/125/1 To * [new reference] HEAD -> refs/for/master/topic EOF @@ -145,7 +149,8 @@ test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL)" ' remote: proc-receive> option old-oid remote: proc-receive> option new-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/changes/23/123/1 + remote: post-receive< refs/changes/24/124/2 To * [new reference] HEAD -> refs/for/master/topic EOF diff --git a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh index f4a2c56e14..1dc8551bc6 100644 --- a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh +++ b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh @@ -41,7 +41,9 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for remote: proc-receive> option old-oid remote: proc-receive> option new-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/for/master/topic + remote: post-receive< refs/changes/24/124/1 + remote: post-receive< refs/changes/25/125/1 To * HEAD:refs/for/master/topic [new reference] Done @@ -100,7 +102,9 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for remote: proc-receive> option new-oid remote: proc-receive> option forced-update remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/changes/24/124/1 + remote: post-receive< refs/for/master/topic + remote: post-receive< refs/changes/25/125/1 To * HEAD:refs/for/master/topic [new reference] Done @@ -147,7 +151,8 @@ test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL/porc remote: proc-receive> option old-oid remote: proc-receive> option new-oid remote: # post-receive hook - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/changes/23/123/1 + remote: post-receive< refs/changes/24/124/2 To * HEAD:refs/for/master/topic [new reference] Done diff --git a/t/t5411/test-0038-report-mixed-refs.sh b/t/t5411/test-0038-report-mixed-refs.sh index 1dd6a97a97..bfc8d586d6 100644 --- a/t/t5411/test-0038-report-mixed-refs.sh +++ b/t/t5411/test-0038-report-mixed-refs.sh @@ -53,7 +53,7 @@ test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL)" ' remote: post-receive< refs/heads/baz remote: post-receive< refs/for/next/topic2 remote: post-receive< refs/heads/foo - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/for/master/topic To .. -> master * [new branch] HEAD -> bar diff --git a/t/t5411/test-0039-report-mixed-refs--porcelain.sh b/t/t5411/test-0039-report-mixed-refs--porcelain.sh index 32ebf63dcf..5d021a4837 100644 --- a/t/t5411/test-0039-report-mixed-refs--porcelain.sh +++ b/t/t5411/test-0039-report-mixed-refs--porcelain.sh @@ -53,7 +53,7 @@ test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL/porcel remote: post-receive< refs/heads/baz remote: post-receive< refs/for/next/topic2 remote: post-receive< refs/heads/foo - remote: post-receive< refs/for/master/topic + remote: post-receive< refs/for/master/topic To :refs/heads/master .. * HEAD:refs/heads/bar [new branch] From patchwork Mon Aug 24 17:41:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733887 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 8DDDB13B1 for ; Mon, 24 Aug 2020 17:42:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 62E382074D for ; Mon, 24 Aug 2020 17:42:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="etcsuJsb" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727034AbgHXRmo (ORCPT ); Mon, 24 Aug 2020 13:42:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35754 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726645AbgHXRmS (ORCPT ); Mon, 24 Aug 2020 13:42:18 -0400 Received: from mail-pj1-x1032.google.com (mail-pj1-x1032.google.com [IPv6:2607:f8b0:4864:20::1032]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8E06AC0613ED for ; Mon, 24 Aug 2020 10:42:18 -0700 (PDT) Received: by mail-pj1-x1032.google.com with SMTP id q1so4584370pjd.1 for ; Mon, 24 Aug 2020 10:42:18 -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=lIVXQ3guhKr0I28n1MWdQImuARMyzdwetKvWNhgqxBY=; b=etcsuJsbA4/bDL6sHTv9I9HNn3lbt96GYpMbF01stf2NaNa9ICYbipXKYQ7tcXCAHW 7y0uGt4td2D8tBymt5HNmJO00Eh4xg9KFulvZNyqdBRkFkcylwCgD4Nsa7z2A5W5UbwI 3woq+BZcV7URJqPPE4LH4rrVnatH/nvRoeaCQr6sPIi4EWrEguHxGh70RMxNHImto5hO hNGSr7hB0QpxVV/Vgfkkln5LwAY6NmmyzI7H/6CSvMSY0DsftrkGsiZf20TaBrGkrddM lJPOMuovtHeVbZcMSYVq4gR4F1a73qlmSKbmP6Cdq4DbvNg8rKlfSijOP2oHyeOojp/T iQXw== 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=lIVXQ3guhKr0I28n1MWdQImuARMyzdwetKvWNhgqxBY=; b=XnxovCjXGunpTvsc1+XvXJ9lL/h8Dyb1djNzCdYoH9XjbP1s4eQskC2jFmeLgWNzD7 k0zYSUfHDH+bJGA6+MdJYxFe+JmE5Ere2BqUNRCfzrrJAZ+jsz0IOdTNLgQ6VtFt2VGT IDajs02oiSEldWbfg/lPyAU8PV3e/fiDr5TlrF4Wru6cmH0kcY8ZCG13Q2aTotHu8vzN kNeWnjN86XPmcYB3VJ/V7q5M5MheoPFgeTJ/Kb2jkb8rU/hGHsEEN6nHVO+JWdj7qdpK 19oeiiaasnBPKVtE59z3TziQMBPaF9E5bxSfsL8Uj8hA/uMOBifPSdQo0iuv8wNC7r59 lE7g== X-Gm-Message-State: AOAM531JcgamWPVxBohWsS0n2QOJkkzFGycsmiWlJbNEqSvRodtS+aph +lFzQYrF4EE9E3krlhbRFHY= X-Google-Smtp-Source: ABdhPJzMkXmETPqopGWIhpy9wStUsINdMGuhvJSJYB6FbULR66aLk6QWWfpLT+1FTRJ+DyTKFjyDWg== X-Received: by 2002:a17:902:c20a:: with SMTP id 10mr3452275pll.38.1598290937762; Mon, 24 Aug 2020 10:42:17 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.16 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:16 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin , Jeff King Subject: [PATCH v18 05/10] New capability "report-status-v2" for git-push Date: Mon, 24 Aug 2020 13:41:57 -0400 Message-Id: <20200824174202.11710-6-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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 new introduced "proc-receive" hook may handle a command for a pseudo-reference with a zero-old as its old-oid, while the hook may create or update a reference with different name, different new-oid, and different old-oid (the reference may exist already with a non-zero old-oid). Current "report-status" protocol cannot report the status for such reference rewrite. Add new capability "report-status-v2" and new report protocol which is not backward compatible for report of git-push. If a user pushes to a pseudo-reference "refs/for/master/topic", and "receive-pack" creates two new references "refs/changes/23/123/1" and "refs/changes/24/124/1", for client without the knowledge of "report-status-v2", "receive-pack" will only send "ok/ng" directives in the report, such as: ok ref/for/master/topic But for client which has the knowledge of "report-status-v2", "receive-pack" will use "option" directives to report more attributes for the reference given by the above "ok/ng" directive. ok refs/for/master/topic option refname refs/changes/23/123/1 option new-oid ok refs/for/master/topic option refname refs/changes/24/124/1 option new-oid The client will report two new created references to the end user. Suggested-by: Junio C Hamano Suggested-by: Jeff King Signed-off-by: Jiang Xin --- builtin/receive-pack.c | 54 +++++++- builtin/send-pack.c | 19 +++ remote.h | 1 + send-pack.c | 101 +++++++++++--- t/t5411-proc-receive-hook.sh | 9 ++ t/t5411/once-0010-report-status-v1.sh | 90 ++++++++++++ t/t5411/test-0032-report-with-options.sh | 14 +- ...est-0033-report-with-options--porcelain.sh | 14 +- ...t-0036-report-multi-rewrite-for-one-ref.sh | 11 +- ...rt-multi-rewrite-for-one-ref--porcelain.sh | 11 +- t/t5411/test-0038-report-mixed-refs.sh | 2 +- .../test-0039-report-mixed-refs--porcelain.sh | 2 +- transport-helper.c | 128 ++++++++++++++---- transport.c | 116 ++++++++++++---- 14 files changed, 472 insertions(+), 100 deletions(-) create mode 100644 t/t5411/once-0010-report-status-v1.sh diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 38f230248d..d6a216b2e3 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -56,6 +56,7 @@ static int advertise_push_options; static int unpack_limit = 100; static off_t max_input_size; static int report_status; +static int report_status_v2; static int use_sideband; static int use_atomic; static int use_push_options; @@ -239,7 +240,7 @@ static void show_ref(const char *path, const struct object_id *oid) struct strbuf cap = STRBUF_INIT; strbuf_addstr(&cap, - "report-status delete-refs side-band-64k quiet"); + "report-status report-status-v2 delete-refs side-band-64k quiet"); if (advertise_atomic_push) strbuf_addstr(&cap, " atomic"); if (prefer_ofs_delta) @@ -1937,6 +1938,8 @@ static struct command *read_head_info(struct packet_reader *reader, const char *feature_list = reader->line + linelen + 1; if (parse_feature_request(feature_list, "report-status")) report_status = 1; + if (parse_feature_request(feature_list, "report-status-v2")) + report_status_v2 = 1; if (parse_feature_request(feature_list, "side-band-64k")) use_sideband = LARGE_PACKET_MAX; if (parse_feature_request(feature_list, "quiet")) @@ -2248,6 +2251,51 @@ static void report(struct command *commands, const char *unpack_status) strbuf_release(&buf); } +static void report_v2(struct command *commands, const char *unpack_status) +{ + struct command *cmd; + struct strbuf buf = STRBUF_INIT; + struct ref_push_report *report; + + packet_buf_write(&buf, "unpack %s\n", + unpack_status ? unpack_status : "ok"); + for (cmd = commands; cmd; cmd = cmd->next) { + int count = 0; + + if (cmd->error_string) { + packet_buf_write(&buf, "ng %s %s\n", + cmd->ref_name, + cmd->error_string); + continue; + } + packet_buf_write(&buf, "ok %s\n", + cmd->ref_name); + for (report = cmd->report; report; report = report->next) { + if (count++ > 0) + packet_buf_write(&buf, "ok %s\n", + cmd->ref_name); + if (report->ref_name) + packet_buf_write(&buf, "option refname %s\n", + report->ref_name); + if (report->old_oid) + packet_buf_write(&buf, "option old-oid %s\n", + oid_to_hex(report->old_oid)); + if (report->new_oid) + packet_buf_write(&buf, "option new-oid %s\n", + oid_to_hex(report->new_oid)); + if (report->forced_update) + packet_buf_write(&buf, "option forced-update\n"); + } + } + packet_buf_flush(&buf); + + if (use_sideband) + send_sideband(1, 1, buf.buf, buf.len, use_sideband); + else + write_or_die(1, buf.buf, buf.len); + strbuf_release(&buf); +} + static int delete_only(struct command *commands) { struct command *cmd; @@ -2356,7 +2404,9 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) &push_options); if (pack_lockfile) unlink_or_warn(pack_lockfile); - if (report_status) + if (report_status_v2) + report_v2(commands, unpack_status); + else if (report_status) report(commands, unpack_status); run_receive_hook(commands, "post-receive", 1, &push_options); diff --git a/builtin/send-pack.c b/builtin/send-pack.c index f2c5a34402..2777cc4371 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -29,10 +29,12 @@ static struct send_pack_args args; static void print_helper_status(struct ref *ref) { struct strbuf buf = STRBUF_INIT; + struct ref_push_report *report; for (; ref; ref = ref->next) { const char *msg = NULL; const char *res; + int count = 0; switch(ref->status) { case REF_STATUS_NONE: @@ -94,6 +96,23 @@ static void print_helper_status(struct ref *ref) } strbuf_addch(&buf, '\n'); + if (ref->status == REF_STATUS_OK) { + for (report = ref->report; report; report = report->next) { + if (count++ > 0) + strbuf_addf(&buf, "ok %s\n", ref->name); + if (report->ref_name) + strbuf_addf(&buf, "option refname %s\n", + report->ref_name); + if (report->old_oid) + strbuf_addf(&buf, "option old-oid %s\n", + oid_to_hex(report->old_oid)); + if (report->new_oid) + strbuf_addf(&buf, "option new-oid %s\n", + oid_to_hex(report->new_oid)); + if (report->forced_update) + strbuf_addstr(&buf, "option forced-update\n"); + } + } write_or_die(1, buf.buf, buf.len); } strbuf_release(&buf); diff --git a/remote.h b/remote.h index ca7735b441..6d1e5c49f8 100644 --- a/remote.h +++ b/remote.h @@ -148,6 +148,7 @@ struct ref { REF_STATUS_ATOMIC_PUSH_FAILED } status; char *remote_status; + struct ref_push_report *report; struct ref *peer_ref; /* when renaming */ char name[FLEX_ARRAY]; /* more */ }; diff --git a/send-pack.c b/send-pack.c index d1b7edc995..dfaf505c96 100644 --- a/send-pack.c +++ b/send-pack.c @@ -153,25 +153,79 @@ static int receive_status(struct packet_reader *reader, struct ref *refs) { struct ref *hint; int ret; + struct ref_push_report *report = NULL; + int new_report = 0; + int once = 0; hint = NULL; ret = receive_unpack_status(reader); while (1) { + struct object_id old_oid, new_oid; + const char *head; const char *refname; - char *msg; + char *p; if (packet_reader_read(reader) != PACKET_READ_NORMAL) break; - if (!starts_with(reader->line, "ok ") && !starts_with(reader->line, "ng ")) { - error("invalid ref status from remote: %s", reader->line); + head = reader->line; + p = strchr(head, ' '); + if (!p) { + error("invalid status line from remote: %s", reader->line); ret = -1; break; } + *p++ = '\0'; - refname = reader->line + 3; - msg = strchr(refname, ' '); - if (msg) - *msg++ = '\0'; + if (!strcmp(head, "option")) { + const char *key, *val; + if (!hint || !(report || new_report)) { + if (!once++) + error("'option' without a matching 'ok/ng' directive"); + ret = -1; + continue; + } + if (new_report) { + if (!hint->report) { + hint->report = xcalloc(1, sizeof(struct ref_push_report)); + report = hint->report; + } else { + report = hint->report; + while (report->next) + report = report->next; + report->next = xcalloc(1, sizeof(struct ref_push_report)); + report = report->next; + } + new_report = 0; + } + key = p; + p = strchr(key, ' '); + if (p) + *p++ = '\0'; + val = p; + if (!strcmp(key, "refname")) + report->ref_name = xstrdup_or_null(val); + else if (!strcmp(key, "old-oid") && val && + !parse_oid_hex(val, &old_oid, &val)) + report->old_oid = oiddup(&old_oid); + else if (!strcmp(key, "new-oid") && val && + !parse_oid_hex(val, &new_oid, &val)) + report->new_oid = oiddup(&new_oid); + else if (!strcmp(key, "forced-update")) + report->forced_update = 1; + continue; + } + + report = NULL; + new_report = 0; + if (strcmp(head, "ok") && strcmp(head, "ng")) { + error("invalid ref status from remote: %s", head); + ret = -1; + break; + } + refname = p; + p = strchr(refname, ' '); + if (p) + *p++ = '\0'; /* first try searching at our hint, falling back to all refs */ if (hint) hint = find_ref_by_name(hint, refname); @@ -179,22 +233,27 @@ static int receive_status(struct packet_reader *reader, struct ref *refs) hint = find_ref_by_name(refs, refname); if (!hint) { warning("remote reported status on unknown ref: %s", - refname); + refname); continue; } - if (hint->status != REF_STATUS_EXPECTING_REPORT) { + if (hint->status != REF_STATUS_EXPECTING_REPORT && + hint->status != REF_STATUS_OK && + hint->status != REF_STATUS_REMOTE_REJECT) { warning("remote reported status on unexpected ref: %s", - refname); + refname); continue; } - - if (reader->line[0] == 'o' && reader->line[1] == 'k') - hint->status = REF_STATUS_OK; - else + if (!strcmp(head, "ng")) { hint->status = REF_STATUS_REMOTE_REJECT; - hint->remote_status = xstrdup_or_null(msg); - /* start our next search from the next ref */ - hint = hint->next; + if (p) + hint->remote_status = xstrdup(p); + else + hint->remote_status = "failed"; + } else { + hint->status = REF_STATUS_OK; + hint->remote_status = xstrdup_or_null(p); + new_report = 1; + } } return ret; } @@ -369,7 +428,9 @@ int send_pack(struct send_pack_args *args, struct packet_reader reader; /* Does the other end support the reporting? */ - if (server_supports("report-status")) + if (server_supports("report-status-v2")) + status_report = 2; + else if (server_supports("report-status")) status_report = 1; if (server_supports("delete-refs")) allow_deleting_refs = 1; @@ -418,8 +479,10 @@ int send_pack(struct send_pack_args *args, use_push_options = push_options_supported && args->push_options; - if (status_report) + if (status_report == 1) strbuf_addstr(&cap_buf, " report-status"); + else if (status_report == 2) + strbuf_addstr(&cap_buf, " report-status-v2"); if (use_sideband) strbuf_addstr(&cap_buf, " side-band-64k"); if (quiet_supported && (args->quiet || !args->progress)) diff --git a/t/t5411-proc-receive-hook.sh b/t/t5411-proc-receive-hook.sh index 3a684353a8..746487286f 100755 --- a/t/t5411-proc-receive-hook.sh +++ b/t/t5411-proc-receive-hook.sh @@ -78,6 +78,15 @@ run_proc_receive_hook_test() { # Initialize the upstream repository and local workbench. setup_upstream_and_workbench +# Load test cases that only need to be executed once. +for t in "$TEST_DIRECTORY"/t5411/once-*.sh +do + . "$t" +done + +# Initialize the upstream repository and local workbench. +setup_upstream_and_workbench + # Run test cases for 'proc-receive' hook on local file protocol. run_proc_receive_hook_test local diff --git a/t/t5411/once-0010-report-status-v1.sh b/t/t5411/once-0010-report-status-v1.sh new file mode 100644 index 0000000000..bf410dc418 --- /dev/null +++ b/t/t5411/once-0010-report-status-v1.sh @@ -0,0 +1,90 @@ +test_expect_success "setup proc-receive hook" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/for/master/topic1" \ + -r "option fall-through" \ + -r "ok refs/for/master/topic2" \ + -r "option refname refs/for/changes/23/123/1" \ + -r "option new-oid $A" \ + -r "ok refs/for/master/topic2" \ + -r "option refname refs/for/changes/24/124/2" \ + -r "option old-oid $B" \ + -r "option new-oid $A" \ + -r "option forced-update" \ + -r "ng refs/for/next/topic target branch not exist" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : (B) refs/for/master/topic1(A) foo(A) refs/for/next/topic(A) refs/for/master/topic2(A) +test_expect_success "proc-receive: report status v1" ' + { + if test -z "$GIT_DEFAULT_HASH" || test "$GIT_DEFAULT_HASH" = "sha1" + then + printf "%s %s refs/heads/master\0report-status\n" \ + $A $B | packetize + else + printf "%s %s refs/heads/master\0report-status object-format=$GIT_DEFAULT_HASH\n" \ + $A $B | packetize + fi && + printf "%s %s refs/for/master/topic1\n" \ + $ZERO_OID $A | packetize && + printf "%s %s refs/heads/foo\n" \ + $ZERO_OID $A | packetize && + printf "%s %s refs/for/next/topic\n" \ + $ZERO_OID $A | packetize && + printf "%s %s refs/for/master/topic2\n" \ + $ZERO_OID $A | packetize && + printf 0000 && + printf "" | git -C "$upstream" pack-objects --stdout + } | git receive-pack "$upstream" --stateless-rpc \ + >out 2>&1 && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + # pre-receive hook + pre-receive< refs/heads/master + pre-receive< refs/for/master/topic1 + pre-receive< refs/heads/foo + pre-receive< refs/for/next/topic + pre-receive< refs/for/master/topic2 + # proc-receive hook + proc-receive< refs/for/master/topic1 + proc-receive< refs/for/next/topic + proc-receive< refs/for/master/topic2 + proc-receive> ok refs/for/master/topic1 + proc-receive> option fall-through + proc-receive> ok refs/for/master/topic2 + proc-receive> option refname refs/for/changes/23/123/1 + proc-receive> option new-oid + proc-receive> ok refs/for/master/topic2 + proc-receive> option refname refs/for/changes/24/124/2 + proc-receive> option old-oid + proc-receive> option new-oid + proc-receive> option forced-update + proc-receive> ng refs/for/next/topic target branch not exist + 000eunpack ok + 0019ok refs/heads/master + 001eok refs/for/master/topic1 + 0016ok refs/heads/foo + 0033ng refs/for/next/topic target branch not exist + 001eok refs/for/master/topic2 + 0000# post-receive hook + post-receive< refs/heads/master + post-receive< refs/for/master/topic1 + post-receive< refs/heads/foo + post-receive< refs/for/changes/23/123/1 + post-receive< refs/for/changes/24/124/2 + EOF + test_cmp expect actual && + + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/for/master/topic1 + refs/heads/foo + refs/heads/master + EOF + test_cmp expect actual +' diff --git a/t/t5411/test-0032-report-with-options.sh b/t/t5411/test-0032-report-with-options.sh index c559c207fa..b77b78c49f 100644 --- a/t/t5411/test-0032-report-with-options.sh +++ b/t/t5411/test-0032-report-with-options.sh @@ -56,7 +56,7 @@ test_expect_success "proc-receive: report option refname ($PROTOCOL)" ' remote: # post-receive hook remote: post-receive< refs/pull/123/head To - * [new reference] HEAD -> refs/for/master/topic + * [new reference] HEAD -> refs/pull/123/head EOF test_cmp expect actual ' @@ -89,7 +89,7 @@ test_expect_success "proc-receive: report option refname and forced-update ($PRO remote: # post-receive hook remote: post-receive< refs/pull/123/head To - * [new reference] HEAD -> refs/for/master/topic + * [new reference] HEAD -> refs/pull/123/head EOF test_cmp expect actual ' @@ -123,7 +123,7 @@ test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL) remote: # post-receive hook remote: post-receive< refs/pull/123/head To - * [new reference] HEAD -> refs/for/master/topic + .. HEAD -> refs/pull/123/head EOF test_cmp expect actual ' @@ -155,7 +155,7 @@ test_expect_success "proc-receive: report option old-oid ($PROTOCOL)" ' remote: # post-receive hook remote: post-receive< refs/for/master/topic To - * [new reference] HEAD -> refs/for/master/topic + .. HEAD -> refs/for/master/topic EOF test_cmp expect actual ' @@ -189,7 +189,7 @@ test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL) remote: # post-receive hook remote: post-receive< refs/for/master/topic To - * [new reference] HEAD -> refs/for/master/topic + .. HEAD -> refs/for/master/topic EOF test_cmp expect actual ' @@ -241,9 +241,9 @@ test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL)" ' remote: post-receive< refs/for/a/b/c/topic remote: post-receive< refs/pull/124/head To - * [new reference] HEAD -> refs/for/next/topic + * [new reference] HEAD -> refs/pull/123/head * [new reference] HEAD -> refs/for/a/b/c/topic - * [new reference] HEAD -> refs/for/master/topic + + ... HEAD -> refs/pull/124/head (forced update) EOF test_cmp expect actual && diff --git a/t/t5411/test-0033-report-with-options--porcelain.sh b/t/t5411/test-0033-report-with-options--porcelain.sh index ea9312234e..1fe352b686 100644 --- a/t/t5411/test-0033-report-with-options--porcelain.sh +++ b/t/t5411/test-0033-report-with-options--porcelain.sh @@ -57,7 +57,7 @@ test_expect_success "proc-receive: report option refname ($PROTOCOL/porcelain)" remote: # post-receive hook remote: post-receive< refs/pull/123/head To - * HEAD:refs/for/master/topic [new reference] + * HEAD:refs/pull/123/head [new reference] Done EOF test_cmp expect actual @@ -92,7 +92,7 @@ test_expect_success "proc-receive: report option refname and forced-update ($PRO remote: # post-receive hook remote: post-receive< refs/pull/123/head To - * HEAD:refs/for/master/topic [new reference] + * HEAD:refs/pull/123/head [new reference] Done EOF test_cmp expect actual @@ -127,7 +127,7 @@ test_expect_success "proc-receive: report option refname and old-oid ($PROTOCOL/ remote: # post-receive hook remote: post-receive< refs/pull/123/head To - * HEAD:refs/for/master/topic [new reference] + HEAD:refs/pull/123/head .. Done EOF test_cmp expect actual @@ -160,7 +160,7 @@ test_expect_success "proc-receive: report option old-oid ($PROTOCOL/porcelain)" remote: # post-receive hook remote: post-receive< refs/for/master/topic To - * HEAD:refs/for/master/topic [new reference] + HEAD:refs/for/master/topic .. Done EOF test_cmp expect actual @@ -195,7 +195,7 @@ test_expect_success "proc-receive: report option old-oid and new-oid ($PROTOCOL/ remote: # post-receive hook remote: post-receive< refs/for/master/topic To - * HEAD:refs/for/master/topic [new reference] + HEAD:refs/for/master/topic .. Done EOF test_cmp expect actual @@ -249,9 +249,9 @@ test_expect_success "proc-receive: report with multiple rewrites ($PROTOCOL/porc remote: post-receive< refs/for/a/b/c/topic remote: post-receive< refs/pull/124/head To - * HEAD:refs/for/next/topic [new reference] + * HEAD:refs/pull/123/head [new reference] * HEAD:refs/for/a/b/c/topic [new reference] - * HEAD:refs/for/master/topic [new reference] + + HEAD:refs/pull/124/head ... (forced update) Done EOF test_cmp expect actual && diff --git a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh index 67cc4a8a4c..27d58edd14 100644 --- a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh +++ b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh @@ -45,7 +45,9 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for remote: post-receive< refs/changes/24/124/1 remote: post-receive< refs/changes/25/125/1 To - * [new reference] HEAD -> refs/for/master/topic + .. HEAD -> refs/for/master/topic + * [new reference] HEAD -> refs/changes/24/124/1 + .. HEAD -> refs/changes/25/125/1 EOF test_cmp expect actual && git -C "$upstream" show-ref >out && @@ -105,7 +107,9 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for remote: post-receive< refs/for/master/topic remote: post-receive< refs/changes/25/125/1 To - * [new reference] HEAD -> refs/for/master/topic + * [new reference] HEAD -> refs/changes/24/124/1 + .. HEAD -> refs/for/master/topic + + ... HEAD -> refs/changes/25/125/1 (forced update) EOF test_cmp expect actual && git -C "$upstream" show-ref >out && @@ -152,7 +156,8 @@ test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL)" ' remote: post-receive< refs/changes/23/123/1 remote: post-receive< refs/changes/24/124/2 To - * [new reference] HEAD -> refs/for/master/topic + * [new reference] HEAD -> refs/changes/23/123/1 + .. HEAD -> refs/changes/24/124/2 EOF test_cmp expect actual && git -C "$upstream" show-ref >out && diff --git a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh index 1dc8551bc6..77b5b22ed4 100644 --- a/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh +++ b/t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh @@ -45,7 +45,9 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for remote: post-receive< refs/changes/24/124/1 remote: post-receive< refs/changes/25/125/1 To - * HEAD:refs/for/master/topic [new reference] + HEAD:refs/for/master/topic .. + * HEAD:refs/changes/24/124/1 [new reference] + HEAD:refs/changes/25/125/1 .. Done EOF test_cmp expect actual && @@ -106,7 +108,9 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for remote: post-receive< refs/for/master/topic remote: post-receive< refs/changes/25/125/1 To - * HEAD:refs/for/master/topic [new reference] + * HEAD:refs/changes/24/124/1 [new reference] + HEAD:refs/for/master/topic .. + + HEAD:refs/changes/25/125/1 ... (forced update) Done EOF test_cmp expect actual && @@ -154,7 +158,8 @@ test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL/porc remote: post-receive< refs/changes/23/123/1 remote: post-receive< refs/changes/24/124/2 To - * HEAD:refs/for/master/topic [new reference] + * HEAD:refs/changes/23/123/1 [new reference] + HEAD:refs/changes/24/124/2 .. Done EOF test_cmp expect actual && diff --git a/t/t5411/test-0038-report-mixed-refs.sh b/t/t5411/test-0038-report-mixed-refs.sh index bfc8d586d6..a74a2cb449 100644 --- a/t/t5411/test-0038-report-mixed-refs.sh +++ b/t/t5411/test-0038-report-mixed-refs.sh @@ -60,7 +60,7 @@ test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL)" ' * [new branch] HEAD -> baz * [new reference] HEAD -> refs/for/next/topic2 * [new branch] HEAD -> foo - * [new reference] HEAD -> refs/for/master/topic + .. HEAD -> refs/for/master/topic ! [remote rejected] HEAD -> refs/for/next/topic1 (fail to call Web API) ! [remote rejected] HEAD -> refs/for/next/topic3 (proc-receive failed to report status) EOF diff --git a/t/t5411/test-0039-report-mixed-refs--porcelain.sh b/t/t5411/test-0039-report-mixed-refs--porcelain.sh index 5d021a4837..e4baa13ea3 100644 --- a/t/t5411/test-0039-report-mixed-refs--porcelain.sh +++ b/t/t5411/test-0039-report-mixed-refs--porcelain.sh @@ -60,7 +60,7 @@ test_expect_success "proc-receive: report update of mixed refs ($PROTOCOL/porcel * HEAD:refs/heads/baz [new branch] * HEAD:refs/for/next/topic2 [new reference] * HEAD:refs/heads/foo [new branch] - * HEAD:refs/for/master/topic [new reference] + HEAD:refs/for/master/topic .. ! HEAD:refs/for/next/topic1 [remote rejected] (fail to call Web API) ! HEAD:refs/for/next/topic3 [remote rejected] (proc-receive failed to report status) Done diff --git a/transport-helper.c b/transport-helper.c index a46afcb69d..1738c81ea0 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -719,13 +719,61 @@ static int fetch(struct transport *transport, return -1; } +struct push_update_ref_state { + struct ref *hint; + struct ref_push_report *report; + int new_report; +}; + static int push_update_ref_status(struct strbuf *buf, - struct ref **ref, + struct push_update_ref_state *state, struct ref *remote_refs) { char *refname, *msg; int status, forced = 0; + if (starts_with(buf->buf, "option ")) { + struct object_id old_oid, new_oid; + const char *key, *val; + char *p; + + if (!state->hint || !(state->report || state->new_report)) + die(_("'option' without a matching 'ok/error' directive")); + if (state->new_report) { + if (!state->hint->report) { + state->hint->report = xcalloc(1, sizeof(struct ref_push_report)); + state->report = state->hint->report; + } else { + state->report = state->hint->report; + while (state->report->next) + state->report = state->report->next; + state->report->next = xcalloc(1, sizeof(struct ref_push_report)); + state->report = state->report->next; + } + state->new_report = 0; + } + key = buf->buf + 7; + p = strchr(key, ' '); + if (p) + *p++ = '\0'; + val = p; + if (!strcmp(key, "refname")) + state->report->ref_name = xstrdup_or_null(val); + else if (!strcmp(key, "old-oid") && val && + !parse_oid_hex(val, &old_oid, &val)) + state->report->old_oid = oiddup(&old_oid); + else if (!strcmp(key, "new-oid") && val && + !parse_oid_hex(val, &new_oid, &val)) + state->report->new_oid = oiddup(&new_oid); + else if (!strcmp(key, "forced-update")) + state->report->forced_update = 1; + /* Not update remote namespace again. */ + return 1; + } + + state->report = NULL; + state->new_report = 0; + if (starts_with(buf->buf, "ok ")) { status = REF_STATUS_OK; refname = buf->buf + 3; @@ -781,16 +829,16 @@ static int push_update_ref_status(struct strbuf *buf, } } - if (*ref) - *ref = find_ref_by_name(*ref, refname); - if (!*ref) - *ref = find_ref_by_name(remote_refs, refname); - if (!*ref) { + if (state->hint) + state->hint = find_ref_by_name(state->hint, refname); + if (!state->hint) + state->hint = find_ref_by_name(remote_refs, refname); + if (!state->hint) { warning(_("helper reported unexpected status of %s"), refname); return 1; } - if ((*ref)->status != REF_STATUS_NONE) { + if (state->hint->status != REF_STATUS_NONE) { /* * Earlier, the ref was marked not to be pushed, so ignore the ref * status reported by the remote helper if the latter is 'no match'. @@ -799,9 +847,11 @@ static int push_update_ref_status(struct strbuf *buf, return 1; } - (*ref)->status = status; - (*ref)->forced_update |= forced; - (*ref)->remote_status = msg; + if (status == REF_STATUS_OK) + state->new_report = 1; + state->hint->status = status; + state->hint->forced_update |= forced; + state->hint->remote_status = msg; return !(status == REF_STATUS_OK); } @@ -809,37 +859,57 @@ static int push_update_refs_status(struct helper_data *data, struct ref *remote_refs, int flags) { + struct ref *ref; + struct ref_push_report *report; struct strbuf buf = STRBUF_INIT; - struct ref *ref = remote_refs; - int ret = 0; + struct push_update_ref_state state = { remote_refs, NULL, 0 }; for (;;) { - char *private; - if (recvline(data, &buf)) { - ret = 1; - break; + strbuf_release(&buf); + return 1; } - if (!buf.len) break; + push_update_ref_status(&buf, &state, remote_refs); + } + strbuf_release(&buf); - if (push_update_ref_status(&buf, &ref, remote_refs)) - continue; + if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update) + return 0; - if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update) - continue; + /* propagate back the update to the remote namespace */ + for (ref = remote_refs; ref; ref = ref->next) { + char *private; - /* propagate back the update to the remote namespace */ - private = apply_refspecs(&data->rs, ref->name); - if (!private) + if (ref->status != REF_STATUS_OK) continue; - update_ref("update by helper", private, &ref->new_oid, NULL, - 0, 0); - free(private); + + if (!ref->report) { + private = apply_refspecs(&data->rs, ref->name); + if (!private) + continue; + update_ref("update by helper", private, &(ref->new_oid), + NULL, 0, 0); + free(private); + } else { + for (report = ref->report; report; report = report->next) { + private = apply_refspecs(&data->rs, + report->ref_name + ? report->ref_name + : ref->name); + if (!private) + continue; + update_ref("update by helper", private, + report->new_oid + ? report->new_oid + : &(ref->new_oid), + NULL, 0, 0); + free(private); + } + } } - strbuf_release(&buf); - return ret; + return 0; } static void set_common_push_options(struct transport *transport, diff --git a/transport.c b/transport.c index 26fefd13c1..e146de6c4e 100644 --- a/transport.c +++ b/transport.c @@ -461,13 +461,21 @@ void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int v static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, + struct ref_push_report *report, int porcelain, int summary_width) { + const char *to_name; + + if (report && report->ref_name) + to_name = report->ref_name; + 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 +489,11 @@ 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); @@ -493,27 +503,52 @@ static void print_ref_status(char flag, const char *summary, } } -static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_width) +static void print_ok_ref_status(struct ref *ref, + struct ref_push_report *report, + int porcelain, int summary_width) { + struct object_id *old_oid; + struct object_id *new_oid; + const char *ref_name; + int forced_update; + + if (report && report->old_oid) + old_oid = report->old_oid; + else + old_oid = &ref->old_oid; + if (report && report->new_oid) + new_oid = report->new_oid; + else + new_oid = &ref->new_oid; + if (report && report->forced_update) + forced_update = report->forced_update; + else + forced_update = ref->forced_update; + if (report && report->ref_name) + ref_name = report->ref_name; + else + ref_name = ref->name; + if (ref->deletion) print_ref_status('-', "[deleted]", ref, NULL, NULL, - porcelain, summary_width); - else if (is_null_oid(&ref->old_oid)) + report, porcelain, summary_width); + else if (is_null_oid(old_oid)) print_ref_status('*', - (starts_with(ref->name, "refs/tags/") + (starts_with(ref_name, "refs/tags/") ? "[new tag]" - : (starts_with(ref->name, "refs/heads/") + : (starts_with(ref_name, "refs/heads/") ? "[new branch]" : "[new reference]")), - ref, ref->peer_ref, NULL, porcelain, summary_width); + ref, ref->peer_ref, NULL, + report, porcelain, summary_width); else { struct strbuf quickref = STRBUF_INIT; char type; const char *msg; - strbuf_add_unique_abbrev(&quickref, &ref->old_oid, + strbuf_add_unique_abbrev(&quickref, old_oid, DEFAULT_ABBREV); - if (ref->forced_update) { + if (forced_update) { strbuf_addstr(&quickref, "..."); type = '+'; msg = "forced update"; @@ -522,16 +557,17 @@ static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_widt type = ' '; msg = NULL; } - strbuf_add_unique_abbrev(&quickref, &ref->new_oid, + strbuf_add_unique_abbrev(&quickref, new_oid, DEFAULT_ABBREV); print_ref_status(type, quickref.buf, ref, ref->peer_ref, msg, - porcelain, summary_width); + report, porcelain, summary_width); strbuf_release(&quickref); } } -static int print_one_push_status(struct ref *ref, const char *dest, int count, +static int print_one_push_report(struct ref *ref, const char *dest, int count, + struct ref_push_report *report, int porcelain, int summary_width) { if (!count) { @@ -543,65 +579,89 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, switch(ref->status) { case REF_STATUS_NONE: print_ref_status('X', "[no match]", ref, NULL, NULL, - porcelain, summary_width); + report, porcelain, summary_width); break; case REF_STATUS_REJECT_NODELETE: print_ref_status('!', "[rejected]", ref, NULL, "remote does not support deleting refs", - porcelain, summary_width); + report, porcelain, summary_width); break; case REF_STATUS_UPTODATE: print_ref_status('=', "[up to date]", ref, - ref->peer_ref, NULL, porcelain, summary_width); + ref->peer_ref, NULL, + report, porcelain, summary_width); break; case REF_STATUS_REJECT_NONFASTFORWARD: print_ref_status('!', "[rejected]", ref, ref->peer_ref, - "non-fast-forward", porcelain, summary_width); + "non-fast-forward", + report, porcelain, summary_width); break; case REF_STATUS_REJECT_ALREADY_EXISTS: print_ref_status('!', "[rejected]", ref, ref->peer_ref, - "already exists", porcelain, summary_width); + "already exists", + report, porcelain, summary_width); break; case REF_STATUS_REJECT_FETCH_FIRST: print_ref_status('!', "[rejected]", ref, ref->peer_ref, - "fetch first", porcelain, summary_width); + "fetch first", + report, porcelain, summary_width); break; case REF_STATUS_REJECT_NEEDS_FORCE: print_ref_status('!', "[rejected]", ref, ref->peer_ref, - "needs force", porcelain, summary_width); + "needs force", + report, porcelain, summary_width); break; case REF_STATUS_REJECT_STALE: print_ref_status('!', "[rejected]", ref, ref->peer_ref, - "stale info", porcelain, summary_width); + "stale info", + report, porcelain, summary_width); break; case REF_STATUS_REJECT_SHALLOW: print_ref_status('!', "[rejected]", ref, ref->peer_ref, "new shallow roots not allowed", - porcelain, summary_width); + report, porcelain, summary_width); break; case REF_STATUS_REMOTE_REJECT: print_ref_status('!', "[remote rejected]", ref, ref->deletion ? NULL : ref->peer_ref, - ref->remote_status, porcelain, summary_width); + ref->remote_status, + report, porcelain, summary_width); break; case REF_STATUS_EXPECTING_REPORT: print_ref_status('!', "[remote failure]", ref, ref->deletion ? NULL : ref->peer_ref, "remote failed to report status", - porcelain, summary_width); + report, porcelain, summary_width); break; case REF_STATUS_ATOMIC_PUSH_FAILED: print_ref_status('!', "[rejected]", ref, ref->peer_ref, - "atomic push failed", porcelain, summary_width); + "atomic push failed", + report, porcelain, summary_width); break; case REF_STATUS_OK: - print_ok_ref_status(ref, porcelain, summary_width); + print_ok_ref_status(ref, report, porcelain, summary_width); break; } return 1; } +static int print_one_push_status(struct ref *ref, const char *dest, int count, + int porcelain, int summary_width) +{ + struct ref_push_report *report; + int n = 0; + + if (!ref->report) + return print_one_push_report(ref, dest, count, + NULL, porcelain, summary_width); + + for (report = ref->report; report; report = report->next) + print_one_push_report(ref, dest, count + n++, + report, porcelain, summary_width); + return n; +} + static int measure_abbrev(const struct object_id *oid, int sofar) { char hex[GIT_MAX_HEXSZ + 1]; From patchwork Mon Aug 24 17:41:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733879 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 417AD13A4 for ; Mon, 24 Aug 2020 17:42:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2A4B42074D for ; Mon, 24 Aug 2020 17:42:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="rapOb22t" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726585AbgHXRmf (ORCPT ); Mon, 24 Aug 2020 13:42:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35756 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726691AbgHXRmT (ORCPT ); Mon, 24 Aug 2020 13:42:19 -0400 Received: from mail-pl1-x643.google.com (mail-pl1-x643.google.com [IPv6:2607:f8b0:4864:20::643]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 57702C061795 for ; Mon, 24 Aug 2020 10:42:19 -0700 (PDT) Received: by mail-pl1-x643.google.com with SMTP id y6so4571815plk.10 for ; Mon, 24 Aug 2020 10:42:19 -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=JKkzv5uHWjStIPLmBqjV+ImS+rOXWcOFxrifeT45Lcw=; b=rapOb22tMWGjwb5+mo+TBYNAHXpTfIvy/RSrJbSt7CncifEjPQQb59CyToGXH6Lclh rCiq10E/DgiDynLv7oi45vkIOyqyhVjNmK/jbeUac1LOIOh1XIlEjkqbOg8OdNPp9WwK tqMUisAZf5AhaefzWEQ96PItB1Ymv2Vj699dBFAVan35ThUzSWOPNRvAlLKlnklAyZka eCiXnKQHP6Ha1hv6uJBcS/Uj/nGe2wIqWEUX0cuUvVbeacAlefWcpqykeIw7qzCKdRV+ 7wAaYyGiZ59ooZ8NnitUmtXt0E1dOoqgynM7qdZlzSDaOGVFf/MOHt1KwZZJ3xe3FA8m Ujqg== 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=JKkzv5uHWjStIPLmBqjV+ImS+rOXWcOFxrifeT45Lcw=; b=SIrvc+DqsUOmiRDA+jpjjwWDSYS7q8T0PmTj8AFBv++cMYFHroXjlzN3Lg4d1lsbH/ jKojCY+HZQOdWrZQ4M/TdtQsxp3gp6DXNJVvBVIERxvnUMmWVT7H/7uUFUwR383QdQ1s J+IQtInxY4m0qvTiGkCO6qb1+yjy25/X2o77FUnkJCRi3feyzPPRyngKurdLbTfUvGxc R/3nKbO/J8QshVifVbOsN90QmeZKi/hoTTIEN1O3ks+kS1YUN08R8HsxVeeTJVbqO0nh /+tw+rr4Fz+e0/3b8TjH3nPZGlXBrOyFW3ULzPkxS/enNTU2io9BDgYa6jQbOQLUxDkO 86DQ== X-Gm-Message-State: AOAM532RFrKZiwm40NX8jRgsGLHVSQGzePu+dzxerR0iRLlNffh8QhTi NUQ3abucE4l0ZcIUF6ykF5SrHHVn3VIq5w== X-Google-Smtp-Source: ABdhPJyI3FJsed0Rm8r14v6liWXpvxMycU3SWU9Y0gObF5QEXGWPXikKkyGXD2YM1LGKNQQDIpIXLQ== X-Received: by 2002:a17:902:8d8a:: with SMTP id v10mr4453774plo.249.1598290938851; Mon, 24 Aug 2020 10:42:18 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.17 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:18 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v18 06/10] doc: add document for capability report-status-v2 Date: Mon, 24 Aug 2020 13:41:58 -0400 Message-Id: <20200824174202.11710-7-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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 ABNF notation for capability 'report-status-v2' which extends capability 'report-status' by adding additional option lines. Signed-off-by: Jiang Xin --- Documentation/technical/pack-protocol.txt | 43 +++++++++++++++++-- .../technical/protocol-capabilities.txt | 17 ++++++-- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/Documentation/technical/pack-protocol.txt b/Documentation/technical/pack-protocol.txt index d5ce4eea8a..7547b9ca89 100644 --- a/Documentation/technical/pack-protocol.txt +++ b/Documentation/technical/pack-protocol.txt @@ -503,8 +503,8 @@ The reference discovery phase is done nearly the same way as it is in the fetching protocol. Each reference obj-id and name on the server is sent in packet-line format to the client, followed by a flush-pkt. The only real difference is that the capability listing is different - the only -possible values are 'report-status', 'delete-refs', 'ofs-delta' and -'push-options'. +possible values are 'report-status', 'report-status-v2', 'delete-refs', +'ofs-delta', 'atomic' and 'push-options'. Reference Update Request and Packfile Transfer ---------------------------------------------- @@ -625,7 +625,7 @@ Report Status ------------- After receiving the pack data from the sender, the receiver sends a -report if 'report-status' capability is in effect. +report if 'report-status' or 'report-status-v2' capability is in effect. It is a short listing of what happened in that update. It will first list the status of the packfile unpacking as either 'unpack ok' or 'unpack [error]'. Then it will list the status for each of the references @@ -647,6 +647,43 @@ update was successful, or 'ng [refname] [error]' if the update was not. error-msg = 1*(OCTET) ; where not "ok" ---- +New capability "report-status-v2" extends the protocol by adding new option +lines in order to support reporting of reference rewritten by the +"proc-receive" hook. The "proc-receive" hook may handle a command for a +pseudo-reference which may create or update one or more references, and each +reference may have different name, different new-oid, and different old-oid. + +---- + report-status-v2 = unpack-status + 1*(command-status-v2) + flush-pkt + + unpack-status = PKT-LINE("unpack" SP unpack-result) + unpack-result = "ok" / error-msg + + command-status-v2 = command-ok-v2 / command-fail-v2 + command-ok-v2 = command-ok + *option-line + command-fail-v2 = command-fail + *option-line + + command-ok = PKT-LINE("ok" SP refname) + command-fail = PKT-LINE("ng" SP refname SP error-msg) + + error-msg = 1*(OCTET) ; where not "ok" + + option-line = *1(option-refname) + *1(option-old-oid) + *1(option-new-oid) + *1(option-forced-update) + + option-refname = PKT-LINE("option" SP "refname" SP refname) + option-old-oid = PKT-LINE("option" SP "old-oid" SP obj-id) + option-new-oid = PKT-LINE("option" SP "new-oid" SP obj-id) + option-force = PKT-LINE("option" SP "forced-update") + +---- + Updates can be unsuccessful for a number of reasons. The reference can have changed since the reference discovery phase was originally sent, meaning someone pushed in the meantime. The reference being pushed could be a diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt index 2b267c0da6..91fd976094 100644 --- a/Documentation/technical/protocol-capabilities.txt +++ b/Documentation/technical/protocol-capabilities.txt @@ -22,9 +22,9 @@ was sent. Server MUST NOT ignore capabilities that client requested and server advertised. As a consequence of these rules, server MUST NOT advertise capabilities it does not understand. -The 'atomic', 'report-status', 'delete-refs', 'quiet', and 'push-cert' -capabilities are sent and recognized by the receive-pack (push to server) -process. +The 'atomic', 'report-status', 'report-status-v2', 'delete-refs', 'quiet', +and 'push-cert' capabilities are sent and recognized by the receive-pack +(push to server) process. The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized by both upload-pack and receive-pack protocols. The 'agent' capability @@ -269,6 +269,17 @@ each reference was updated successfully. If any of those were not successful, it will send back an error message. See pack-protocol.txt for example messages. +report-status-v2 +---------------- + +Capability 'report-status-v2' extends capability 'report-status' by +adding new option lines in order to support reference rewritten by +the"proc-receive" hook. The "proc-receive" hook may handle a command +for a pseudo-reference which may create or update a reference with +different name, new-oid, and old-oid. While the capability +"report-status" cannot report for such case. See pack-protocol.txt +for details. + delete-refs ----------- From patchwork Mon Aug 24 17:41:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733881 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 A971713A4 for ; Mon, 24 Aug 2020 17:42:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 82E1A2074D for ; Mon, 24 Aug 2020 17:42:40 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="UwGNBLnP" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726502AbgHXRmh (ORCPT ); Mon, 24 Aug 2020 13:42:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35762 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726697AbgHXRmU (ORCPT ); Mon, 24 Aug 2020 13:42:20 -0400 Received: from mail-pf1-x444.google.com (mail-pf1-x444.google.com [IPv6:2607:f8b0:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6E8CEC061574 for ; Mon, 24 Aug 2020 10:42:20 -0700 (PDT) Received: by mail-pf1-x444.google.com with SMTP id x25so5197629pff.4 for ; Mon, 24 Aug 2020 10:42: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=Za1V3GoXM4agdw0RbCtALGld12GtZVZSh15nsBgsU1Y=; b=UwGNBLnPexZVBg6R7ebB4il0SFy8UUbtwOt34r1ybhwDz74ysTp7rN43N3BRYVYNkg S+mzlFQl6K5ud6MiQaKMCrB3f+2yAImEOLdwBMbtk0R26a7IfP7sKVR94Lgoyz+b8oew NVaxwoSoCYLQoaY2KV8QU1oRYt7StnysMZatkfcIqhaJxakLozzeD4jDTX0qsTcWqEZp 4iX+bVPPaRePnVtlv2S8BLl2x6k5n2T/BkO0C8IBhpyZd33hFFamnzBiSpVPgnDn1EBp sSIzNptF5oavClo4/t7y0cnLLS/Arh6XPBsBou88XnN5CwLvQVOXXnwPxpQpC0Nw7ama 8+tg== 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=Za1V3GoXM4agdw0RbCtALGld12GtZVZSh15nsBgsU1Y=; b=W+d17VuetPfEYAPdrLybeUwLQQXU5WF+0Eod6F8Tzgjy4G/UPL4EK83f4VizSBu0ZE 4B38psENe3llP/861HtyHRsgXJhrvcW8XenZl5CPaz9y9BtzgIycGWD6uq+POh/B8hpG 0o0z2ZzPugDV7gBHtLF3pST80OA/Ylw3xhIUV0ZrjO9wo9Q0VwOpip8i8yshunbRIiSq G8Xtss8qvUpvz3Cq09SG6cbpPc5992TP0fKWreNO6p3wQaccmg9DpwCdTJgQbBfqh5A6 NjKpjiTc6whAnqZ8Zh8puQwkgvCoQX7ptIkoqbb3hcUAm2dK4VuN8cpmY+6jIrrOy29R uT7g== X-Gm-Message-State: AOAM531XgMODy0eQhvuPnQjVAUbL6U5V8Wz5DUg6aJQJfBQmPcEHG9od cCsp/kX5m7G6Lz5UB2bAgdfM4ja1LN8FSQ== X-Google-Smtp-Source: ABdhPJxMwVV4rX9rQuL1jvZ8hLCAONKQAUzVzFrXWjFbHH6WZAgzQc/yQEEinK2hdTYyDLRBnqTW9g== X-Received: by 2002:a62:8cd3:: with SMTP id m202mr4717703pfd.184.1598290939817; Mon, 24 Aug 2020 10:42:19 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.18 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:19 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v18 07/10] receive-pack: new config receive.procReceiveRefs Date: Mon, 24 Aug 2020 13:41:59 -0400 Message-Id: <20200824174202.11710-8-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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 given by the config variables match the reference names of the commands which are sent from 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 hook "proc-receive". Optional modifiers can be provided in the beginning of the value to filter commands for specific actions: create (a), mofify (m), delete (d). A `!` can be included in the modifiers to negate the reference prefix entry. E.g.: git config --system --add receive.procReceiveRefs ad:refs/heads Signed-off-by: Jiang Xin --- Documentation/config/receive.txt | 21 +++ builtin/receive-pack.c | 106 ++++++++++++++- t/t5411/once-0010-report-status-v1.sh | 4 + t/t5411/test-0010-proc-receive-settings.sh | 7 + t/t5411/test-0040-process-all-refs.sh | 113 ++++++++++++++++ .../test-0041-process-all-refs--porcelain.sh | 114 ++++++++++++++++ t/t5411/test-0050-proc-receive-refs.sh | 128 ++++++++++++++++++ 7 files changed, 486 insertions(+), 7 deletions(-) create mode 100644 t/t5411/test-0010-proc-receive-settings.sh create mode 100644 t/t5411/test-0040-process-all-refs.sh create mode 100644 t/t5411/test-0041-process-all-refs--porcelain.sh create mode 100644 t/t5411/test-0050-proc-receive-refs.sh diff --git a/Documentation/config/receive.txt b/Documentation/config/receive.txt index 65f78aac37..86bb9adeb7 100644 --- a/Documentation/config/receive.txt +++ b/Documentation/config/receive.txt @@ -114,6 +114,27 @@ 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 hook "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 the hook "proc-receive". ++ +Optional modifiers can be provided in the beginning of the value to filter +commands for specific actions: create (a), mofify (m), delete (d). +A `!` can be included in the modifiers to negate the reference prefix entry. +E.g.: ++ + git config --system --add receive.procReceiveRefs ad:refs/heads + 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 d6a216b2e3..3eecb8c33c 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -97,6 +97,17 @@ static int keepalive_in_sec = 5; static struct tmp_objdir *tmp_objdir; +static struct proc_receive_ref { + unsigned int want_add:1, + want_delete:1, + want_modify:1, + negative_ref:1; + char *ref_prefix; + struct proc_receive_ref *next; +} *proc_receive_ref; + +static void proc_receive_ref_append(const char *prefix); + static enum deny_action parse_deny_action(const char *var, const char *value) { if (value) { @@ -229,6 +240,13 @@ static int receive_pack_config(const char *var, const char *value, void *cb) return 0; } + if (strcmp(var, "receive.procreceiverefs") == 0) { + if (!value) + return config_error_nonbool(var); + proc_receive_ref_append(value); + return 0; + } + return git_default_config(var, value, cb); } @@ -324,6 +342,79 @@ struct command { char ref_name[FLEX_ARRAY]; /* more */ }; +static void proc_receive_ref_append(const char *prefix) +{ + struct proc_receive_ref *ref_pattern; + char *p; + int len; + + ref_pattern = xcalloc(1, sizeof(struct proc_receive_ref)); + p = strchr(prefix, ':'); + if (p) { + while (prefix < p) { + if (*prefix == 'a') + ref_pattern->want_add = 1; + else if (*prefix == 'd') + ref_pattern->want_delete = 1; + else if (*prefix == 'm') + ref_pattern->want_modify = 1; + else if (*prefix == '!') + ref_pattern->negative_ref = 1; + prefix++; + } + prefix++; + } else { + ref_pattern->want_add = 1; + ref_pattern->want_delete = 1; + ref_pattern->want_modify = 1; + } + len = strlen(prefix); + while (len && prefix[len - 1] == '/') + len--; + ref_pattern->ref_prefix = xmemdupz(prefix, len); + if (!proc_receive_ref) { + proc_receive_ref = ref_pattern; + } else { + struct proc_receive_ref *end; + + end = proc_receive_ref; + while (end->next) + end = end->next; + end->next = ref_pattern; + } +} + +static int proc_receive_ref_matches(struct command *cmd) +{ + struct proc_receive_ref *p; + + if (!proc_receive_ref) + return 0; + + for (p = proc_receive_ref; p; p = p->next) { + const char *match = p->ref_prefix; + const char *remains; + + if (!p->want_add && is_null_oid(&cmd->old_oid)) + continue; + else if (!p->want_delete && is_null_oid(&cmd->new_oid)) + continue; + else if (!p->want_modify && + !is_null_oid(&cmd->old_oid) && + !is_null_oid(&cmd->new_oid)) + continue; + + if (skip_prefix(cmd->ref_name, match, &remains) && + (!*remains || *remains == '/')) { + if (!p->negative_ref) + return 1; + } else if (p->negative_ref) { + return 1; + } + } + return 0; +} + static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2))); static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2))); @@ -1812,14 +1903,15 @@ 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_ref) { + 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 (proc_receive_ref_matches(cmd)) { + cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED; + run_proc_receive = 1; + } } } diff --git a/t/t5411/once-0010-report-status-v1.sh b/t/t5411/once-0010-report-status-v1.sh index bf410dc418..dc2cf4a522 100644 --- a/t/t5411/once-0010-report-status-v1.sh +++ b/t/t5411/once-0010-report-status-v1.sh @@ -1,3 +1,7 @@ +test_expect_success "setup receive.procReceiveRefs" ' + git -C "$upstream" config --add receive.procReceiveRefs refs/for +' + test_expect_success "setup proc-receive hook" ' write_script "$upstream/hooks/proc-receive" <<-EOF printf >&2 "# proc-receive hook\n" diff --git a/t/t5411/test-0010-proc-receive-settings.sh b/t/t5411/test-0010-proc-receive-settings.sh new file mode 100644 index 0000000000..a36809927b --- /dev/null +++ b/t/t5411/test-0010-proc-receive-settings.sh @@ -0,0 +1,7 @@ +test_expect_success "add two receive.procReceiveRefs settings" ' + ( + cd "$upstream" && + git config --add receive.procReceiveRefs refs/for && + git config --add receive.procReceiveRefs refs/review/ + ) +' diff --git a/t/t5411/test-0040-process-all-refs.sh b/t/t5411/test-0040-process-all-refs.sh new file mode 100644 index 0000000000..b07c999f53 --- /dev/null +++ b/t/t5411/test-0040-process-all-refs.sh @@ -0,0 +1,113 @@ +test_expect_success "config receive.procReceiveRefs = refs ($PROTOCOL)" ' + git -C "$upstream" config --unset-all receive.procReceiveRefs && + git -C "$upstream" config --add receive.procReceiveRefs refs +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "setup upstream branches ($PROTOCOL)" ' + ( + cd "$upstream" && + git update-ref refs/heads/master $B && + git update-ref refs/heads/foo $A && + git update-ref refs/heads/bar $A && + git update-ref refs/heads/baz $A + ) + +' + +test_expect_success "setup proc-receive hook ($PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/heads/master" \ + -r "option fall-through" \ + -r "ok refs/heads/foo" \ + -r "option fall-through" \ + -r "ok refs/heads/bar" \ + -r "option fall-through" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/123/head" \ + -r "option old-oid $A" \ + -r "option new-oid $B" \ + -r "ok refs/for/next/topic" \ + -r "option refname refs/pull/124/head" \ + -r "option old-oid $B" \ + -r "option new-oid $A" \ + -r "option forced-update" + EOF +' + +# Refs of upstream : master(B) foo(A) bar(A)) baz(A) +# Refs of workbench: master(A) tags/v123 +# git push -f : master(A) (NULL) (B) refs/for/master/topic(A) refs/for/next/topic(A) +test_expect_success "proc-receive: process all refs ($PROTOCOL)" ' + 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> ok refs/heads/master + remote: proc-receive> option fall-through + remote: proc-receive> ok refs/heads/foo + remote: proc-receive> option fall-through + remote: proc-receive> ok refs/heads/bar + remote: proc-receive> option fall-through + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/next/topic + remote: proc-receive> option refname refs/pull/124/head + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> option forced-update + 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/pull/123/head + remote: post-receive< refs/pull/124/head + To + .. -> bar + - [deleted] foo + + ... HEAD -> master (forced update) + .. HEAD -> refs/pull/123/head + + ... HEAD -> refs/pull/124/head (forced update) + 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 +' + +# Refs of upstream : master(A) bar(A) baz(B) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL)" ' + ( + cd "$upstream" && + git update-ref -d refs/heads/bar && + git update-ref -d refs/heads/baz + ) +' diff --git a/t/t5411/test-0041-process-all-refs--porcelain.sh b/t/t5411/test-0041-process-all-refs--porcelain.sh new file mode 100644 index 0000000000..0dd9824616 --- /dev/null +++ b/t/t5411/test-0041-process-all-refs--porcelain.sh @@ -0,0 +1,114 @@ +test_expect_success "config receive.procReceiveRefs = refs ($PROTOCOL/porcelain)" ' + git -C "$upstream" config --unset-all receive.procReceiveRefs && + git -C "$upstream" config --add receive.procReceiveRefs refs +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "setup upstream branches ($PROTOCOL/porcelain)" ' + ( + cd "$upstream" && + git update-ref refs/heads/master $B && + git update-ref refs/heads/foo $A && + git update-ref refs/heads/bar $A && + git update-ref refs/heads/baz $A + ) + +' + +test_expect_success "setup proc-receive hook ($PROTOCOL/porcelain)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/heads/master" \ + -r "option fall-through" \ + -r "ok refs/heads/foo" \ + -r "option fall-through" \ + -r "ok refs/heads/bar" \ + -r "option fall-through" \ + -r "ok refs/for/master/topic" \ + -r "option refname refs/pull/123/head" \ + -r "option old-oid $A" \ + -r "option new-oid $B" \ + -r "ok refs/for/next/topic" \ + -r "option refname refs/pull/124/head" \ + -r "option old-oid $B" \ + -r "option new-oid $A" \ + -r "option forced-update" + EOF +' + +# Refs of upstream : master(B) foo(A) bar(A)) baz(A) +# Refs of workbench: master(A) tags/v123 +# git push -f : master(A) (NULL) (B) refs/for/master/topic(A) refs/for/next/topic(A) +test_expect_success "proc-receive: process all refs ($PROTOCOL/porcelain)" ' + git -C workbench push --porcelain -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> ok refs/heads/master + remote: proc-receive> option fall-through + remote: proc-receive> ok refs/heads/foo + remote: proc-receive> option fall-through + remote: proc-receive> ok refs/heads/bar + remote: proc-receive> option fall-through + remote: proc-receive> ok refs/for/master/topic + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/for/next/topic + remote: proc-receive> option refname refs/pull/124/head + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> option forced-update + 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/pull/123/head + remote: post-receive< refs/pull/124/head + To + :refs/heads/bar .. + - :refs/heads/foo [deleted] + + HEAD:refs/heads/master ... (forced update) + HEAD:refs/pull/123/head .. + + HEAD:refs/pull/124/head ... (forced update) + Done + 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 +' + +# Refs of upstream : master(A) bar(A) baz(B) +# Refs of workbench: master(A) tags/v123 +test_expect_success "cleanup ($PROTOCOL/porcelain)" ' + ( + cd "$upstream" && + git update-ref -d refs/heads/bar && + git update-ref -d refs/heads/baz + ) +' diff --git a/t/t5411/test-0050-proc-receive-refs.sh b/t/t5411/test-0050-proc-receive-refs.sh new file mode 100644 index 0000000000..85e4784678 --- /dev/null +++ b/t/t5411/test-0050-proc-receive-refs.sh @@ -0,0 +1,128 @@ +test_expect_success "config receive.procReceiveRefs with modifiers ($PROTOCOL)" ' + ( + cd "$upstream" && + git config --unset-all receive.procReceiveRefs && + git config --add receive.procReceiveRefs m:refs/heads/master && + git config --add receive.procReceiveRefs ad:refs/heads && + git config --add receive.procReceiveRefs "a!:refs/heads" + ) +' + +test_expect_success "setup proc-receive hook ($PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/heads/master" \ + -r "option refname refs/pull/123/head" \ + -r "option old-oid $A" \ + -r "option new-oid $B" \ + -r "ok refs/tags/v123 " \ + -r "option refname refs/pull/124/head" + EOF +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +# git push : master(B) tags/v123 +test_expect_success "proc-receive: update branch and new tag ($PROTOCOL)" ' + git -C workbench push origin \ + $B:refs/heads/master \ + v123 >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/tags/v123 + remote: # proc-receive hook + remote: proc-receive< refs/heads/master + remote: proc-receive< refs/tags/v123 + remote: proc-receive> ok refs/heads/master + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/tags/v123 + remote: proc-receive> option refname refs/pull/124/head + remote: # post-receive hook + remote: post-receive< refs/pull/123/head + remote: post-receive< refs/pull/124/head + To + .. -> refs/pull/123/head + * [new reference] v123 -> 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/master + EOF + test_cmp expect actual +' + +# Refs of upstream : master(A) +# Refs of workbench: master(A) tags/v123 +test_expect_success "setup upstream: create tags/v123 ($PROTOCOL)" ' + git -C "$upstream" update-ref refs/tags/v123 $TAG && + git -C "$upstream" show-ref >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/heads/master + refs/tags/v123 + EOF + test_cmp expect actual +' + +test_expect_success "setup proc-receive hook ($PROTOCOL)" ' + write_script "$upstream/hooks/proc-receive" <<-EOF + printf >&2 "# proc-receive hook\n" + test-tool proc-receive -v \ + -r "ok refs/heads/master" \ + -r "option refname refs/pull/123/head" \ + -r "option old-oid $A" \ + -r "option new-oid $ZERO_OID" \ + -r "ok refs/heads/next" \ + -r "option refname refs/pull/124/head" \ + -r "option new-oid $A" + EOF +' + +# Refs of upstream : master(A) tags/v123 +# Refs of workbench: master(A) tags/v123 +# git push : NULL NULL next(A) +test_expect_success "proc-receive: create/delete branch, and delete tag ($PROTOCOL)" ' + git -C workbench push origin \ + :refs/heads/master \ + $A:refs/heads/next \ + :refs/tags/v123 >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/tags/v123 + remote: pre-receive< refs/heads/next + remote: # proc-receive hook + remote: proc-receive< refs/heads/master + remote: proc-receive< refs/heads/next + remote: proc-receive> ok refs/heads/master + remote: proc-receive> option refname refs/pull/123/head + remote: proc-receive> option old-oid + remote: proc-receive> option new-oid + remote: proc-receive> ok refs/heads/next + remote: proc-receive> option refname refs/pull/124/head + remote: proc-receive> option new-oid + remote: # post-receive hook + remote: post-receive< refs/pull/123/head + remote: post-receive< refs/tags/v123 + remote: post-receive< refs/pull/124/head + To + - [deleted] refs/pull/123/head + - [deleted] v123 + * [new reference] -> 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/master + EOF + test_cmp expect actual +' From patchwork Mon Aug 24 17:42:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733883 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 F139713A4 for ; Mon, 24 Aug 2020 17:42:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D80E22067C for ; Mon, 24 Aug 2020 17:42:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="UyrcWOv+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726983AbgHXRml (ORCPT ); Mon, 24 Aug 2020 13:42:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35764 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726739AbgHXRmV (ORCPT ); Mon, 24 Aug 2020 13:42:21 -0400 Received: from mail-pf1-x443.google.com (mail-pf1-x443.google.com [IPv6:2607:f8b0:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 39263C061575 for ; Mon, 24 Aug 2020 10:42:21 -0700 (PDT) Received: by mail-pf1-x443.google.com with SMTP id u20so5210980pfn.0 for ; Mon, 24 Aug 2020 10:42: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=ZbjBKbEB2r1yCYXKtStnZ7+mr9/hXSOM9JTZLF1YMEs=; b=UyrcWOv+UesAENMZGs3ugA231m7fVy3DQyuwMm4xu3Ds/uvsEf56PhJtfqenrWPWVr chp56Ke1O3dUdsNMaFY1AWUHjRyJBFQL8DDEc0b89xxmJiFdi/9SDHv+Blx3XB2iOzpk EZp3+CzEQ/wBm3SnssONbWRn7d6oHlwIjI2MbI/6Pjb0Sr5JT2Qlxdgsjcbpc58VcxIR nF/9tPpwnVtksgU9jIp/VdOygu6ho+H4/JdET+Si4K77FDPWJ80MjqA6cjOTs6eDPfUn MXImYGur2qbXFob/4BmJIf3PXgI3mQvtOzkqAx9y0L/EefDKR640ODrCG6itrVl5zwjk zaqA== 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=ZbjBKbEB2r1yCYXKtStnZ7+mr9/hXSOM9JTZLF1YMEs=; b=CIUuhxwgrf/1MTq+8Fgd0Olj0o4uB6hpYg6WDY8VaBCqFgYaDwxeQ79KvcseQ0/LWR Rjn8SvJzKuaFPLcSRxtCXsB9k5ibOCpgo5TXPNHigA9cc6EBnEN0y4vRKXAZtgzGqfYG Qi42kWXjtA9OIN7tV9rD2CJ2GEaYkvcyXvl8i6xHvg4KMnO78KqkAakkCGDLcM8MnWcc AoFN+N5zd0NSP4mPiUYook9rDWOFt6R9OecH0owHJPuy5QHT7y8Q7+s0FXewAyhETOvB oPT2Njshwtj3BHJPuQIsmeR9BUxebh0FKQZqNqpTQkCqqec0yokmYiUk54KXmfA8BOKb YtGg== X-Gm-Message-State: AOAM533q0+Sq5XEBaPUueoSMzzNPMepo5cy5LzQx06aZ8vHNsWyBEiVC yJb2qqbkb+cm47Wr9rQvfNs= X-Google-Smtp-Source: ABdhPJznFJDwFxBrr8bjWqgR8vGFBkQo5Z9upv4fbrNmp4ovTu2il1tBdEf6gKWKGWREtQeUKoV3Ng== X-Received: by 2002:aa7:9386:: with SMTP id t6mr5060758pfe.220.1598290940618; Mon, 24 Aug 2020 10:42:20 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.19 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:20 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v18 08/10] t5411: test updates of remote-tracking branches Date: Mon, 24 Aug 2020 13:42:00 -0400 Message-Id: <20200824174202.11710-9-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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 In order to test update of remote-tracking branches for special refs, add new "remote.origin.fetch" settings and test cases. Signed-off-by: Jiang Xin --- ...t-0036-report-multi-rewrite-for-one-ref.sh | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh index 27d58edd14..8eec3a1ed8 100644 --- a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh +++ b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh @@ -1,3 +1,18 @@ +test_expect_success "setup git config for remote-tracking of special refs" ' + ( + cd workbench && + if ! git config --get-all remote.origin.fetch | grep refs/for/ + then + git config --add remote.origin.fetch \ + "+refs/for/*:refs/t/for/*" && + git config --add remote.origin.fetch \ + "+refs/pull/*:refs/t/pull/*" && + git config --add remote.origin.fetch \ + "+refs/changes/*:refs/t/changes/*" + fi + ) +' + test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 1st rewrite, $PROTOCOL)" ' write_script "$upstream/hooks/proc-receive" <<-EOF printf >&2 "# proc-receive hook\n" @@ -58,6 +73,17 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for test_cmp expect actual ' +test_expect_success "proc-receive: check remote-tracking #1 ($PROTOCOL)" ' + git -C workbench show-ref | + grep -v -e refs/remotes -e refs/heads -e refs/tags >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/t/for/master/topic + EOF + test_cmp expect actual && + git -C workbench update-ref -d refs/t/for/master/topic +' + test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL)" ' write_script "$upstream/hooks/proc-receive" <<-EOF printf >&2 "# proc-receive hook\n" @@ -120,6 +146,17 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for test_cmp expect actual ' +test_expect_success "proc-receive: check remote-tracking #2 ($PROTOCOL)" ' + git -C workbench show-ref | + grep -v -e refs/remotes -e refs/heads -e refs/tags >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/t/for/master/topic + EOF + test_cmp expect actual && + git -C workbench update-ref -d refs/t/for/master/topic +' + test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL)" ' write_script "$upstream/hooks/proc-receive" <<-EOF printf >&2 "# proc-receive hook\n" @@ -167,3 +204,14 @@ test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL)" ' EOF test_cmp expect actual ' + +test_expect_success "proc-receive: check remote-tracking #3 ($PROTOCOL)" ' + git -C workbench show-ref | + grep -v -e refs/remotes -e refs/heads -e refs/tags >out && + make_user_friendly_and_stable_output actual && + cat >expect <<-EOF && + refs/t/for/master/topic + EOF + test_cmp expect actual && + git -C workbench update-ref -d refs/t/for/master/topic +' From patchwork Mon Aug 24 17:42:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733885 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 1822713B1 for ; Mon, 24 Aug 2020 17:42:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F37302074D for ; Mon, 24 Aug 2020 17:42:43 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="DOIt3KP8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726873AbgHXRmm (ORCPT ); Mon, 24 Aug 2020 13:42:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35772 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726782AbgHXRmW (ORCPT ); Mon, 24 Aug 2020 13:42:22 -0400 Received: from mail-pj1-x1042.google.com (mail-pj1-x1042.google.com [IPv6:2607:f8b0:4864:20::1042]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F02FBC061796 for ; Mon, 24 Aug 2020 10:42:21 -0700 (PDT) Received: by mail-pj1-x1042.google.com with SMTP id q1so4584449pjd.1 for ; Mon, 24 Aug 2020 10:42: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=JGGKBcITccHjiRJHVfcma4u6SOE3ZV+JtgU29AUPZdc=; b=DOIt3KP8QT64C6t5ehvz4FYsMjAT5dujD2H7WNW4x8zVwiPCxxKqjChmOrfiOwy1Gn J4KfhHeFqOkiSIPt+eMJZ9taVpQHpzB+vbv4XjFRrmfG1NgF986mtkMH0bfEV8xV2UP9 3+NZMj6fuQj6Y9ZSvpcs6BO0eP97RF/2VxSS465C6EPfiqTn3cXdW4b2VvaQeiGn0bJQ J1X1g5wTltqfX76y2LJoSStLSSWA9HI4uXbXfL/O0duH7T4MZC4VVpyP3s2Rs1liZbRW cSFJyL/ybwOV3WNoQjl6QA6/BWALpvg7XTnlzmGn3GGOylkhFgf89ZAe9QQ3K0CbzRpt 5HnA== 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=JGGKBcITccHjiRJHVfcma4u6SOE3ZV+JtgU29AUPZdc=; b=JXzO9llqsu10WdTHPTXyUveKv7HFPPS/wW5962CDprVcZ7XLptX/1mqvRma29NFH4L qZXir8bVeDNmGtfGxwHI2pciNP8j8PPY6ZmA21CsYI7Wy+ALaa4MGqGPgNaCZhlM2z5y 4Fy2YMyL5A8cotnOTEl5m+s3p8gaiHo7iGID5u8GTB9uIWca5GsSRkUlWwlzhqRBMpJv DC+3tcNqJG0f5lE8hBwy1+q1QtPvAhLm9iTyyTTN5ZdBWNan6DWicVQMdiGh0XB6AmQW CC19jOGmAapA+oijkSEd5Gzcm0FvRMkMyfLnE6Ntk1V1Un/LY1T40i+edr1Jrf5NydZ0 lnXw== X-Gm-Message-State: AOAM5314muc+DnvcZ9NuDVCwh0myvAcCUVBkXU9whNVukZifFejHKWZI HUzKKJEuAmASFI0JruUtCN4= X-Google-Smtp-Source: ABdhPJzVLp1Tj2CWPPwEwsP4WFxp4EjYsdvuXebCaSguIV0oKe/O6RCtDFX1oIB7HrpqyVHiLa+Wfw== X-Received: by 2002:a17:90a:6a8d:: with SMTP id u13mr317275pjj.166.1598290941568; Mon, 24 Aug 2020 10:42:21 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.20 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:21 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v18 09/10] transport: parse report options for tracking refs Date: Mon, 24 Aug 2020 13:42:01 -0400 Message-Id: <20200824174202.11710-10-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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 pseudo reference (such as "refs/for/master/topic"), may create or update one or more references. The real names of the references will be stored in the report options. Parse report options to create or update remote-tracking branches properly. Signed-off-by: Jiang Xin --- ...t-0036-report-multi-rewrite-for-one-ref.sh | 22 +++++++--- transport.c | 40 ++++++++++++++----- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh index 8eec3a1ed8..73283d81e8 100644 --- a/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh +++ b/t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh @@ -78,10 +78,14 @@ test_expect_success "proc-receive: check remote-tracking #1 ($PROTOCOL)" ' grep -v -e refs/remotes -e refs/heads -e refs/tags >out && make_user_friendly_and_stable_output actual && cat >expect <<-EOF && - refs/t/for/master/topic + refs/t/changes/24/124/1 + refs/t/changes/25/125/1 + refs/t/for/master/topic EOF test_cmp expect actual && - git -C workbench update-ref -d refs/t/for/master/topic + git -C workbench update-ref -d refs/t/for/master/topic && + git -C workbench update-ref -d refs/t/changes/24/124/1 && + git -C workbench update-ref -d refs/t/changes/25/125/1 ' test_expect_success "setup proc-receive hook (multiple rewrites for one ref, no refname for the 2nd rewrite, $PROTOCOL)" ' @@ -151,10 +155,14 @@ test_expect_success "proc-receive: check remote-tracking #2 ($PROTOCOL)" ' grep -v -e refs/remotes -e refs/heads -e refs/tags >out && make_user_friendly_and_stable_output actual && cat >expect <<-EOF && - refs/t/for/master/topic + refs/t/changes/24/124/1 + refs/t/changes/25/125/1 + refs/t/for/master/topic EOF test_cmp expect actual && - git -C workbench update-ref -d refs/t/for/master/topic + git -C workbench update-ref -d refs/t/for/master/topic && + git -C workbench update-ref -d refs/t/changes/24/124/1 && + git -C workbench update-ref -d refs/t/changes/25/125/1 ' test_expect_success "setup proc-receive hook (multiple rewrites for one ref, $PROTOCOL)" ' @@ -210,8 +218,10 @@ test_expect_success "proc-receive: check remote-tracking #3 ($PROTOCOL)" ' grep -v -e refs/remotes -e refs/heads -e refs/tags >out && make_user_friendly_and_stable_output actual && cat >expect <<-EOF && - refs/t/for/master/topic + refs/t/changes/23/123/1 + refs/t/changes/24/124/2 EOF test_cmp expect actual && - git -C workbench update-ref -d refs/t/for/master/topic + git -C workbench update-ref -d refs/t/changes/24/124/1 && + git -C workbench update-ref -d refs/t/changes/25/125/2 ' diff --git a/transport.c b/transport.c index e146de6c4e..7d37baea64 100644 --- a/transport.c +++ b/transport.c @@ -437,28 +437,48 @@ int transport_refs_pushed(struct ref *ref) return 0; } -void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose) +static void update_tracking_ref(struct remote *remote, char *refname, + struct object_id *new_oid, int deletion, + int verbose) { struct refspec_item rs; - if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE) - return; - - rs.src = ref->name; + rs.src = refname; rs.dst = NULL; - if (!remote_find_tracking(remote, &rs)) { if (verbose) fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst); - if (ref->deletion) { + if (deletion) delete_ref(NULL, rs.dst, NULL, 0); - } else - update_ref("update by push", rs.dst, &ref->new_oid, - NULL, 0, 0); + else + update_ref("update by push", rs.dst, new_oid, + NULL, 0, 0); free(rs.dst); } } +void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose) +{ + char *refname; + struct object_id *new_oid; + struct ref_push_report *report; + + if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE) + return; + + report = ref->report; + if (!report) + update_tracking_ref(remote, ref->name, &ref->new_oid, + ref->deletion, verbose); + else + for (; report; report = report->next) { + refname = report->ref_name ? (char *)report->ref_name : ref->name; + new_oid = report->new_oid ? report->new_oid : &ref->new_oid; + update_tracking_ref(remote, refname, new_oid, + is_null_oid(new_oid), verbose); + } +} + static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, struct ref_push_report *report, From patchwork Mon Aug 24 17:42:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11733889 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 779E513B1 for ; Mon, 24 Aug 2020 17:42:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 605F72074D for ; Mon, 24 Aug 2020 17:42:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hhp2H5gJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727053AbgHXRmr (ORCPT ); Mon, 24 Aug 2020 13:42:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35774 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726793AbgHXRmX (ORCPT ); Mon, 24 Aug 2020 13:42:23 -0400 Received: from mail-pg1-x532.google.com (mail-pg1-x532.google.com [IPv6:2607:f8b0:4864:20::532]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C0504C061797 for ; Mon, 24 Aug 2020 10:42:22 -0700 (PDT) Received: by mail-pg1-x532.google.com with SMTP id g1so1102767pgm.9 for ; Mon, 24 Aug 2020 10:42: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=F/T2p8krcQte0QRUp0q/Umun859q0E7dBe5wj5OgB8Y=; b=hhp2H5gJ588TulzgWPGiADT/4zWVI8ufuYWKO8GZ4dlzbaMdZHjG3sL0Ra5kuqncrq /W9L8oefy0hghkiPJo76+377Yh4mtaFizCyPm3tF2E8I8QMMRcNUjwSPjgk39Mv1W8JE 3tO2bo4olpFSb3RUF3YkGuHeWxrK8i9vPSixFmAmKitCJe1EW6NHnaAMi21bNjsXm/PT f0DUYAcrBkvIQKF5FdG5HholsJiPJ6N0CcQ8fybsXQp/v7WJeJKVwcUvlAfCxKmnpWOH dPi2lcMdZEUKXWNLVUXssPQ7Ugv+GgbDpeQr5jJRHsVnZe4aDiKjHiNeQsnSyn8RliDz Z2jw== 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=F/T2p8krcQte0QRUp0q/Umun859q0E7dBe5wj5OgB8Y=; b=tpg00XB9/LjbGjYfo4IeGNo1XErfLeitUvmKc+A4FW+9IMtm/uK9hObt0GOSLLiSzK evx2/AYsTRQFtsyGT1HXq6ELvbrH7I9h6VPHSEr4by7LWGQmAOp3fX0aRB8ujvKinVwK J8Vt2PZlsWvB/n8yi1+NYXCY5mhDzW3FT0Ars2LPfmHwzHllQATBLKRGn3FVqn1f+WZ6 wQDkvmCWqprzoZ1CrgGrLsspFcA93lKobz3dZBlZ5GiPU6KWWcbHTFDmQfYl7FEQCAkn 6zHEfrVp/lge2InBBu3osXWJDdkzFZy60zqfZ1dh4KEDHAmpQDIlIpxjta8FNbLda4f0 WdOQ== X-Gm-Message-State: AOAM5328OqaEBXbO4CeCFumYcx8zVC27zSRnTNUzHnYmiPj9Vgk2x8RP jJNpLoWYc03JFG9aG7+SdpQ= X-Google-Smtp-Source: ABdhPJxPm+dWTfctHkHLN0aDpwBMit4eP4/ceg5a1Hdju/HbLTiMGhC6Et5IKGJrEboAY8yGewVFXw== X-Received: by 2002:a62:206:: with SMTP id 6mr4821492pfc.228.1598290942316; Mon, 24 Aug 2020 10:42:22 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id b15sm9773162pgk.14.2020.08.24.10.42.21 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 24 Aug 2020 10:42:21 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v18 10/10] doc: add documentation for the proc-receive hook Date: Mon, 24 Aug 2020 13:42:02 -0400 Message-Id: <20200824174202.11710-11-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200815171740.6257-1-worldhello.net@gmail.com> References: <20200815171740.6257-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 receive-pack" that accepts requests by "git push" learned to outsource some of the ref updates to the new "proc-receive" hook. Signed-off-by: Jiang Xin --- Documentation/githooks.txt | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt index 81f2a87e88..d66154f606 100644 --- a/Documentation/githooks.txt +++ b/Documentation/githooks.txt @@ -333,6 +333,68 @@ 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]. If the server has +set the multi-valued config variable `receive.procReceiveRefs`, and the +commands sent to 'receive-pack' have matching reference names, these +commands will be executed by this hook, instead of by the internal +`execute_commands()` function. This hook is responsible for updating +the relevant references and reporting the results back to 'receive-pack'. + +This hook executes once for the receive operation. It takes no +arguments, but uses a pkt-line format protocol to communicate with +'receive-pack' to read commands, push-options and send results. In the +following example for the protocol, the letter 'S' stands for +'receive-pack' and the letter 'H' stands for this hook. + + # Version and features 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( ) + S: ... ... + S: flush-pkt + # Send push-options only if the 'push-options' feature is enabled. + S: PKT-LINE(push-option) + S: ... ... + S: flush-pkt + + # Receive result from the hook. + # OK, run this command successfully. + H: PKT-LINE(ok ) + # NO, I reject it. + H: PKT-LINE(ng ) + # Fall through, let 'receive-pack' to execute it. + H: PKT-LINE(ok ) + H: PKT-LINE(option fall-through) + # OK, but has an alternate reference. The alternate reference name + # and other status can be given in options + H: PKT-LINE(ok ) + H: PKT-LINE(option refname ) + H: PKT-LINE(option old-oid ) + H: PKT-LINE(option new-oid ) + H: PKT-LINE(option forced-update) + H: ... ... + H: flush-pkt + +Each command for the 'proc-receive' hook may point to a pseudo-reference +and always has a zero-old as its old-oid, while the 'proc-receive' hook +may update an alternate reference and the alternate reference may exist +already with a non-zero old-oid. For this case, this hook will use +"option" directives to report extended attributes for the reference given +by the above "ok/ng" directive. + +The report of the commands of this hook should have the same order as +the input. The exit status of the 'proc-receive' hook only determines +the success or failure of the group of commands sent to it, unless +atomic push is in use. + [[post-receive]] post-receive ~~~~~~~~~~~~