Search code examples
pythongithub-api

how to download patch for pull request in github using github-api


I am trying to write a script that would download all the open "pull-requests" for a given repo into a folder with the file names as ".patch".

I am using https://pypi.org/project/ghapi/.

I have been able to login and get the list of open pull-requests and also the url that should be used for getting the patch.

However I did not find any API that could be used to directly download the patch.

If the repo is a public repository, I can use the "requests" package directly download it. However my repo is private, and hence will need authentication.

Here is my sample code

from ghapi.core import GhApi
import requests

github_token=<my token>
api=GhApi(owner=<my-org>, repo=<my-repo>,token=github_token )

for (pr_number,patch_url) in map(lambda pr: (pr['number'], pr['patch_url']), api.pulls.list(state="open", per_page=100, page=1 )):
    print(pr_number, patch_url)
    r=requests.get(patch_url, headers={'Authorization':'token '+github_token})
    open("%d.patch"%(pr_number),'wb').write(r.content)

Can someone let me know if I am missing something. I keep getting "Not Found" with the above. However, if I open the URL directly from my browser, I can see the patch.

Thanks


Solution

  • The patch_url attribute returned by api.pulls.list(...) isn't an API url; you can tell because it doesn't contain the API endpoint (api.github.com). That means it doesn't support authentication using an API token. It's meant to be presented to the user and fetched in a browser.

    If you want to get a pull request in patch format via the API, you need to fetch the pull request using a specific content-type:

    for pull in api.pulls.list(state="open", per_page=100, page=1):
        patch = api(pull.url, headers={"Accept": "application/vnd.github.patch"})
        print(patch)
    

    The api documentation shows what content types you can use when fetching pull requests.


    A warning, because I found out the hard way: while the requests module correctly treats headers as case-insensitive (so accept is the same as Accept), the ghapi module does not. When overriding the Accept header you must use the same capitalization as the module uses.