diff --git a/include/git2/remote.h b/include/git2/remote.h index 0d7fd230f..bb5aac4e1 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -14,6 +14,7 @@ #include "indexer.h" #include "strarray.h" #include "transport.h" +#include "push.h" /** * @file git2/remote.h @@ -389,6 +390,22 @@ GIT_EXTERN(int) git_remote_fetch( const git_signature *signature, const char *reflog_message); +/** + * Perform a push + * + * Peform all the steps from a push. + * + * @param remote the remote to push to + * @param refspecs the refspecs to use for pushing + * @param opts the options + * @param signature signature to use for the reflog of updated references + * @param reflog_message message to use for the reflog of upated references + */ +GIT_EXTERN(int) git_remote_push(git_remote *remote, + git_strarray *refspecs, + const git_push_options *opts, + const git_signature *signature, const char *reflog_message); + /** * Get a list of the configured remotes for a repo * @@ -461,6 +478,28 @@ struct git_remote_callbacks { */ int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data); + /** + * Function to call with progress information during pack + * building. Be aware that this is called inline with pack + * building operations, so performance may be affected. + */ + git_packbuilder_progress pack_progress; + + /** + * Function to call with progress information during the + * upload portion of a push. Be aware that this is called + * inline with pack building operations, so performance may be + * affected. + */ + git_push_transfer_progress push_transfer_progress; + + /** + * Called for each updated reference on push. If `status` is + * not `NULL`, the update was rejected by the remote server + * and `status` contains the reason given. + */ + int (*push_update_reference)(const char *refname, const char *status, void *data); + /** * This will be passed to each of the callbacks in this struct * as the last parameter. diff --git a/src/remote.c b/src/remote.c index cc9f85cd1..524d5a3d4 100644 --- a/src/remote.c +++ b/src/remote.c @@ -2111,3 +2111,53 @@ int git_remote_default_branch(git_buf *out, git_remote *remote) return git_buf_puts(out, guess->name); } + +int git_remote_push(git_remote *remote, git_strarray *refspecs, const git_push_options *opts, + const git_signature *signature, const char *reflog_message) +{ + int error; + size_t i; + git_push *push = NULL; + git_remote_callbacks *cbs; + + assert(remote && refspecs); + + if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH)) < 0) + return error; + + if ((error = git_push_new(&push, remote)) < 0) + goto cleanup; + + if (opts && (error = git_push_set_options(push, opts)) < 0) + goto cleanup; + + for (i = 0; i < refspecs->count; i++) { + if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0) + goto cleanup; + } + + cbs = &remote->callbacks; + if ((error = git_push_set_callbacks(push, + cbs->pack_progress, cbs->payload, + cbs->push_transfer_progress, cbs->payload)) < 0) + goto cleanup; + + if ((error = git_push_finish(push)) < 0) + goto cleanup; + + if (!git_push_unpack_ok(push)) { + error = -1; + giterr_set(GITERR_NET, "error in the remote while trying to unpack"); + goto cleanup; + } + + if ((error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0) + goto cleanup; + + error = git_push_update_tips(push, signature, reflog_message); + +cleanup: + git_remote_disconnect(remote); + git_push_free(push); + return error; +} diff --git a/tests/online/push_util.h b/tests/online/push_util.h index 7736912d6..3d4a38834 100644 --- a/tests/online/push_util.h +++ b/tests/online/push_util.h @@ -12,7 +12,7 @@ extern const git_oid OID_ZERO; * @param data pointer to a record_callbacks_data instance */ #define RECORD_CALLBACKS_INIT(data) \ - { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, data } + { GIT_REMOTE_CALLBACKS_VERSION, NULL, NULL, cred_acquire_cb, NULL, NULL, record_update_tips_cb, NULL, NULL, NULL, data } typedef struct { char *name;