Repository: PyGithub/PyGithub

Issue:
Feature Request: Deployments API
It appears that the Deployments API isn't currently in PyGithub. This API has been around for years. Is there any chance it could get added to PyGithub?

https://developer.github.com/v3/repos/deployments/


Discussion:
I'm going to work on this in my spare time, but I fear it's going to be as large as the branch protection rabbit hole I fell into -- see 171cc567ae4b4850a6270d3ed728a2f995a7462f
@s-t-e-v-e-n-k no pressure here, but did you manage to get this working?
i'm very interested in this for a personal project :) 
I worked on this yesterday, and I think I have enough of it implemented, but I need to find some time to write tests before I propose a PR.
@eMerzh @jamiegs I've pushed up a branch linked above that implements it, but I'm not certain about a few sharp edges. Are you guys able to test it out in the real world and tell me what feels awkward/wrong?
awesome @s-t-e-v-e-n-k ❤️ ... i'll try to give it a go in the next week, but it seems to have everything i need :)
@eMerzh Have you had a chance to test this? Merging it soon would be awesome.
hey, sorry, bit late, but it seems to work as expected :)

thanks for this ...

@eMerzh Thanks for the confirmation, I'll push up a PR soon and we can get this in a proper release.

Resolving patch:
diff --git a/github/Deployment.py b/github/Deployment.py
new file mode 100644
--- /dev/null
+++ b/github/Deployment.py
@@ -0,0 +1,187 @@
+# -*- coding: utf-8 -*-
+
+############################ Copyrights and license ############################
+#                                                                              #
+# Copyright 2020 Steve Kowalik <steven@wedontsleep.org>                        #
+#                                                                              #
+# This file is part of PyGithub.                                               #
+# http://pygithub.readthedocs.io/                                              #
+#                                                                              #
+# PyGithub is free software: you can redistribute it and/or modify it under    #
+# the terms of the GNU Lesser General Public License as published by the Free  #
+# Software Foundation, either version 3 of the License, or (at your option)    #
+# any later version.                                                           #
+#                                                                              #
+# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY  #
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    #
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more #
+# details.                                                                     #
+#                                                                              #
+# You should have received a copy of the GNU Lesser General Public License     #
+# along with PyGithub. If not, see <http://www.gnu.org/licenses/>.             #
+#                                                                              #
+################################################################################
+
+import github.GithubObject
+
+
+class Deployment(github.GithubObject.CompletableGithubObject):
+    """
+    This class represents Deployments. The reference can be found here https://developer.github.com/v3/repos/deployments
+    """
+
+    def __repr__(self):
+        return self.get__repr__({"id": self._id.value, "url": self._url.value})
+
+    @property
+    def id(self):
+        """
+        :type: int
+        """
+        self._completeIfNotSet(self._id)
+        return self._id.value
+
+    @property
+    def url(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._url)
+        return self._url.value
+
+    @property
+    def sha(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._sha)
+        return self._sha.value
+
+    @property
+    def task(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._task)
+        return self._task.value
+
+    @property
+    def payload(self):
+        """
+        :type: dict
+        """
+        self._completeIfNotSet(self._payload)
+        return self._payload.value
+
+    @property
+    def original_environment(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._original_environment)
+        return self._original_environment.value
+
+    @property
+    def environment(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._environment)
+        return self._environment.value
+
+    @property
+    def description(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._description)
+        return self._description.value
+
+    @property
+    def creator(self):
+        """
+        :type: :class:`github.NamedUser.NamedUser`
+        """
+        self._completeIfNotSet(self._creator)
+        return self._creator.value
+
+    @property
+    def created_at(self):
+        """
+        :type: datetime
+        """
+        self._completeIfNotSet(self._created_at)
+        return self._created_at.value
+
+    @property
+    def updated_at(self):
+        """
+        :type: datetime
+        """
+        self._completeIfNotSet(self._updated_at)
+        return self._updated_at.value
+
+    @property
+    def statuses_url(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._statuses_url)
+        return self._statuses_url.value
+
+    @property
+    def repository_url(self):
+        """
+        :type: string
+        """
+        self._completeIfNotSet(self._repository_url)
+        return self._repository_url.value
+
+    def _initAttributes(self):
+        self._id = github.GithubObject.NotSet
+        self._url = github.GithubObject.NotSet
+        self._sha = github.GithubObject.NotSet
+        self._task = github.GithubObject.NotSet
+        self._payload = github.GithubObject.NotSet
+        self._original_environment = github.GithubObject.NotSet
+        self._environment = github.GithubObject.NotSet
+        self._description = github.GithubObject.NotSet
+        self._creator = github.GithubObject.NotSet
+        self._created_at = github.GithubObject.NotSet
+        self._updated_at = github.GithubObject.NotSet
+        self._statuses_url = github.GithubObject.NotSet
+        self._repository_url = github.GithubObject.NotSet
+
+    def _useAttributes(self, attributes):
+        if "id" in attributes:  # pragma no branch
+            self._id = self._makeIntAttribute(attributes["id"])
+        if "url" in attributes:  # pragma no branch
+            self._url = self._makeStringAttribute(attributes["url"])
+        if "sha" in attributes:  # pragma no branch
+            self._sha = self._makeStringAttribute(attributes["sha"])
+        if "task" in attributes:  # pragma no branch
+            self._task = self._makeStringAttribute(attributes["task"])
+        if "payload" in attributes:  # pragma no branch
+            self._payload = self._makeDictAttribute(attributes["payload"])
+        if "original_environment" in attributes:  # pragma no branch
+            self._original_environment = self._makeStringAttribute(
+                attributes["original_environment"]
+            )
+        if "environment" in attributes:  # pragma no branch
+            self._environment = self._makeStringAttribute(attributes["environment"])
+        if "description" in attributes:  # pragma no branch
+            self._description = self._makeStringAttribute(attributes["description"])
+        if "creator" in attributes:  # pragma no branch
+            self._creator = self._makeClassAttribute(
+                github.NamedUser.NamedUser, attributes["creator"]
+            )
+        if "created_at" in attributes:  # pragma no branch
+            self._created_at = self._makeDatetimeAttribute(attributes["created_at"])
+        if "updated_at" in attributes:  # pragma no branch
+            self._updated_at = self._makeDatetimeAttribute(attributes["updated_at"])
+        if "statuses_url" in attributes:  # pragma no branch
+            self._statuses_url = self._makeStringAttribute(attributes["statuses_url"])
+        if "repository_url" in attributes:  # pragma no branch
+            self._repository_url = self._makeStringAttribute(
+                attributes["repository_url"]
+            )
diff --git a/github/Repository.py b/github/Repository.py
--- a/github/Repository.py
+++ b/github/Repository.py
@@ -98,6 +98,7 @@
 import github.CommitComment
 import github.Comparison
 import github.ContentFile
+import github.Deployment
 import github.Download
 import github.Event
 import github.GitBlob
@@ -1720,6 +1721,114 @@ def get_contents(self, path, ref=github.GithubObject.NotSet):
             self._requester, headers, data, completed=True
         )
 
+    def get_deployments(
+        self,
+        sha=github.GithubObject.NotSet,
+        ref=github.GithubObject.NotSet,
+        task=github.GithubObject.NotSet,
+        environment=github.GithubObject.NotSet,
+    ):
+        """
+        :calls: `GET /repos/:owner/:repo/deployments <https://developer.github.com/v3/repos/deployments/>`_
+        :param: sha: string
+        :param: ref: string
+        :param: task: string
+        :param: environment: string
+        :rtype: :class:`github.PaginatedList.PaginatedList` of :class:`github.Deployment.Deployment`
+        """
+        assert sha is github.GithubObject.NotSet or isinstance(sha, str), sha
+        assert ref is github.GithubObject.NotSet or isinstance(ref, str), ref
+        assert task is github.GithubObject.NotSet or isinstance(task, str), task
+        assert environment is github.GithubObject.NotSet or isinstance(
+            environment, str
+        ), environment
+        parameters = {}
+        if sha is not github.GithubObject.NotSet:
+            parameters["sha"] = sha
+        if ref is not github.GithubObject.NotSet:
+            parameters["ref"] = ref
+        if task is not github.GithubObject.NotSet:
+            parameters["task"] = task
+        if environment is not github.GithubObject.NotSet:
+            parameters["environment"] = environment
+        return github.PaginatedList.PaginatedList(
+            github.Deployment.Deployment,
+            self._requester,
+            self.url + "/deployments",
+            parameters,
+        )
+
+    def get_deployment(self, id_):
+        """
+        :calls: `GET /repos/:owner/:repo/deployments/:deployment_id <https://developer.github.com/v3/repos/deployments/>`_
+        :param: id_: int
+        :rtype: :class:`github.Deployment.Deployment`
+        """
+        assert isinstance(id_, int), id_
+        headers, data = self._requester.requestJsonAndCheck(
+            "GET", self.url + "/deployments/" + str(id_)
+        )
+        return github.Deployment.Deployment(
+            self._requester, headers, data, completed=True
+        )
+
+    def create_deployment(
+        self,
+        ref,
+        task=github.GithubObject.NotSet,
+        auto_merge=github.GithubObject.NotSet,
+        required_contexts=github.GithubObject.NotSet,
+        payload=github.GithubObject.NotSet,
+        environment=github.GithubObject.NotSet,
+        description=github.GithubObject.NotSet,
+    ):
+        """
+        :calls: `POST /repos/:owner/:repo/deployments <https://developer.github.com/v3/repos/deployments/>`_
+        :param: ref: string
+        :param: auto_merge: bool
+        :param: required_contexts: list of statuses
+        :param: payload: json
+        :param: environment: string
+        :param: description: string
+        :rtype: :class:`github.Deployment.Deployment`
+        """
+        assert isinstance(ref, str), ref
+        assert task is github.GithubObject.NotSet or isinstance(task, str), task
+        assert auto_merge is github.GithubObject.NotSet or isinstance(
+            auto_merge, bool
+        ), auto_merge
+        assert required_contexts is github.GithubObject.NotSet or isinstance(
+            required_contexts, list
+        ), required_contexts  # need to do better checking here
+        assert payload is github.GithubObject.NotSet or isinstance(
+            payload, str
+        ), payload  # How to assert it's JSON?
+        assert environment is github.GithubObject.NotSet or isinstance(
+            environment, str
+        ), environment
+        assert description is github.GithubObject.NotSet or isinstance(
+            description, str
+        ), description
+        post_parameters = {"ref": ref}
+        if task is not github.GithubObject.NotSet:
+            post_parameters["task"] = task
+        if auto_merge is not github.GithubObject.NotSet:
+            post_parameters["auto_merge"] = auto_merge
+        if required_contexts is not github.GithubObject.NotSet:
+            post_parameters["required_contexts"] = required_contexts
+        if payload is not github.GithubObject.NotSet:
+            post_parameters["payload"] = payload
+        if environment is not github.GithubObject.NotSet:
+            post_parameters["environment"] = environment
+        if description is not github.GithubObject.NotSet:
+            post_parameters["description"] = description
+        headers, data = self._requester.requestJsonAndCheck(
+            "POST", self.url + "/deployments", input=post_parameters,
+        )
+        return github.Deployment.Deployment(
+            self._requester, headers, data, completed=True
+        )
+
     def get_top_referrers(self):
         """
         :calls: `GET /repos/:owner/:repo/traffic/popular/referrers <https://developer.github.com/v3/repos/traffic/>`_


Test patch:
diff --git a/tests/Deployment.py b/tests/Deployment.py
new file mode 100644
--- /dev/null
+++ b/tests/Deployment.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+
+############################ Copyrights and license ############################
+#                                                                              #
+# Copyright 2020 Steve Kowalik <steven@wedontsleep.org>                        #
+#                                                                              #
+# This file is part of PyGithub.                                               #
+# http://pygithub.readthedocs.io/                                              #
+#                                                                              #
+# PyGithub is free software: you can redistribute it and/or modify it under    #
+# the terms of the GNU Lesser General Public License as published by the Free  #
+# Software Foundation, either version 3 of the License, or (at your option)    #
+# any later version.                                                           #
+#                                                                              #
+# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY  #
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    #
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more #
+# details.                                                                     #
+#                                                                              #
+# You should have received a copy of the GNU Lesser General Public License     #
+# along with PyGithub. If not, see <http://www.gnu.org/licenses/>.             #
+#                                                                              #
+################################################################################
+
+import datetime
+
+from . import Framework
+
+
+class Deployment(Framework.TestCase):
+    def setUp(self):
+        super().setUp()
+        self.deployment = (
+            self.g.get_user().get_repo("PyGithub").get_deployment(201741959)
+        )
+
+    def testAttributes(self):
+        self.assertEqual(self.deployment.id, 201741959)
+        self.assertEqual(
+            self.deployment.url,
+            "https://api.github.com/repos/jacquev6/PyGithub/deployments/201741959",
+        )
+        self.assertEqual(
+            self.deployment.sha, "8f039d9c4ebd6f24b4bb04634ed062375c11b751"
+        )
+        self.assertEqual(self.deployment.task, "deploy")
+        self.assertEqual(self.deployment.payload, {})
+        self.assertEqual(self.deployment.original_environment, "production")
+        self.assertEqual(self.deployment.environment, "production")
+        self.assertIs(self.deployment.description, None)
+        self.assertEqual(self.deployment.creator.login, "jacquev6")
+        created_at = datetime.datetime(2020, 2, 14, 3, 41, 5)
+        self.assertEqual(self.deployment.created_at, created_at)
+        self.assertEqual(self.deployment.updated_at, created_at)
+        self.assertEqual(
+            self.deployment.statuses_url,
+            "https://api.github.com/repos/jacquev6/PyGithub/deployments/201741959/statuses",
+        )
+        self.assertEqual(
+            self.deployment.repository_url,
+            "https://api.github.com/repos/jacquev6/PyGithub",
+        )
diff --git a/tests/ReplayData/Deployment.setUp.txt b/tests/ReplayData/Deployment.setUp.txt
new file mode 100644
--- /dev/null
+++ b/tests/ReplayData/Deployment.setUp.txt
@@ -0,0 +1,33 @@
+https
+GET
+api.github.com
+None
+/user
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('status', '200 OK'), ('x-ratelimit-remaining', '4967'), ('content-length', '801'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('etag', '"27524c635501121933f4f78c95b1945a"'), ('date', 'Fri, 18 May 2012 20:12:19 GMT'), ('content-type', 'application/json; charset=utf-8')]
+{"owned_private_repos":5,"collaborators":0,"type":"User","hireable":false,"avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","public_gists":1,"company":"Criteo","bio":"","url":"https://api.github.com/users/jacquev6","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","private_gists":5,"plan":{"collaborators":1,"private_repos":5,"name":"micro","space":614400},"public_repos":11,"followers":13,"login":"jacquev6","blog":"http://vincent-jacques.net","email":"vincent@vincent-jacques.net","disk_usage":16852,"html_url":"https://github.com/jacquev6","name":"Vincent Jacques","total_private_repos":5,"created_at":"2010-07-09T06:10:06Z","location":"Paris, France","id":327146,"following":24}
+
+https
+GET
+api.github.com
+None
+/repos/jacquev6/PyGithub
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('status', '200 OK'), ('x-ratelimit-remaining', '4966'), ('content-length', '1097'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('etag', '"c5eec74d4b76b80283636a8efe1a132c"'), ('date', 'Fri, 18 May 2012 20:12:20 GMT'), ('content-type', 'application/json; charset=utf-8')]
+{"svn_url":"https://github.com/jacquev6/PyGithub","has_wiki":false,"has_issues":true,"updated_at":"2012-05-18T05:29:54Z","forks":2,"homepage":"http://vincent-jacques.net/PyGithub","git_url":"git://github.com/jacquev6/PyGithub.git","url":"https://api.github.com/repos/jacquev6/PyGithub","clone_url":"https://github.com/jacquev6/PyGithub.git","open_issues":17,"fork":false,"ssh_url":"git@github.com:jacquev6/PyGithub.git","pushed_at":"2012-05-18T05:18:16Z","size":304,"private":false,"has_downloads":true,"watchers":13,"html_url":"https://github.com/jacquev6/PyGithub","owner":{"avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","url":"https://api.github.com/users/jacquev6","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","login":"jacquev6","id":327146},"name":"PyGithub","permissions":{"pull":true,"admin":true,"push":true},"mirror_url":null,"language":"Python","description":"Python library implementing the full Github API v3","created_at":"2012-02-25T12:53:47Z","id":3544490}
+
+https
+GET
+api.github.com
+None
+/repos/jacquev6/PyGithub/deployments/201741959
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('date', 'Fri, 14 Feb 2020 04:11:55 GMT'), ('content-type', 'application/json; charset=utf-8'), ('transfer-encoding', 'chunked'), ('server', 'GitHub.com'), ('status', '200 OK'), ('x-ratelimit-limit', '5000'), ('x-ratelimit-remaining', '4990'), ('x-ratelimit-reset', '1581655004'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('etag', 'W/"5993bf380aa8497ca54ef1fb542fdaa3"'), ('last-modified', 'Fri, 14 Feb 2020 03:41:05 GMT'), ('x-oauth-scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages'), ('x-accepted-oauth-scopes', 'repo, repo_deployment'), ('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'"), ('content-encoding', 'gzip'), ('x-github-request-id', '8CEE:072D:1E6D91:22D592:5E461DF5')]
+{"url":"https://api.github.com/repos/jacquev6/PyGithub/deployments/201741959","id":201741959,"node_id":"MDEwOkRlcGxveW1lbnQyMDE3NDE5NTk=","sha":"8f039d9c4ebd6f24b4bb04634ed062375c11b751","ref":"8f039d9c4ebd6f24b4bb04634ed062375c11b751","task":"deploy","payload":{},"original_environment":"production","environment":"production","description":null,"creator":{"type":"User","disk_usage":16976,"public_gists":3,"bio":"","blog":"http://vincent-jacques.net","url":"https://api.github.com/users/jacquev6","private_gists":5,"collaborators":0,"plan":{"private_repos":5,"collaborators":1,"name":"micro","space":614400},"avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","company":"Criteo","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","login":"jacquev6","email":"vincent@vincent-jacques.net","total_private_repos":5,"followers":13,"name":"VincentJacques","public_repos":11,"created_at":"2010-07-09T06:10:06Z","location":"Paris,France","id":327146,"owned_private_repos":5,"following":24,"html_url":"https://github.com/jacquev6","hireable":false},"created_at":"2020-02-14T03:41:05Z","updated_at":"2020-02-14T03:41:05Z","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/deployments/201741959/statuses","repository_url":"https://api.github.com/repos/jacquev6/PyGithub"}
+
diff --git a/tests/ReplayData/Repository.testCreateDeployment.txt b/tests/ReplayData/Repository.testCreateDeployment.txt
new file mode 100644
--- /dev/null
+++ b/tests/ReplayData/Repository.testCreateDeployment.txt
@@ -0,0 +1,11 @@
+https
+POST
+api.github.com
+None
+/repos/jacquev6/PyGithub/deployments
+{'Content-Type': 'application/json', 'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+{"ref": "8f039d9c4ebd6f24b4bb04634ed062375c11b751"}
+201
+[('date', 'Fri, 14 Feb 2020 03:41:05 GMT'), ('content-type', 'application/json; charset=utf-8'), ('content-length', '1562'), ('server', 'GitHub.com'), ('status', '201 Created'), ('x-ratelimit-limit', '5000'), ('x-ratelimit-remaining', '4992'), ('x-ratelimit-reset', '1581655004'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('etag', '"5993bf380aa8497ca54ef1fb542fdaa3"'), ('last-modified', 'Fri, 14 Feb 2020 03:41:05 GMT'), ('x-oauth-scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages'), ('x-accepted-oauth-scopes', ''), ('location', 'https://api.github.com/repos/s-t-e-v-e-n-k/test/deployments/201741959'), ('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', 'BEF6:11D9:1CEF2A:2137B1:5E4616CD')]
+{"url":"https://api.github.com/repos/jacquev6/PyGithub/deployments/201741959","id":201741959,"node_id":"MDEwOkRlcGxveW1lbnQyMDE3NDE5NTk=","sha":"8f039d9c4ebd6f24b4bb04634ed062375c11b751","ref":"8f039d9c4ebd6f24b4bb04634ed062375c11b751","task":"deploy","payload":{},"original_environment":"production","environment":"production","description":null,"creator":{"type":"User","disk_usage":16976,"public_gists":3,"bio":"","blog":"http://vincent-jacques.net","url":"https://api.github.com/users/jacquev6","private_gists":5,"collaborators":0,"plan":{"private_repos":5,"collaborators":1,"name":"micro","space":614400},"avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","company":"Criteo","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","login":"jacquev6","email":"vincent@vincent-jacques.net","total_private_repos":5,"followers":13,"name":"VincentJacques","public_repos":11,"created_at":"2010-07-09T06:10:06Z","location":"Paris,France","id":327146,"owned_private_repos":5,"following":24,"html_url":"https://github.com/jacquev6","hireable":false},"created_at":"2020-02-14T03:41:05Z","updated_at":"2020-02-14T03:41:05Z","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/deployments/201741959/statuses","repository_url":"https://api.github.com/repos/jacquev6/PyGithub"}
+
diff --git a/tests/ReplayData/Repository.testGetDeployments.txt b/tests/ReplayData/Repository.testGetDeployments.txt
new file mode 100644
--- /dev/null
+++ b/tests/ReplayData/Repository.testGetDeployments.txt
@@ -0,0 +1,11 @@
+https
+GET
+api.github.com
+None
+/repos/jacquev6/PyGithub/deployments
+{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'}
+None
+200
+[('date', 'Fri, 14 Feb 2020 04:11:55 GMT'), ('content-type', 'application/json; charset=utf-8'), ('transfer-encoding', 'chunked'), ('server', 'GitHub.com'), ('status', '200 OK'), ('x-ratelimit-limit', '5000'), ('x-ratelimit-remaining', '4990'), ('x-ratelimit-reset', '1581655004'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('etag', 'W/"5993bf380aa8497ca54ef1fb542fdaa3"'), ('last-modified', 'Fri, 14 Feb 2020 03:41:05 GMT'), ('x-oauth-scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages'), ('x-accepted-oauth-scopes', 'repo, repo_deployment'), ('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'"), ('content-encoding', 'gzip'), ('x-github-request-id', '8CEE:072D:1E6D91:22D592:5E461DF5')]
+[{"url":"https://api.github.com/repos/jacquev6/PyGithub/deployments/201741959","id":201741959,"node_id":"MDEwOkRlcGxveW1lbnQyMDE3NDE5NTk=","sha":"8f039d9c4ebd6f24b4bb04634ed062375c11b751","ref":"8f039d9c4ebd6f24b4bb04634ed062375c11b751","task":"deploy","payload":{},"original_environment":"production","environment":"production","description":null,"creator":{"type":"User","disk_usage":16976,"public_gists":3,"bio":"","blog":"http://vincent-jacques.net","url":"https://api.github.com/users/jacquev6","private_gists":5,"collaborators":0,"plan":{"private_repos":5,"collaborators":1,"name":"micro","space":614400},"avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","company":"Criteo","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","login":"jacquev6","email":"vincent@vincent-jacques.net","total_private_repos":5,"followers":13,"name":"VincentJacques","public_repos":11,"created_at":"2010-07-09T06:10:06Z","location":"Paris,France","id":327146,"owned_private_repos":5,"following":24,"html_url":"https://github.com/jacquev6","hireable":false},"created_at":"2020-02-14T03:41:05Z","updated_at":"2020-02-14T03:41:05Z","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/deployments/201741959/statuses","repository_url":"https://api.github.com/repos/jacquev6/PyGithub"}]
+
diff --git a/tests/Repository.py b/tests/Repository.py
--- a/tests/Repository.py
+++ b/tests/Repository.py
@@ -1192,6 +1192,16 @@ def testGetContentsWithRef(self):
             43929,
         )
 
+    def testCreateDeployment(self):
+        deployment = self.repo.create_deployment(
+            "8f039d9c4ebd6f24b4bb04634ed062375c11b751"
+        )
+        self.assertEqual(deployment.id, 201741959)
+
+    def testGetDeployments(self):
+        deployments = self.repo.get_deployments()
+        self.assertListKeyEqual(deployments, lambda d: d.id, [201741959])
+
     def testCreateFile(self):
         newFile = "doc/testCreateUpdateDeleteFile.md"
         content = "Hello world".encode()