Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
45301cca
Commit
45301cca
authored
Nov 18, 2014
by
Edward Thomson
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2608 from libgit2/cmn/remote-push
Provide a convenience function `git_remote_push()`
parents
8b5b814e
64e3e6d4
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
214 additions
and
59 deletions
+214
-59
include/git2/remote.h
+40
-0
src/remote.c
+60
-0
tests/online/push.c
+85
-58
tests/online/push_util.c
+16
-0
tests/online/push_util.h
+13
-1
No files found.
include/git2/remote.h
View file @
45301cca
...
...
@@ -14,6 +14,7 @@
#include "indexer.h"
#include "strarray.h"
#include "transport.h"
#include "push.h"
/**
* @file git2/remote.h
...
...
@@ -390,6 +391,23 @@ GIT_EXTERN(int) git_remote_fetch(
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. If none are
* passed, the configured refspecs will be used
* @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
*
* The string array must be freed by the user.
...
...
@@ -462,6 +480,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.
*/
...
...
src/remote.c
View file @
45301cca
...
...
@@ -2115,3 +2115,63 @@ 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
;
git_refspec
*
spec
;
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
;
if
(
refspecs
&&
refspecs
->
count
>
0
)
{
for
(
i
=
0
;
i
<
refspecs
->
count
;
i
++
)
{
if
((
error
=
git_push_add_refspec
(
push
,
refspecs
->
strings
[
i
]))
<
0
)
goto
cleanup
;
}
}
else
{
git_vector_foreach
(
&
remote
->
refspecs
,
i
,
spec
)
{
if
(
!
spec
->
push
)
continue
;
if
((
error
=
git_push_add_refspec
(
push
,
spec
->
string
))
<
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
;
}
tests/online/push.c
View file @
45301cca
...
...
@@ -89,46 +89,38 @@ static int cred_acquire_cb(
return
-
1
;
}
/* the results of a push status. when used for expected values, msg may be NULL
* to indicate that it should not be matched. */
typedef
struct
{
const
char
*
ref
;
int
success
;
const
char
*
msg
;
}
push_status
;
/**
* git_push_status_foreach callback that records status entries.
* @param data (git_vector *) of push_status instances
*/
static
int
record_push_status_cb
(
const
char
*
ref
,
const
char
*
msg
,
void
*
data
)
static
int
record_push_status_cb
(
const
char
*
ref
,
const
char
*
msg
,
void
*
payload
)
{
git_vector
*
statuses
=
(
git_vector
*
)
data
;
record_callbacks_data
*
data
=
(
record_callbacks_data
*
)
payload
;
push_status
*
s
;
cl_assert
(
s
=
git__malloc
(
sizeof
(
*
s
)));
s
->
ref
=
ref
;
cl_assert
(
s
=
git__calloc
(
1
,
sizeof
(
*
s
)));
if
(
ref
)
cl_assert
(
s
->
ref
=
git__strdup
(
ref
));
s
->
success
=
(
msg
==
NULL
);
s
->
msg
=
msg
;
if
(
msg
)
cl_assert
(
s
->
msg
=
git__strdup
(
msg
));
git_vector_insert
(
statuses
,
s
);
git_vector_insert
(
&
data
->
statuses
,
s
);
return
0
;
}
static
void
do_verify_push_status
(
git_push
*
push
,
const
push_status
expected
[],
const
size_t
expected_len
)
static
void
do_verify_push_status
(
record_callbacks_data
*
data
,
const
push_status
expected
[],
const
size_t
expected_len
)
{
git_vector
actual
=
GIT_VECTOR_INIT
;
git_vector
*
actual
=
&
data
->
statuses
;
push_status
*
iter
;
bool
failed
=
false
;
size_t
i
;
git_push_status_foreach
(
push
,
record_push_status_cb
,
&
actual
);
if
(
expected_len
!=
actual
.
length
)
if
(
expected_len
!=
actual
->
length
)
failed
=
true
;
else
git_vector_foreach
(
&
actual
,
i
,
iter
)
git_vector_foreach
(
actual
,
i
,
iter
)
if
(
strcmp
(
expected
[
i
].
ref
,
iter
->
ref
)
||
(
expected
[
i
].
success
!=
iter
->
success
)
||
(
expected
[
i
].
msg
&&
(
!
iter
->
msg
||
strcmp
(
expected
[
i
].
msg
,
iter
->
msg
))))
{
...
...
@@ -149,7 +141,7 @@ static void do_verify_push_status(git_push *push, const push_status expected[],
git_buf_puts
(
&
msg
,
"
\n
ACTUAL:
\n
"
);
git_vector_foreach
(
&
actual
,
i
,
iter
)
{
git_vector_foreach
(
actual
,
i
,
iter
)
{
if
(
iter
->
success
)
git_buf_printf
(
&
msg
,
"%s: success
\n
"
,
iter
->
ref
);
else
...
...
@@ -161,10 +153,10 @@ static void do_verify_push_status(git_push *push, const push_status expected[],
git_buf_free
(
&
msg
);
}
git_vector_foreach
(
&
actual
,
i
,
iter
)
git_vector_foreach
(
actual
,
i
,
iter
)
git__free
(
iter
);
git_vector_free
(
&
actual
);
git_vector_free
(
actual
);
}
/**
...
...
@@ -431,22 +423,24 @@ void test_online_push__cleanup(void)
static
int
push_pack_progress_cb
(
int
stage
,
unsigned
int
current
,
unsigned
int
total
,
void
*
payload
)
{
int
*
calls
=
(
int
*
)
payload
;
record_callbacks_data
*
data
=
(
record_callbacks_data
*
)
payload
;
GIT_UNUSED
(
stage
);
GIT_UNUSED
(
current
);
GIT_UNUSED
(
total
);
if
(
*
calls
<
0
)
return
*
calls
;
(
*
calls
)
++
;
if
(
data
->
pack_progress_calls
<
0
)
return
data
->
pack_progress_calls
;
data
->
pack_progress_calls
++
;
return
0
;
}
static
int
push_transfer_progress_cb
(
unsigned
int
current
,
unsigned
int
total
,
size_t
bytes
,
void
*
payload
)
{
int
*
calls
=
(
int
*
)
payload
;
record_callbacks_data
*
data
=
(
record_callbacks_data
*
)
payload
;
GIT_UNUSED
(
current
);
GIT_UNUSED
(
total
);
GIT_UNUSED
(
bytes
);
if
(
*
calls
<
0
)
return
*
calls
;
(
*
calls
)
++
;
if
(
data
->
transfer_progress_calls
<
0
)
return
data
->
transfer_progress_calls
;
data
->
transfer_progress_calls
++
;
return
0
;
}
...
...
@@ -466,62 +460,63 @@ static void do_push(
expected_ref
expected_refs
[],
size_t
expected_refs_len
,
int
expected_ret
,
int
check_progress_cb
,
int
check_update_tips_cb
)
{
git_push
*
push
;
git_push_options
opts
=
GIT_PUSH_OPTIONS_INIT
;
size_t
i
;
int
pack_progress_calls
=
0
,
transfer_progress_calls
=
0
;
int
error
;
git_strarray
specs
=
{
0
};
git_signature
*
pusher
;
git_remote_callbacks
callbacks
;
record_callbacks_data
*
data
;
if
(
_remote
)
{
/* Auto-detect the number of threads to use */
opts
.
pb_parallelism
=
0
;
cl_git_pass
(
git_signature_now
(
&
pusher
,
"Foo Bar"
,
"foo@example.com"
));
cl_git_pass
(
git_remote_connect
(
_remote
,
GIT_DIRECTION_PUSH
));
cl_git_pass
(
git_push_new
(
&
push
,
_remote
));
cl_git_pass
(
git_push_set_options
(
push
,
&
opts
))
;
memcpy
(
&
callbacks
,
git_remote_get_callbacks
(
_remote
),
sizeof
(
callbacks
));
data
=
callbacks
.
payload
;
if
(
check_progress_cb
)
{
/* if EUSER, then abort in transfer */
if
(
expected_ret
==
GIT_EUSER
)
transfer_progress_calls
=
GIT_EUSER
;
callbacks
.
pack_progress
=
push_pack_progress_cb
;
callbacks
.
push_transfer_progress
=
push_transfer_progress_cb
;
callbacks
.
push_update_reference
=
record_push_status_cb
;
cl_git_pass
(
git_remote_set_callbacks
(
_remote
,
&
callbacks
))
;
cl_git_pass
(
git_push_set_callbacks
(
push
,
push_pack_progress_cb
,
&
pack_progress_calls
,
push_transfer_progress_cb
,
&
transfer_progress_calls
)
);
if
(
refspecs_len
)
{
specs
.
count
=
refspecs_len
;
specs
.
strings
=
git__calloc
(
refspecs_len
,
sizeof
(
char
*
));
cl_assert
(
specs
.
strings
);
}
for
(
i
=
0
;
i
<
refspecs_len
;
i
++
)
cl_git_pass
(
git_push_add_refspec
(
push
,
refspecs
[
i
]));
specs
.
strings
[
i
]
=
(
char
*
)
refspecs
[
i
];
/* if EUSER, then abort in transfer */
if
(
check_progress_cb
&&
expected_ret
==
GIT_EUSER
)
data
->
transfer_progress_calls
=
GIT_EUSER
;
error
=
git_remote_push
(
_remote
,
&
specs
,
&
opts
,
pusher
,
"test push"
);
git__free
(
specs
.
strings
);
if
(
expected_ret
<
0
)
{
cl_git_fail_with
(
git_push_finish
(
push
),
expected_ret
);
cl_assert_equal_i
(
0
,
git_push_unpack_ok
(
push
));
cl_git_fail_with
(
expected_ret
,
error
);
}
else
{
cl_git_pass
(
git_push_finish
(
push
));
cl_assert_equal_i
(
1
,
git_push_unpack_ok
(
push
));
cl_git_pass
(
error
);
}
if
(
check_progress_cb
&&
!
expected_ret
)
{
cl_assert
(
pack_progress_calls
>
0
);
cl_assert
(
transfer_progress_calls
>
0
);
if
(
check_progress_cb
&&
expected_ret
==
0
)
{
cl_assert
(
data
->
pack_progress_calls
>
0
);
cl_assert
(
data
->
transfer_progress_calls
>
0
);
}
do_verify_push_status
(
push
,
expected_statuses
,
expected_statuses_len
);
do_verify_push_status
(
data
,
expected_statuses
,
expected_statuses_len
);
verify_refs
(
_remote
,
expected_refs
,
expected_refs_len
);
cl_git_pass
(
git_push_update_tips
(
push
,
pusher
,
"test push"
));
verify_tracking_branches
(
_remote
,
expected_refs
,
expected_refs_len
);
if
(
check_update_tips_cb
)
verify_update_tips_callback
(
_remote
,
expected_refs
,
expected_refs_len
);
git_push_free
(
push
);
git_remote_disconnect
(
_remote
);
git_signature_free
(
pusher
);
}
...
...
@@ -882,3 +877,35 @@ void test_online_push__notes(void)
git_signature_free
(
signature
);
}
void
test_online_push__configured
(
void
)
{
git_oid
note_oid
,
*
target_oid
,
expected_oid
;
git_signature
*
signature
;
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
}
};
const
char
*
specs_del
[]
=
{
":refs/notes/commits"
};
git_oid_fromstr
(
&
expected_oid
,
"8461a99b27b7043e58ff6e1f5d2cf07d282534fb"
);
target_oid
=
&
_oid_b6
;
cl_git_pass
(
git_remote_add_push
(
_remote
,
specs
[
0
]));
/* Create note to push */
cl_git_pass
(
git_signature_new
(
&
signature
,
"nulltoken"
,
"emeric.fermas@gmail.com"
,
1323847743
,
60
));
/* Wed Dec 14 08:29:03 2011 +0100 */
cl_git_pass
(
git_note_create
(
&
note_oid
,
_repo
,
signature
,
signature
,
NULL
,
target_oid
,
"hello world
\n
"
,
0
));
do_push
(
NULL
,
0
,
exp_stats
,
ARRAY_SIZE
(
exp_stats
),
exp_refs
,
ARRAY_SIZE
(
exp_refs
),
0
,
1
,
1
);
/* And make sure to delete the note */
do_push
(
specs_del
,
ARRAY_SIZE
(
specs_del
),
exp_stats
,
1
,
NULL
,
0
,
0
,
0
,
0
);
git_signature_free
(
signature
);
}
tests/online/push_util.c
View file @
45301cca
...
...
@@ -14,15 +14,31 @@ void updated_tip_free(updated_tip *t)
git__free
(
t
);
}
void
push_status_free
(
push_status
*
s
)
{
git__free
(
s
->
ref
);
git__free
(
s
->
msg
);
git__free
(
s
);
}
void
record_callbacks_data_clear
(
record_callbacks_data
*
data
)
{
size_t
i
;
updated_tip
*
tip
;
push_status
*
status
;
git_vector_foreach
(
&
data
->
updated_tips
,
i
,
tip
)
updated_tip_free
(
tip
);
git_vector_free
(
&
data
->
updated_tips
);
git_vector_foreach
(
&
data
->
statuses
,
i
,
status
)
push_status_free
(
status
);
git_vector_free
(
&
data
->
statuses
);
data
->
pack_progress_calls
=
0
;
data
->
transfer_progress_calls
=
0
;
}
int
record_update_tips_cb
(
const
char
*
refname
,
const
git_oid
*
a
,
const
git_oid
*
b
,
void
*
data
)
...
...
tests/online/push_util.h
View file @
45301cca
...
...
@@ -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
;
...
...
@@ -22,6 +22,9 @@ typedef struct {
typedef
struct
{
git_vector
updated_tips
;
git_vector
statuses
;
int
pack_progress_calls
;
int
transfer_progress_calls
;
}
record_callbacks_data
;
typedef
struct
{
...
...
@@ -29,6 +32,15 @@ typedef struct {
const
git_oid
*
oid
;
}
expected_ref
;
/* the results of a push status. when used for expected values, msg may be NULL
* to indicate that it should not be matched. */
typedef
struct
{
char
*
ref
;
int
success
;
char
*
msg
;
}
push_status
;
void
updated_tip_free
(
updated_tip
*
t
);
void
record_callbacks_data_clear
(
record_callbacks_data
*
data
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment