From b83ffbf8937895f3d052ccfb528725a924d1d50b Mon Sep 17 00:00:00 2001 From: Enix Yu Date: Wed, 23 Dec 2015 10:35:09 +0800 Subject: [PATCH] add content file create/update/delete api --- github/Repository.py | 147 +++++++++++++++++++++++++++++++++++++ github/tests/Repository.py | 10 +++ 2 files changed, 157 insertions(+) diff --git a/github/Repository.py b/github/Repository.py index be765169..54ab14d6 100644 --- a/github/Repository.py +++ b/github/Repository.py @@ -32,6 +32,7 @@ import urllib import datetime +from base64 import b64encode import github.GithubObject import github.PaginatedList @@ -1216,6 +1217,152 @@ class Repository(github.GithubObject.CompletableGithubObject): ) return github.ContentFile.ContentFile(self._requester, headers, data, completed=True) + def create_file(self, path, message, content, + branch=github.GithubObject.NotSet, + committer=github.GithubObject.NotSet, + author=github.GithubObject.NotSet): + """Create a file in this repository. + :calls: `PUT /repos/:owner/:repo/contents/:path `_ + :param path: string, (required), path of the file in the repository + :param message: string, (required), commit message + :param content: bytes, (required), the actual data in the file + :param branch: string, (optional), branch to create the commit on. Defaults to the default branch of the repository + :param committer: dict, (optional), if no information is given the authenticated user's information will be used. You must specify both a name and email. + :param author: dict, (optional), if omitted this will be filled in with committer information. If passed, you must specify both a name and email. + :rtype: { + 'content': :class:`ContentFile `:, + 'commit': :class:`Commit `} + """ + assert isinstance(path, (str, unicode)), \ + 'path must be str/unicode object' + assert isinstance(message, (str, unicode)), \ + 'message must be str/unicode object' + assert isinstance(content, bytes), \ + 'content must be a byte object' + assert branch is github.GithubObject.NotSet \ + or isinstance(branch, (str, unicode)), \ + 'branch must be a str/unicode object' + assert author is github.GithubObject.NotSet \ + or isinstance(author, github.InputGitAuthor), \ + 'author must be a github.InputGitAuthor object' + assert committer is github.GithubObject.NotSet \ + or isinstance(committer, github.InputGitAuthor), \ + 'committer must be a github.InputGitAuthor object' + + content = b64encode(content).decode('utf-8') + put_parameters = {'message': message, 'content': content} + + if branch is not github.GithubObject.NotSet: + put_parameters['branch'] = branch + if author is not github.GithubObject.NotSet: + put_parameters["author"] = author._identity + if committer is not github.GithubObject.NotSet: + put_parameters["committer"] = committer._identity + + headers, data = self._requester.requestJsonAndCheck( + "PUT", + self.url + "/contents" + path, + parameters=put_parameters + ) + + if headers.get('status') == '201 Created' \ + and 'content' in data and 'commit' in data: + data['content'] = github.ContentFile.ContentFile( + self._requester, headers, data, completed=True) + data['commit'] = github.Commit.Commit( + self._requester, headers, data, completed=True) + + return data + + def update_file(self, path, message, content, sha, + branch=github.GithubObject.NotSet, + committer=github.GithubObject.NotSet, + author=github.GithubObject.NotSet): + """This method updates a file in a repository + :calls: `PUT /repos/:owner/:repo/contents/:path `_ + :param path: string, Required. The content path. + :param message: string, Required. The commit message. + :param content: string, Required. The updated file content, Base64 encoded. + :param sha: string, Required. The blob SHA of the file being replaced. + :param branch: string. The branch name. Default: the repository’s default branch (usually master) + :rtype: { + 'content': :class:`ContentFile `:, + 'commit': :class:`Commit `} + """ + assert isinstance(path, (str, unicode)), \ + 'path must be str/unicode object' + assert isinstance(message, (str, unicode)), \ + 'message must be str/unicode object' + assert isinstance(content, bytes), \ + 'content must be a byte object' + assert isinstance(sha, (str, unicode)), \ + 'sha must be a str/unicode object' + assert branch is github.GithubObject.NotSet \ + or isinstance(branch, (str, unicode)), \ + 'branch must be a str/unicode object' + assert author is github.GithubObject.NotSet \ + or isinstance(author, github.InputGitAuthor), \ + 'author must be a github.InputGitAuthor object' + assert committer is github.GithubObject.NotSet \ + or isinstance(committer, github.InputGitAuthor), \ + 'committer must be a github.InputGitAuthor object' + + content = b64encode(content).decode('utf-8') + put_parameters = {'message': message, 'content': content, + 'sha': sha} + + if branch is not github.GithubObject.NotSet: + put_parameters['branch'] = branch + if author is not github.GithubObject.NotSet: + put_parameters["author"] = author._identity + if committer is not github.GithubObject.NotSet: + put_parameters["committer"] = committer._identity + + headers, data = self._requester.requestJsonAndCheck( + "PUT", + self.url + "/contents" + path, + parameters=put_parameters + ) + + if headers.get('status') == '200 OK' \ + and 'content' in data and 'commit' in data: + data['content'] = github.ContentFile.ContentFile( + self._requester, headers, data, completed=True) + data['commit'] = github.Commit.Commit( + self._requester, headers, data, completed=True) + + return data + + def delete_file(self, path, message, sha, + branch=github.GithubObject.NotSet): + """This method delete a file in a repository + :calls: `DELETE /repos/:owner/:repo/contents/:path `_ + :param path: string, Required. The content path. + :param message: string, Required. The commit message. + :param sha: string, Required. The blob SHA of the file being replaced. + :param branch: string. The branch name. Default: the repository’s default branch (usually master) + :rtype: None + """ + assert isinstance(path, (str, unicode)), \ + 'path must be str/unicode object' + assert isinstance(message, (str, unicode)), \ + 'message must be str/unicode object' + assert isinstance(sha, (str, unicode)), \ + 'sha must be a str/unicode object' + assert branch is github.GithubObject.NotSet \ + or isinstance(branch, (str, unicode)), \ + 'branch must be a str/unicode object' + + url_parameters = {'message': message, 'sha': sha} + if branch is not github.GithubObject.NotSet: + url_parameters['branch'] = branch + + headers, data = self._requester.requestJsonAndCheck( + "DELETE", + self.url + "/contents/" + path, + parameters=url_parameters + ) + def get_dir_contents(self, path, ref=github.GithubObject.NotSet): """ :calls: `GET /repos/:owner/:repo/contents/:path `_ diff --git a/github/tests/Repository.py b/github/tests/Repository.py index a2d9bb76..f016407c 100644 --- a/github/tests/Repository.py +++ b/github/tests/Repository.py @@ -412,6 +412,16 @@ class Repository(Framework.TestCase): self.assertEqual(len(self.repo.get_readme(ref="refs/heads/topic/ExperimentOnDocumentation").content), 6747) self.assertEqual(len(self.repo.get_contents("doc/ReferenceOfClasses.md", ref="refs/heads/topic/ExperimentOnDocumentation").content), 43929) + def testCreateFile(self): + self.repo.create_file('', '', ) + + def testUpdateFile(self): + pass + + def testDeleteFile(self): + pass + + def testGetArchiveLink(self): self.assertEqual(self.repo.get_archive_link("tarball"), "https://nodeload.github.com/jacquev6/PyGithub/tarball/master") self.assertEqual(self.repo.get_archive_link("zipball"), "https://nodeload.github.com/jacquev6/PyGithub/zipball/master")