From patchwork Fri Mar 13 12:23:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11436817 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 99920139A for ; Fri, 13 Mar 2020 12:23:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6630720749 for ; Fri, 13 Mar 2020 12:23:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="SbFQtU7q" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726646AbgCMMXl (ORCPT ); Fri, 13 Mar 2020 08:23:41 -0400 Received: from mail-pj1-f66.google.com ([209.85.216.66]:55048 "EHLO mail-pj1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726495AbgCMMXl (ORCPT ); Fri, 13 Mar 2020 08:23:41 -0400 Received: by mail-pj1-f66.google.com with SMTP id np16so4082831pjb.4 for ; Fri, 13 Mar 2020 05:23:40 -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=Wd7nI0zYG7imupVlmf/R4x1VUVB/7pnY6pJzCqnzgrw=; b=SbFQtU7qKgYG7OJ6ZSHLhphRaOjYL+zvd5r/5r9GPntHXb4oinL3qUh+tj2LU0YOTH 5PjGIU6cULNlwnwlkTG3cFsTM3NcIxsInrhah22v12hR0wFhqpwser8Yn789rcYBdLWP /X7LX1i9fDrb9WPMyqqyw1ovZ/KmCGHsi8lnrILbaNGoPrYCR4nlSvb349JNO/vgcBZ7 cNoRx3LzH+p2sduK+Y7OTYg0C2iJVzBbgtZcL33fUaGzMgl8o0bCboXEbiQMLSjAz6c+ YcIG8XVrIF48EpleOT3Cn2DAj6yz5neDc2rWcohxt/RyI+q4UJ/RHRUlGDKSKLZIFmQh dFIQ== 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=Wd7nI0zYG7imupVlmf/R4x1VUVB/7pnY6pJzCqnzgrw=; b=fbI0SsuOSztc8iu8QIBp2sXhfeVHTE63PZqPDorpzat6QzN+bwml2kV3M0O9AmG+u2 WuqwIlIo5+mzXBt1161i2t8949mmZzi5A5ovrjfKTHbP6duiquh53VgHT2IRqlrm84k8 /K6way3eW/TCftRLlOSxkZ5oEMKNX+J45aMD7GsxHO7SdsAFP00zoxOlMNoSF8FXFjrD D9knEHm4lbiqeKX8INEX8JrvPenCeeMoO0jnUT3pKGtdOpIjNyKuyMQk+Isqdv6U9Elk mvBPY2eEVWK2VvEw9YR0OBJv4v0np/GPg+cTzpzApCBcdVjram4D0pijYLuU+F8upx+E 5zpw== X-Gm-Message-State: ANhLgQ1hli3OBPMpgf+f7A0ndAsxgH6/yi+qIwD3zLKIXUKDc4CnjE5B V3AEJYVi1uS20gAI2J5mRqM= X-Google-Smtp-Source: ADFU+vsTtXBMbV2LPWlMH0M3MbfFFxIie7tdPP5O61eHWZuDejw9hnjBfcVaB8Iilh6W5ZSzVvhU4A== X-Received: by 2002:a17:902:a701:: with SMTP id w1mr11887960plq.165.1584102219804; Fri, 13 Mar 2020 05:23:39 -0700 (PDT) Received: from localhost.localdomain ([47.89.83.4]) by smtp.gmail.com with ESMTPSA id 134sm5346690pfy.27.2020.03.13.05.23.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 13 Mar 2020 05:23:39 -0700 (PDT) From: Jiang Xin X-Google-Original-From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v3 1/4] receive-pack: add new proc-receive hook Date: Fri, 13 Mar 2020 20:23:15 +0800 Message-Id: <20200313122318.78000-2-zhiyou.jx@alibaba-inc.com> X-Mailer: git-send-email 2.26.0.rc1.5.gca1e965b06 In-Reply-To: References: MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org 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 (`have_special_ref`) 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. This "proc-receive" hook reads 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. S: PKT-LINE(version=1\0push-options ...) S: flush-pkt H: PKT-LINE(version=1\0push-options ...) H: flush-pkt S: PKT-LINE(old-oid new-oid ref) S: ... ... S: flush-pkt # Optional, only if push-options is negotiated. S: PKT-LINE(push-option) S: ... ... S: flush-pkt # OK, run this command successfully. H: PKT-LINE(old-oid new-oid ref ok) # NO, I reject it. H: PKT-LINE(old-oid new-oid ref ng reason) # OK, but use an alternate reference. (in latter commit) H: PKT-LINE(old-oid new-oid ref ok ref:alt-ref) # It will fallthrough to receive-pack to execute. (in latter commit) H: PKT-LINE(old-oid new-oid ref ft) H: ... ... H: flush-pkt After receiving a command, the hook can create/update another alternate reference. For example, a command for a reference "refs/for/master" may create a special reference, such as "refs/pull/123/head". The alternate reference can be returned from the result in an extensible format like " []". The result will be stored in a command list, and "receive-pack" will use the result to replace the commands that have specific `have_special_ref` field turned on. Signed-off-by: Jiang Xin --- builtin/receive-pack.c | 244 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 239 insertions(+), 5 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 2cc18bbffd..8cda2b9cf7 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -312,7 +312,8 @@ struct command { struct command *next; const char *error_string; unsigned int skip_update:1, - did_not_exist:1; + did_not_exist:1, + have_special_ref:1; int index; struct object_id old_oid; struct object_id new_oid; @@ -817,6 +818,209 @@ static int run_update_hook(struct command *cmd) return finish_command(&proc); } +static int read_proc_receive_result(struct packet_reader *reader, + struct command **commands) +{ + struct command **tail = commands; + int code = 0; + + for (;;) { + struct object_id old_oid, new_oid; + struct command *cmd; + const char *refname; + const char *p; + char *status; + char *msg = NULL; + + if (packet_reader_read(reader) != PACKET_READ_NORMAL) { + break; + } + + if (parse_oid_hex(reader->line, &old_oid, &p) || + *p++ != ' ' || + parse_oid_hex(p, &new_oid, &p) || + *p++ != ' ') + die("protocol error: proc-receive expected 'old new ref status [msg]', got '%s'", + reader->line); + + refname = p; + status = strchr(p, ' '); + if (!status) + die("protocol error: proc-receive expected 'old new ref status [msg]', got '%s'", + reader->line); + *status++ = '\0'; + + FLEX_ALLOC_MEM(cmd, ref_name, refname, strlen(refname)); + oidcpy(&cmd->old_oid, &old_oid); + oidcpy(&cmd->new_oid, &new_oid); + cmd->have_special_ref = 1; + + if (strlen(status) > 2 && *(status + 2) == ' ') { + msg = status + 2; + *msg++ = '\0'; + } + if (strlen(status) != 2) + die("protocol error: proc-receive has bad status '%s' for '%s'", + status, reader->line); + if (!strcmp(status, "ng")) { + if (msg) + cmd->error_string = xstrdup(msg); + else + cmd->error_string = "failed"; + code = 1; + } else if (strcmp("ok", status)) { + rp_warning("unknown proc-receive status '%s' for '%s'", + status, reader->line); + cmd->error_string = "bad status"; + code = 1; + } + + *tail = cmd; + tail = &cmd->next; + } + 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 *result_commands = NULL; + struct command *cmd; + const char *argv[2]; + struct packet_reader reader; + int pr_use_push_options = 0; + int version = 0; + int code; + + argv[0] = find_hook("proc-receive"); + if (!argv[0]) { + rp_error("cannot to find hook 'proc-receive'"); + return 1; + } + argv[1] = NULL; + + proc.argv = argv; + proc.in = -1; + proc.out = -1; + proc.trace2_hook_name = "proc-receive"; + + if (use_sideband) { + memset(&muxer, 0, sizeof(muxer)); + muxer.proc = copy_to_sideband; + muxer.in = -1; + code = start_async(&muxer); + if (code) + return code; + proc.err = muxer.in; + } else { + proc.err = 0; + } + + code = start_command(&proc); + if (code) { + if (use_sideband) + finish_async(&muxer); + return code; + } + + sigchain_push(SIGPIPE, SIG_IGN); + + /* Version negotiaton */ + packet_reader_init(&reader, proc.out, NULL, 0, + PACKET_READ_CHOMP_NEWLINE | + PACKET_READ_DIE_ON_ERR_PACKET); + packet_write_fmt(proc.in, "version=1%c%s\n", + '\0', + use_push_options ? "push-options": ""); + for (;;) { + int linelen; + + if (packet_reader_read(&reader) != PACKET_READ_NORMAL) + break; + + if (reader.pktlen > 8 && starts_with(reader.line, "version=")) { + version = atoi(reader.line+8); + linelen = strlen(reader.line); + if (linelen < reader.pktlen) { + const char *feature_list = reader.line + linelen + 1; + if (parse_feature_request(feature_list, "push-options")) + pr_use_push_options = 1; + } + } + } + + if (version != 1) + die("protocol error: unknown proc-receive version '%d'", version); + + /* Send commands */ + for (cmd = *commands; cmd; cmd = cmd->next) { + char *old_hex, *new_hex; + + if (!cmd->have_special_ref || cmd->skip_update || + cmd->did_not_exist || cmd->error_string) + continue; + + old_hex = oid_to_hex(&cmd->old_oid); + new_hex = oid_to_hex(&cmd->new_oid); + + packet_write_fmt(proc.in, "%s %s %s", + old_hex, new_hex, cmd->ref_name); + } + packet_flush(proc.in); + + /* Send push options */ + if (pr_use_push_options) { + struct string_list_item *item; + + for_each_string_list_item(item, push_options) + packet_write_fmt(proc.in, "%s", item->string); + + packet_flush(proc.in); + } + + /* Read result from proc-receive */ + code = read_proc_receive_result(&reader, &result_commands); + close(proc.in); + close(proc.out); + if (finish_command(&proc)) + die("proc-receive did not exit properly"); + + /* After receiving the result from the "proc-receive" hook, + * "receive-pack" will use the result to replace commands that + * have specific `have_special_ref` field. + */ + for (cmd = *commands; cmd; cmd = cmd->next) + if (!cmd->have_special_ref) + break; + + if (!cmd || cmd->have_special_ref) { + cmd = result_commands; + } else { + struct command *tail = cmd; + for (;;) { + if (!tail->next) + break; + else if (tail->next->have_special_ref) + tail->next = tail->next->next; + else + tail = tail->next; + } + tail->next = result_commands; + } + *commands = cmd; + + // TODO: sort commands or not? + + if (use_sideband) + finish_async(&muxer); + + sigchain_pop(SIGPIPE); + + return code; +} + static char *refuse_unconfigured_deny_msg = N_("By default, updating the current branch in a non-bare repository\n" "is denied, because it will make the index and work tree inconsistent\n" @@ -1392,7 +1596,7 @@ static void execute_commands_non_atomic(struct command *commands, struct strbuf err = STRBUF_INIT; for (cmd = commands; cmd; cmd = cmd->next) { - if (!should_process_cmd(cmd)) + if (!should_process_cmd(cmd) || cmd->have_special_ref) continue; transaction = ref_transaction_begin(&err); @@ -1432,7 +1636,7 @@ static void execute_commands_atomic(struct command *commands, } for (cmd = commands; cmd; cmd = cmd->next) { - if (!should_process_cmd(cmd)) + if (!should_process_cmd(cmd) || cmd->have_special_ref) continue; cmd->error_string = update(cmd, si); @@ -1458,16 +1662,19 @@ static void execute_commands_atomic(struct command *commands, strbuf_release(&err); } -static void execute_commands(struct command *commands, +static void execute_commands(struct command **orig_commands, const char *unpacker_error, struct shallow_info *si, const struct string_list *push_options) { + struct command *commands = *orig_commands; struct check_connected_options opt = CHECK_CONNECTED_INIT; struct command *cmd; struct iterate_data data; struct async muxer; int err_fd = 0; + int have_special_ref = 0; + int have_normal_ref = 0; if (unpacker_error) { for (cmd = commands; cmd; cmd = cmd->next) @@ -1497,6 +1704,22 @@ 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->have_special_ref = 1; + have_special_ref = 1; + } else { + have_normal_ref = 1; + } + } + if (run_receive_hook(commands, "pre-receive", 0, push_options)) { for (cmd = commands; cmd; cmd = cmd->next) { if (!cmd->error_string) @@ -1523,6 +1746,17 @@ 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 (have_special_ref) { + if (run_proc_receive_hook(orig_commands, push_options)) { + for (cmd = commands; cmd; cmd = cmd->next) { + if (!cmd->error_string && (cmd->have_special_ref || use_atomic)) + cmd->error_string = "fail to run proc-receive hook"; + } + } else { + commands = *orig_commands; + } + } + if (use_atomic) execute_commands_atomic(commands, si); else @@ -2019,7 +2253,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) update_shallow_info(commands, &si, &ref); } use_keepalive = KEEPALIVE_ALWAYS; - execute_commands(commands, unpack_status, &si, + execute_commands(&commands, unpack_status, &si, &push_options); if (pack_lockfile) unlink_or_warn(pack_lockfile); From patchwork Fri Mar 13 12:23:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11436821 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 DA1F8139A for ; Fri, 13 Mar 2020 12:23:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B0D032074A for ; Fri, 13 Mar 2020 12:23:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="dePLiHQC" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726674AbgCMMXo (ORCPT ); Fri, 13 Mar 2020 08:23:44 -0400 Received: from mail-pl1-f172.google.com ([209.85.214.172]:37265 "EHLO mail-pl1-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726495AbgCMMXo (ORCPT ); Fri, 13 Mar 2020 08:23:44 -0400 Received: by mail-pl1-f172.google.com with SMTP id f16so4198823plj.4 for ; Fri, 13 Mar 2020 05:23:42 -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=xgoW0Gi3MEdhHptU4qsN60lX7ZW0zkclbNP8S5BC6CY=; b=dePLiHQC+EKmTz5HetP/ZkE8fIivvXkf3y6tTLlfqdBsDxR06Zh+DWQSKKcNsaj95b Oue9QXr6nzU3s85VUnuHNeBqpkcwITDYUGGwepvOJVjsb9RGh8zk6jelZZeyhNV7AQAm fSGY9qmYECV41LINBNPoE0nx54QvS06xj+j9g9qO8YHAlvJpZ++GK27PXDp7pkELshwv /1wffoQz+CvMnkUGOLih3Uojv8AkWYh/Ma2fshCDWId0K8o5I3pbU9eqQP/ZwIxawm23 vcJLDWgDfrD9S/OFazDje3RnV18l3y4GS4MtJT8zSZmuKo2lR5RrhFOMw+srLMiav2TU E2Ig== 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=xgoW0Gi3MEdhHptU4qsN60lX7ZW0zkclbNP8S5BC6CY=; b=YmVTzictcaV4TO4zgg8xvaXKT5+d3LcgpT9cFsyXCpE8f3I+8wxYCvJY95xqmWfATP NHgzK5VQ1Zk2UiStDOtuXZ4izFCQjrwm0eSqdfk+5LMgojxhxIBKSwuvZSZiGMJ12anU 8G8NlB+wNJhdwRAU1nLnUZk3XlwqnEbP9GmWtqRJ7qTbsMRFF8kg2NY1DXzJJh3K2FxJ 4r6iSKmIycasws6Z/S9OxMH0hfIioLslj7qGzfGpjsbxHadgz1YCAiwEu7A1+lmg3XWE Fx6o/ppGKzgcHeXdCymVkDUSDwmKfWRpftdY51OECdJftuJ6IEPO6JTzog7gWSmH2zqF a7jQ== X-Gm-Message-State: ANhLgQ2ugSXkKBOeva1faigMazNu/uWE9eMPpDCQGByHb5zLcVOfAdyK niGcDy+DXebMLMf/adoT9po= X-Google-Smtp-Source: ADFU+vsMtfK6w4ghAv9ue6Rf/DfudgVGc44r4tedJZnfAEZtsjGLOxgAFWDplGHc0soQ/y0lX67JUQ== X-Received: by 2002:a17:902:6ac2:: with SMTP id i2mr12725830plt.221.1584102221617; Fri, 13 Mar 2020 05:23:41 -0700 (PDT) Received: from localhost.localdomain ([47.89.83.4]) by smtp.gmail.com with ESMTPSA id 134sm5346690pfy.27.2020.03.13.05.23.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 13 Mar 2020 05:23:41 -0700 (PDT) From: Jiang Xin X-Google-Original-From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v3 2/4] receive-pack: refactor report for proc-receive Date: Fri, 13 Mar 2020 20:23:16 +0800 Message-Id: <20200313122318.78000-3-zhiyou.jx@alibaba-inc.com> X-Mailer: git-send-email 2.26.0.rc1.5.gca1e965b06 In-Reply-To: References: MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org The "proc-receive" may update one or more references, and will send its result one by one in pkt-line format. Each line of the result has four fields and one optional message field, as " []". See the following example: # OK, run this command successfully. PKT-LINE(old-oid new-oid ref ok) # NO, I reject it. PKT-LINE(old-oid new-oid ref ng reason) # OK, but use an alternate reference. PKT-LINE(old-oid new-oid ref ok ref:alt-ref) # It will fallthrough to receive-pack to execute. PKT-LINE(old-oid new-oid ref ft) The first three fields have the same foramt as a command. The forth field has a two-letter status code. Available status code: * ok: The command runs successfully. If the optional message has a prefix "ref:", the hook has created/updated an alternate reference instead. * ng: Fail to run the command. Error message is in the optional message field. * ft: Will fallthrough to receive-pack to execute. Signed-off-by: Jiang Xin --- builtin/receive-pack.c | 21 ++++++++++++++++----- transport.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 8cda2b9cf7..23f1ae3795 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -311,6 +311,7 @@ static void write_head_info(void) struct command { struct command *next; const char *error_string; + const char *extra_string; unsigned int skip_update:1, did_not_exist:1, have_special_ref:1; @@ -868,7 +869,12 @@ static int read_proc_receive_result(struct packet_reader *reader, else cmd->error_string = "failed"; code = 1; - } else if (strcmp("ok", status)) { + } else if (!strcmp("ok", status)) { + cmd->extra_string = xstrdup_or_null(msg); + } else if (!strcmp("ft", status)) { + /* Unset "have_special_ref" field, will execute by "receive-pack" */ + cmd->have_special_ref = 0; + } else { rp_warning("unknown proc-receive status '%s' for '%s'", status, reader->line); cmd->error_string = "bad status"; @@ -2133,12 +2139,17 @@ static void report(struct command *commands, const char *unpack_status) packet_buf_write(&buf, "unpack %s\n", unpack_status ? unpack_status : "ok"); for (cmd = commands; cmd; cmd = cmd->next) { - if (!cmd->error_string) - packet_buf_write(&buf, "ok %s\n", - cmd->ref_name); - else + if (!cmd->error_string) { + if (!cmd->extra_string) + packet_buf_write(&buf, "ok %s\n", + cmd->ref_name); + else + packet_buf_write(&buf, "ok %s%c%s\n", + cmd->ref_name, ' ', cmd->extra_string); + } else { packet_buf_write(&buf, "ng %s %s\n", cmd->ref_name, cmd->error_string); + } } packet_buf_flush(&buf); diff --git a/transport.c b/transport.c index 1fdc7dac1a..a4f2a5cc6f 100644 --- a/transport.c +++ b/transport.c @@ -463,11 +463,17 @@ static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg, int porcelain, int summary_width) { + char *to_name = to->name; + + if (to->remote_status) { + if (!strncmp("ref:", to->remote_status, 4)) + to_name = to->remote_status + 4; + } if (porcelain) { if (from) - fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to->name); + fprintf(stdout, "%c\t%s:%s\t", flag, from->name, to_name); else - fprintf(stdout, "%c\t:%s\t", flag, to->name); + fprintf(stdout, "%c\t:%s\t", flag, to_name); if (msg) fprintf(stdout, "%s (%s)\n", summary, msg); else @@ -481,9 +487,9 @@ static void print_ref_status(char flag, const char *summary, fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width, summary, reset); if (from) - fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name)); + fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to_name)); else - fputs(prettify_refname(to->name), stderr); + fputs(prettify_refname(to_name), stderr); if (msg) { fputs(" (", stderr); fputs(msg, stderr); @@ -498,12 +504,21 @@ static void print_ok_ref_status(struct ref *ref, int porcelain, int summary_widt if (ref->deletion) print_ref_status('-', "[deleted]", ref, NULL, NULL, porcelain, summary_width); - else if (is_null_oid(&ref->old_oid)) + else if (is_null_oid(&ref->old_oid)) { + char *refname, *summary; + if (ref->remote_status && !strncmp(ref->remote_status, "ref:", 4)) + refname = ref->remote_status + 4; + else + refname = ref->name; + if (starts_with(refname, "refs/tags/")) + summary = "[new tag]"; + else if (starts_with(refname, "refs/heads/")) + summary = "[new branch]"; + else + summary = "[new reference]"; print_ref_status('*', - (starts_with(ref->name, "refs/tags/") ? "[new tag]" : - "[new branch]"), - ref, ref->peer_ref, NULL, porcelain, summary_width); - else { + summary, ref, ref->peer_ref, NULL, porcelain, summary_width); + } else { struct strbuf quickref = STRBUF_INIT; char type; const char *msg; From patchwork Fri Mar 13 12:23:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11436825 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 400981392 for ; Fri, 13 Mar 2020 12:23:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 1F0EC20749 for ; Fri, 13 Mar 2020 12:23:49 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="jK297KcA" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726621AbgCMMXr (ORCPT ); Fri, 13 Mar 2020 08:23:47 -0400 Received: from mail-pl1-f195.google.com ([209.85.214.195]:46605 "EHLO mail-pl1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726216AbgCMMXr (ORCPT ); Fri, 13 Mar 2020 08:23:47 -0400 Received: by mail-pl1-f195.google.com with SMTP id w12so4178557pll.13 for ; Fri, 13 Mar 2020 05:23:44 -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=4SJjKPjsE9uSOROLgo/QFhP14LqTGd/44sUbiJeiTPE=; b=jK297KcAWEhgOhqHTV1TppkraSCpVsCVcwqwwWepaBKZ2RGF78N1btAitlDsrwz2ay z/abojtjUKyAeZ2ww5yxr6THWscuvXgBogSKbgdRNXer4ZSdY8zHs6hCoaV2qDH4Pz6V jznNkxvSwZsTbWWtgNJav8sK7e+WIbPnEXa8cHMLlIk/vZk8iZQ5zG1ZCdUgyDP6rNvF C3izEeSvMBgZw12Eo7JoMvaXHDHO6REWcSpWiKpPTT4TBbVVg/e6QyfwuaWySmk8NQlx amylGlXplE72nNWfMMJDGspMLevqPNty72ObekMphb0HmEQPcMvHKlYHRik2sBJAXd2h tnNQ== 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=4SJjKPjsE9uSOROLgo/QFhP14LqTGd/44sUbiJeiTPE=; b=DZg+wNEsOLhvxRvI7OGB2a8B10S0z6OwlrInmpts/B05BF5QSGNr763HQqMpCExzX2 3jFjwhbZHqdoko/wBWA/m5SoxTBzgf3Le02iTzKmDstEDiA0h3SccUJzfAbVldGpfMH+ qiiHdr8LHgKVcfH9WBp07uXqWY86aa6wttyKIjx+cdm1Q5NWWtfiQZz/Ce2PvoZPwbJ1 wN0mEi2M872IMWes/hfuUe1avS/NxmhxbBVfofHZE+gFyXcilmOO4IunpOSdwNtjWhjq 0tYWjKlo3iKJ6PMiiRtkHQqpGsnFWPbHkaqMZPYXDyzNX1XpQCdu+1IgpXDB98bkFpq/ xgNw== X-Gm-Message-State: ANhLgQ00lnK095ll1xUTAjGrtRnTjLofFQZhwBam0OcC75Pt+iHTGbIz 5rGpILtV4CEsah6jOnW3FSs= X-Google-Smtp-Source: ADFU+vuMzBv9ozugaaKcSJXQ7nPM7XO+DvNUjElzwKBFy28qPEIReSNfgE/bYjJ3/goz6Dg5rhDC7g== X-Received: by 2002:a17:90a:ec0f:: with SMTP id l15mr9403863pjy.133.1584102224019; Fri, 13 Mar 2020 05:23:44 -0700 (PDT) Received: from localhost.localdomain ([47.89.83.4]) by smtp.gmail.com with ESMTPSA id 134sm5346690pfy.27.2020.03.13.05.23.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 13 Mar 2020 05:23:43 -0700 (PDT) From: Jiang Xin X-Google-Original-From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v3 3/4] refs.c: refactor to reuse ref_is_hidden() Date: Fri, 13 Mar 2020 20:23:17 +0800 Message-Id: <20200313122318.78000-4-zhiyou.jx@alibaba-inc.com> X-Mailer: git-send-email 2.26.0.rc1.5.gca1e965b06 In-Reply-To: References: MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Add new function `ref_is_matched()` to reuse `ref_is_hidden()`. Will use this function for `receive-pack` to check commands with specific prefixes. Test case t5512 covered this change. Signed-off-by: Jiang Xin --- refs.c | 11 ++++++++--- refs.h | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/refs.c b/refs.c index 1ab0bb54d3..229159ea1a 100644 --- a/refs.c +++ b/refs.c @@ -1389,13 +1389,18 @@ int parse_hide_refs_config(const char *var, const char *value, const char *secti } int ref_is_hidden(const char *refname, const char *refname_full) +{ + return ref_is_matched(hide_refs, refname, refname_full); +} + +int ref_is_matched(struct string_list *match_refs, const char *refname, const char *refname_full) { int i; - if (!hide_refs) + if (!match_refs) return 0; - for (i = hide_refs->nr - 1; i >= 0; i--) { - const char *match = hide_refs->items[i].string; + for (i = match_refs->nr - 1; i >= 0; i--) { + const char *match = match_refs->items[i].string; const char *subject; int neg = 0; const char *p; diff --git a/refs.h b/refs.h index 545029c6d8..a2ea043f7f 100644 --- a/refs.h +++ b/refs.h @@ -739,6 +739,7 @@ int parse_hide_refs_config(const char *var, const char *value, const char *); * parameter always points to the full ref name. */ int ref_is_hidden(const char *, const char *); +int ref_is_matched(struct string_list *, const char *, const char *); enum ref_type { REF_TYPE_PER_WORKTREE, /* refs inside refs/ but not shared */ From patchwork Fri Mar 13 12:23:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiang Xin X-Patchwork-Id: 11436823 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 5AEF7139A for ; Fri, 13 Mar 2020 12:23:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3182C20749 for ; Fri, 13 Mar 2020 12:23:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XZajg8df" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726718AbgCMMXr (ORCPT ); Fri, 13 Mar 2020 08:23:47 -0400 Received: from mail-pf1-f194.google.com ([209.85.210.194]:44772 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726495AbgCMMXr (ORCPT ); Fri, 13 Mar 2020 08:23:47 -0400 Received: by mail-pf1-f194.google.com with SMTP id b72so5135037pfb.11 for ; Fri, 13 Mar 2020 05:23:46 -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=ekPZz8iOLJx4/6kv+ASWoRDXpr4PcLjcUGJbkcLghXg=; b=XZajg8dfF4aD7Wsy7ZKUw6Pcr/smVi6cZiooptZy9x58d9SEEadkT67LoMWHLpw+E6 BwXA+C4iuEgZ/4ECvLYm/VsWoj4GfCEYw7fG2kXPXdPYezqqUllhU4zJ4lq1N0HtVAT/ 5XfzKRUpaFbtKlrsdA5codMhn/lgjt4zUP/Y5D4HeiRkYmTFP1C9KWU02B9mO0U1ssrf DlcVA5sLERGw9KfNKYQzma5idgT8UFXVehAc/9HExqvAEeYep8KunsoG1OmD1CurrnjS yMhaQLCScUu+HG8Gqdg15R+oU1iMwcYSGhEf22NL1rr7amKB38XA93TueN3ev9MfHUx7 h9Ag== 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=ekPZz8iOLJx4/6kv+ASWoRDXpr4PcLjcUGJbkcLghXg=; b=RaG/3d9Jo4svohBHPVWqKeFGUmCVEtPkoHZaoxnXu6s3sJfOYvs74tNfS+1/Iy60Ov +kwPckpjF8bBx7IlGz5PTwmLGwjCA3rrgYHOtrqrgMyMyOr6dZInyrclTJw9Td0iar52 MHJOs7REb6HqWSvzZRoQukcvhWJdN135lvRNQw5WlfVPTEZfyA87qo304I6abYhDWLK9 gWyk4CQyBuKAEWx53WyUqtJLfYqjlhHA5yRGg939qLTv2Ks0wkwfpDtd9BPm+HT3HL7X qtVPJWbgnERP3Z184gHfGddcZWyxHA2WG3eqjwA/ouXj6PEm/u6nUlsC1jpnXsISgLSd mAQA== X-Gm-Message-State: ANhLgQ2CxeosphRo4whr61LE5DVVsruvvnrJkFrVAs0UlxTydGMPcmij r2X6LfTrRG/N8wT0VIsaosI= X-Google-Smtp-Source: ADFU+vvf0xJ2j+wjXNK4Rc6DGbDhy0AA27ZMYcYSY4Fgrpi5Hihv2MU0EfC9g6OkIy3Zsf9x/YSA/A== X-Received: by 2002:a63:87c1:: with SMTP id i184mr12414348pge.287.1584102225901; Fri, 13 Mar 2020 05:23:45 -0700 (PDT) Received: from localhost.localdomain ([47.89.83.4]) by smtp.gmail.com with ESMTPSA id 134sm5346690pfy.27.2020.03.13.05.23.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 13 Mar 2020 05:23:45 -0700 (PDT) From: Jiang Xin X-Google-Original-From: Jiang Xin To: Junio C Hamano , Git List Cc: Jiang Xin Subject: [PATCH v3 4/4] receive-pack: new config receive.procReceiveRefs Date: Fri, 13 Mar 2020 20:23:18 +0800 Message-Id: <20200313122318.78000-5-zhiyou.jx@alibaba-inc.com> X-Mailer: git-send-email 2.26.0.rc1.5.gca1e965b06 In-Reply-To: References: MIME-Version: 1.0 Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Add a new multi-valued config variable "receive.procReceiveRefs" for `receive-pack` command, like the follows: git config --system --add receive.procReceiveRefs refs/for/ git config --system --add receive.procReceiveRefs refs/drafts/ If the specific prefix strings match the reference names of the commands which are sent by git client to `receive-pack`, these commands will be executed by an external hook (named "proc-receive"), instead of the internal `execute_commands` function. For example, if it is set to "refs/for/", pushing to a reference such as "refs/for/master" will not create or update reference "refs/for/master", but may create or update a pull request directly by running the external hook. Signed-off-by: Jiang Xin --- Documentation/config/receive.txt | 14 +++++++++ builtin/receive-pack.c | 49 ++++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/Documentation/config/receive.txt b/Documentation/config/receive.txt index 65f78aac37..0178f2d478 100644 --- a/Documentation/config/receive.txt +++ b/Documentation/config/receive.txt @@ -114,6 +114,20 @@ receive.hideRefs:: An attempt to update or delete a hidden ref by `git push` is rejected. +receive.procReceiveRefs:: + This is a multi-valued variable that defines reference prefixes + to match the commands in `receive-pack`. Commands matching the + prefixes will be executed by an external hooks "proc-receive", + instead of the internal `execute_commands` function. If this + variable is not defined, the "proc-receive" hook will never be + used, and all commands will be executed by the internal + `execute_commands` function. + + For example, if this variable is set to "refs/for/", pushing to + reference such as "refs/for/master" will not create or update a + reference named "refs/for/master", but may create or update a + pull request directly by running an external hook. + receive.updateServerInfo:: If set to true, git-receive-pack will run git-update-server-info after receiving data from git-push and updating refs. diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 23f1ae3795..2b796e654d 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -76,6 +76,7 @@ static struct object_id push_cert_oid; static struct signature_check sigcheck; static const char *push_cert_nonce; static const char *cert_nonce_seed; +static struct string_list proc_receive_refs; static const char *NONCE_UNSOLICITED = "UNSOLICITED"; static const char *NONCE_BAD = "BAD"; @@ -228,6 +229,20 @@ static int receive_pack_config(const char *var, const char *value, void *cb) return 0; } + if (strcmp(var, "receive.procreceiverefs") == 0) { + char *prefix; + int len; + + if (!value) + return config_error_nonbool(var); + prefix = xstrdup(value); + len = strlen(prefix); + while (len && prefix[len - 1] == '/') + prefix[--len] = '\0'; + string_list_insert(&proc_receive_refs, prefix); + return 0; + } + return git_default_config(var, value, cb); } @@ -1713,17 +1728,30 @@ static void execute_commands(struct command **orig_commands, /* Try to find commands that have special prefix in their reference names, * and mark them to run an external "proc-receive" hook later. */ - for (cmd = commands; cmd; cmd = cmd->next) { - if (!should_process_cmd(cmd)) - continue; + if (proc_receive_refs.nr > 0) { + struct strbuf refname_full = STRBUF_INIT; + size_t prefix_len; - /* TODO: replace the fixed prefix by looking up git config variables. */ - if (!strncmp(cmd->ref_name, "refs/for/", 9)) { - cmd->have_special_ref = 1; - have_special_ref = 1; - } else { - have_normal_ref = 1; + strbuf_addstr(&refname_full, get_git_namespace()); + prefix_len = refname_full.len; + + for (cmd = commands; cmd; cmd = cmd->next) { + if (!should_process_cmd(cmd)) + continue; + + strbuf_setlen(&refname_full, prefix_len); + strbuf_addstr(&refname_full, cmd->ref_name); + if (ref_is_matched(&proc_receive_refs, cmd->ref_name, refname_full.buf)) { + cmd->have_special_ref = 1; + have_special_ref = 1; + } else { + have_normal_ref = 1; + } } + + strbuf_release(&refname_full); + } else { + have_normal_ref = 1; } if (run_receive_hook(commands, "pre-receive", 0, push_options)) { @@ -2187,6 +2215,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) OPT_END() }; + string_list_init(&proc_receive_refs, 0); + packet_trace_identity("receive-pack"); argc = parse_options(argc, argv, prefix, options, receive_pack_usage, 0); @@ -2302,5 +2332,6 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) oid_array_clear(&shallow); oid_array_clear(&ref); free((void *)push_cert_nonce); + string_list_clear(&proc_receive_refs, 0); return 0; }