8000 Add support for Commit Reference SHA-1 · parlarjb/github3.py@5c4d537 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5c4d537

Browse files
Add support for Commit Reference SHA-1
Resolves: sigmavirus24#585 Added a custom betamax matcher for In-None-Match header
1 parent 872c813 commit 5c4d537

File tree

7 files changed

+151
-0
lines changed

7 files changed

+151
-0
lines changed

github3/repos/branch.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,26 @@ def _update_attributes(self, branch):
3838
def _repr(self):
3939
return '<Repository Branch [{0}]>'.format(self.name)
4040

41+
def latest_sha(self, differs_from=''):
42+
"""Check if SHA-1 is the same as remote branch
43+
44+
See: https://git.io/vaqIw
45+
46+
:param differs_from string: (optional), sha to compare against
47+
:returns: strring of the SHA or None
48+
"""
49+
# If-None-Match returns 200 instead of 304 value does not have quotes
50+
headers = {
51+
'Accept': 'application/vnd.github.chitauri-preview+sha',
52+
'If-None-Match': '"{0}"'.format(differs_from)
53+
}
54+
base = self._api.split('/branches', 1)[0]
55+
url = self._build_url('commits', self.name, base_url=base)
56+
resp = self._get(url, headers=headers)
57+
if resp:
58+
sha = None if self._boolean(resp, 304, 200) else resp.content
59+
return sha
60+
4161
def protect(self, enforcement=None, status_checks=None):
4262
"""Enable force push protection and configure status check enforcement.
4363
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.loki-preview+json", "User-Agent": "github3.py/1.0.0a4", "Accept-Charset": "utf-8", "Connection": "keep-alive", "Content-Type": "application/json"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/branches/develop"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1XTY/TMBD9K1G47m6c76QSAokTAm5wAVaVY08Si8QOtlNYqv53xmm72xYQTRdx2luVet68eZ4vr31Je/AXPocVdGrwr3ym+l5Yf7H2TUvxnyKPWBHGdV3lNCGszFgcpRHPswSSIi6SJClJSnl5ZEpH2yrtQHb4r6n0XinNqWEKT0JPRYfgRjQ9XQk9mih5ORrQ5kYqDUN3d9MI247VDdLB85xaxzIiYXZN4msSvg/LRZouwvCjv9lztvD/PPZgDG0cp3egG/CGses8DV9HMNZ7lhaJV2vVe+/evtEjNKDDssiDncif5Wf5YXAhcY8rZqwWsjGeVV5LV+DZFjwtmtZ6o+68WunpCx4ce5CWWqEkKmI1oPf9JYU1lBGPSJ4ygCSrirCiZVxHJCtoWcVpGPI0JGWOhgiKrFtrB7MIAjqIA6UDlF6Z4PBWgu09xDfDnfsZOL8mONsfXs4jHW7z0QQz8xClWjI1Ssxk8jgSFxBobd8tj+N+SOc/yrt1dEGg5sTXrEudG17gDFBdg7n0UOadaoQ8KWg8ILi/iBJSxAQPr6il+pTq9NHsctB1AKakRXhX+MEYbI1frJ7HiNboHYaD9f+Wy1M7ORIbLc6/GTxcq65T3xDllPRx0fzqKLi3vEfBEr8QBS3XgcIegNphSBsnhDB2PqnJao1VbOxScIdjUHsNfDaxnR3S+iaR0XrqGxPgWBmmxeCa1HyCR9aIpnRDpfgxtbz5aGjtcnRqabMjnKzQGscipvps863ZOhi0WFF256TRwECsUOwLIU/sEdHeDW4AfcCkcNILC0vKe1eGNe0MnM7FpxI9mmtPJXpJUT2V6G4pDX7T9S8p0YHqaZguPu13OVweq4jxkpdhDCnJKG69CSdFlvI0SouCZyXLeARY849YrfZjf4a382fn4dK422rO9rO52gvBKI9JWVAKhEesInGaFzxnSQgh5JDWhNGsikv+b4SY4e1RQpztZ3OLHXzZCfkFswM1ga6+dHGvNJWsxb394ZnnYjiAO2M9dZv/PQBSG7SywKbnCNIDSasOcC+z+OBx0+7rKNxqgauCHc0SvbNtHCDxScPArZDLzr06kYVUcju63MidFsDvU0lMv4Uc1WiuBX7FBdD5w0cIPhrNNRP+7Waz+Qkez2dHxQ4AAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept", "x-github-media-type": "github.loki-preview; format=json", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "W/\"30b5e0e1742d28983cbab707d60d71af\"", "cache-control": "public, max-age=60, s-maxage=60", "status": "200 OK", "x-ratelimit-remaining": "39", "x-served-by": "d0b3c2c33a23690498aa8e70a435a259", "access-control-expose-headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "D54E579D:1D925:22B6F96:56E29E4A", "date": "Fri, 11 Mar 2016 10:30:34 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains; preload", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1457695532"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/branches/develop"}, "recorded_at": "2016-03-11T10:30:34"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.chitauri-preview+sha", "User-Agent": "github3.py/1.0.0a4", "Accept-Charset": "utf-8", "Connection": "keep-alive", "If-None-Match": "\"872c813ffb7a40c96c3252d764e4838444905ad9\"", "Content-Type": "application/json"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/commits/develop"}, "response": {"body": {"string": "", "encoding": null}, "headers": {"status": "304 Not Modified", "x-ratelimit-remaining": "39", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "content-security-policy": "default-src 'none'", "access-control-expose-headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "x-github-request-id": "D54E579D:1D925:22B6FA2:56E29E4A", "strict-transport-security": "max-age=31536000; includeSubdomains; preload", "vary": "Accept", "server": "GitHub.com", "last-modified": "Tue, 01 Mar 2016 19:55:11 GMT", "x-ratelimit-limit": "60", "etag": "\"872c813ffb7a40c96c3252d764e4838444905ad9\"", "x-served-by": "c6c65e5196703428e7641f7d1e9bc353", "cache-control": "public, max-age=60, s-maxage=60", "date": "Fri, 11 Mar 2016 10:30:35 GMT", "access-control-allow-origin": "*", "x-frame-options": "deny", "x-ratelimit-reset": "1457695532"}, "status": {"message": "Not Modified", "code": 304}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/commits/develop"}, "recorded_at": "2016-03-11T10:30:34"}], "recorded_with": "betamax/0.5.0"}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"http_interactions": [{"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.loki-preview+json", "User-Agent": "github3.py/1.0.0a4", "Accept-Charset": "utf-8", "Connection": "keep-alive", "Content-Type": "application/json"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/branches/develop"}, "response": {"body": {"string": "", "base64_string": "H4sIAAAAAAAAA+1XTY/TMBD9K1G47m6c76QSAokTAm5wAVaVY08Si8QOtlNYqv53xmm72xYQTRdx2luVet68eZ4vr31Je/AXPocVdGrwr3ym+l5Yf7H2TUvxnyKPWBHGdV3lNCGszFgcpRHPswSSIi6SJClJSnl5ZEpH2yrtQHb4r6n0XinNqWEKT0JPRYfgRjQ9XQk9mih5ORrQ5kYqDUN3d9MI247VDdLB85xaxzIiYXZN4msSvg/LRZouwvCjv9lztvD/PPZgDG0cp3egG/CGses8DV9HMNZ7lhaJV2vVe+/evtEjNKDDssiDncif5Wf5YXAhcY8rZqwWsjGeVV5LV+DZFjwtmtZ6o+68WunpCx4ce5CWWqEkKmI1oPf9JYU1lBGPSJ4ygCSrirCiZVxHJCtoWcVpGPI0JGWOhgiKrFtrB7MIAjqIA6UDlF6Z4PBWgu09xDfDnfsZOL8mONsfXs4jHW7z0QQz8xClWjI1Ssxk8jgSFxBobd8tj+N+SOc/yrt1dEGg5sTXrEudG17gDFBdg7n0UOadaoQ8KWg8ILi/iBJSxAQPr6il+pTq9NHsctB1AKakRXhX+MEYbI1frJ7HiNboHYaD9f+Wy1M7ORIbLc6/GTxcq65T3xDllPRx0fzqKLi3vEfBEr8QBS3XgcIegNphSBsnhDB2PqnJao1VbOxScIdjUHsNfDaxnR3S+iaR0XrqGxPgWBmmxeCa1HyCR9aIpnRDpfgxtbz5aGjtcnRqabMjnKzQGscipvps863ZOhi0WFF256TRwECsUOwLIU/sEdHeDW4AfcCkcNILC0vKe1eGNe0MnM7FpxI9mmtPJXpJUT2V6G4pDX7T9S8p0YHqaZguPu13OVweq4jxkpdhDCnJKG69CSdFlvI0SouCZyXLeARY849YrfZjf4a382fn4dK422rO9rO52gvBKI9JWVAKhEesInGaFzxnSQgh5JDWhNGsikv+b4SY4e1RQpztZ3OLHXzZCfkFswM1ga6+dHGvNJWsxb394ZnnYjiAO2M9dZv/PQBSG7SywKbnCNIDSasOcC+z+OBx0+7rKNxqgauCHc0SvbNtHCDxScPArZDLzr06kYVUcju63MidFsDvU0lMv4Uc1WiuBX7FBdD5w0cIPhrNNRP+7Waz+Qkez2dHxQ4AAA==", "encoding": "utf-8"}, "headers": {"vary": "Accept", "x-github-media-type": "github.loki-preview; format=json", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "W/\"30b5e0e1742d28983cbab707d60d71af\"", "cache-control": "public, max-age=60, s-maxage=60", "status": "200 OK", "x-ratelimit-remaining": "37", "x-served-by": "a474937f3b2fa272558fa6dc951018ad", "access-control-expose-headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "transfer-encoding": "chunked", "x-github-request-id": "D54E579D:1D92B:A49F068:56E29E4B", "date": "Fri, 11 Mar 2016 10:30:35 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "content-encoding": "gzip", "strict-transport-security": "max-age=31536000; includeSubdomains; preload", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1457695532"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/branches/develop"}, "recorded_at": "2016-03-11T10:30:35"}, {"request": {"body": {"string": "", "encoding": "utf-8"}, "headers": {"Accept-Encoding": "gzip, deflate", "Accept": "application/vnd.github.chitauri-preview+sha", "User-Agent": "github3.py/1.0.0a4", "Accept-Charset": "utf-8", "Connection": "keep-alive", "If-None-Match": "\"fakesha12\"", "Content-Type": "application/json"}, "method": "GET", "uri": "https://api.github.com/repos/sigmavirus24/github3.py/commits/develop"}, "response": {"body": {"string": "872c813ffb7a40c96c3252d764e4838444905ad9", "encoding": "utf-8"}, "headers": {"content-length": "40", "vary": "Accept", "x-github-media-type": "github.v3; param=chitauri-preview; format=sha", "x-xss-protection": "1; mode=block", "x-content-type-options": "nosniff", "etag": "\"872c813ffb7a40c96c3252d764e4838444905ad9\"", "cache-control": "public, max-age=60, s-maxage=60", "status": "200 OK", "x-ratelimit-remaining": "36", "x-served-by": "7f48e2f7761567e923121f17538d7a6d", "access-control-expose-headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "x-github-request-id": "D54E579D:1D92B:A49F0A5:56E29E4B", "last-modified": "Tue, 01 Mar 2016 19:55:11 GMT", "date": "Fri, 11 Mar 2016 10:30:35 GMT", "access-control-allow-origin": "*", "content-security-policy": "default-src 'none'", "strict-transport-security": "max-age=31536000; includeSubdomains; preload", "server": "GitHub.com", "x-ratelimit-limit": "60", "x-frame-options": "deny", "content-type": "application/vnd.github.chitauri-preview+sha; charset=utf-8", "x-ratelimit-reset": "1457695532"}, "status": {"message": "OK", "code": 200}, "url": "https://api.github.com/repos/sigmavirus24/github3.py/commits/develop"}, "recorded_at": "2016-03-11T10:30:35"}], "recorded_with": "betamax/0.5.0"}

tests/conftest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,17 @@ def betamax_simple_body(request):
4242
def enterprise_url(request):
4343
"""Configure class with enterprise url."""
4444
request.cls.enterprise_url = 'https://enterprise.github3.com'
45+
46+
47+
class IfNoneMatchMatcher(betamax.BaseMatcher):
48+
49+
name = 'if-none-match'
50+
51+
def match(self, request, recorded_request):
52+
request_header = request.headers.get('If-None-Match')
53+
recorded_header = recorded_request['headers'].get('If-None-Match')
54+
matches = True if request_header == recorded_header else False
55+
return matches
56+
57+
58+
betamax.Betamax.register_request_matcher(IfNoneMatchMatcher)

tests/integration/test_repos_branch.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,29 @@ def test_unprotect(self):
5252
branch = next(repository.branches(protected=True))
5353
branch.unprotect()
5454
assert branch.protection == expected
55+
56+
def test_latest_sha(self):
57+
repository = self.gh.repository('sigmavirus24', 'github3.py')
58+
cassette_name = self.cassette_name('latest_sha')
59+
betamax_kwargs = {
60+
'match_requests_on': ['method', 'uri', 'if-none-match']
61+
}
62+
with self.recorder.use_cassette(cassette_name, **betamax_kwargs):
63+
branch = repository.branch('develop')
64+
sha = '872c813ffb7a40c96c3252d764e4838444905ad9'
65+
latest_sha = branch.latest_sha(differs_from=sha)
66+
67+
assert latest_sha is None
68+
69+
def test_latest_sha_differs(self):
70+
repository = self.gh.repository('sigmavirus24', 'github3.py')
71+
cassette_name = self.cassette_name('latest_sha_differs')
72+
betamax_kwargs = {
73+
'match_requests_on': ['method', 'uri', 'if-none-match']
74+
}
75+
with self.recorder.use_cassette(cassette_name, **betamax_kwargs):
76+
branch = repository.branch('develop')
77+
sha = 'fakesha12'
78+
latest_sha = branch.latest_sha(differs_from=sha)
79+
80+
assert isinstance(latest_sha, str)

tests/unit/json/repos_branch_example

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"name": "master",
3+
"protection": {
4+
"enabled": false,
5+
"required_status_checks": {
6+
"enforcement_level": "off",
7+
"contexts": [
8+
9+
]
10+
}
11+
},
12+
"commit": {
13+
"sha": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
14+
"commit": {
15+
"author": {
16+
"name": "The Octocat",
17+
"date": "2012-03-06T15:06:50-08:00",
18+
"email": "octocat@nowhere.com"
19+
},
20+
"url": "https://api.github.com/repos/octocat/Hello-World/git/commits/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
21+
"message": "Merge pull request #6 from Spaceghost/patch-1\n\nNew line at end of file.",
22+
"tree": {
23+
"sha": "b4eecafa9be2f2006ce1b709d6857b07069b4608",
24+
"url": "https://api.github.com/repos/octocat/Hello-World/git/trees/b4eecafa9be2f2006ce1b709d6857b07069b4608"
25+
},
26+
"committer": {
27+
"name": "The Octocat",
28+
"date": "2012-03-06T15:06:50-08:00",
29+
"email": "octocat@nowhere.com"
30+
}
31+
},
32+
"author": {
33+
"gravatar_id": "",
34+
"avatar_url": "https://secure.gravatar.com/avatar/7ad39074b0584bc555d0417ae3e7d974?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
35+
"url": "https://api.github.com/users/octocat",
36+
"id": 583231,
37+
"login": "octocat"
38+
},
39+
"parents": [
40+
{
41+
"sha": "553c2077f0edc3d5dc5d17262f6aa498e69d6f8e",
42+
"url": "https://api.github.com/repos/octocat/Hello-World/commits/553c2077f0edc3d5dc5d17262f6aa498e69d6f8e"
43+
},
44+
{
45+
"sha": "762941318ee16e59dabbacb1b4049eec22f0d303",
46+
"url": "https://api.github.com/repos/octocat/Hello-World/commits/762941318ee16e59dabbacb1b4049eec22f0d303"
47+
}
48+
],
49+
"url": "https://api.github.com/repos/octocat/Hello-World/commits/7fd1a60b01f91b314f59955a4e4d4e80d8edf11d",
50+
"committer": {
51+
"gravatar_id": "",
52+
"avatar_url": "https://secure.gravatar.com/avatar/7ad39074b0584bc555d0417ae3e7d974?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png",
53+
"url": "https://api.github.com/users/octocat",
54+
"id": 583231,
55+
"login": "octocat"
56+
}
57+
},
58+
"_links": {
59+
"html": "https://github.com/octocat/Hello-World/tree/master",
60+
"self": "https://api.github.com/repos/octocat/Hello-World/branches/master"
61+
}
62+
}

tests/unit/test_repos_branch.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""Unit tests for methods implemented on Branch."""
2+
import github3
3+
from . import helper
4+
5+
get_example_data = helper.create_example_data_helper('repos_branch_example')
6+
url_for = helper.create_url_helper(
7+
'https://api.github.com/repos/octocat/Hello-World/commits/master'
8+
)
9+
10+
11+
class TestBranch(helper.UnitHelper):
12+
"""Branch unit tests."""
13+
14+
described_class = github3.repos.branch.Branch
15+
example_data = get_example_data()
16+
17+
def test_latest_sha(self):
18+
"""Verify the request for retreiving the latest_sha."""
19+
headers = {
20+
'Accept': 'application/vnd.github.chitauri-preview+sha',
21+
'If-None-Match': '"123"'
22+
}
23+
self.instance.latest_sha(differs_from='123')
24+
self.session.get.assert_called_once_with(
25+
url_for(),
26+
headers=headers
27+
)

0 commit comments

Comments
 (0)
0