Diff
Modified: trunk/Tools/ChangeLog (271505 => 271506)
--- trunk/Tools/ChangeLog 2021-01-15 00:14:45 UTC (rev 271505)
+++ trunk/Tools/ChangeLog 2021-01-15 00:58:01 UTC (rev 271506)
@@ -1,3 +1,26 @@
+2021-01-14 Jonathan Bedard <[email protected]>
+
+ [webkitscmpy] Add GitHub credentials
+ https://bugs.webkit.org/show_bug.cgi?id=220562
+ <rdar://problem/73063457>
+
+ Reviewed by Dewei Zhu.
+
+ * Scripts/libraries/webkitscmpy/setup.py: Bump version.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py: Bump version, add keyring.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py:
+ (GitHub):
+ (GitHub.__enter__): Set username and token in environment.
+ (GitHub.__exit__): Unset username and token in environment.
+ * Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py:
+ (GitHub.__init__):
+ (GitHub.credentials): Search for credentials in both environment and keyring before
+ prompting user.
+ (GitHub.request): Use GitHub credentials, if they are available.
+ * Scripts/webkitpy/__init__.py: Move keyring to webkitscmpy.
+ * Scripts/webkitpy/common/net/credentials.py: New version of keyring prints output when
+ Imported, suppress this output.
+
2021-01-14 Alex Christensen <[email protected]>
Add dotless j and small N to unicode lookalike character list
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/setup.py (271505 => 271506)
--- trunk/Tools/Scripts/libraries/webkitscmpy/setup.py 2021-01-15 00:14:45 UTC (rev 271505)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/setup.py 2021-01-15 00:58:01 UTC (rev 271506)
@@ -30,7 +30,7 @@
setup(
name='webkitscmpy',
- version='0.8.1',
+ version='0.9.0',
description='Library designed to interact with git and svn repositories.',
long_description=readme(),
classifiers=[
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py (271505 => 271506)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2021-01-15 00:14:45 UTC (rev 271505)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/__init__.py 2021-01-15 00:58:01 UTC (rev 271506)
@@ -46,9 +46,11 @@
"Please install webkitcorepy with `pip install webkitcorepy --extra-index-url <package index URL>`"
)
-version = Version(0, 8, 1)
+version = Version(0, 9, 0)
+AutoInstall.register(Package('entrypoints', Version(0, 3, 0)))
AutoInstall.register(Package('fasteners', Version(0, 15, 0)))
+AutoInstall.register(Package('keyring', Version(18, 0, 1)))
AutoInstall.register(Package('monotonic', Version(1, 5)))
AutoInstall.register(Package('xmltodict', Version(0, 12, 0)))
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py (271505 => 271506)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py 2021-01-15 00:14:45 UTC (rev 271505)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/mocks/remote/git_hub.py 2021-01-15 00:58:01 UTC (rev 271506)
@@ -58,7 +58,30 @@
self.head = self.commits[self.default_branch][-1]
self.tags = {}
+ self._environment = None
+ def __enter__(self):
+ prefix = self.remote.split('/')[0].replace('.', '_').upper()
+ username_key = '{}_USERNAME'.format(prefix)
+ token_key = '{}_ACCESS_TOKEN'.format(prefix)
+ self._environment = {
+ username_key: os.environ.get(username_key),
+ token_key: os.environ.get(token_key),
+ }
+ os.environ[username_key] = 'username'
+ os.environ[token_key] = 'token'
+
+ return super(GitHub, self).__enter__()
+
+ def __exit__(self, *args, **kwargs):
+ result = super(GitHub, self).__exit__(*args, **kwargs)
+ for key in self._environment.keys():
+ if self._environment[key]:
+ os.environ[key] = self._environment[key]
+ else:
+ del os.environ[key]
+ return result
+
def commit(self, ref):
if ref in self.commits:
return self.commits[ref][-1]
Modified: trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py (271505 => 271506)
--- trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py 2021-01-15 00:14:45 UTC (rev 271505)
+++ trunk/Tools/Scripts/libraries/webkitscmpy/webkitscmpy/remote/git_hub.py 2021-01-15 00:58:01 UTC (rev 271506)
@@ -21,12 +21,16 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import calendar
+import getpass
+import os
import re
import requests
import six
+import sys
from datetime import datetime
-from webkitcorepy import decorators
+from requests.auth import HTTPBasicAuth
+from webkitcorepy import OutputCapture, decorators
from webkitscmpy import Commit, Contributor
from webkitscmpy.remote.scm import Scm
from xml.dom import minidom
@@ -51,17 +55,73 @@
owner=self.owner,
name=self.name,
))
+ self._cached_credentials = None
super(GitHub, self).__init__(url, dev_branches=dev_branches, prod_branches=prod_branches, contributors=contributors)
+ def credentials(self, required=True):
+ if self._cached_credentials:
+ return self._cached_credentials
+
+ prefix = self.url.split('/')[2].replace('.', '_').upper()
+ username = os.environ.get('{}_USERNAME'.format(prefix))
+ access_token = os.environ.get('{}_ACCESS_TOKEN'.format(prefix))
+ if username and access_token:
+ self._cached_credentials = (username, access_token)
+ return username, access_token
+
+ with OutputCapture():
+ import keyring
+
+ username_prompted = False
+ password_prompted = False
+ if not username:
+ username = keyring.get_password(self.api_url, 'username')
+ if not username and required:
+ if not sys.stderr.isatty() or not sys.stdin.isatty():
+ raise OSError('No tty to prompt user for username')
+ sys.stderr.write("Authentication required to use GitHub's API\n")
+ sys.stderr.write("Please generate a 'Personal access token' via 'Developer settings' for your user\n")
+ sys.stderr.write('Username: ')
+ username = (input if sys.version_info > (3, 0) else raw_input)()
+ username_prompted = True
+
+ if not access_token and required:
+ access_token = keyring.get_password(self.api_url, username)
+ if not access_token:
+ if not sys.stderr.isatty() or not sys.stdin.isatty():
+ raise OSError('No tty to prompt user for username')
+ access_token = getpass.getpass('API key: ')
+ password_prompted = True
+
+ if username_prompted or password_prompted:
+ self._cached_credentials = (username, access_token)
+ sys.stderr.write('Store username and access token in system keyring for {}? (Y/N): '.format(self.api_url))
+ response = (input if sys.version_info > (3, 0) else raw_input)()
+ if response.lower() in ['y', 'yes', 'ok']:
+ sys.stderr.write('Storing credentials...\n')
+ keyring.set_password(self.api_url, 'username', username)
+ keyring.set_password(self.api_url, username, access_token)
+ else:
+ sys.stderr.write('Credentials cached in process.\n')
+
+ return username, access_token
+
@property
def is_git(self):
return True
- def request(self, path=None, params=None, headers=None):
+ def request(self, path=None, params=None, headers=None, authenticated=None):
headers = {key: value for key, value in headers.items()} if headers else dict()
headers['Accept'] = headers.get('Accept', 'application/vnd.github.v3+json')
+ username, access_token = self.credentials(required=bool(authenticated))
+ auth = HTTPBasicAuth(username, access_token) if username and access_token else None
+ if authenticated is False:
+ auth = None
+ if authenticated and not auth:
+ raise self.Exception('Request requires authentication, none provided')
+
params = {key: value for key, value in params.items()} if params else dict()
params['per_page'] = params.get('per_page', 100)
params['page'] = params.get('page', 1)
@@ -72,7 +132,7 @@
name=self.name,
path='/{}'.format(path) if path else '',
)
- response = requests.get(url, params=params, headers=headers)
+ response = requests.get(url, params=params, headers=headers, auth=auth)
if response.status_code != 200:
return None
result = response.json()
@@ -79,7 +139,7 @@
while isinstance(response.json(), list) and len(response.json()) == params['per_page']:
params['page'] += 1
- response = requests.get(url, params=params, headers=headers)
+ response = requests.get(url, params=params, headers=headers, auth=auth)
if response.status_code != 200:
raise self.Exception("Failed to assemble pagination requests for '{}', failed on page {}".format(url, params['page']))
result += response.json()
Modified: trunk/Tools/Scripts/webkitpy/__init__.py (271505 => 271506)
--- trunk/Tools/Scripts/webkitpy/__init__.py 2021-01-15 00:14:45 UTC (rev 271505)
+++ trunk/Tools/Scripts/webkitpy/__init__.py 2021-01-15 00:58:01 UTC (rev 271506)
@@ -41,7 +41,6 @@
AutoInstall.register(Package('importlib_metadata', Version(1, 7, 0)))
AutoInstall.register(Package('genshi', Version(0, 7, 3), pypi_name='Genshi'))
AutoInstall.register(Package('html5lib', Version(1, 1)))
-AutoInstall.register(Package('keyring', Version(7, 3, 1)))
AutoInstall.register(Package('logilab.common', Version(0, 58, 1), pypi_name='logilab-common', aliases=['logilab']))
AutoInstall.register(Package('logilab.astng', Version(0, 24, 1), pypi_name='logilab-astng', aliases=['logilab']))
AutoInstall.register(Package('mechanize', Version(0, 4, 5)))
Modified: trunk/Tools/Scripts/webkitpy/common/net/credentials.py (271505 => 271506)
--- trunk/Tools/Scripts/webkitpy/common/net/credentials.py 2021-01-15 00:14:45 UTC (rev 271505)
+++ trunk/Tools/Scripts/webkitpy/common/net/credentials.py 2021-01-15 00:58:01 UTC (rev 271506)
@@ -30,15 +30,19 @@
# Python module for reading stored web credentials from the OS.
import logging
-import keyring
import os
import platform
import re
+from webkitcorepy import OutputCapture
+
from webkitpy.common.checkout.scm import Git
from webkitpy.common.system.executive import Executive, ScriptError
from webkitpy.common.system.user import User
+with OutputCapture():
+ import keyring
+
_log = logging.getLogger(__name__)