0

I am trying to use PyGithub (https://pygithub.readthedocs.io/en/latest/apis.html) to get the deployment and report the status somewhere else. I have the following script:

from github import Github

# Github Enterprise with custom hostname
g = Github(base_url="https://{hostname}/api/v3", login_or_token="sometoken")
# get the repository
repo = g.get_repo("PyGithub/PyGithub")
# HTTP POST to /repos/:owner/:repo/deployments
deployment = repo.create_deployment(ref = 'master', environment = 'DEV', description= 'Deploying to the environment')
# getting the status
status = deployment.get_status(deployment.id)
# HTTP POST to /repos/:owner/:repo/deployments/:deployment_id/statuses
deployment.create_status(state = status.state, environment = 'DEV', description = 'deploying completed')

But it complains with:

'Repository' object has no attribute 'create_deployment'

while I see the function in (https://pygithub.readthedocs.io/en/latest/github_objects/Repository.html#github.Repository.Repository).

What am I missing?

I basically want to use those two endpoints. I was not able to find any other github API in python but even that would be fine as well.

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
harry123
  • 760
  • 1
  • 7
  • 22

1 Answers1

2

First, make sure you are using an updated version of PyGithub.

The Deployments API was only added on release version 1.47.

  • Release Notes:

    "Add Deployments API (#1424) (3d93ee1)"

  • PR #1424:

    Add a new class, Deployment to describe a deployment performed utilising GitHub. Add three methods onto Repository to list them and create them.

If you are using <1.47, then that method doesn't exist yet.

Second, I think you misunderstood parameters for deployment.get_status.

The docs are a bit unclear, but it is expecting a Deployment Status ID, not a Deployment ID. The method makes a request to the /repos/{owner}/{repo}/deployments/{deployment_id}/statuses/{status_id} endpoint to "view a deployment status for a deployment", and the code appends the passed-in id to the /statuses/ URL:

https://github.com/PyGithub/PyGithub/blob/master/github/Deployment.py#L180

def get_status(self, id_):
    """
    :calls: `GET /repos/:owner/deployments/:deployment_id/statuses/:status_id  <https://developer.github.com/v3/repos/deployments/#get-a-deployment-status>`_
    :param id_: int
    :rtype: :class:`github.DeploymentStatus.DeploymentStatus`
    """
    assert isinstance(id_, int), id_
    headers, data = self._requester.requestJsonAndCheck(
        "GET",
        self.url + "/statuses/" + str(id_),
        headers={"Accept": self._get_accept_header()},
    )

The correct API would probably be get_statuses for listing all the deployment statuses for a particular deployment. Then grab one of those IDs and pass that to get_status to get a specific DeploymentStatus object. (Though, you could also just loop through the get_statuses list, each one is already a DeploymentStatus object). If you don't have any Deployment Status yet, then you create one with create_status:

# create a Deployment
# POST /repos/{owner}/{repo}/deployments
deployment = repo.create_deployment(ref='master', description='Deploying to the environment')

# list Deployment Statuses
# https://docs.github.com/en/rest/reference/repos#list-deployment-statuses
# GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses
for status in deployment.get_statuses():
    print(status.id)  # For new deployments, this would be empty

# create a Deployment Status
# https://docs.github.com/en/rest/reference/repos#create-a-deployment-status
# POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses
new_deployment_status = deployment.create_status(state='inactive', description='inactive deployment')
print(new_deployment_status.state)

# list Deployment Statuses
# https://docs.github.com/en/rest/reference/repos#list-deployment-statuses
# GET /repos/{owner}/{repo}/deployments/{deployment_id}/statuses
for status in deployment.get_statuses():
    print(status.state, status.id)  # This should now the newly created status
#         'inactive',   461997990

# get a specific Deployment Status
deployment_status = deployment.get_statuses()[0]
deployment_status_0 = deployment.get_status(deployment_status.id))
Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
  • Thanks a lot. This makes a lot more sense. I just have one question. If we create a status first, will that be updated at all? When I am running the `create_deployment()` and `create_status()`, I get the environment and the `statename` next to it. How will the status change to `success`? Shouldn't the steps be like, we create a deployment -> use the deployment id -> check status -> POST the status then? – harry123 Jan 16 '21 at 23:33
  • @amyJ The PyGithub APIs are just calling Github's APIs, so I suggest reading first Github's docs on Deployment: https://docs.github.com/en/rest/reference/repos#deployments. The Deployment Status is a way for allowing "*external services to mark deployments with an error, failure, pending, in_progress, queued, or success state that systems listening to deployment_status events can consume*". In that diagram, your script is the "Tooling", and then some "3rd Party" service could be the one creating and updating the deployment status. – Gino Mempin Jan 17 '21 at 01:18
  • @amyJ "*Shouldn't the steps be like, we create a deployment -> use the deployment id -> check status -> POST the status then?*": Well, you can't *force* your workflow onto the APIs. It's the opposite: adapt your workflow *based* on the available APIs. From the [Deployments diagram](https://docs.github.com/en/rest/reference/repos#deployments) if it's just between "Tooling" and "Github", then you might not need to create/update the deployment status at all. You could just call `get_statuses` on the created deployment and check each one for the state (updated by some other Github service). – Gino Mempin Jan 17 '21 at 01:31