Title: [271506] trunk/Tools
Revision
271506
Author
[email protected]
Date
2021-01-14 16:58:01 -0800 (Thu, 14 Jan 2021)

Log Message

[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.

Modified Paths

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__)
 
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to