From ecc6f2fb8399d84e5b2bf043376dfc51f43f3e90 Mon Sep 17 00:00:00 2001 From: Russell Sim Date: Fri, 25 Nov 2022 13:35:08 +0100 Subject: [PATCH 1/4] push: support push-options Push options are an optional capability of a git server. If they are listed in the servers capabilities, when the client lists push-options in it's list of capabilities, then the client sends it's list of push options followed by a flush-pkt. So, If we have any declared push options, then we will list it as a client capability, and send the options. If the request contains push options but the server has no push options capability, then error. --- include/git2/remote.h | 5 +++++ include/git2/sys/remote.h | 3 +++ src/libgit2/push.c | 25 +++++++++++++++++++++++++ src/libgit2/push.h | 1 + src/libgit2/remote.c | 7 +++++++ src/libgit2/transports/smart.c | 3 +++ src/libgit2/transports/smart.h | 4 +++- src/libgit2/transports/smart_protocol.c | 19 +++++++++++++++++++ 8 files changed, 66 insertions(+), 1 deletion(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 8c9c26f3fd5..108fcfe716e 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -812,6 +812,11 @@ typedef struct { * Extra headers for this push operation */ git_strarray custom_headers; + + /** + * Push options + */ + git_strarray push_options; } git_push_options; #define GIT_PUSH_OPTIONS_VERSION 1 diff --git a/include/git2/sys/remote.h b/include/git2/sys/remote.h index 0eae9234deb..07309ab09b6 100644 --- a/include/git2/sys/remote.h +++ b/include/git2/sys/remote.h @@ -26,6 +26,9 @@ typedef enum { /** Remote supports fetching an individual reachable object. */ GIT_REMOTE_CAPABILITY_REACHABLE_OID = (1 << 1), + + /** Remote supports push options. */ + GIT_REMOTE_CAPABILITY_PUSH_OPTIONS = (1 << 2), } git_remote_capability_t; /** diff --git a/src/libgit2/push.c b/src/libgit2/push.c index d477b4f0dc6..b1cbcd4ae10 100644 --- a/src/libgit2/push.c +++ b/src/libgit2/push.c @@ -68,6 +68,14 @@ int git_push_new(git_push **out, git_remote *remote, const git_push_options *opt return -1; } + if (git_vector_init(&p->push_options, 0, git__strcmp_cb) < 0) { + git_vector_free(&p->status); + git_vector_free(&p->specs); + git_vector_free(&p->updates); + git__free(p); + return -1; + } + *out = p; return 0; } @@ -472,12 +480,23 @@ static int filter_refs(git_remote *remote) int git_push_finish(git_push *push) { int error; + unsigned int remote_caps; if (!git_remote_connected(push->remote)) { git_error_set(GIT_ERROR_NET, "remote is disconnected"); return -1; } + if ((error = git_remote_capabilities(&remote_caps, push->remote)) < 0){ + git_error_set(GIT_ERROR_INVALID, "remote capabilities not available"); + return -1; + } + + if (git_vector_length(&push->push_options) > 0 && !(remote_caps & GIT_REMOTE_CAPABILITY_PUSH_OPTIONS)) { + git_error_set(GIT_ERROR_INVALID, "push-options not supported by remote"); + return -1; + } + if ((error = filter_refs(push->remote)) < 0 || (error = do_push(push)) < 0) return error; @@ -521,6 +540,7 @@ void git_push_free(git_push *push) push_spec *spec; push_status *status; git_push_update *update; + char *option; unsigned int i; if (push == NULL) @@ -543,6 +563,11 @@ void git_push_free(git_push *push) } git_vector_free(&push->updates); + git_vector_foreach(&push->push_options, i, option) { + git__free(option); + } + git_vector_free(&push->push_options); + git__free(push); } diff --git a/src/libgit2/push.h b/src/libgit2/push.h index fc72e845eee..17c3e2f6845 100644 --- a/src/libgit2/push.h +++ b/src/libgit2/push.h @@ -34,6 +34,7 @@ struct git_push { git_vector specs; git_vector updates; bool report_status; + git_vector push_options; /* report-status */ bool unpack_ok; diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 02d271d7d9d..a1be7162906 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2958,6 +2958,13 @@ int git_remote_upload( } } + if (opts && opts->push_options.count > 0) + for (i = 0; i < opts->push_options.count; ++i) { + if ((error = git_vector_insert(&push->push_options, git__strdup(opts->push_options.strings[i]))) < 0) { + goto cleanup; + } + } + if ((error = git_push_finish(push)) < 0) goto cleanup; diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c index 7f57dba2a42..4de8a3d78a4 100644 --- a/src/libgit2/transports/smart.c +++ b/src/libgit2/transports/smart.c @@ -233,6 +233,9 @@ static int git_smart__capabilities(unsigned int *capabilities, git_transport *tr *capabilities = 0; + if (t->caps.push_options) + *capabilities |= GIT_REMOTE_CAPABILITY_PUSH_OPTIONS; + if (t->caps.want_tip_sha1) *capabilities |= GIT_REMOTE_CAPABILITY_TIP_OID; diff --git a/src/libgit2/transports/smart.h b/src/libgit2/transports/smart.h index 9323d6c444e..2aea414e940 100644 --- a/src/libgit2/transports/smart.h +++ b/src/libgit2/transports/smart.h @@ -32,6 +32,7 @@ #define GIT_CAP_SYMREF "symref" #define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want" #define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want" +#define GIT_CAP_PUSH_OPTIONS "push-options" extern bool git_smart__ofs_delta_enabled; @@ -132,7 +133,8 @@ typedef struct transport_smart_caps { report_status:1, thin_pack:1, want_tip_sha1:1, - want_reachable_sha1:1; + want_reachable_sha1:1, + push_options:1; } transport_smart_caps; typedef int (*packetsize_cb)(size_t received, void *payload); diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 09778b33575..525053f420e 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -190,6 +190,12 @@ int git_smart__detect_caps(git_pkt_ref *pkt, transport_smart_caps *caps, git_vec continue; } + if (!git__prefixcmp(ptr, GIT_CAP_PUSH_OPTIONS)) { + caps->common = caps->push_options = 1; + ptr += strlen(GIT_CAP_PUSH_OPTIONS); + continue; + } + if (!git__prefixcmp(ptr, GIT_CAP_THIN_PACK)) { caps->common = caps->thin_pack = 1; ptr += strlen(GIT_CAP_THIN_PACK); @@ -642,6 +648,7 @@ int git_smart__download_pack( static int gen_pktline(git_str *buf, git_push *push) { push_spec *spec; + char *option; size_t i, len; char old_id[GIT_OID_SHA1_HEXSIZE+1], new_id[GIT_OID_SHA1_HEXSIZE+1]; @@ -654,6 +661,8 @@ static int gen_pktline(git_str *buf, git_push *push) ++len; /* '\0' */ if (push->report_status) len += strlen(GIT_CAP_REPORT_STATUS) + 1; + if (git_vector_length(&push->push_options) > 0) + len += strlen(GIT_CAP_PUSH_OPTIONS) + 1; len += strlen(GIT_CAP_SIDE_BAND_64K) + 1; } @@ -669,6 +678,10 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_REPORT_STATUS); } + if (git_vector_length(&push->push_options) > 0) { + git_str_putc(buf, ' '); + git_str_printf(buf, GIT_CAP_PUSH_OPTIONS); + } git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_SIDE_BAND_64K); } @@ -676,6 +689,12 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_putc(buf, '\n'); } + if (git_vector_length(&push->push_options) > 0) { + git_str_printf(buf, "0000"); + git_vector_foreach(&push->push_options, i, option) { + git_str_printf(buf, "%04"PRIxZ"%s", strlen(option) + 4 , option); + } + } git_str_puts(buf, "0000"); return git_str_oom(buf) ? -1 : 0; } From c45d1c6e889dd5740970d402eb3642fe8e93e482 Mon Sep 17 00:00:00 2001 From: bansheerubber Date: Tue, 19 Apr 2022 16:23:46 -0700 Subject: [PATCH 2/4] push: implement ci tests We found that the best way to test push options was to receive them via a git hooks script, and output them to a location that the CI tests could read to check and see if the push options were interpreted by git correctly. Co-Authored-By: pireads Co-Authored-By: lotdeef Co-Authored-By: PSI497 <497.psi.497@gmail.com> --- .github/workflows/main.yml | 11 +++ ci/hooks/pre-receive | 2 + ci/test.sh | 46 +++++++++++- tests/libgit2/online/push.c | 144 +++++++++++++++++++++++++++--------- 4 files changed, 168 insertions(+), 35 deletions(-) create mode 100755 ci/hooks/pre-receive diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ec1c828d67c..005d830b3ec 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -84,6 +84,17 @@ jobs: strategy: matrix: platform: + - name: "Linux (Focal, Clang, mbedTLS, push-options)" + id: focal-clang-mbedtls + container: + name: focal + env: + CC: clang-10 + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON + RUN_PUSH_OPTONS_TESTS: true + SKIP_SSH_TESTS: true + os: ubuntu-latest - name: "Linux (Xenial, GCC, OpenSSL)" id: xenial-gcc-openssl container: diff --git a/ci/hooks/pre-receive b/ci/hooks/pre-receive new file mode 100755 index 00000000000..92be65ce01f --- /dev/null +++ b/ci/hooks/pre-receive @@ -0,0 +1,2 @@ +#!/bin/sh +printf "$GIT_PUSH_OPTION_0$GIT_PUSH_OPTION_1$GIT_PUSH_OPTION_2" > %file% diff --git a/ci/test.sh b/ci/test.sh index 0e1d39e8d4f..63062f07f78 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -e +set -ex if [ -n "$SKIP_TESTS" ]; then exit 0 @@ -106,7 +106,15 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then echo "Starting git daemon (standard)..." GIT_STANDARD_DIR=`mktemp -d ${TMPDIR}/git_standard.XXXXXXXX` git init --bare "${GIT_STANDARD_DIR}/test.git" >/dev/null + git config --file "${GIT_STANDARD_DIR}/test.git/config" receive.advertisePushOptions true + for f in $(ls ${SOURCE_DIR}/ci/hooks) + do + sed "s=%file%=${TMPDIR}/push-option-result-git-daemon=g" "${SOURCE_DIR}/ci/hooks/$f" > "${GIT_STANDARD_DIR}/test.git/hooks/${f}" + chmod +x "$GIT_STANDARD_DIR/test.git/hooks/${f}" + done + git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GIT_STANDARD_DIR}" "${GIT_STANDARD_DIR}" 2>/dev/null & + GIT_STANDARD_PID=$! echo "Starting git daemon (namespace)..." @@ -134,6 +142,14 @@ if [ -z "$SKIP_NTLM_TESTS" -o -z "$SKIP_ONLINE_TESTS" ]; then echo "Starting HTTP server..." HTTP_DIR=`mktemp -d ${TMPDIR}/http.XXXXXXXX` git init --bare "${HTTP_DIR}/test.git" + git config --file "${HTTP_DIR}/test.git/config" receive.advertisePushOptions true + + for f in $(ls ${SOURCE_DIR}/ci/hooks) + do + sed "s=%file%=${TMPDIR}/push-option-result-git-ntlm=g" "${SOURCE_DIR}/ci/hooks/$f" > "${HTTP_DIR}/test.git/hooks/${f}" + chmod +x "$HTTP_DIR/test.git/hooks/${f}" + done + java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${HTTP_DIR}" & HTTP_PID=$! fi @@ -143,6 +159,14 @@ if [ -z "$SKIP_SSH_TESTS" ]; then HOME=`mktemp -d ${TMPDIR}/home.XXXXXXXX` SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX` git init --bare "${SSHD_DIR}/test.git" >/dev/null + git config --file "${SSHD_DIR}/test.git/config" receive.advertisePushOptions true + + for f in $(ls ${SOURCE_DIR}/ci/hooks) + do + sed "s=%file%=${TMPDIR}/push-option-result-git-ssh=g" "${SOURCE_DIR}/ci/hooks/$f" > "${SSHD_DIR}/test.git/hooks/${f}" + chmod +x "$SSHD_DIR/test.git/hooks/${f}" + done + cat >"${SSHD_DIR}/sshd_config" <<-EOF Port 2222 ListenAddress 0.0.0.0 @@ -243,8 +267,12 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then echo "Running gitdaemon (standard) tests" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" = "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-daemon" + fi export GITTEST_REMOTE_URL="git://localhost/test.git" run_test gitdaemon + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL echo "" @@ -289,10 +317,14 @@ if [ -z "$SKIP_NTLM_TESTS" ]; then echo "Running NTLM tests (IIS emulation)" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" = "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-ntlm" + fi export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" run_test auth_clone_and_push + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS @@ -301,10 +333,14 @@ if [ -z "$SKIP_NTLM_TESTS" ]; then echo "Running NTLM tests (Apache emulation)" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-ntlm" + fi export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" run_test auth_clone_and_push + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS @@ -354,16 +390,24 @@ if [ -z "$SKIP_SSH_TESTS" ]; then echo "Running ssh tests" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-ssh" + fi export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git" run_test ssh + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL echo "" echo "Running ssh tests (scp-style paths)" echo "" + if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then + export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-ssh" + fi export GITTEST_REMOTE_URL="[localhost:2222]:$SSHD_DIR/test.git" run_test ssh + unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER diff --git a/tests/libgit2/online/push.c b/tests/libgit2/online/push.c index d9208d28a7c..d7dbda3bcad 100644 --- a/tests/libgit2/online/push.c +++ b/tests/libgit2/online/push.c @@ -5,6 +5,7 @@ #include "push_util.h" #include "refspec.h" #include "remote.h" +#include "futils.h" static git_repository *_repo; @@ -20,6 +21,8 @@ static char *_remote_ssh_passphrase = NULL; static char *_remote_default = NULL; static char *_remote_expectcontinue = NULL; +static char *_remote_push_options_result = NULL; + static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *); static git_remote *_remote; @@ -367,6 +370,7 @@ void test_online_push__initialize(void) _remote_ssh_passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE"); _remote_default = cl_getenv("GITTEST_REMOTE_DEFAULT"); _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE"); + _remote_push_options_result = cl_getenv("GITTEST_PUSH_OPTION_RESULT"); _remote = NULL; /* Skip the test if we're missing the remote URL */ @@ -422,6 +426,7 @@ void test_online_push__cleanup(void) git__free(_remote_ssh_passphrase); git__free(_remote_default); git__free(_remote_expectcontinue); + git__free(_remote_push_options_result); /* Freed by cl_git_sandbox_cleanup */ _repo = NULL; @@ -472,7 +477,8 @@ static void do_push( const char *refspecs[], size_t refspecs_len, push_status expected_statuses[], size_t expected_statuses_len, expected_ref expected_refs[], size_t expected_refs_len, - int expected_ret, int check_progress_cb, int check_update_tips_cb) + int expected_ret, int check_progress_cb, int check_update_tips_cb, + git_strarray push_options) { git_push_options opts = GIT_PUSH_OPTIONS_INIT; size_t i; @@ -484,6 +490,9 @@ static void do_push( /* Auto-detect the number of threads to use */ opts.pb_parallelism = 0; + if(push_options.count != 0) + opts.push_options = push_options; + memcpy(&opts.callbacks, &_record_cbs, sizeof(git_remote_callbacks)); data = opts.callbacks.payload; @@ -533,7 +542,8 @@ static void do_push( /* Call push_finish() without ever calling git_push_add_refspec() */ void test_online_push__noop(void) { - do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0, 1); + git_strarray push_options = { 0 }; + do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0, 1, push_options); } void test_online_push__b1(void) @@ -541,9 +551,10 @@ void test_online_push__b1(void) const char *specs[] = { "refs/heads/b1:refs/heads/b1" }; push_status exp_stats[] = { { "refs/heads/b1", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b2(void) @@ -551,9 +562,10 @@ void test_online_push__b2(void) const char *specs[] = { "refs/heads/b2:refs/heads/b2" }; push_status exp_stats[] = { { "refs/heads/b2", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b2", &_oid_b2 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b3(void) @@ -561,9 +573,10 @@ void test_online_push__b3(void) const char *specs[] = { "refs/heads/b3:refs/heads/b3" }; push_status exp_stats[] = { { "refs/heads/b3", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b3", &_oid_b3 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b4(void) @@ -571,9 +584,10 @@ void test_online_push__b4(void) const char *specs[] = { "refs/heads/b4:refs/heads/b4" }; push_status exp_stats[] = { { "refs/heads/b4", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b4", &_oid_b4 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b5(void) @@ -581,15 +595,17 @@ void test_online_push__b5(void) const char *specs[] = { "refs/heads/b5:refs/heads/b5" }; push_status exp_stats[] = { { "refs/heads/b5", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b5", &_oid_b5 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__b5_cancel(void) { const char *specs[] = { "refs/heads/b5:refs/heads/b5" }; - do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1, 1); + git_strarray push_options = { 0 }; + do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1, 1, push_options); } void test_online_push__multi(void) @@ -618,9 +634,10 @@ void test_online_push__multi(void) { "refs/heads/b4", &_oid_b4 }, { "refs/heads/b5", &_oid_b5 } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); cl_git_pass(git_reflog_read(&log, _repo, "refs/remotes/test/b1")); entry = git_reflog_entry_byindex(log, 0); @@ -645,12 +662,14 @@ void test_online_push__implicit_tgt(void) { "refs/heads/b2", &_oid_b2 } }; + git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); + do_push(specs2, ARRAY_SIZE(specs2), exp_stats2, ARRAY_SIZE(exp_stats2), - exp_refs2, ARRAY_SIZE(exp_refs2), 0, 0, 0); + exp_refs2, ARRAY_SIZE(exp_refs2), 0, 0, 0, push_options); } void test_online_push__fast_fwd(void) @@ -670,21 +689,22 @@ void test_online_push__fast_fwd(void) /* Force should have no effect on a fast forward push */ const char *specs_ff_force[] = { "+refs/heads/b6:refs/heads/b1" }; + git_strarray push_options = { 0 }; do_push(specs_init, ARRAY_SIZE(specs_init), exp_stats_init, ARRAY_SIZE(exp_stats_init), - exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 1, 1); + exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 1, 1, push_options); do_push(specs_ff, ARRAY_SIZE(specs_ff), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), - exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0); + exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0, push_options); do_push(specs_reset, ARRAY_SIZE(specs_reset), exp_stats_init, ARRAY_SIZE(exp_stats_init), - exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 0, 0); + exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 0, 0, push_options); do_push(specs_ff_force, ARRAY_SIZE(specs_ff_force), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), - exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0); + exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0, push_options); } void test_online_push__tag_commit(void) @@ -692,9 +712,10 @@ void test_online_push__tag_commit(void) const char *specs[] = { "refs/tags/tag-commit:refs/tags/tag-commit" }; push_status exp_stats[] = { { "refs/tags/tag-commit", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-commit", &_tag_commit } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__tag_tree(void) @@ -702,9 +723,10 @@ void test_online_push__tag_tree(void) const char *specs[] = { "refs/tags/tag-tree:refs/tags/tag-tree" }; push_status exp_stats[] = { { "refs/tags/tag-tree", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-tree", &_tag_tree } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__tag_blob(void) @@ -712,9 +734,10 @@ void test_online_push__tag_blob(void) const char *specs[] = { "refs/tags/tag-blob:refs/tags/tag-blob" }; push_status exp_stats[] = { { "refs/tags/tag-blob", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-blob", &_tag_blob } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__tag_lightweight(void) @@ -722,9 +745,10 @@ void test_online_push__tag_lightweight(void) const char *specs[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" }; push_status exp_stats[] = { { "refs/tags/tag-lightweight", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-lightweight", &_tag_lightweight } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); } void test_online_push__tag_to_tag(void) @@ -732,9 +756,10 @@ void test_online_push__tag_to_tag(void) const char *specs[] = { "refs/tags/tag-tag:refs/tags/tag-tag" }; push_status exp_stats[] = { { "refs/tags/tag-tag", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-tag", &_tag_tag } }; + git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 0, 0); + exp_refs, ARRAY_SIZE(exp_refs), 0, 0, 0, push_options); } void test_online_push__force(void) @@ -749,19 +774,64 @@ void test_online_push__force(void) push_status exp_stats2_force[] = { { "refs/heads/tgt", 1 } }; expected_ref exp_refs2_force[] = { { "refs/heads/tgt", &_oid_b4 } }; + git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); do_push(specs2, ARRAY_SIZE(specs2), NULL, 0, - exp_refs1, ARRAY_SIZE(exp_refs1), GIT_ENONFASTFORWARD, 0, 0); + exp_refs1, ARRAY_SIZE(exp_refs1), GIT_ENONFASTFORWARD, 0, 0, push_options); /* Non-fast-forward update with force should pass. */ record_callbacks_data_clear(&_record_cbs_data); do_push(specs2_force, ARRAY_SIZE(specs2_force), exp_stats2_force, ARRAY_SIZE(exp_stats2_force), - exp_refs2_force, ARRAY_SIZE(exp_refs2_force), 0, 1, 1); + exp_refs2_force, ARRAY_SIZE(exp_refs2_force), 0, 1, 1, push_options); +} + +static void push_option_test(git_strarray push_options, const char *expected_option) +{ + const char *specs[] = { "refs/heads/b1:refs/heads/b1" }; + push_status exp_stats[] = { { "refs/heads/b1", 1 } }; + expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } }; + git_str push_options_result = GIT_STR_INIT; + + /* Skip the test if we're missing the push options result file */ + if (!_remote_push_options_result) + cl_skip(); + + do_push(specs, ARRAY_SIZE(specs), + exp_stats, ARRAY_SIZE(exp_stats), + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + + if (git_futils_readbuffer(&push_options_result, _remote_push_options_result) < 0) + cl_fail("Failed to read push options result file"); + + cl_assert_equal_strn(expected_option, git_str_cstr(&push_options_result), + strlen(expected_option)); + + git_str_dispose(&push_options_result); +} + +void test_online_push__options(void) +{ + char *push_options_string_args_test_1[1] = { "test_string" }; + git_strarray push_options_test_1 = { push_options_string_args_test_1, 1 }; + + char *push_options_string_args_test_2[2] = { "test_string", "another arg?" }; + git_strarray push_options_test_2 = { push_options_string_args_test_2, 2 }; + + char *push_options_string_args_test_3[1] = { "πŸ‘¨πŸΏβ€πŸ’» but can it do unicode? πŸ‡ΊπŸ‡¦" }; + git_strarray push_options_test_3 = { push_options_string_args_test_3, 1 }; + + char *push_options_string_args_test_4[3] = { "\0", "\0", "\0" }; + git_strarray push_options_test_4 = { push_options_string_args_test_4, 3 }; + + push_option_test(push_options_test_1, "test_string"); + push_option_test(push_options_test_2, "test_stringanother arg?"); + push_option_test(push_options_test_3, "πŸ‘¨πŸΏβ€πŸ’» but can it do unicode? πŸ‡ΊπŸ‡¦"); + push_option_test(push_options_test_4, "\0\0\0"); } void test_online_push__delete(void) @@ -790,9 +860,10 @@ void test_online_push__delete(void) /* Force has no effect for delete. */ const char *specs_delete_force[] = { "+:refs/heads/tgt1" }; + git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); /* When deleting a non-existent branch, the git client sends zero for both * the old and new commit id. This should succeed on the server with the @@ -802,23 +873,25 @@ void test_online_push__delete(void) */ do_push(specs_del_fake, ARRAY_SIZE(specs_del_fake), exp_stats_fake, 1, - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + do_push(specs_del_fake_force, ARRAY_SIZE(specs_del_fake_force), exp_stats_fake, 1, - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); /* Delete one of the pushed branches. */ do_push(specs_delete, ARRAY_SIZE(specs_delete), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), - exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0); + exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0, push_options); /* Re-push branches and retry delete with force. */ do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0); + exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + do_push(specs_delete_force, ARRAY_SIZE(specs_delete_force), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), - exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0); + exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0, push_options); } void test_online_push__bad_refspecs(void) @@ -845,15 +918,17 @@ void test_online_push__expressions(void) const char *specs_left_expr[] = { "refs/heads/b2~1:refs/heads/b2" }; /* TODO: Find a more precise way of checking errors than a exit code of -1. */ + git_strarray push_options = { 0 }; do_push(specs_left_expr, ARRAY_SIZE(specs_left_expr), NULL, 0, - NULL, 0, -1, 0, 0); + NULL, 0, -1, 0, 0, push_options); } void test_online_push__notes(void) { git_oid note_oid, *target_oid, expected_oid; git_signature *signature; + git_strarray push_options = { 0 }; const char *specs[] = { "refs/notes/commits:refs/notes/commits" }; push_status exp_stats[] = { { "refs/notes/commits", 1 } }; expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; @@ -869,13 +944,13 @@ void test_online_push__notes(void) do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); /* And make sure to delete the note */ do_push(specs_del, ARRAY_SIZE(specs_del), exp_stats, 1, - NULL, 0, 0, 0, 0); + NULL, 0, 0, 0, 0, push_options); git_signature_free(signature); } @@ -885,6 +960,7 @@ void test_online_push__configured(void) git_oid note_oid, *target_oid, expected_oid; git_signature *signature; git_remote *old_remote; + git_strarray push_options = { 0 }; const char *specs[] = { "refs/notes/commits:refs/notes/commits" }; push_status exp_stats[] = { { "refs/notes/commits", 1 } }; expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; @@ -905,13 +981,13 @@ void test_online_push__configured(void) do_push(NULL, 0, exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1); + exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); /* And make sure to delete the note */ do_push(specs_del, ARRAY_SIZE(specs_del), exp_stats, 1, - NULL, 0, 0, 0, 0); + NULL, 0, 0, 0, 0, push_options); git_signature_free(signature); } From 39669956fb510fb7b13289f6ce959884969dbebd Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 5 Feb 2024 10:58:14 +0000 Subject: [PATCH 3/4] push: "push_options" are now "remote_push_options" Since we use `git_push_options` as the options structure to our `git_push` command, much like we do everywhere else, "push_options" becomes ambiguous. "remote_options" isn't much better for us. Call them "remote_push_options", which is still quite bad, and not particularly insightful for end users, but at least something that we can discuss unambiguously. --- include/git2/remote.h | 4 +- src/libgit2/push.c | 11 +- src/libgit2/push.h | 2 +- src/libgit2/remote.c | 10 +- src/libgit2/transports/smart_protocol.c | 8 +- tests/libgit2/online/push.c | 167 +++++++++++++++--------- 6 files changed, 123 insertions(+), 79 deletions(-) diff --git a/include/git2/remote.h b/include/git2/remote.h index 1f41f8c787f..7ad820ad3c3 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -848,9 +848,9 @@ typedef struct { git_strarray custom_headers; /** - * Push options + * "Push options" to deliver to the remote. */ - git_strarray push_options; + git_strarray remote_push_options; } git_push_options; #define GIT_PUSH_OPTIONS_VERSION 1 diff --git a/src/libgit2/push.c b/src/libgit2/push.c index d718170c82a..e065858826a 100644 --- a/src/libgit2/push.c +++ b/src/libgit2/push.c @@ -68,7 +68,7 @@ int git_push_new(git_push **out, git_remote *remote, const git_push_options *opt return -1; } - if (git_vector_init(&p->push_options, 0, git__strcmp_cb) < 0) { + if (git_vector_init(&p->remote_push_options, 0, git__strcmp_cb) < 0) { git_vector_free(&p->status); git_vector_free(&p->specs); git_vector_free(&p->updates); @@ -505,12 +505,13 @@ int git_push_finish(git_push *push) return -1; } - if ((error = git_remote_capabilities(&remote_caps, push->remote)) < 0){ + if ((error = git_remote_capabilities(&remote_caps, push->remote)) < 0) { git_error_set(GIT_ERROR_INVALID, "remote capabilities not available"); return -1; } - if (git_vector_length(&push->push_options) > 0 && !(remote_caps & GIT_REMOTE_CAPABILITY_PUSH_OPTIONS)) { + if (git_vector_length(&push->remote_push_options) > 0 && + !(remote_caps & GIT_REMOTE_CAPABILITY_PUSH_OPTIONS)) { git_error_set(GIT_ERROR_INVALID, "push-options not supported by remote"); return -1; } @@ -581,10 +582,10 @@ void git_push_free(git_push *push) } git_vector_free(&push->updates); - git_vector_foreach(&push->push_options, i, option) { + git_vector_foreach(&push->remote_push_options, i, option) { git__free(option); } - git_vector_free(&push->push_options); + git_vector_free(&push->remote_push_options); git__free(push); } diff --git a/src/libgit2/push.h b/src/libgit2/push.h index 17c3e2f6845..40a1823e45b 100644 --- a/src/libgit2/push.h +++ b/src/libgit2/push.h @@ -34,7 +34,7 @@ struct git_push { git_vector specs; git_vector updates; bool report_status; - git_vector push_options; + git_vector remote_push_options; /* report-status */ bool unpack_ok; diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 4adc57c4d09..9eb4bac8b2f 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -2982,11 +2982,13 @@ int git_remote_upload( } } - if (opts && opts->push_options.count > 0) - for (i = 0; i < opts->push_options.count; ++i) { - if ((error = git_vector_insert(&push->push_options, git__strdup(opts->push_options.strings[i]))) < 0) { + if (opts && opts->remote_push_options.count > 0) + for (i = 0; i < opts->remote_push_options.count; ++i) { + char *optstr = git__strdup(opts->remote_push_options.strings[i]); + GIT_ERROR_CHECK_ALLOC(optstr); + + if ((error = git_vector_insert(&push->remote_push_options, optstr)) < 0) goto cleanup; - } } if ((error = git_push_finish(push)) < 0) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index 85ad65c6227..13f97b7274f 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -797,7 +797,7 @@ static int gen_pktline(git_str *buf, git_push *push) ++len; /* '\0' */ if (push->report_status) len += strlen(GIT_CAP_REPORT_STATUS) + 1; - if (git_vector_length(&push->push_options) > 0) + if (git_vector_length(&push->remote_push_options) > 0) len += strlen(GIT_CAP_PUSH_OPTIONS) + 1; len += strlen(GIT_CAP_SIDE_BAND_64K) + 1; } @@ -814,7 +814,7 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_REPORT_STATUS); } - if (git_vector_length(&push->push_options) > 0) { + if (git_vector_length(&push->remote_push_options) > 0) { git_str_putc(buf, ' '); git_str_printf(buf, GIT_CAP_PUSH_OPTIONS); } @@ -825,9 +825,9 @@ static int gen_pktline(git_str *buf, git_push *push) git_str_putc(buf, '\n'); } - if (git_vector_length(&push->push_options) > 0) { + if (git_vector_length(&push->remote_push_options) > 0) { git_str_printf(buf, "0000"); - git_vector_foreach(&push->push_options, i, option) { + git_vector_foreach(&push->remote_push_options, i, option) { git_str_printf(buf, "%04"PRIxZ"%s", strlen(option) + 4 , option); } } diff --git a/tests/libgit2/online/push.c b/tests/libgit2/online/push.c index 1f5f141f53b..cfd43209da4 100644 --- a/tests/libgit2/online/push.c +++ b/tests/libgit2/online/push.c @@ -26,7 +26,7 @@ static char *_ssh_cmd = NULL; static char *_remote_push_options_result = NULL; -static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *); +static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *); static git_remote *_remote; static record_callbacks_data _record_cbs_data = {{ 0 }}; @@ -492,7 +492,7 @@ static void do_push( push_status expected_statuses[], size_t expected_statuses_len, expected_ref expected_refs[], size_t expected_refs_len, int expected_ret, int check_progress_cb, int check_update_tips_cb, - git_strarray push_options) + git_strarray *remote_push_options) { git_push_options opts = GIT_PUSH_OPTIONS_INIT; size_t i; @@ -504,8 +504,8 @@ static void do_push( /* Auto-detect the number of threads to use */ opts.pb_parallelism = 0; - if(push_options.count != 0) - opts.push_options = push_options; + if (remote_push_options) + memcpy(&opts.remote_push_options, remote_push_options, sizeof(git_strarray)); memcpy(&opts.callbacks, &_record_cbs, sizeof(git_remote_callbacks)); data = opts.callbacks.payload; @@ -550,14 +550,12 @@ static void do_push( verify_update_tips_callback(_remote, expected_refs, expected_refs_len); } - } /* Call push_finish() without ever calling git_push_add_refspec() */ void test_online_push__noop(void) { - git_strarray push_options = { 0 }; - do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0, 1, push_options); + do_push(NULL, 0, NULL, 0, NULL, 0, 0, 0, 1, NULL); } void test_online_push__b1(void) @@ -565,10 +563,11 @@ void test_online_push__b1(void) const char *specs[] = { "refs/heads/b1:refs/heads/b1" }; push_status exp_stats[] = { { "refs/heads/b1", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b2(void) @@ -576,10 +575,11 @@ void test_online_push__b2(void) const char *specs[] = { "refs/heads/b2:refs/heads/b2" }; push_status exp_stats[] = { { "refs/heads/b2", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b2", &_oid_b2 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b3(void) @@ -587,10 +587,11 @@ void test_online_push__b3(void) const char *specs[] = { "refs/heads/b3:refs/heads/b3" }; push_status exp_stats[] = { { "refs/heads/b3", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b3", &_oid_b3 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b4(void) @@ -598,10 +599,11 @@ void test_online_push__b4(void) const char *specs[] = { "refs/heads/b4:refs/heads/b4" }; push_status exp_stats[] = { { "refs/heads/b4", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b4", &_oid_b4 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b5(void) @@ -609,17 +611,17 @@ void test_online_push__b5(void) const char *specs[] = { "refs/heads/b5:refs/heads/b5" }; push_status exp_stats[] = { { "refs/heads/b5", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b5", &_oid_b5 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__b5_cancel(void) { const char *specs[] = { "refs/heads/b5:refs/heads/b5" }; - git_strarray push_options = { 0 }; - do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1, 1, push_options); + do_push(specs, ARRAY_SIZE(specs), NULL, 0, NULL, 0, GIT_EUSER, 1, 1, NULL); } void test_online_push__multi(void) @@ -648,10 +650,11 @@ void test_online_push__multi(void) { "refs/heads/b4", &_oid_b4 }, { "refs/heads/b5", &_oid_b5 } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); cl_git_pass(git_reflog_read(&log, _repo, "refs/remotes/test/b1")); entry = git_reflog_entry_byindex(log, 0); @@ -672,18 +675,21 @@ void test_online_push__implicit_tgt(void) const char *specs2[] = { "refs/heads/b2" }; push_status exp_stats2[] = { { "refs/heads/b2", 1 } }; expected_ref exp_refs2[] = { - { "refs/heads/b1", &_oid_b1 }, - { "refs/heads/b2", &_oid_b2 } + { "refs/heads/b1", &_oid_b1 }, + { "refs/heads/b2", &_oid_b2 } }; - git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 1, 1, + NULL); do_push(specs2, ARRAY_SIZE(specs2), exp_stats2, ARRAY_SIZE(exp_stats2), - exp_refs2, ARRAY_SIZE(exp_refs2), 0, 0, 0, push_options); + exp_refs2, ARRAY_SIZE(exp_refs2), + 0, 0, 0, + NULL); } void test_online_push__fast_fwd(void) @@ -703,22 +709,29 @@ void test_online_push__fast_fwd(void) /* Force should have no effect on a fast forward push */ const char *specs_ff_force[] = { "+refs/heads/b6:refs/heads/b1" }; - git_strarray push_options = { 0 }; do_push(specs_init, ARRAY_SIZE(specs_init), exp_stats_init, ARRAY_SIZE(exp_stats_init), - exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 1, 1, push_options); + exp_refs_init, ARRAY_SIZE(exp_refs_init), + 0, 1, 1, + NULL); do_push(specs_ff, ARRAY_SIZE(specs_ff), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), - exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0, push_options); + exp_refs_ff, ARRAY_SIZE(exp_refs_ff), + 0, 0, 0, + NULL); do_push(specs_reset, ARRAY_SIZE(specs_reset), exp_stats_init, ARRAY_SIZE(exp_stats_init), - exp_refs_init, ARRAY_SIZE(exp_refs_init), 0, 0, 0, push_options); + exp_refs_init, ARRAY_SIZE(exp_refs_init), + 0, 0, 0, + NULL); do_push(specs_ff_force, ARRAY_SIZE(specs_ff_force), exp_stats_ff, ARRAY_SIZE(exp_stats_ff), - exp_refs_ff, ARRAY_SIZE(exp_refs_ff), 0, 0, 0, push_options); + exp_refs_ff, ARRAY_SIZE(exp_refs_ff), + 0, 0, 0, + NULL); } void test_online_push__tag_commit(void) @@ -726,10 +739,11 @@ void test_online_push__tag_commit(void) const char *specs[] = { "refs/tags/tag-commit:refs/tags/tag-commit" }; push_status exp_stats[] = { { "refs/tags/tag-commit", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-commit", &_tag_commit } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__tag_tree(void) @@ -737,10 +751,11 @@ void test_online_push__tag_tree(void) const char *specs[] = { "refs/tags/tag-tree:refs/tags/tag-tree" }; push_status exp_stats[] = { { "refs/tags/tag-tree", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-tree", &_tag_tree } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__tag_blob(void) @@ -748,10 +763,11 @@ void test_online_push__tag_blob(void) const char *specs[] = { "refs/tags/tag-blob:refs/tags/tag-blob" }; push_status exp_stats[] = { { "refs/tags/tag-blob", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-blob", &_tag_blob } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__tag_lightweight(void) @@ -759,10 +775,11 @@ void test_online_push__tag_lightweight(void) const char *specs[] = { "refs/tags/tag-lightweight:refs/tags/tag-lightweight" }; push_status exp_stats[] = { { "refs/tags/tag-lightweight", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-lightweight", &_tag_lightweight } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__tag_to_tag(void) @@ -770,10 +787,11 @@ void test_online_push__tag_to_tag(void) const char *specs[] = { "refs/tags/tag-tag:refs/tags/tag-tag" }; push_status exp_stats[] = { { "refs/tags/tag-tag", 1 } }; expected_ref exp_refs[] = { { "refs/tags/tag-tag", &_tag_tag } }; - git_strarray push_options = { 0 }; do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 0, 0, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 0, 0, + NULL); } void test_online_push__force(void) @@ -788,20 +806,25 @@ void test_online_push__force(void) push_status exp_stats2_force[] = { { "refs/heads/tgt", 1 } }; expected_ref exp_refs2_force[] = { { "refs/heads/tgt", &_oid_b4 } }; - git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 1, 1, + NULL); do_push(specs2, ARRAY_SIZE(specs2), NULL, 0, - exp_refs1, ARRAY_SIZE(exp_refs1), GIT_ENONFASTFORWARD, 0, 0, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + GIT_ENONFASTFORWARD, 0, 0, + NULL); /* Non-fast-forward update with force should pass. */ record_callbacks_data_clear(&_record_cbs_data); do_push(specs2_force, ARRAY_SIZE(specs2_force), exp_stats2_force, ARRAY_SIZE(exp_stats2_force), - exp_refs2_force, ARRAY_SIZE(exp_refs2_force), 0, 1, 1, push_options); + exp_refs2_force, ARRAY_SIZE(exp_refs2_force), + 0, 1, 1, + NULL); } static void push_option_test(git_strarray push_options, const char *expected_option) @@ -817,7 +840,9 @@ static void push_option_test(git_strarray push_options, const char *expected_opt do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + &push_options); if (git_futils_readbuffer(&push_options_result, _remote_push_options_result) < 0) cl_fail("Failed to read push options result file"); @@ -874,10 +899,11 @@ void test_online_push__delete(void) /* Force has no effect for delete. */ const char *specs_delete_force[] = { "+:refs/heads/tgt1" }; - git_strarray push_options = { 0 }; do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 1, 1, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 1, 1, + NULL); /* When deleting a non-existent branch, the git client sends zero for both * the old and new commit id. This should succeed on the server with the @@ -887,25 +913,35 @@ void test_online_push__delete(void) */ do_push(specs_del_fake, ARRAY_SIZE(specs_del_fake), exp_stats_fake, 1, - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 0, 0, + NULL); do_push(specs_del_fake_force, ARRAY_SIZE(specs_del_fake_force), exp_stats_fake, 1, - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 0, 0, + NULL); /* Delete one of the pushed branches. */ do_push(specs_delete, ARRAY_SIZE(specs_delete), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), - exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0, push_options); + exp_refs_delete, ARRAY_SIZE(exp_refs_delete), + 0, 0, 0, + NULL); /* Re-push branches and retry delete with force. */ do_push(specs1, ARRAY_SIZE(specs1), exp_stats1, ARRAY_SIZE(exp_stats1), - exp_refs1, ARRAY_SIZE(exp_refs1), 0, 0, 0, push_options); + exp_refs1, ARRAY_SIZE(exp_refs1), + 0, 0, 0, + NULL); do_push(specs_delete_force, ARRAY_SIZE(specs_delete_force), exp_stats_delete, ARRAY_SIZE(exp_stats_delete), - exp_refs_delete, ARRAY_SIZE(exp_refs_delete), 0, 0, 0, push_options); + exp_refs_delete, ARRAY_SIZE(exp_refs_delete), + 0, 0, 0, + NULL); } void test_online_push__bad_refspecs(void) @@ -947,19 +983,17 @@ void test_online_push__expressions(void) { "refs/heads/b6", &_oid_b6 } }; - git_strarray push_options = { 0 }; - do_push(specs_left_expr, ARRAY_SIZE(specs_left_expr), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, - push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); } void test_online_push__notes(void) { git_oid note_oid, *target_oid, expected_oid; git_signature *signature; - git_strarray push_options = { 0 }; const char *specs[] = { "refs/notes/commits:refs/notes/commits" }; push_status exp_stats[] = { { "refs/notes/commits", 1 } }; expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; @@ -975,13 +1009,17 @@ void test_online_push__notes(void) do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); /* And make sure to delete the note */ do_push(specs_del, ARRAY_SIZE(specs_del), exp_stats, 1, - NULL, 0, 0, 0, 0, push_options); + NULL, 0, + 0, 0, 0, + NULL); git_signature_free(signature); } @@ -991,7 +1029,6 @@ void test_online_push__configured(void) git_oid note_oid, *target_oid, expected_oid; git_signature *signature; git_remote *old_remote; - git_strarray push_options = { 0 }; const char *specs[] = { "refs/notes/commits:refs/notes/commits" }; push_status exp_stats[] = { { "refs/notes/commits", 1 } }; expected_ref exp_refs[] = { { "refs/notes/commits", &expected_oid } }; @@ -1012,13 +1049,17 @@ void test_online_push__configured(void) do_push(NULL, 0, exp_stats, ARRAY_SIZE(exp_stats), - exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, push_options); + exp_refs, ARRAY_SIZE(exp_refs), + 0, 1, 1, + NULL); /* And make sure to delete the note */ do_push(specs_del, ARRAY_SIZE(specs_del), exp_stats, 1, - NULL, 0, 0, 0, 0, push_options); + NULL, 0, + 0, 0, 0, + NULL); git_signature_free(signature); } From 85279f06aae1796d1551609041c5e0cf691bb297 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Mon, 5 Feb 2024 11:48:19 +0000 Subject: [PATCH 4/4] ci: update push options tests Keep the push options tests more constrained to our CI environment; writing files within the test sandbox instead of outside of it. Provide the path to the output file in the test data. In addition, add the repository to the test resources instead of recreating the hooks every time. --- ci/hooks/pre-receive | 2 - ci/test.sh | 60 +++++-------------- tests/libgit2/online/push.c | 34 +++++++---- tests/resources/pushoptions.git/HEAD | 1 + .../pushoptions.git/branches/.gitignore | 0 tests/resources/pushoptions.git/config | 8 +++ tests/resources/pushoptions.git/description | 1 + .../pushoptions.git/hooks/pre-receive | 3 + tests/resources/pushoptions.git/info/exclude | 6 ++ .../pushoptions.git/objects/info/.gitignore | 0 .../pushoptions.git/objects/pack/.gitignore | 0 .../pushoptions.git/refs/heads/.gitignore | 0 .../pushoptions.git/refs/tags/.gitignore | 0 13 files changed, 57 insertions(+), 58 deletions(-) delete mode 100755 ci/hooks/pre-receive create mode 100644 tests/resources/pushoptions.git/HEAD create mode 100644 tests/resources/pushoptions.git/branches/.gitignore create mode 100644 tests/resources/pushoptions.git/config create mode 100644 tests/resources/pushoptions.git/description create mode 100755 tests/resources/pushoptions.git/hooks/pre-receive create mode 100644 tests/resources/pushoptions.git/info/exclude create mode 100644 tests/resources/pushoptions.git/objects/info/.gitignore create mode 100644 tests/resources/pushoptions.git/objects/pack/.gitignore create mode 100644 tests/resources/pushoptions.git/refs/heads/.gitignore create mode 100644 tests/resources/pushoptions.git/refs/tags/.gitignore diff --git a/ci/hooks/pre-receive b/ci/hooks/pre-receive deleted file mode 100755 index 92be65ce01f..00000000000 --- a/ci/hooks/pre-receive +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -printf "$GIT_PUSH_OPTION_0$GIT_PUSH_OPTION_1$GIT_PUSH_OPTION_2" > %file% diff --git a/ci/test.sh b/ci/test.sh index 8543169ce5c..4217568226a 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -set -ex +set -e if [ -n "$SKIP_TESTS" ]; then if [ -z "$SKIP_OFFLINE_TESTS" ]; then SKIP_OFFLINE_TESTS=1; fi @@ -162,14 +162,7 @@ echo "" if should_run "GITDAEMON_TESTS"; then echo "Starting git daemon (standard)..." GIT_STANDARD_DIR=`mktemp -d ${TMPDIR}/git_standard.XXXXXXXX` - git init --bare "${GIT_STANDARD_DIR}/test.git" >/dev/null - git config --file "${GIT_STANDARD_DIR}/test.git/config" receive.advertisePushOptions true - for f in $(ls ${SOURCE_DIR}/ci/hooks) - do - sed "s=%file%=${TMPDIR}/push-option-result-git-daemon=g" "${SOURCE_DIR}/ci/hooks/$f" > "${GIT_STANDARD_DIR}/test.git/hooks/${f}" - chmod +x "$GIT_STANDARD_DIR/test.git/hooks/${f}" - done - + cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${GIT_STANDARD_DIR}/test.git" git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GIT_STANDARD_DIR}" "${GIT_STANDARD_DIR}" 2>/dev/null & GIT_STANDARD_PID=$! @@ -204,14 +197,7 @@ if should_run "NTLM_TESTS" || should_run "ONLINE_TESTS"; then echo "Starting HTTP server..." HTTP_DIR=`mktemp -d ${TMPDIR}/http.XXXXXXXX` - git init --bare "${HTTP_DIR}/test.git" - git config --file "${HTTP_DIR}/test.git/config" receive.advertisePushOptions true - - for f in $(ls ${SOURCE_DIR}/ci/hooks) - do - sed "s=%file%=${TMPDIR}/push-option-result-git-ntlm=g" "${SOURCE_DIR}/ci/hooks/$f" > "${HTTP_DIR}/test.git/hooks/${f}" - chmod +x "$HTTP_DIR/test.git/hooks/${f}" - done + cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${HTTP_DIR}/test.git" java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${HTTP_DIR}" & HTTP_PID=$! @@ -220,14 +206,8 @@ fi if should_run "SSH_TESTS"; then echo "Starting SSH server..." SSHD_DIR=`mktemp -d ${TMPDIR}/sshd.XXXXXXXX` - git init --bare "${SSHD_DIR}/test.git" >/dev/null - git config --file "${SSHD_DIR}/test.git/config" receive.advertisePushOptions true - - for f in $(ls ${SOURCE_DIR}/ci/hooks) - do - sed "s=%file%=${TMPDIR}/push-option-result-git-ssh=g" "${SOURCE_DIR}/ci/hooks/$f" > "${SSHD_DIR}/test.git/hooks/${f}" - chmod +x "$SSHD_DIR/test.git/hooks/${f}" - done + cp -R "${SOURCE_DIR}/tests/resources/pushoptions.git" "${SSHD_DIR}/test.git" + ls -FlasR "${SSHD_DIR}" cat >"${SSHD_DIR}/sshd_config" <<-EOF Port 2222 @@ -344,13 +324,11 @@ if should_run "GITDAEMON_TESTS"; then echo "Running gitdaemon (standard) tests" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" = "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-daemon" - fi export GITTEST_REMOTE_URL="git://localhost/test.git" + export GITTEST_PUSH_OPTIONS=true run_test gitdaemon - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL + unset GITTEST_PUSH_OPTIONS echo "" echo "Running gitdaemon (namespace) tests" @@ -402,33 +380,29 @@ if should_run "NTLM_TESTS"; then echo "Running NTLM tests (IIS emulation)" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" = "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-ntlm" - fi export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" + export GITTEST_PUSH_OPTIONS=true run_test auth_clone_and_push - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS + unset GITTEST_PUSH_OPTIONS echo "" echo "Running NTLM tests (Apache emulation)" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-git-ntlm" - fi export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git" export GITTEST_REMOTE_USER="foo" export GITTEST_REMOTE_PASS="baz" + export GITTEST_PUSH_OPTIONS=true run_test auth_clone_and_push - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL unset GITTEST_REMOTE_USER unset GITTEST_REMOTE_PASS + unset GITTEST_PUSH_OPTIONS fi if should_run "NEGOTIATE_TESTS" && -n "$GITTEST_NEGOTIATE_PASSWORD" ; then @@ -477,25 +451,21 @@ if should_run "SSH_TESTS"; then echo "Running ssh tests" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-ssh" - fi export GITTEST_REMOTE_URL="ssh://localhost:2222/$SSHD_DIR/test.git" + export GITTEST_PUSH_OPTIONS=true run_test ssh - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL + unset GITTEST_PUSH_OPTIONS echo "" echo "Running ssh tests (scp-style paths)" echo "" - if [[ "$RUN_PUSH_OPTONS_TESTS" == "true " ]]; then - export GITTEST_PUSH_OPTION_RESULT="${TMPDIR}/push-option-result-ssh" - fi export GITTEST_REMOTE_URL="[localhost:2222]:$SSHD_DIR/test.git" + export GITTEST_PUSH_OPTIONS=true run_test ssh - unset GITTEST_PUSH_OPTION_RESULT unset GITTEST_REMOTE_URL + unset GITTEST_PUSH_OPTIONS unset GITTEST_SSH_CMD diff --git a/tests/libgit2/online/push.c b/tests/libgit2/online/push.c index cfd43209da4..e5693bf346c 100644 --- a/tests/libgit2/online/push.c +++ b/tests/libgit2/online/push.c @@ -21,11 +21,11 @@ static char *_remote_ssh_passphrase = NULL; static char *_remote_default = NULL; static char *_remote_expectcontinue = NULL; +static char *_remote_push_options = NULL; + static char *_orig_ssh_cmd = NULL; static char *_ssh_cmd = NULL; -static char *_remote_push_options_result = NULL; - static int cred_acquire_cb(git_credential **, const char *, const char *, unsigned int, void *); static git_remote *_remote; @@ -373,7 +373,7 @@ void test_online_push__initialize(void) _remote_ssh_passphrase = cl_getenv("GITTEST_REMOTE_SSH_PASSPHRASE"); _remote_default = cl_getenv("GITTEST_REMOTE_DEFAULT"); _remote_expectcontinue = cl_getenv("GITTEST_REMOTE_EXPECTCONTINUE"); - _remote_push_options_result = cl_getenv("GITTEST_PUSH_OPTION_RESULT"); + _remote_push_options = cl_getenv("GITTEST_PUSH_OPTIONS"); _remote = NULL; _orig_ssh_cmd = cl_getenv("GIT_SSH"); @@ -437,7 +437,7 @@ void test_online_push__cleanup(void) git__free(_remote_ssh_passphrase); git__free(_remote_default); git__free(_remote_expectcontinue); - git__free(_remote_push_options_result); + git__free(_remote_push_options); git__free(_orig_ssh_cmd); git__free(_ssh_cmd); @@ -449,6 +449,7 @@ void test_online_push__cleanup(void) record_callbacks_data_clear(&_record_cbs_data); + cl_fixture_cleanup("push-options-result"); cl_fixture_cleanup("testrepo.git"); cl_git_sandbox_cleanup(); } @@ -827,30 +828,41 @@ void test_online_push__force(void) NULL); } -static void push_option_test(git_strarray push_options, const char *expected_option) +static void push_option_test(git_strarray given_options, const char *expected_option) { const char *specs[] = { "refs/heads/b1:refs/heads/b1" }; push_status exp_stats[] = { { "refs/heads/b1", 1 } }; expected_ref exp_refs[] = { { "refs/heads/b1", &_oid_b1 } }; + git_str push_options_path = GIT_STR_INIT; git_str push_options_result = GIT_STR_INIT; + char *options[16]; + git_strarray push_options = { options, given_options.count + 1 }; + size_t i; /* Skip the test if we're missing the push options result file */ - if (!_remote_push_options_result) + if (!_remote_push_options) cl_skip(); + cl_assert(given_options.count < 16); + + cl_git_pass(git_str_joinpath(&push_options_path, clar_sandbox_path(), "push-options-result")); + + options[0] = push_options_path.ptr; + for (i = 0; i < given_options.count; i++) + options[i + 1] = given_options.strings[i]; + do_push(specs, ARRAY_SIZE(specs), exp_stats, ARRAY_SIZE(exp_stats), exp_refs, ARRAY_SIZE(exp_refs), 0, 1, 1, &push_options); - if (git_futils_readbuffer(&push_options_result, _remote_push_options_result) < 0) - cl_fail("Failed to read push options result file"); - - cl_assert_equal_strn(expected_option, git_str_cstr(&push_options_result), - strlen(expected_option)); + cl_assert(git_fs_path_exists(push_options_path.ptr)); + cl_git_pass(git_futils_readbuffer(&push_options_result, push_options_path.ptr)); + cl_assert_equal_s(expected_option, git_str_cstr(&push_options_result)); git_str_dispose(&push_options_result); + git_str_dispose(&push_options_path); } void test_online_push__options(void) diff --git a/tests/resources/pushoptions.git/HEAD b/tests/resources/pushoptions.git/HEAD new file mode 100644 index 00000000000..b870d82622c --- /dev/null +++ b/tests/resources/pushoptions.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/main diff --git a/tests/resources/pushoptions.git/branches/.gitignore b/tests/resources/pushoptions.git/branches/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/resources/pushoptions.git/config b/tests/resources/pushoptions.git/config new file mode 100644 index 00000000000..23d39788fa7 --- /dev/null +++ b/tests/resources/pushoptions.git/config @@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true + ignorecase = true + precomposeunicode = true +[receive] + advertisePushOptions = true diff --git a/tests/resources/pushoptions.git/description b/tests/resources/pushoptions.git/description new file mode 100644 index 00000000000..498b267a8c7 --- /dev/null +++ b/tests/resources/pushoptions.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests/resources/pushoptions.git/hooks/pre-receive b/tests/resources/pushoptions.git/hooks/pre-receive new file mode 100755 index 00000000000..24f48d34c54 --- /dev/null +++ b/tests/resources/pushoptions.git/hooks/pre-receive @@ -0,0 +1,3 @@ +#!/bin/sh +printf "${GIT_PUSH_OPTION_1}${GIT_PUSH_OPTION_2}${GIT_PUSH_OPTION_3}" > "${GIT_PUSH_OPTION_0}" +exit 0 diff --git a/tests/resources/pushoptions.git/info/exclude b/tests/resources/pushoptions.git/info/exclude new file mode 100644 index 00000000000..a5196d1be8f --- /dev/null +++ b/tests/resources/pushoptions.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests/resources/pushoptions.git/objects/info/.gitignore b/tests/resources/pushoptions.git/objects/info/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/resources/pushoptions.git/objects/pack/.gitignore b/tests/resources/pushoptions.git/objects/pack/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/resources/pushoptions.git/refs/heads/.gitignore b/tests/resources/pushoptions.git/refs/heads/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/resources/pushoptions.git/refs/tags/.gitignore b/tests/resources/pushoptions.git/refs/tags/.gitignore new file mode 100644 index 00000000000..e69de29bb2d