2121import ssl
2222
2323
24+ class GitHubApiException (Exception ):
25+ """General exception type for GitHub related REST API failures"""
26+
27+
28+ def create_ssl_context ():
29+ """Create an insecure context for SSL connection"""
30+ context = ssl .create_default_context ()
31+ context .check_hostname = False
32+ context .verify_mode = ssl .CERT_NONE
33+ return context
34+
35+
2436class GitHubApi :
2537
26- def __init__ (self , owner , project , oauth_token , server = "api.github.com" ,
38+ def __init__ (self , owner , repo , oauth_token , server = "api.github.com" ,
2739 uploads_server = "uploads.github.com" , debuglevel = 0 ):
28- logging .debug ("Creating GitHub API connection for %s/%s" , owner , project )
40+ logging .debug ("Creating GitHub API connection for %s/%s" , owner , repo )
2941 self ._server = server
30- self ._connection = http .client .HTTPSConnection (server )
42+ self ._connection = http .client .HTTPSConnection (server ,
43+ context = create_ssl_context ())
3144 self ._connection .set_debuglevel (debuglevel )
3245 self ._owner = owner
33- self ._project = project
34- self ._project_url = "/repos/{0 }/{1}" . format ( owner , project )
46+ self ._project = repo
47+ self ._project_url = f "/repos/{ owner } /{ repo } "
3548 self ._http_headers = {
3649 "Authorization" : "token " + oauth_token ,
3750 "User-Agent" : "Python" ,
@@ -47,28 +60,81 @@ def __init__(self, owner, project, oauth_token, server="api.github.com",
4760 context = uploads_ssl_context )
4861 self ._uploads_connection .set_debuglevel (debuglevel )
4962
50- def create_release (self , git_tag , name , description , draft , prerelease ):
63+ def _request (self , method , url , request = None ):
64+ self ._connection .request (
65+ method , url , json .dumps (request ), self ._http_headers )
66+ response = self ._connection .getresponse ()
67+ response_body = response .read ().decode ("utf-8" )
68+
69+ try :
70+ response_data = json .loads (str (response_body ))
71+ except json .decoder .JSONDecodeError :
72+ response_data = str (response_body )
73+
74+ return response .status , response_data
75+
76+ def create_release (self , tag , name , description , draft , prerelease ):
5177 """Returns release id"""
52- logging .info ("Creating release %s at %s/%s" , name , self ._owner , self ._project )
78+ logging .info ("Creating release \' %s\' at \' %s/%s\' " , tag , self ._owner ,
79+ self ._project )
5380 url = self ._project_url + "/releases"
5481 req = {
55- "tag_name" : git_tag ,
82+ "tag_name" : tag ,
5683 "name" : name ,
5784 "body" : description ,
5885 "draft" : draft ,
5986 "prerelease" : prerelease ,
6087 }
61- self ._connection .request ("POST" , url , json .dumps (req ), self ._http_headers )
62- response = self ._connection .getresponse ()
63- response_text = response .read ().decode ("utf-8" ) # read() returns 'bytes' not 'string'
64- logging .debug (response_text )
65- response_data = json .loads (response_text )
88+ status , response_data = self ._request ("POST" , url , req )
89+ if status != 201 :
90+ raise GitHubApiException (response_data ["message" ])
91+
6692 return response_data ["id" ]
6793
94+ def last_commit_hash_on_branch (self , branch ):
95+ """Get last commit hash on branch"""
96+ logging .info ("Get last commit on branch: \' %s\' at \' %s/%s\' " , branch ,
97+ self ._owner ,
98+ self ._project )
99+ url = self ._project_url + f"/commits/{ branch } "
100+ status , response_data = self ._request ("GET" , url )
101+
102+ if status != 200 :
103+ raise GitHubApiException (response_data ["message" ])
104+
105+ return response_data ["sha" ]
106+
107+ def create_tag_reference (self , ref , sha ):
108+ """Create a tag reference with GitHub REST API"""
109+ logging .info ("Create tag reference \' %s\' at \' %s/%s\' " , ref , self ._owner ,
110+ self ._project )
111+ url = self ._project_url + "/git/refs"
112+
113+ req = {
114+ "ref" : f"refs/tags/{ ref } " ,
115+ "sha" : sha
116+ }
117+ status , response_data = self ._request ("POST" , url , req )
118+ if status != 201 :
119+ raise GitHubApiException (response_data ["message" ])
120+
121+ def delete_tag_reference (self , ref ):
122+ """Delete a tag reference with GitHub REST API"""
123+ logging .info ("Delete tag \' %s\' at \' %s/%s\' " ,
124+ ref , self ._owner , self ._project )
125+ url = self ._project_url + f"/git/refs/tags/{ ref } "
126+
127+ status , response_data = self ._request ("DELETE" , url )
128+
129+ if status != 204 :
130+ raise GitHubApiException (response_data ['message' ])
131+
68132 def upload_asset (self , release_id , asset ):
133+ """Upload release assets with GitHub REST API"""
69134 logging .info ("Uploading asset: %s" , asset )
70135 name = os .path .basename (asset )
71- url = "{0}/releases/{1}/assets?name={2}" .format (self ._project_url , release_id , name )
136+ url = "{0}/releases/{1}/assets?name={2}" .format (self ._project_url , release_id ,
137+ name )
72138 (mime_type , _ ) = mimetypes .guess_type (asset )
73139 asset_headers = self ._http_headers .copy ()
74140 asset_headers ["Content-Type" ] = mime_type
0 commit comments