implement push support
Implement push support via Remote.push which is called with a single refspec and raises GitError (with an appropriate message where possible) if the push fails. Note that local push to non-bare repository is currently not supported by libgit2.
This commit is contained in:
parent
74b1628e51
commit
134d87ab2a
@ -15,4 +15,5 @@ The Remote type
|
||||
.. autoattribute:: pygit2.Remote.refspec_count
|
||||
.. automethod:: pygit2.Remote.get_refspec
|
||||
.. automethod:: pygit2.Remote.fetch
|
||||
.. automethod:: pygit2.Remote.push
|
||||
.. automethod:: pygit2.Remote.save
|
||||
|
66
src/remote.c
66
src/remote.c
@ -218,10 +218,76 @@ Remote_save(Remote *self, PyObject *args)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
push_status_foreach_callback(const char *ref, const char *msg, void *data)
|
||||
{
|
||||
const char **msg_dst = (const char **)data;
|
||||
if (msg != NULL && *msg_dst == NULL)
|
||||
*msg_dst = msg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Remote_push__doc__,
|
||||
"push(refspec)\n"
|
||||
"\n"
|
||||
"Push the given refspec to the remote. Raises ``GitError`` on error.");
|
||||
|
||||
PyObject *
|
||||
Remote_push(Remote *self, PyObject *args)
|
||||
{
|
||||
git_push *push = NULL;
|
||||
const char *refspec = NULL;
|
||||
const char *msg = NULL;
|
||||
int err;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &refspec))
|
||||
return NULL;
|
||||
|
||||
err = git_push_new(&push, self->remote);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
err = git_push_add_refspec(push, refspec);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
err = git_push_finish(push);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
if (!git_push_unpack_ok(push)) {
|
||||
git_push_free(push);
|
||||
PyErr_SetString(GitError, "Remote failed to unpack objects");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_push_status_foreach(push, push_status_foreach_callback, &msg);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
if (msg != NULL) {
|
||||
git_push_free(push);
|
||||
PyErr_SetString(GitError, msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_push_update_tips(push);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
git_push_free(push);
|
||||
Py_RETURN_NONE;
|
||||
|
||||
error:
|
||||
git_push_free(push);
|
||||
return Error_set(err);
|
||||
}
|
||||
|
||||
|
||||
PyMethodDef Remote_methods[] = {
|
||||
METHOD(Remote, fetch, METH_NOARGS),
|
||||
METHOD(Remote, save, METH_NOARGS),
|
||||
METHOD(Remote, get_refspec, METH_O),
|
||||
METHOD(Remote, push, METH_VARARGS),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
@ -124,5 +124,45 @@ class EmptyRepositoryTest(utils.EmptyRepoTestCase):
|
||||
self.assertEqual(stats['received_objects'], REMOTE_REPO_OBJECTS)
|
||||
|
||||
|
||||
class PushTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.origin_ctxtmgr = utils.TemporaryRepository(('git', 'testrepo.git'))
|
||||
self.clone_ctxtmgr = utils.TemporaryRepository(('git', 'testrepo.git'))
|
||||
self.origin = pygit2.Repository(self.origin_ctxtmgr.__enter__())
|
||||
self.clone = pygit2.Repository(self.clone_ctxtmgr.__enter__())
|
||||
self.remote = self.clone.create_remote('origin', self.origin.path)
|
||||
|
||||
def tearDown(self):
|
||||
self.origin_ctxtmgr.__exit__(None, None, None)
|
||||
self.clone_ctxtmgr.__exit__(None, None, None)
|
||||
|
||||
def test_push_fast_forward_commits_to_remote_succeeds(self):
|
||||
tip = self.clone[self.clone.head.target]
|
||||
oid = self.clone.create_commit(
|
||||
'refs/heads/master', tip.author, tip.author, 'empty commit',
|
||||
tip.tree.oid, [tip.oid]
|
||||
)
|
||||
self.remote.push('refs/heads/master')
|
||||
self.assertEqual(self.origin[self.origin.head.target].oid, oid)
|
||||
|
||||
def test_push_when_up_to_date_succeeds(self):
|
||||
self.remote.push('refs/heads/master')
|
||||
origin_tip = self.origin[self.origin.head.target].oid
|
||||
clone_tip = self.clone[self.clone.head.target].oid
|
||||
self.assertEqual(origin_tip, clone_tip)
|
||||
|
||||
def test_push_non_fast_forward_commits_to_remote_fails(self):
|
||||
tip = self.origin[self.origin.head.target]
|
||||
oid = self.origin.create_commit(
|
||||
'refs/heads/master', tip.author, tip.author, 'some commit',
|
||||
tip.tree.oid, [tip.oid]
|
||||
)
|
||||
tip = self.clone[self.clone.head.target]
|
||||
oid = self.clone.create_commit(
|
||||
'refs/heads/master', tip.author, tip.author, 'other commit',
|
||||
tip.tree.oid, [tip.oid]
|
||||
)
|
||||
self.assertRaises(pygit2.GitError, self.remote.push, 'refs/heads/master')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user