Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add [optional] update kwarg to create_tag() #725

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 27 additions & 2 deletions github3/repos/repo.py
Expand Up @@ -1011,6 +1011,25 @@ def create_ref(self, ref, sha):
json = self._json(self._post(url, data=data), 201)
return self._instance_or_null(Reference, json)

@requires_auth
def update_ref(self, ref, sha, force=False):
"""Update a reference in this repository.

:param str ref: (required), fully qualified name of the reference,
e.g. ``refs/heads/master``. If it doesn't start with ``refs`` and
contain at least two slashes, GitHub's API will reject it.
:param str sha: (required), SHA1 value to set the reference to
:param bool force: (optional), force update of a pre-existing ref.
:returns: :class:`Reference <github3.git.Reference>` if successful
else None
"""
json = None
if ref and ref.startswith('refs') and ref.count('/') >= 2 and sha:
data = {'sha': sha, 'force': force}
url = self._build_url('git', ref, base_url=self._api)
json = self._json(self._patch(url, data=dumps(data)), 200)
return self._instance_or_null(Reference, json)

@requires_auth
def create_release(self, tag_name, target_commitish=None, name=None,
body=None, draft=False, prerelease=False):
Expand Down Expand Up @@ -1067,7 +1086,7 @@ def create_status(self, sha, state, target_url=None, description=None,

@requires_auth
def create_tag(self, tag, message, sha, obj_type, tagger,
lightweight=False):
lightweight=False, update=False):
"""Create a tag in this repository.

By default, this method creates an annotated tag. If you wish to
Expand All @@ -1090,6 +1109,8 @@ def create_tag(self, tag, message, sha, obj_type, tagger,
tagger and the date it was tagged
:param bool lightweight: (optional), if False, create an annotated
tag, otherwise create a lightweight tag (a Reference).
:param bool update: (optional), if True, force the update of an
existing annotated tag.
:returns: If lightweight == False: :class:`Tag <github3.git.Tag>` if
successful, else None. If lightweight == True: :class:`Reference
<github3.git.Reference>`
Expand All @@ -1104,7 +1125,11 @@ def create_tag(self, tag, message, sha, obj_type, tagger,
url = self._build_url('git', 'tags', base_url=self._api)
json = self._json(self._post(url, data=data), 201)
if json:
self.create_ref('refs/tags/' + tag, json.get('sha'))
if update:
self.update_ref('refs/tags/' + tag, json.get('sha'),
force=True)
else:
self.create_ref('refs/tags/' + tag, json.get('sha'))
return self._instance_or_null(Tag, json)

@requires_auth
Expand Down
57 changes: 57 additions & 0 deletions tests/unit/test_repos_repo.py
Expand Up @@ -440,6 +440,34 @@ def test_create_ref_requires_a_truthy_sha(self):

assert self.session.post.called is False

def test_update_ref(self):
"""Verify the request to update a reference."""
ref = 'refs/heads/foo'
sha = 'my-fake-sha'
self.instance.update_ref(ref, sha)

self.patch_called_with(
url_for('git/' + ref),
data={
'sha': sha,
'force': False,
}
)

def test_update_ref_force(self):
"""Verify the request to force update a reference."""
ref = 'refs/heads/foo'
sha = 'my-fake-sha'
self.instance.update_ref(ref, sha, force=True)

self.patch_called_with(
url_for('git/' + ref),
data={
'sha': sha,
'force': True,
}
)

def test_create_status(self):
"""Verify the request for creating a status on a commit."""
data = {
Expand Down Expand Up @@ -498,6 +526,35 @@ def test_create_tag_that_is_not_lightweight(self):
},
)

def test_create_tag_that_is_not_lightweight_and_forced(self):
"""Verify we can create an annotated tag."""
self.instance.create_tag(
tag='tag-name',
message='message',
sha='my-sha',
obj_type='commit',
tagger={'name': 'Ian Cordasco',
'email': 'example@example.com',
'date': '2015-11-01T12:16:00Z'},
lightweight=False,
update=True
)

self.post_called_with(
url_for('git/tags'),
data={
'tag': 'tag-name',
'message': 'message',
'object': 'my-sha',
'type': 'commit',
'tagger': {
'name': 'Ian Cordasco',
'email': 'example@example.com',
'date': '2015-11-01T12:16:00Z',
},
},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless I'm missing something, this doesn't validate that the call went through update_ref instead of create_ref. Is there a way you could validate that instead?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the internal call chain matter? This is a behavioral test that verifies that the given input produces the desired result.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because as a unit test, we want to ensure the right decision path is used, and that the code path you've added is exercised. We should at least see patch called instead of post.

)

def test_create_tree(self):
"""Verify the request to create a tree."""
self.instance.create_tree([{'foo': 'bar'}])
Expand Down