5
url = 'https://github.abc.defcom/api/v3/repos/abc/def/releases/401/assets?name=foo.sh'
r = requests.post(url, headers={'Content-Type':'application/binary'}, data=open('sometext.txt','r'), auth=('user','password'))

This is giving me

>>> r.text
u'{"message":"Not Found","documentation_url":"https://developer.github.com/enterprise/2.4/v3"}'

Where am I going wrong?

Ankur Agarwal
  • 19,924
  • 32
  • 117
  • 182

2 Answers2

5

So I'll preface this with the advice that if you use a library it's as easy as:

from github3 import GitHubEnterprise

gh = GitHubEnterprise(token=my_token)
repository = gh.repository('abc', 'def')
release = repository.release(id=401)
asset = release.upload_asset(content_type='application/binary', name='foo.sh', asset=open('sometext.txt', 'rb'))

With that in mind, I'll also preface this with "application/binary" is not a real media type (see: https://www.iana.org/assignments/media-types/media-types.xhtml)

Next, if you read the documentation, you'll notice that GitHub requires clients that have real SNI (Server Name Indication), so depending on your version of Python, you may also have to install pyOpenSSL, pyasn1, and ndg-httpsclient from PyPI.

I'm not sure what the URL looks like for enterprise instances, but for public GitHub, it looks like:

https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets?name=foo.sh

So you're going to have that as url, plus you're going to want your auth credentials (in your case you seem to want to use basic auth). Then you're going to want a valid media-type in the headers, e.g.,

headers = {'Content-Type': 'text/plain'}

And your call would look pretty much exactly correct:

requests.post(url, headers=headers, data=open('file.txt', 'rb'), auth=(username, password))

To get the correct url, you should do:

release = requests.get(release_url, auth=(username, password))
upload_url = release.json().get('upload_url')

Note this is a URITemplate. You'll need to remove the templating or use a library like uritemplate.py to parse it and use it to build your URL for you.

One last reminder, github3.py (the library in the original example) takes care of all of this for you.

Ian Stapleton Cordasco
  • 20,880
  • 4
  • 61
  • 69
3

APIv3 upload example without any external dependencies

Usage:

GITHUB_TOKEN=<token> ./create-release username/reponame <tag-name> <path-to-upload>

Script:

#!/usr/bin/env python3

import json
import os
import sys

from urllib.parse import urlencode
from urllib.request import Request, urlopen

repo = sys.argv[1]
tag = sys.argv[2]
upload_file = sys.argv[3]

token = os.environ['GITHUB_TOKEN']

url_template = 'https://{}.github.com/repos/' + repo + '/releases'

# Create.
_json = json.loads(urlopen(Request(
    url_template.format('api'),
    json.dumps({
        'tag_name': tag,
        'name': tag,
        'prerelease': True,
    }).encode(),
    headers={
        'Accept': 'application/vnd.github.v3+json',
        'Authorization': 'token ' + token,
    },
)).read().decode())
release_id = _json['id']

# Upload.
with open(upload_file, 'br') as myfile:
    content = myfile.read()
_json = json.loads(urlopen(Request(
    url_template.format('uploads') + '/' + str(release_id) + '/assets?' \
      + urlencode({'name': os.path.split(upload_file)[1]}),
    content,
    headers={
        'Accept': 'application/vnd.github.v3+json',
        'Authorization': 'token ' + token,
        'Content-Type': 'application/zip',
    },
)).read().decode())

Superset question with any language: How to release a build artifact asset on GitHub with a script?