From patchwork Sat Aug 15 17:17:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715687 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 1E848109B for ; Sat, 15 Aug 2020 21:54:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0340E23447 for ; Sat, 15 Aug 2020 21:54:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="U9jxWtMT" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728660AbgHOVyH (ORCPT ); Sat, 15 Aug 2020 17:54:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45600 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729135AbgHOVwi (ORCPT ); Sat, 15 Aug 2020 17:52:38 -0400 Received: from mail-pj1-x1041.google.com (mail-pj1-x1041.google.com [IPv6:2607:f8b0:4864:20::1041]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 11E0FC0068C6 for ; Sat, 15 Aug 2020 10:17:52 -0700 (PDT) Received: by mail-pj1-x1041.google.com with SMTP id i92so6561248pje.0 for ; Sat, 15 Aug 2020 10:17:52 -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=caKEKWGdKp+5Ap1E012huXnjXEaCWna2Ltkuc1hh8KE=; b=U9jxWtMTVcY+gmsz5Cw+PX+5/chgF5F1ju3P99m/QyrxFqnuDtMNqqWBM4+CJST8tb Vr7S6dE+5QtGLqIspOmwOIK+26rzBuhxe/NIJ28qcbDZG+S/BXgWGNP7CAj5I14MfG+C c0vENllxhTbchixaH4urD4XwBYS3A2o4+KdM1+wOPrnt2UAqzgz64ojPhcp9itx1UBJr giGSnZLly3iRf2ABQKDHkzU9G8t9aZucSjs5RsKaoV7SutBgPxpfBA4RZGFbhi7vm+A/ vuJdBRs6Q8N7mii+B1tGMx3d2Rst45Pmqor5LcHAbkWHRz1SDrdTg1bJU6hHgpdaDT+o 3Dbw== 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=caKEKWGdKp+5Ap1E012huXnjXEaCWna2Ltkuc1hh8KE=; b=CDES59cTgjNHRt2zwRAFEe+1E6xO8eqXCadoYmpyR16lEociBhhn3zDgSoYQbGHLE8 M/lW8cNEB2fU/AFBm/Aa1BkTuh+KQvw5FygsVIyZKYy+UChOzm6ybgvfEOR72iTt3Qiz W/CWnNnyFm6aLSw1QGFejWNojKLf2tZpoX/vxOqd1dwWNGWvEfRGN8RZquUHT8sfkmPY 3bYNBo+uvbAtcDRWX+8PVdKSoakKMrIq+w4CG/q7R0dd4i9HXquxL04vFD68DZlpfpHN JTiTqoQPwi5YVV9woWdFVmBubQCay9yaKzpq1KBaINXmVZaO3+FDM5gGC3VVCZIibO7M G//g== X-Gm-Message-State: AOAM532SpbVVU97nXDJPnuMnVwbls6aHQuhz9cG/sRiDwxE5RtiZBx94 ATYDY33bb8HcRh/Nm9mSRW8= X-Google-Smtp-Source: ABdhPJxq84sptUz3FCs5WAQ6EOujhFNDUj2YuIqXq2+rTvT7/tYEpV6glhnkM6Tk3IzcuheDzq9eeA== X-Received: by 2002:a17:90a:8d0b:: with SMTP id c11mr6735463pjo.196.1597511869497; Sat, 15 Aug 2020 10:17:49 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.48 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:49 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v17 01/10] transport: not report a non-head push as a branch Date: Sat, 15 Aug 2020 13:17:31 -0400 Message-Id: <20200815171740.6257-2-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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 36ad20a849..d11382f769 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 2d4fd851dc..19b033dc6a 100644 --- a/transport.c +++ b/transport.c @@ -499,9 +499,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 Sat Aug 15 17:17:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715791 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 5ED82618 for ; Sat, 15 Aug 2020 22:02:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2C8BA205CB for ; Sat, 15 Aug 2020 22:02:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Rrn5bK0L" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728730AbgHOWC1 (ORCPT ); Sat, 15 Aug 2020 18:02:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45626 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728728AbgHOVvY (ORCPT ); Sat, 15 Aug 2020 17:51:24 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 08797C0068C2 for ; Sat, 15 Aug 2020 10:17:51 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id o5so6015905pgb.2 for ; Sat, 15 Aug 2020 10:17:51 -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=9mv56U4JW/yI/UWrgKXRGpzIC/GlfwoSEOJ/4pVPF7M=; b=Rrn5bK0LqBC+0Cv6VQXhMkxM7QLjBnhlzwln9l/hNl8FKJHly5q6kSaJWfh1Lrkdq8 +UvgDnCT/MSTK1zDZHM7AGaP2padrLXHe5dGdHmK4YA15906anc61eBhFDbRv5v5IlX9 xKuQOVfW8FgQ/H/JB8gvapeGT+HCPofj3YDuz/lvm4GqMs1eirAaUglC6Wov9yBLTxEJ CqR0kHBhv0xjegUdIYvv82XAyFLfUMhHVPnWE9m75sG7cw/RfW+F5SCsGO3zu0GK/R0w 93f0PU96Su9WmrlxYggl7Wv210krc8ZPjBfiDEHAxOk55Z5K8KtU5XhQ0d2r5WoAhYvq Zivg== 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=9mv56U4JW/yI/UWrgKXRGpzIC/GlfwoSEOJ/4pVPF7M=; b=sNN9I8V/nh8TOf7e1bhy/YN79QipX9FDBde/Qjynl7/i3og/YHjIofR5gJXh+ycLsO vSWNgyZFRp/Rd3aRwLuoJ9df5UJJbqmlwMTr6RB87M3ph+ZXkrlvtHvMMmR5WrhyxgPG 2obXi8/rQRyKIo7e3UzM3wvRUzbxQgHbQT25WTamoayqabR8baTYyvtdcbOEyzox59/S bBz1W+k0OOWzhHWDkWlx2kNO0GnxLkez6oGnCMuclQiJxNAN6deuvnYQBlLA9vmndBr2 pfAUjlfpdNWtgUEe3rvCeh48fBTx9Iyrzg0TvwNcJzm8A7WMnhzqO7s5RYrOVDUdsiFT cy8Q== X-Gm-Message-State: AOAM5309PZW0tt90sd2VxhzJ0oSee0LtGFm42N1PxTeNWeBES4snh1Mk PhH3ZCW9ysZcjAASMURX5OE= X-Google-Smtp-Source: ABdhPJxLJMRVgU/SOxqIKWLnM5UunfkfRLNREUdnWc4HQKu3JDKhspIUd0fzTTOjFx+haUdVHa6jHw== X-Received: by 2002:a63:4d8:: with SMTP id 207mr5090223pge.146.1597511870344; Sat, 15 Aug 2020 10:17:50 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.49 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:49 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v17 02/10] t5411: add basic test cases for proc-receive hook Date: Sat, 15 Aug 2020 13:17:32 -0400 Message-Id: <20200815171740.6257-3-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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 Sat Aug 15 17:17:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715737 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 713FA913 for ; Sat, 15 Aug 2020 21:57:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3717E206B6 for ; Sat, 15 Aug 2020 21:57:57 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XGm97smK" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729313AbgHOV54 (ORCPT ); Sat, 15 Aug 2020 17:57:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45646 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728964AbgHOVwC (ORCPT ); Sat, 15 Aug 2020 17:52:02 -0400 Received: from mail-pf1-x434.google.com (mail-pf1-x434.google.com [IPv6:2607:f8b0:4864:20::434]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 31FC8C0068FB for ; Sat, 15 Aug 2020 10:17:54 -0700 (PDT) Received: by mail-pf1-x434.google.com with SMTP id m71so6074769pfd.1 for ; Sat, 15 Aug 2020 10:17:54 -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=sH9I53GWOw+3HmgxjAQhLL5tNLHsfJyQuYZqpiHzWB4=; b=XGm97smKW1rrgDOwVYdqmrUyLRnBroajdOJfxtAcNilw4E3MN/FdNNL+ywVzw0SyLX vur9XnE4g8AX0/8JSlo/unYclh3v211rnF802a/JsOiy/UL/qOfq6NH7OX5e8lV5VcTU uc4iiWJyNpBQIcerLOV1cjxeM+//bKoW7wUrNEePsQrlieUEZZaPtnp66x2C6UD8WG1s U1pSnvOJgg00l2OXlIZlfSlXLLhtC5+CaU3nmeDrAVmoX7a+wvT2iBv4ziOKegYPj3wH ZhHXYiCYPQDbLhwhi3l+6U+PARvektkvW6fJIK4xZVXDTAjtZ6OJou5mxlFiIqvNeJ3X HTjA== 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=sH9I53GWOw+3HmgxjAQhLL5tNLHsfJyQuYZqpiHzWB4=; b=MTAVk2bNUrQDfr75N2jBclS16p3ygeO0Tav5gsqRHh3/gEo/dhu30KToVSkTz1PUx+ djs2nA74j22tdytthNcdDGT7bShXGuQO1Emf8wiulSNZyfIOtDQhmMHkMnk8sTOTJdnt RS3bRCOWmPHjFvZdJbC/csF4aUeCWaVDX61H0pCR9JvetE4TATV0wi2CwuAp91vlwwoz HDPO3uDeY3Jj6eGYT0XKbsq45AFrYCfADHY6IUokkojUJursQCJhDOuUgTnNNvQJMKpH lEPA67URaJ6kD2rsoy8qsA4IrCo3xfQeNu6BJ6pZewHtvOPdiLXedzV4yu5QzxpcBhUF fnXQ== X-Gm-Message-State: AOAM531zinc92K4I2aW1rFKbnzEBLbJUy/bcD4aL4CGPLzZdiQkLfumx avLTWdUv5SErgodjF2KA2w0WJuyQ1Sc= X-Google-Smtp-Source: ABdhPJxrfMBC66DRZjGzbf+bqQFGac56h1xeQLOejA8X1KKCI1J1MJg2/b0QfmjoElysmFfMgUtTfQ== X-Received: by 2002:a63:4713:: with SMTP id u19mr4962064pga.278.1597511871637; Sat, 15 Aug 2020 10:17:51 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.50 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:51 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v17 03/10] receive-pack: add new proc-receive hook Date: Sat, 15 Aug 2020 13:17:33 -0400 Message-Id: <20200815171740.6257-4-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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". Suggested-by: Junio C Hamano Signed-off-by: Jiang Xin --- Makefile | 1 + builtin/receive-pack.c | 351 ++++++++++++++++-- remote.h | 14 + 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, 2659 insertions(+), 31 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 65f8cfb236..48c048584e 100644 --- a/Makefile +++ b/Makefile @@ -719,6 +719,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 439f29d6c7..d0b33ee84b 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -310,11 +310,14 @@ static void write_head_info(void) packet_flush(1); } +#define RUN_PROC_RECEIVE_SCHEDULED 1 +#define RUN_PROC_RECEIVE_RETURNED 2 struct command { struct command *next; - const char *error_string; + 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; @@ -775,7 +778,7 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep) struct command *cmd = state->cmd; while (cmd && - state->skip_broken && (cmd->error_string || cmd->did_not_exist)) + state->skip_broken && (cmd->report.error_message || cmd->did_not_exist)) cmd = cmd->next; if (!cmd) return -1; /* EOF */ @@ -840,6 +843,268 @@ static int run_update_hook(struct command *cmd) return finish_command(&proc); } +static struct command *find_command_by_refname(const struct command *list, + const char *refname) +{ + for (; list; list = list->next) + if (!strcmp(list->ref_name, refname)) + return (struct command *)list; + return NULL; +} + +static int read_proc_receive_report(struct packet_reader *reader, + struct command *commands, + struct strbuf *errmsg) +{ + struct command *cmd; + struct command *hint = NULL; + int code = 0; + int new_options = 1; + + 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")) { + struct ref_push_report_options *options; + const char *key, *val; + + if (!hint) { + if (new_options) { + strbuf_addstr(errmsg, "proc-receive reported 'option' without a matching 'ok/ng' directive\n"); + new_options = 0; + } + code = -1; + continue; + } + options = hint->report.options; + while (options && options->next) + options = options->next; + if (new_options) { + if (!options) { + hint->report.options = xcalloc(1, sizeof(struct ref_push_report_options)); + options = hint->report.options; + } else { + options->next = xcalloc(1, sizeof(struct ref_push_report_options)); + options = options->next; + } + new_options = 0; + } + assert(options); + key = p; + p = strchr(key, ' '); + if (p) + *p++ = '\0'; + val = p; + if (!strcmp(key, "refname")) + options->ref_name = xstrdup_or_null(val); + else if (!strcmp(key, "old-oid") && val && + !parse_oid_hex(val, &old_oid, &val)) + options->old_oid = oiddup(&old_oid); + else if (!strcmp(key, "new-oid") && val && + !parse_oid_hex(val, &new_oid, &val)) + options->new_oid = oiddup(&new_oid); + else if (!strcmp(key, "forced-update")) + options->forced_update = 1; + else if (!strcmp(key, "fall-through")) + /* Fall through, let 'receive-pack' to execute it. */ + hint->run_proc_receive = 0; + continue; + } + + 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; + } + if (!strcmp(head, "ng")) { + if (p) + hint->report.error_message = xstrdup(p); + else + hint->report.error_message = "failed"; + code = -1; + } + if (hint->run_proc_receive) + hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED; + new_options = 1; + } + + for (cmd = commands; cmd; cmd = cmd->next) + if (cmd->run_proc_receive && !cmd->report.error_message && + !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED)) { + cmd->report.error_message = "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->report.error_message) + 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" @@ -1203,7 +1468,7 @@ static void run_update_post_hook(struct command *commands) return; for (cmd = commands; cmd; cmd = cmd->next) { - if (cmd->error_string || cmd->did_not_exist) + if (cmd->report.error_message || cmd->did_not_exist) continue; if (!proc.args.nr) strvec_push(&proc.args, hook); @@ -1237,7 +1502,7 @@ static void check_aliased_update_internal(struct command *cmd, if (!dst_name) { rp_error("refusing update to broken symref '%s'", cmd->ref_name); cmd->skip_update = 1; - cmd->error_string = "broken symref"; + cmd->report.error_message = "broken symref"; return; } dst_name = strip_namespace(dst_name); @@ -1264,7 +1529,7 @@ static void check_aliased_update_internal(struct command *cmd, find_unique_abbrev(&dst_cmd->old_oid, DEFAULT_ABBREV), find_unique_abbrev(&dst_cmd->new_oid, DEFAULT_ABBREV)); - cmd->error_string = dst_cmd->error_string = + cmd->report.error_message = dst_cmd->report.error_message = "inconsistent aliased update"; } @@ -1293,7 +1558,7 @@ static void check_aliased_updates(struct command *commands) string_list_sort(&ref_list); for (cmd = commands; cmd; cmd = cmd->next) { - if (!cmd->error_string) + if (!cmd->report.error_message) check_aliased_update(cmd, &ref_list); } @@ -1330,7 +1595,7 @@ static void set_connectivity_errors(struct command *commands, &opt)) continue; - cmd->error_string = "missing necessary objects"; + cmd->report.error_message = "missing necessary objects"; } } @@ -1369,7 +1634,7 @@ static void reject_updates_to_hidden(struct command *commands) prefix_len = refname_full.len; for (cmd = commands; cmd; cmd = cmd->next) { - if (cmd->error_string) + if (cmd->report.error_message) continue; strbuf_setlen(&refname_full, prefix_len); @@ -1378,9 +1643,9 @@ static void reject_updates_to_hidden(struct command *commands) if (!ref_is_hidden(cmd->ref_name, refname_full.buf)) continue; if (is_null_oid(&cmd->new_oid)) - cmd->error_string = "deny deleting a hidden ref"; + cmd->report.error_message = "deny deleting a hidden ref"; else - cmd->error_string = "deny updating a hidden ref"; + cmd->report.error_message = "deny updating a hidden ref"; } strbuf_release(&refname_full); @@ -1388,7 +1653,7 @@ static void reject_updates_to_hidden(struct command *commands) static int should_process_cmd(struct command *cmd) { - return !cmd->error_string && !cmd->skip_update; + return !cmd->report.error_message && !cmd->skip_update; } static void warn_if_skipped_connectivity_check(struct command *commands, @@ -1415,24 +1680,24 @@ 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); if (!transaction) { rp_error("%s", err.buf); strbuf_reset(&err); - cmd->error_string = "transaction failed to start"; + cmd->report.error_message = "transaction failed to start"; continue; } - cmd->error_string = update(cmd, si); + cmd->report.error_message = update(cmd, si); - if (!cmd->error_string + if (!cmd->report.error_message && ref_transaction_commit(transaction, &err)) { rp_error("%s", err.buf); strbuf_reset(&err); - cmd->error_string = "failed to update ref"; + cmd->report.error_message = "failed to update ref"; } ref_transaction_free(transaction); } @@ -1455,12 +1720,12 @@ 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); + cmd->report.error_message = update(cmd, si); - if (cmd->error_string) + if (cmd->report.error_message) goto failure; } @@ -1473,8 +1738,8 @@ static void execute_commands_atomic(struct command *commands, failure: for (cmd = commands; cmd; cmd = cmd->next) - if (!cmd->error_string) - cmd->error_string = reported_error; + if (!cmd->report.error_message) + cmd->report.error_message = reported_error; cleanup: ref_transaction_free(transaction); @@ -1491,10 +1756,11 @@ 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) - cmd->error_string = "unpacker error"; + cmd->report.error_message = "unpacker error"; return; } @@ -1520,10 +1786,25 @@ 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) - cmd->error_string = "pre-receive hook declined"; + if (!cmd->report.error_message) + cmd->report.error_message = "pre-receive hook declined"; } return; } @@ -1534,8 +1815,8 @@ static void execute_commands(struct command *commands, */ if (tmp_objdir_migrate(tmp_objdir) < 0) { for (cmd = commands; cmd; cmd = cmd->next) { - if (!cmd->error_string) - cmd->error_string = "unable to migrate objects to permanent storage"; + if (!cmd->report.error_message) + cmd->report.error_message = "unable to migrate objects to permanent storage"; } return; } @@ -1546,6 +1827,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->report.error_message && + !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED) && + (cmd->run_proc_receive || use_atomic)) + cmd->report.error_message = "fail to run proc-receive hook"; + if (use_atomic) execute_commands_atomic(commands, si); else @@ -1916,7 +2205,7 @@ static void update_shallow_info(struct command *commands, if (is_null_oid(&cmd->new_oid)) continue; if (ref_status[cmd->index]) { - cmd->error_string = "shallow update not allowed"; + cmd->report.error_message = "shallow update not allowed"; cmd->skip_update = 1; } } @@ -1931,12 +2220,12 @@ static void report(struct command *commands, const char *unpack_status) packet_buf_write(&buf, "unpack %s\n", unpack_status ? unpack_status : "ok"); for (cmd = commands; cmd; cmd = cmd->next) { - if (!cmd->error_string) + if (!cmd->report.error_message) packet_buf_write(&buf, "ok %s\n", cmd->ref_name); else packet_buf_write(&buf, "ng %s %s\n", - cmd->ref_name, cmd->error_string); + cmd->ref_name, cmd->report.error_message); } packet_buf_flush(&buf); @@ -2040,7 +2329,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) if (!check_cert_push_options(&push_options)) { struct command *cmd; for (cmd = commands; cmd; cmd = cmd->next) - cmd->error_string = "inconsistent push options"; + cmd->report.error_message = "inconsistent push options"; } prepare_shallow_info(&si, &shallow); diff --git a/remote.h b/remote.h index 5e3ea5a26d..ab2e86a2a5 100644 --- a/remote.h +++ b/remote.h @@ -93,6 +93,20 @@ int for_each_remote(each_remote_fn fn, void *priv); int remote_has_url(struct remote *remote, const char *url); +struct ref_push_report_options { + const char *ref_name; + struct object_id *old_oid; + struct object_id *new_oid; + unsigned int forced_update:1; + struct ref_push_report_options *next; +}; + +struct ref_push_report { + const char *message; + const char *error_message; + struct ref_push_report_options *options; +}; + 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..4f352a7baf --- /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 = 0; +static int die_readline = 0; +static int no_push_options = 0; +static int use_atomic = 0; +static int use_push_options = 0; +static int verbose = 0; +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 Sat Aug 15 17:17:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715795 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 E55B5109B for ; Sat, 15 Aug 2020 22:03:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AEB6E2087D for ; Sat, 15 Aug 2020 22:03:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="NwgRohj+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729776AbgHOWD0 (ORCPT ); Sat, 15 Aug 2020 18:03:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45640 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728680AbgHOVvL (ORCPT ); Sat, 15 Aug 2020 17:51:11 -0400 Received: from mail-pj1-x1033.google.com (mail-pj1-x1033.google.com [IPv6:2607:f8b0:4864:20::1033]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 269F4C0068FA for ; Sat, 15 Aug 2020 10:17:54 -0700 (PDT) Received: by mail-pj1-x1033.google.com with SMTP id kr4so5791746pjb.2 for ; Sat, 15 Aug 2020 10:17:54 -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=CpZQpGB0vzKAC3f5FxXN6eb6VAM0B9/iVSYmoZuJUPY=; b=NwgRohj+HWz+5qV6MOCtljVNMORFsevV/ZQb/+sqW8n1t2efVsCJVKkQAOyWPzkPN5 rxyO9QyvgzwKzsCfhYQdZ4gwPuZZpNOInHj9466bin99Yt2acpFUiYBCVFPu2agW7y3k ZQ6xsx1D3MTm9iKrtRIa+Ac5VAeygP5wfjkpY6J0zIwU9UcVcE5uSa5VWq2hyYdyvUXR TlJlXqiJ02S2uR4/3SIdZIOMUjdZYMdRuRDlav0hPHUytfL6aJDyx5YPSt5WiR77herX EczGZGBmzmEKcvHajUq7FMu6sabl5Pp8uo8e9/q3iIitmE5tsapSq71JT7zvrG0jaFu9 ylkA== 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=CpZQpGB0vzKAC3f5FxXN6eb6VAM0B9/iVSYmoZuJUPY=; b=Y6lTG1G1aj5UoN4jwwU6wb4iqgZA4fQS0wvKhRugFJu8aPIWHMAP+H4SJqwq/y2R8U Hmn/aoGdQcjlXUsBOLDEv9JwkED5ZeUrqoOToWIwDE6GTEwR/lLHwWb+n8QgzzO+NrMs bvzBsXCI0zRfLG8i5PCGBWZWNQpQhUiU1kDHLT7IeoqwqjYic4WUKutGzYJSr6iHZZ1X JaYZL/mpcT7WpdMK2e6QhJP0iz3t7B2XVTVPDKRfBFZxPHmvTMZOwa6LlEVhJOegwQ9l 6FWRz1qcI802il9aJaNqZqvbgkPzRuQFg7XryLZ+0/nO3KjoolFuOeKtZKt2BjkDHlYW ZpTw== X-Gm-Message-State: AOAM532Kz7VAHK7pWYjFOEGtPbpqVGC00Xe+42Gg3/vStyvIpRJwS1CT Qwc5/c3Pva8IMh6Omq2d/XU= X-Google-Smtp-Source: ABdhPJxfDEapmzZbopVNtNnUog1UqvO148BvoKLtDRAPWVvFBw5OUlW/D/VJVFeB2BFn8COKb6pljg== X-Received: by 2002:a17:90a:2208:: with SMTP id c8mr6554248pje.123.1597511872573; Sat, 15 Aug 2020 10:17:52 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.51 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:52 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin , Jeff King Subject: [PATCH v17 04/10] New capability "report-status-v2" for git-push Date: Sat, 15 Aug 2020 13:17:34 -0400 Message-Id: <20200815171740.6257-5-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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 | 52 +++++++- builtin/send-pack.c | 21 +++- remote.c | 4 +- remote.h | 2 +- send-pack.c | 99 ++++++++++++--- t/t5411-proc-receive-hook.sh | 9 ++ t/t5411/once-0010-report-status-v1.sh | 89 +++++++++++++ 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 | 53 +++++++- transport.c | 118 +++++++++++++----- 15 files changed, 424 insertions(+), 77 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 d0b33ee84b..58972aa7cf 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -57,6 +57,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; @@ -240,7 +241,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) @@ -1918,6 +1919,8 @@ static struct command *read_head_info(struct packet_reader *reader, int len = 0; 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")) @@ -2236,6 +2239,49 @@ 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_options *options; + + packet_buf_write(&buf, "unpack %s\n", + unpack_status ? unpack_status : "ok"); + for (cmd = commands; cmd; cmd = cmd->next) { + int count = 0; + + if (!cmd->report.error_message) + packet_buf_write(&buf, "ok %s\n", + cmd->ref_name); + else + packet_buf_write(&buf, "ng %s %s\n", + cmd->ref_name, + cmd->report.error_message); + for (options = cmd->report.options; options; options = options->next) { + if (count++ > 0) + packet_buf_write(&buf, "ok %s\n", cmd->ref_name); + if (options->ref_name) + packet_buf_write(&buf, "option refname %s\n", + options->ref_name); + if (options->old_oid) + packet_buf_write(&buf, "option old-oid %s\n", + oid_to_hex(options->old_oid)); + if (options->new_oid) + packet_buf_write(&buf, "option new-oid %s\n", + oid_to_hex(options->new_oid)); + if (options->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; @@ -2344,7 +2390,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 2b9610f121..9d0df751d6 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_options *options; for (; ref; ref = ref->next) { const char *msg = NULL; const char *res; + int count = 0; switch(ref->status) { case REF_STATUS_NONE: @@ -86,14 +88,29 @@ static void print_helper_status(struct ref *ref) strbuf_reset(&buf); strbuf_addf(&buf, "%s %s", res, ref->name); - if (ref->remote_status) - msg = ref->remote_status; + if (ref->report.error_message) + msg = ref->report.error_message; if (msg) { strbuf_addch(&buf, ' '); quote_two_c_style(&buf, "", msg, 0); } strbuf_addch(&buf, '\n'); + for (options = ref->report.options; options; options = options->next) { + if (count++ > 0) + strbuf_addf(&buf, "ok %s\n", ref->name); + if (options->ref_name) + strbuf_addf(&buf, "option refname %s\n", + options->ref_name); + if (options->old_oid) + strbuf_addf(&buf, "option old-oid %s\n", + oid_to_hex(options->old_oid)); + if (options->new_oid) + strbuf_addf(&buf, "option new-oid %s\n", + oid_to_hex(options->new_oid)); + if (options->forced_update) + strbuf_addstr(&buf, "option forced-update\n"); + } write_or_die(1, buf.buf, buf.len); } strbuf_release(&buf); diff --git a/remote.c b/remote.c index c5ed74f91c..682be35fb2 100644 --- a/remote.c +++ b/remote.c @@ -789,7 +789,7 @@ struct ref *copy_ref(const struct ref *ref) memcpy(cpy, ref, len); cpy->next = NULL; cpy->symref = xstrdup_or_null(ref->symref); - cpy->remote_status = xstrdup_or_null(ref->remote_status); + cpy->report.error_message = xstrdup_or_null(ref->report.error_message); cpy->peer_ref = copy_ref(ref->peer_ref); return cpy; } @@ -811,7 +811,7 @@ void free_one_ref(struct ref *ref) if (!ref) return; free_one_ref(ref->peer_ref); - free(ref->remote_status); + free((void *)ref->report.error_message); free(ref->symref); free(ref); } diff --git a/remote.h b/remote.h index ab2e86a2a5..1a7b53fc16 100644 --- a/remote.h +++ b/remote.h @@ -153,7 +153,7 @@ struct ref { REF_STATUS_EXPECTING_REPORT, 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 632f1580ca..5e25352042 100644 --- a/send-pack.c +++ b/send-pack.c @@ -154,25 +154,79 @@ static int receive_status(struct packet_reader *reader, struct ref *refs) { struct ref *hint; int ret; + int new_options = 1; 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'; + + if (!strcmp(head, "option")) { + struct ref_push_report_options *options; + const char *key, *val; + + if (!hint) { + if (new_options) { + error("'option' without a matching 'ok/ng' directive"); + new_options = 0; + } + ret = -1; + continue; + } + options = hint->report.options; + while (options && options->next) + options = options->next; + if (new_options) { + if (!options) { + hint->report.options = xcalloc(1, sizeof(struct ref_push_report_options)); + options = hint->report.options; + } else { + options->next = xcalloc(1, sizeof(struct ref_push_report_options)); + options = options->next; + } + new_options = 0; + } + assert(options); + key = p; + p = strchr(key, ' '); + if (p) + *p++ = '\0'; + val = p; + if (!strcmp(key, "refname")) + options->ref_name = xstrdup_or_null(val); + else if (!strcmp(key, "old-oid") && val && + !parse_oid_hex(val, &old_oid, &val)) + options->old_oid = oiddup(&old_oid); + else if (!strcmp(key, "new-oid") && val && + !parse_oid_hex(val, &new_oid, &val)) + options->new_oid = oiddup(&new_oid); + else if (!strcmp(key, "forced-update")) + options->forced_update = 1; + continue; + } - refname = reader->line + 3; - msg = strchr(refname, ' '); - if (msg) - *msg++ = '\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); @@ -183,19 +237,24 @@ static int receive_status(struct packet_reader *reader, struct ref *refs) 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); 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->report.error_message = xstrdup(p); + else + hint->report.error_message = "failed"; + } else { + hint->status = REF_STATUS_OK; + hint->report.message = xstrdup_or_null(p); + } + new_options = 1; } return ret; } @@ -371,7 +430,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; @@ -423,8 +484,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..56a86d8ed4 --- /dev/null +++ b/t/t5411/once-0010-report-status-v1.sh @@ -0,0 +1,89 @@ +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/master/topic2 + 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 a743aa8018..3742ed3c3d 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/for/master/topic 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/for/master/topic 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/for/master/topic 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/for/master/topic 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 439b97b06e..f18ba9f06f 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/for/master/topic 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/for/master/topic 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/for/master/topic 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/for/master/topic 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 12acf9ea1f..64662afdc6 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 @@ -43,7 +43,9 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for remote: # post-receive hook remote: post-receive< refs/for/master/topic 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 && @@ -101,7 +103,9 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for remote: # post-receive hook remote: post-receive< refs/for/master/topic 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 && @@ -147,7 +151,8 @@ test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL)" ' remote: # post-receive hook remote: post-receive< refs/for/master/topic 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 f4a2c56e14..a7e29af0c2 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 @@ -43,7 +43,9 @@ test_expect_success "proc-receive: multiple rewrite for one ref, no refname for remote: # post-receive hook remote: post-receive< refs/for/master/topic 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 && @@ -102,7 +104,9 @@ test_expect_success "proc-receive: multiple rewrites for one ref, no refname for remote: # post-receive hook remote: post-receive< refs/for/master/topic 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 && @@ -149,7 +153,8 @@ test_expect_success "proc-receive: multiple rewrites for one ref ($PROTOCOL/porc remote: # post-receive hook remote: post-receive< refs/for/master/topic 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 1dd6a97a97..54bec4c026 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 32ebf63dcf..605b3cb5c9 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 defafbf4c1..0029ba18bd 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -729,6 +729,49 @@ static int push_update_ref_status(struct strbuf *buf, { char *refname, *msg; int status, forced = 0; + static struct ref *hint = NULL; + static int new_options = 1; + + if (starts_with(buf->buf, "option ")) { + struct ref_push_report_options *options; + struct object_id old_oid, new_oid; + const char *key, *val; + char *p; + + if (!hint) + die(_("'option' without a matching 'ok/error' directive")); + options = hint->report.options; + while (options && options->next) + options = options->next; + if (new_options) { + if (!options) { + hint->report.options = xcalloc(1, sizeof(struct ref_push_report_options)); + options = hint->report.options; + } else { + options->next = xcalloc(1, sizeof(struct ref_push_report_options)); + options = options->next; + } + new_options = 0; + } + assert(options); + key = buf->buf + 7; + p = strchr(key, ' '); + if (p) + *p++ = '\0'; + val = p; + if (!strcmp(key, "refname")) + options->ref_name = xstrdup_or_null(val); + else if (!strcmp(key, "old-oid") && val && + !parse_oid_hex(val, &old_oid, &val)) + options->old_oid = oiddup(&old_oid); + else if (!strcmp(key, "new-oid") && val && + !parse_oid_hex(val, &new_oid, &val)) + options->new_oid = oiddup(&new_oid); + else if (!strcmp(key, "forced-update")) + options->forced_update = 1; + /* Not update remote namespace again. */ + return 1; + } if (starts_with(buf->buf, "ok ")) { status = REF_STATUS_OK; @@ -791,8 +834,11 @@ static int push_update_ref_status(struct strbuf *buf, *ref = find_ref_by_name(remote_refs, refname); if (!*ref) { warning(_("helper reported unexpected status of %s"), refname); + hint = NULL; return 1; } + hint = *ref; + new_options = 1; if ((*ref)->status != REF_STATUS_NONE) { /* @@ -805,7 +851,12 @@ static int push_update_ref_status(struct strbuf *buf, (*ref)->status = status; (*ref)->forced_update |= forced; - (*ref)->remote_status = msg; + if (msg) { + if (status == REF_STATUS_OK) + (*ref)->report.message = msg; + else + (*ref)->report.error_message = msg; + } return !(status == REF_STATUS_OK); } diff --git a/transport.c b/transport.c index 19b033dc6a..10f7dbbcd0 100644 --- a/transport.c +++ b/transport.c @@ -460,13 +460,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_options *options, int porcelain, int summary_width) { + const char *to_name; + + if (options && options->ref_name) + to_name = options->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 @@ -480,9 +488,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); @@ -492,27 +502,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_options *options, + int porcelain, int summary_width) { + struct object_id *old_oid; + struct object_id *new_oid; + const char *ref_name; + int forced_update; + + if (options && options->old_oid) + old_oid = options->old_oid; + else + old_oid = &ref->old_oid; + if (options && options->new_oid) + new_oid = options->new_oid; + else + new_oid = &ref->new_oid; + if (options && options->forced_update) + forced_update = options->forced_update; + else + forced_update = ref->forced_update; + if (options && options->ref_name) + ref_name = options->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)) + options, 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, + options, 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"; @@ -521,17 +556,18 @@ 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); + options, porcelain, summary_width); strbuf_release(&quickref); } } -static int print_one_push_status(struct ref *ref, const char *dest, int count, - int porcelain, int summary_width) +static int _print_one_push_status(struct ref *ref, const char *dest, int count, + struct ref_push_report_options *options, + int porcelain, int summary_width) { if (!count) { char *url = transport_anonymize_url(dest); @@ -542,65 +578,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); + options, porcelain, summary_width); break; case REF_STATUS_REJECT_NODELETE: print_ref_status('!', "[rejected]", ref, NULL, "remote does not support deleting refs", - porcelain, summary_width); + options, 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, + options, 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", + options, 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", + options, 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", + options, 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", + options, porcelain, summary_width); break; case REF_STATUS_REJECT_STALE: print_ref_status('!', "[rejected]", ref, ref->peer_ref, - "stale info", porcelain, summary_width); + "stale info", + options, 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); + options, 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->report.error_message, + options, 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); + options, 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", + options, porcelain, summary_width); break; case REF_STATUS_OK: - print_ok_ref_status(ref, porcelain, summary_width); + print_ok_ref_status(ref, options, 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_options *options; + int n = 0; + + if (!ref->report.options) + return _print_one_push_status(ref, dest, count, + NULL, porcelain, summary_width); + + for (options = ref->report.options; options; options = options->next) + _print_one_push_status(ref, dest, count + n++, + options, porcelain, summary_width); + return n; +} + static int measure_abbrev(const struct object_id *oid, int sofar) { char hex[GIT_MAX_HEXSZ + 1]; From patchwork Sat Aug 15 17:17:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715789 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 D1658109B for ; Sat, 15 Aug 2020 22:02:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B2B8820781 for ; Sat, 15 Aug 2020 22:02:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="n3FW6jKJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729735AbgHOWC1 (ORCPT ); Sat, 15 Aug 2020 18:02:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45624 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728732AbgHOVvY (ORCPT ); Sat, 15 Aug 2020 17:51:24 -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 078BCC0068F8 for ; Sat, 15 Aug 2020 10:17:53 -0700 (PDT) Received: by mail-pf1-x444.google.com with SMTP id f193so6053747pfa.12 for ; Sat, 15 Aug 2020 10:17:53 -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=kvitj2ntuR2/UytI/5U9IbwHvrC6MX8tJb6rNyP+GYE=; b=n3FW6jKJrrdEl7gyEeKp1Cqv7M8+Mxw6cBJf1CWGyIYo1QqxaPbE1axM4KlO/FmeT/ ktCgpyX3Upg8XT9ubmUAPgT/WacB5lHF1RLd228W9mQyPkP2FwzFhShWVoTbLXFazGUC dbecuFPD4R5nIVCQMYMa0x1HyT3gFh5wxhzjnEfeJyOYuWNArH6ahLoDcyl8Zi9yBvnB 5muPWsL61CM/qDjZOcG+Y+Emd8SwT5F+iUqjfvBK/HSr7wy/6MUZohsUE3lgYUNhdUKI hCCFw86IFQ/d3FRcy23pji0XWNkuRJ2qJrMxZ/OcTpd7mYhzKGnT/AZBFNdHVd2kFdK5 kQ7Q== 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=kvitj2ntuR2/UytI/5U9IbwHvrC6MX8tJb6rNyP+GYE=; b=Iug/2L76w/CLtRXwCs9siDfI73zCZxtt1KpL4FtkzqomJznG/QmtBqMBUE0U3dBGue J+8BS2TwlkdI2ElYU8i3ECkhTAMfMwZVZeZ22/sGD3xAuuHBLad6+QL6RITXDh1lPKCk J6gGY86/LAwGXEKJW9LS/Zq3y3H9VIXfnEL5t0HzBEq+AFcOKYNWP5BCRdecek9kxKRo 9Fs9EkBCFKASklIkbZZ8mkhzjPfxWKk+xW/h2Sz4EUIX6oL+EWWyddpRQYh2kAvk5JgW Wb7rPZ1csqQ5rqyF/mCkCqTwL9wnn49D57EgrTpSFilU6OH98xeLt69FGq2bjZjbhsyb xq0A== X-Gm-Message-State: AOAM530x0Qlh68E1aNd6hVHJevR//7FlFzYwm3GX5HhypLwV1oArXaZW DfFMxY0MC8DXgc4azeSyu04= X-Google-Smtp-Source: ABdhPJwsDbIC6AcbaAoHRvtl56npF6VTf3HYrgDGU+oudHQZh7QQXf0GGE9G2wxTDWDPbl3x7h3fig== X-Received: by 2002:a63:fe0a:: with SMTP id p10mr5009227pgh.255.1597511873414; Sat, 15 Aug 2020 10:17:53 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.52 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:52 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v17 05/10] doc: add document for capability report-status-v2 Date: Sat, 15 Aug 2020 13:17:35 -0400 Message-Id: <20200815171740.6257-6-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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 a4573d12ce..01eb1629a8 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 36ccd14f97..78c0c4b3e2 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 @@ -284,6 +284,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 Sat Aug 15 17:17:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715727 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 84E74913 for ; Sat, 15 Aug 2020 21:57:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5DE9720791 for ; Sat, 15 Aug 2020 21:57:13 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="vIrFmQlz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729469AbgHOV5J (ORCPT ); Sat, 15 Aug 2020 17:57:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45598 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726458AbgHOVwJ (ORCPT ); Sat, 15 Aug 2020 17:52:09 -0400 Received: from mail-pj1-x1030.google.com (mail-pj1-x1030.google.com [IPv6:2607:f8b0:4864:20::1030]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 696B9C0068BC for ; Sat, 15 Aug 2020 10:17:55 -0700 (PDT) Received: by mail-pj1-x1030.google.com with SMTP id c10so6560406pjn.1 for ; Sat, 15 Aug 2020 10:17:55 -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=pHIUHMq1L/XNr2cbF7yh0h0ZcpFhFcWLb8XNh8pk5Go=; b=vIrFmQlz8fMeOe4oDrF6s3XP9ijAhqxAh/5e9/rw0DiRt+fm4PTJ7qGlDiGTr1tRGt hVUJeOCSsehSmZ2E80P/liLHGBSHSpCLpZOeSybDbbFuxu0yWtz/fmh2ZFTteBnmaNqo +QVPFhQG8gsiz679ssYPw1GF8PywKXV1dNOOa2WJdrWvlvk/HcQxIkme6TumoPO/7ESB 312lP/aFWuzHHj04hgVI5N/g0yQ26IsbHWpZfP8ADZbSuSXZyhs6tF463RedIlfNFQKQ y61Yw0ZQD6+jQJNhtmXOsu/4yjRsqCYM0SdicCSLaM6a0XAW+p93rPX+Lx7VrBmg4J1R ynnA== 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=pHIUHMq1L/XNr2cbF7yh0h0ZcpFhFcWLb8XNh8pk5Go=; b=dlp0f1yTK2G9fM2MoU/N78nqsZ1gsS/CJkpGYe8uiDzBEP7gwzL0LvkiS7m1tsUs0E 1KAQH/k5mIBSh2omVyELfL1CiwmRUyyaJ++0h4yW8sdb2F/wtI6YyId5JH2WGFjpACbO 82VblSv1v0QTsA7T9f16QQVRMEP4Q62NwQwioVQrU7IxrDBM3wSICWoTxKhGeld+tcFE WaH3CztMzIcZe2g7k4yWXkY66aPniX9rLF91v4Z1E2oh/K4cPTh2DFpGLS5i1P7iPPZK 6TwzmpAyPO8qX3qE5+JvWeFn7fdiD6S5orWYqjxhPc3AkbYR+WUGQYcW4OPasSKVIuGZ 7Txw== X-Gm-Message-State: AOAM5335LJaNeFp1G9Y2uo8BRj1zVLgbKxyS9H5bPxAJo0jooWqCFrgm oeLlcAaOo1/2BrKW12h+ogU= X-Google-Smtp-Source: ABdhPJyk/eHAh3RF4Vzdj3cP9NKRPDC7uy8/BKW4m5qKS99wynHlC0XTW+/V0Qn1vnSM/Y4+Z+swkA== X-Received: by 2002:a17:902:76c5:: with SMTP id j5mr5898134plt.87.1597511874368; Sat, 15 Aug 2020 10:17:54 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.53 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:53 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v17 06/10] receive-pack: feed report options to post-receive Date: Sat, 15 Aug 2020 13:17:36 -0400 Message-Id: <20200815171740.6257-7-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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 | 29 ++++++++++++++++--- t/t5411/once-0010-report-status-v1.sh | 3 +- 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 +- 8 files changed, 59 insertions(+), 27 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 58972aa7cf..a687218167 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -777,17 +777,38 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep) { struct receive_hook_feed_state *state = state_; struct command *cmd = state->cmd; + static struct ref_push_report_options *options = NULL; while (cmd && state->skip_broken && (cmd->report.error_message || cmd->did_not_exist)) 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 (!options) + options = cmd->report.options; + if (options) { + struct object_id *old_oid; + struct object_id *new_oid; + const char *ref_name; + + old_oid = options->old_oid ? options->old_oid : &cmd->old_oid; + new_oid = options->new_oid ? options->new_oid : &cmd->new_oid; + ref_name = options->ref_name ? options->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); + options = options->next; + if (!options) + 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; diff --git a/t/t5411/once-0010-report-status-v1.sh b/t/t5411/once-0010-report-status-v1.sh index 56a86d8ed4..bf410dc418 100644 --- a/t/t5411/once-0010-report-status-v1.sh +++ b/t/t5411/once-0010-report-status-v1.sh @@ -74,7 +74,8 @@ test_expect_success "proc-receive: report status v1" ' post-receive< refs/heads/master post-receive< refs/for/master/topic1 post-receive< refs/heads/foo - post-receive< refs/for/master/topic2 + post-receive< refs/for/changes/23/123/1 + post-receive< refs/for/changes/24/124/2 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 3742ed3c3d..b77b78c49f 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/pull/123/head 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/pull/123/head 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 .. HEAD -> refs/pull/123/head 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 .. 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 .. 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/pull/123/head * [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 f18ba9f06f..1fe352b686 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/pull/123/head [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/pull/123/head [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/pull/123/head .. 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 .. 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 .. 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/pull/123/head [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 64662afdc6..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 @@ -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] HEAD -> refs/changes/24/124/1 @@ -101,7 +103,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/changes/24/124/1 .. HEAD -> refs/for/master/topic @@ -149,7 +153,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/changes/23/123/1 .. HEAD -> refs/changes/24/124/2 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 a7e29af0c2..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 @@ -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 .. * HEAD:refs/changes/24/124/1 [new reference] @@ -102,7 +104,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/changes/24/124/1 [new reference] HEAD:refs/for/master/topic .. @@ -151,7 +155,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/changes/23/123/1 [new reference] HEAD:refs/changes/24/124/2 .. diff --git a/t/t5411/test-0038-report-mixed-refs.sh b/t/t5411/test-0038-report-mixed-refs.sh index 54bec4c026..a74a2cb449 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 605b3cb5c9..e4baa13ea3 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 Sat Aug 15 17:17:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715779 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 A4A0F618 for ; Sat, 15 Aug 2020 22:02:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 74E0D205CB for ; Sat, 15 Aug 2020 22:02:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="HZ5PlISn" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728737AbgHOWCT (ORCPT ); Sat, 15 Aug 2020 18:02:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45660 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728736AbgHOVvZ (ORCPT ); Sat, 15 Aug 2020 17:51:25 -0400 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0CE68C00214C for ; Sat, 15 Aug 2020 10:17:56 -0700 (PDT) Received: by mail-pg1-x542.google.com with SMTP id p37so6008584pgl.3 for ; Sat, 15 Aug 2020 10:17:56 -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=nsNf4QL1oWA7gvZJamVcHudSK0xhS9L24ksYmbdXjVs=; b=HZ5PlISnhFfmVAYHFpMEd/wtid1ByoWJYHiCZX+Dg6eTz7ClcxZFoz11A2P3mXVSkF psNtEmtuTEey/AGU1ixgBmq4ePtxpwCa8lRmFgYV+fjz9fz3iu2/ImLX/TmVJcKHsfFR OT0RSh6RjeSKKTLmnqGczs/s6kgk0gwxuTlP6GrlM23a7D9arUIqQ/zxKLlFgTUxpddX 4cjc1rxjBnqi3AO4u7/cfq0LilbyvhF1CqOBLTxxAsuZ517bmi9rlM74r2KHwkrE9gY9 DCpVeVBjbM6C3eLiGw8CuFedJB/SloKhri4iiVUQF9xMkXzHHOclJIoJU3q88TKO4Yta 0N0Q== 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=nsNf4QL1oWA7gvZJamVcHudSK0xhS9L24ksYmbdXjVs=; b=dtq70XPMTJyY6nlMkajHX+glXXDt1uec4v6mjrmuimg/4r198/Az7iiQg1RzC8BWyT hksa6NsRp9EbleN+gMxQRJyk2/1W27lqCtnnFVMQQV8d2i8NgeIyjrahVBFlj8JDvZ7v FSG/90YvcRbd1KuAUYwBu1xVbmP98y2k+iytzKj0V5OQwSHF46cOUT8Oqmz6Hh6+nIhW RuPSox2itwe7OKyr/daE+Iy6GqPYazvAMzgVeS3gDbxV5qMtrSghGiEYbMIbIK7NaZdM agAY9Q9LI0AMvmpHCMQstA8krh/3V2n7PiILEyX86eH/+bs3qT8tiRzR+UfwEmVhGzRM P9WQ== X-Gm-Message-State: AOAM532IaOP1Q4pcUTLv73sErznWqtYkVYd5UQVfFmfs15shQXxm5Bxg z4+IGsXfopC8gxIrLXNOuhw= X-Google-Smtp-Source: ABdhPJxjwAyyUM1X9BZ0y+7NdxDEAu2m1XV0l+FAQdE1dFf0JHgDbi73HlCvS302Zo/C6MOKLSzhWA== X-Received: by 2002:aa7:9f10:: with SMTP id g16mr5754069pfr.148.1597511875402; Sat, 15 Aug 2020 10:17:55 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.54 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:54 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v17 07/10] receive-pack: new config receive.procReceiveRefs Date: Sat, 15 Aug 2020 13:17:37 -0400 Message-Id: <20200815171740.6257-8-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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 value of the config variable to filter commands for specific actions: create (a), mofify (m), delete (d). E.g.: git config --system --add receive.procReceiveRefs ad:refs/heads Signed-off-by: Jiang Xin --- Documentation/config/receive.txt | 19 +++ builtin/receive-pack.c | 110 ++++++++++++++- 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, 488 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..7f1a1bd00c 100644 --- a/Documentation/config/receive.txt +++ b/Documentation/config/receive.txt @@ -114,6 +114,25 @@ 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). 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 a687218167..b7e4ee1483 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -98,6 +98,16 @@ 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; + char *ref_prefix; + struct proc_receive_ref *next; +} *proc_receive_ref = NULL; + +static void proc_receive_ref_append(const char *prefix); + static enum deny_action parse_deny_action(const char *var, const char *value) { if (value) { @@ -230,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); } @@ -325,6 +342,84 @@ 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; + prefix++; + } + prefix++; + } else { + ref_pattern->want_add = 1; + ref_pattern->want_delete = 1; + ref_pattern->want_modify = 1; + } + ref_pattern->next = NULL; + ref_pattern->ref_prefix = xstrdup(prefix); + len = strlen(ref_pattern->ref_prefix); + while (len && ref_pattern->ref_prefix[len - 1] == '/') + ref_pattern->ref_prefix[--len] = '\0'; + if (proc_receive_ref == NULL) { + 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; + int neg = 0; + 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 (*match == '!') { + neg = 1; + match++; + } + + if (skip_prefix(cmd->ref_name, match, &remains) && + (!*remains || *remains == '/')) { + if (!neg) + return 1; + } else if (neg) { + 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 +1907,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..50d4f159f8 --- /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 Sat Aug 15 17:17:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715683 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 8796E109B for ; Sat, 15 Aug 2020 21:53:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6D8DA2053B for ; Sat, 15 Aug 2020 21:53:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QcSWt9Mm" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728757AbgHOVxN (ORCPT ); Sat, 15 Aug 2020 17:53:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45652 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729158AbgHOVwn (ORCPT ); Sat, 15 Aug 2020 17:52:43 -0400 Received: from mail-pj1-x1044.google.com (mail-pj1-x1044.google.com [IPv6:2607:f8b0:4864:20::1044]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BDA97C00214D for ; Sat, 15 Aug 2020 10:17:56 -0700 (PDT) Received: by mail-pj1-x1044.google.com with SMTP id d4so5723301pjx.5 for ; Sat, 15 Aug 2020 10:17:56 -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=tx+seKi60p48rZDrSvhq06rOfr3LSqzdUw+gGKvrWf8=; b=QcSWt9MmTgmA0dI6x/WPwNtQapO1h0NYoQ6MXjGD0XwWAqyThUfsRHffhlH35Rnpkp 0AttPe6jkrIDIjoIdC2fz9ArYQ24L7urzYD2qCWFRnQYkqf7SVHQctaof63nJeU9pru9 e/Xa5N7LRL6h4AlH7lFaCyj9krDeVvchHCTiQ5SMho0GXd+SSVUQzMY/GoKoMxzbCTnX +JQ9Be4i7BbBvErUwVeFRXbtCbQeD8s9B+q3kTNp4SnSKD522UJ8zCgnGhCWbEMMZ06/ 0H/C0eGgxz3ekhfLW1ZBUzbVAh626zWXg51Z+obySKlmQO503aLHqa3eJOI44sDr39z9 79FQ== 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=tx+seKi60p48rZDrSvhq06rOfr3LSqzdUw+gGKvrWf8=; b=N21I8wjRw5ah3mriGuqFibnqFt/kOSfctCVyY1rwnM7vKaD6Eoz8XeeDEPgDTMf0No d7zs0iyzDLLWiNpEnYwebJ/XjH4mMS6Q7kaRTrajFrtRyD17yaJEsQSZEFfLYdW+YFZF HLjP+3yXU9j6H+YCaAihqNxsl2RT5c73FsVZkoE6a3dNajuxQdAtsE/4XznB9d4y+4uO kzgKOsYSrN5XJEx1ncTRBHVoe0q9aK/P+0PnptUumpvI7Z5dsx8AD3BWTZ6L6KDhqflb KWK5rOK4h0zDojudoWJQv4jNjnR19zlIs6flNNmxmurxyDAqnBeiMvyslqamLxRvYD0F FIhA== X-Gm-Message-State: AOAM531nkMaGBAeZR6MPXsX7dysTaY2txDTw8dZ3Ziq/RzmDGTLu3Msu Iw8aTnPWAADGYaqAhxc9VTI= X-Google-Smtp-Source: ABdhPJxbpV5/wm1zJAV+LFuZZ2YNRiMtfhLAoQ89aCXg6uAo1EeHAdLXyoMbP5sFXqJCGEUDAOwFVA== X-Received: by 2002:a17:90a:1e65:: with SMTP id w92mr6321289pjw.187.1597511876194; Sat, 15 Aug 2020 10:17:56 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.55 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:55 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v17 08/10] t5411: test updates of remote-tracking branches Date: Sat, 15 Aug 2020 13:17:38 -0400 Message-Id: <20200815171740.6257-9-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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 Sat Aug 15 17:17:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715797 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 2D096618 for ; Sat, 15 Aug 2020 22:03:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 13ABA20639 for ; Sat, 15 Aug 2020 22:03:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="L3B3XSC+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729627AbgHOWDZ (ORCPT ); Sat, 15 Aug 2020 18:03:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45602 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728681AbgHOVvL (ORCPT ); Sat, 15 Aug 2020 17:51:11 -0400 Received: from mail-pl1-x642.google.com (mail-pl1-x642.google.com [IPv6:2607:f8b0:4864:20::642]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2FE35C00217C for ; Sat, 15 Aug 2020 10:17:58 -0700 (PDT) Received: by mail-pl1-x642.google.com with SMTP id t10so5512694plz.10 for ; Sat, 15 Aug 2020 10:17:58 -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=TSdqNxAxMsOh1Tyf9kvR1W1yBNuUnxLAKkzUWjILpoc=; b=L3B3XSC+kRNJwLgjppputT5wmbBufx2i0GANFo/EXd6CT8N7Oz7dwevm9CSPgezPN+ qhKrZveWAobvWt6khHNUXxFA7d6eENtxAuGPYJhtIRTKkARhFqtA5/wj+utEyIWL2llH wt1ie6ejTqf7zyGHg2MSbWJ0BGvfh68R16v8r17snftG1FdIfGsGW4p4+OfPaVhrpS7w 5zbG+ZnzrqvJkx7WpH6/BBjtR0db1fUxcanUFOdDRlnBpiFIRjWYehZgzCygUNSyrRGi ztQGl4P8rYOwEuopSZM71J2+69PhduZPwNiWSZx0plavEWHfrL9dG1RLoU3TZlgY6LAk zaMA== 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=TSdqNxAxMsOh1Tyf9kvR1W1yBNuUnxLAKkzUWjILpoc=; b=Uj5HdnP8bmQdnXFaMKowrvGAm4XcYqmoI7iP1YTtIsmcaYh8YYLqTX836+ThY4hLvV m+/aKKNrUrO2H5nsnPtQ+QcFSm0n3K0NiZAVlhprnx6TfUxQAYxbhzJXXWMISzuguEJU VWMA5ZSsILsOknTkVJopT1qAnRXVbXU6FxmCxinkfbbAU9/MV0FHb5QdGlpx8xo6Unkv 4oRSEM/jlDsT1uM6x81So+Z2zKmXYzdUlRzZIPi16TDCNo9ntWtuIIhBeVuSZfjwIMJa JTLQC2oAWnUS5goZKK9I5G2MlGJ2w2N0mulXFVj0pVSBx5MmkOAKcRbnzWgNnxzV1cdi LmAw== X-Gm-Message-State: AOAM5336b64k7x+IsF/YvBuzRm3HLa4iKjsTWc3yY7B9uDtFYvVB760j s/rzG6gJ2d2GeNep4U2fRvxBJX39TI4= X-Google-Smtp-Source: ABdhPJwiWyhOZWkne05RQN5S/thxBY4jx2Ubak1Q6ZjUWlVWVhEC2jBbCti3cSUTPnyQjVBsGUdCWQ== X-Received: by 2002:a17:902:8347:: with SMTP id z7mr2680945pln.20.1597511877128; Sat, 15 Aug 2020 10:17:57 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.56 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:56 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v17 09/10] transport: parse report options for tracking refs Date: Sat, 15 Aug 2020 13:17:39 -0400 Message-Id: <20200815171740.6257-10-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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 10f7dbbcd0..fe0c73fa88 100644 --- a/transport.c +++ b/transport.c @@ -436,28 +436,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_options *options; + + if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE) + return; + + options = ref->report.options; + if (!options) + update_tracking_ref(remote, ref->name, &ref->new_oid, + ref->deletion, verbose); + else + for (; options; options = options->next) { + refname = options->ref_name ? (char *)options->ref_name : ref->name; + new_oid = options->new_oid ? options->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_options *options, From patchwork Sat Aug 15 17:17:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11715705 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 48A93913 for ; Sat, 15 Aug 2020 21:55:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 31200206B6 for ; Sat, 15 Aug 2020 21:55:50 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="PMY+9fcW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729350AbgHOVzl (ORCPT ); Sat, 15 Aug 2020 17:55:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45642 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729071AbgHOVwZ (ORCPT ); Sat, 15 Aug 2020 17:52:25 -0400 Received: from mail-pg1-x52b.google.com (mail-pg1-x52b.google.com [IPv6:2607:f8b0:4864:20::52b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A1340C0005DD for ; Sat, 15 Aug 2020 10:17:59 -0700 (PDT) Received: by mail-pg1-x52b.google.com with SMTP id v15so6003558pgh.6 for ; Sat, 15 Aug 2020 10:17:59 -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=fh+DwmfOmldcvLEzNo5wwv/5ahz9TmRejH+rPE4PnzY=; b=PMY+9fcWIxTSCPUI1nHBxDRFIj3/soVZCb5/gAEV/XETaT1kEEaFmZdQdtEGqZQF2T wVNIAzWBR/d+LidyTqSWo3PeW9DSrjZqJ+V7aYRYAw3UMSlrinvBA4+56k+t/u5IB5cB qlTxNsPevZZ5JloTnswVB6xTpIIi/OLVKC7JeWdV2pifIktGObFN7rMRsrfd/85I8T2k UnbmLeViQj8jHY4Oa6ErEjvhxWeSQg6JXd3ki/yBxkuR4mQyz7C6H+rFIwJpOQ5B9Pyh ea/bi9QLO1Gy+RDFwqsDv0J/aAxtFr4vstj8BLlA2qf4AyDUsdCBFzkN/iyZj1Y4fbfh riiQ== 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=fh+DwmfOmldcvLEzNo5wwv/5ahz9TmRejH+rPE4PnzY=; b=FM+kY/PLGsqPj1NT0OeEVIklwqV6UtsgWLVl7YCIUlGTNSL1MtsSntti8tmS5/KLTE LxANfdPNj3B24H6JREtwMP+IPzLHFpaytGOYng68cFc6hZCJ39KAKjqSRefAfKH4MkMr W643fKJHOQ0u1Tu+6GkbsAjOHv3oN2vcfTNN7LcHlA9610FqckQ148cLI9DG/tr03KCU 6M6B61siwbWjK6kejSZhq6MRwHtDDJu9+kJeMd85MdL6RtwKhzaEby0VC+QUqxW6EVIB mDyIO9AzUWa3mn0OEWpxqf359oclJpX0KqlyesNqPsgcwLTGmxFYtKgcON8epfFqk4IC kVLA== X-Gm-Message-State: AOAM53055B7i26JbeNpMlGFFzIzWshnPib4J2eY0qR1Q7y+gdqndJDcA ht54+atV4UKlqZ96z6ZywUphFF05i8E= X-Google-Smtp-Source: ABdhPJxH8W7dHGGFNINQ7Nr56J6NDM1VQQM3PRd1bNsgDA02sPFNpuwQKHi22RHInrKVZ640XI9Mrw== X-Received: by 2002:a62:18c9:: with SMTP id 192mr5619711pfy.23.1597511877991; Sat, 15 Aug 2020 10:17:57 -0700 (PDT) Received: from tigtog.localdomain.localdomain ([144.34.163.219]) by smtp.gmail.com with ESMTPSA id x13sm11040596pga.30.2020.08.15.10.17.57 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 15 Aug 2020 10:17:57 -0700 (PDT) From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v17 10/10] doc: add documentation for the proc-receive hook Date: Sat, 15 Aug 2020 13:17:40 -0400 Message-Id: <20200815171740.6257-11-worldhello.net@gmail.com> X-Mailer: git-send-email 2.26.0.rc0 In-Reply-To: <20200518094039.757-1-worldhello.net@gmail.com> References: <20200518094039.757-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 31b601e4bc..ff2f2f1fb3 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 ~~~~~~~~~~~~