You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

111 lines
3.5 KiB

  1. #!/usr/bin/env python
  2. from __future__ import unicode_literals
  3. import base64
  4. import io
  5. import json
  6. import mimetypes
  7. import netrc
  8. import optparse
  9. import os
  10. import re
  11. import sys
  12. sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  13. from youtube_dl.compat import (
  14. compat_basestring,
  15. compat_getpass,
  16. compat_print,
  17. compat_urllib_request,
  18. )
  19. from youtube_dl.utils import (
  20. make_HTTPS_handler,
  21. sanitized_Request,
  22. )
  23. class GitHubReleaser(object):
  24. _API_URL = 'https://api.github.com/repos/ytdl-org/youtube-dl/releases'
  25. _UPLOADS_URL = 'https://uploads.github.com/repos/ytdl-org/youtube-dl/releases/%s/assets?name=%s'
  26. _NETRC_MACHINE = 'github.com'
  27. def __init__(self, debuglevel=0):
  28. self._init_github_account()
  29. https_handler = make_HTTPS_handler({}, debuglevel=debuglevel)
  30. self._opener = compat_urllib_request.build_opener(https_handler)
  31. def _init_github_account(self):
  32. try:
  33. info = netrc.netrc().authenticators(self._NETRC_MACHINE)
  34. if info is not None:
  35. self._token = info[2]
  36. compat_print('Using GitHub credentials found in .netrc...')
  37. return
  38. else:
  39. compat_print('No GitHub credentials found in .netrc')
  40. except (IOError, netrc.NetrcParseError):
  41. compat_print('Unable to parse .netrc')
  42. self._token = compat_getpass(
  43. 'Type your GitHub PAT (personal access token) and press [Return]: ')
  44. def _call(self, req):
  45. if isinstance(req, compat_basestring):
  46. req = sanitized_Request(req)
  47. req.add_header('Authorization', 'token %s' % self._token)
  48. response = self._opener.open(req).read().decode('utf-8')
  49. return json.loads(response)
  50. def list_releases(self):
  51. return self._call(self._API_URL)
  52. def create_release(self, tag_name, name=None, body='', draft=False, prerelease=False):
  53. data = {
  54. 'tag_name': tag_name,
  55. 'target_commitish': 'master',
  56. 'name': name,
  57. 'body': body,
  58. 'draft': draft,
  59. 'prerelease': prerelease,
  60. }
  61. req = sanitized_Request(self._API_URL, json.dumps(data).encode('utf-8'))
  62. return self._call(req)
  63. def create_asset(self, release_id, asset):
  64. asset_name = os.path.basename(asset)
  65. url = self._UPLOADS_URL % (release_id, asset_name)
  66. # Our files are small enough to be loaded directly into memory.
  67. data = open(asset, 'rb').read()
  68. req = sanitized_Request(url, data)
  69. mime_type, _ = mimetypes.guess_type(asset_name)
  70. req.add_header('Content-Type', mime_type or 'application/octet-stream')
  71. return self._call(req)
  72. def main():
  73. parser = optparse.OptionParser(usage='%prog CHANGELOG VERSION BUILDPATH')
  74. options, args = parser.parse_args()
  75. if len(args) != 3:
  76. parser.error('Expected a version and a build directory')
  77. changelog_file, version, build_path = args
  78. with io.open(changelog_file, encoding='utf-8') as inf:
  79. changelog = inf.read()
  80. mobj = re.search(r'(?s)version %s\n{2}(.+?)\n{3}' % version, changelog)
  81. body = mobj.group(1) if mobj else ''
  82. releaser = GitHubReleaser()
  83. new_release = releaser.create_release(
  84. version, name='youtube-dl %s' % version, body=body)
  85. release_id = new_release['id']
  86. for asset in os.listdir(build_path):
  87. compat_print('Uploading %s...' % asset)
  88. releaser.create_asset(release_id, os.path.join(build_path, asset))
  89. if __name__ == '__main__':
  90. main()