diff --git a/github/Issue.py b/github/Issue.py index 8099457c..b1a40be4 100644 --- a/github/Issue.py +++ b/github/Issue.py @@ -247,6 +247,22 @@ class Issue(github.GithubObject.CompletableGithubObject): self._completeIfNotSet(self._user) return self._user.value + @property + def locked(self): + """ + :type: bool + """ + self._completeIfNotSet(self._locked) + return self._locked.value + + @property + def active_lock_reason(self): + """ + :type: string + """ + self._completeIfNotSet(self._active_lock_reason) + return self._active_lock_reason.value + def as_pull_request(self): """ :calls: `GET /repos/:owner/:repo/pulls/:number `_ @@ -358,6 +374,32 @@ class Issue(github.GithubObject.CompletableGithubObject): ) self._useAttributes(data) + def lock(self, lock_reason): + """ + :calls: `PUT /repos/:owner/:repo/issues/:issue_number/lock `_ + :param lock_reason: string + :rtype: None + """ + assert isinstance(lock_reason, (str, unicode)), lock_reason + put_parameters = dict() + put_parameters["lock_reason"] = lock_reason + headers, data = self._requester.requestJsonAndCheck( + "PUT", + self.url + "/lock", + input=put_parameters, + headers={'Accept': Consts.mediaTypeLockReasonPreview} + ) + + def unlock(self): + """ + :calls: `DELETE /repos/:owner/:repo/issues/:issue_number/lock `_ + :rtype: None + """ + headers, data = self._requester.requestJsonAndCheck( + "DELETE", + self.url + "/lock" + ) + def get_comment(self, id): """ :calls: `GET /repos/:owner/:repo/issues/comments/:id `_ @@ -521,6 +563,8 @@ class Issue(github.GithubObject.CompletableGithubObject): self._user = github.GithubObject.NotSet def _useAttributes(self, attributes): + if "active_lock_reason" in attributes: # pragma no branch + self._active_lock_reason = self._makeStringAttribute(attributes["active_lock_reason"]) if "assignee" in attributes: # pragma no branch self._assignee = self._makeClassAttribute(github.NamedUser.NamedUser, attributes["assignee"]) if "assignees" in attributes: # pragma no branch @@ -552,6 +596,8 @@ class Issue(github.GithubObject.CompletableGithubObject): self._labels = self._makeListOfClassesAttribute(github.Label.Label, attributes["labels"]) if "labels_url" in attributes: # pragma no branch self._labels_url = self._makeStringAttribute(attributes["labels_url"]) + if "locked" in attributes: # pragma no branch + self._locked = self._makeBoolAttribute(attributes["locked"]) if "milestone" in attributes: # pragma no branch self._milestone = self._makeClassAttribute(github.Milestone.Milestone, attributes["milestone"]) if "number" in attributes: # pragma no branch diff --git a/tests/Framework.py b/tests/Framework.py index b334d358..a7082ace 100644 --- a/tests/Framework.py +++ b/tests/Framework.py @@ -128,7 +128,7 @@ class RecordingConnection: # pragma no cover (Class useful only when recording if atLeastPython3: # In Py3, return from "read" is bytes self.__writeLine(output) else: - self.__writeLine(str(output)) + self.__writeLine(output.encode("utf-8")) return FakeHttpResponse(status, headers, output) diff --git a/tests/Issue.py b/tests/Issue.py index 0c9d0138..54097ae1 100644 --- a/tests/Issue.py +++ b/tests/Issue.py @@ -93,6 +93,12 @@ class Issue(Framework.TestCase): self.issue.edit(assignee=None) self.assertEqual(self.issue.assignee, None) + def testLock(self): + self.issue.lock("resolved") + + def testUnlock(self): + self.issue.unlock() + def testCreateComment(self): comment = self.issue.create_comment("Comment created by PyGithub") self.assertEqual(comment.id, 5808311) diff --git a/tests/ReplayData/Issue.testLock.txt b/tests/ReplayData/Issue.testLock.txt new file mode 100644 index 00000000..c646cb53 --- /dev/null +++ b/tests/ReplayData/Issue.testLock.txt @@ -0,0 +1,11 @@ +https +PUT +api.github.com +None +/repos/jacquev6/PyGithub/issues/28/lock +{'Content-Type': 'application/json', 'Accept': 'application/vnd.github.sailor-v-preview+json', 'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +{"lock_reason": "resolved"} +204 +[('Server', 'GitHub.com'), ('Date', 'Fri, 03 May 2019 09:42:52 GMT'), ('Content-Type', 'application/octet-stream'), ('Status', '204 No Content'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4993'), ('X-RateLimit-Reset', '1556880113'), ('X-OAuth-Scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('X-Accepted-OAuth-Scopes', 'public_repo, repo'), ('X-GitHub-Media-Type', 'github.sailor-v-preview; format=json'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '1; mode=block'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('X-GitHub-Request-Id', 'C339:2746:A14FFE:15EFA60:5CCC0D1C')] + + diff --git a/tests/ReplayData/Issue.testUnlock.txt b/tests/ReplayData/Issue.testUnlock.txt new file mode 100644 index 00000000..dfbadb22 --- /dev/null +++ b/tests/ReplayData/Issue.testUnlock.txt @@ -0,0 +1,11 @@ +https +DELETE +api.github.com +None +/repos/jacquev6/PyGithub/issues/28/lock +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +204 +[('Server', 'GitHub.com'), ('Date', 'Fri, 03 May 2019 09:44:22 GMT'), ('Content-Type', 'application/octet-stream'), ('Status', '204 No Content'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4990'), ('X-RateLimit-Reset', '1556880113'), ('X-OAuth-Scopes', 'admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion'), ('X-Accepted-OAuth-Scopes', 'public_repo, repo'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '1; mode=block'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('X-GitHub-Request-Id', 'C373:6113:E26177:1C113F4:5CCC0D75')] + +