1# Copyright (c) 2022 Nordic Semiconductor ASA 2# 3# SPDX-License-Identifier: Apache-2.0 4 5''' 6Generic GitHub helper routines which may be useful to other scripts. 7 8This file is not meant to be run directly, but rather to be imported 9as a module from other scripts. 10''' 11 12# Note that the type annotations are not currently checked by mypy. 13# Unless that changes, they serve as documentation, rather than 14# guarantees from a type checker. 15 16# stdlib 17import getpass 18import os 19import netrc 20import sys 21from typing import Dict 22 23# third party 24import github 25 26def get_github_credentials(ask: bool = True) -> Dict[str, str]: 27 '''Get credentials for constructing a github.Github object. 28 29 This function tries to get github.com credentials from these 30 places, in order: 31 32 1. a ~/.netrc file, if one exists 33 2. a GITHUB_TOKEN environment variable 34 3. if the 'ask' kwarg is truthy, from the user on the 35 at the command line. 36 37 On failure, RuntimeError is raised. 38 39 Scripts often need credentials because anonym access to 40 api.github.com is rate limited more aggressively than 41 authenticated access. Scripts which use anonymous access are 42 therefore more likely to fail due to rate limiting. 43 44 The return value is a dict which can be passed to the 45 github.Github constructor as **kwargs. 46 47 :param ask: if truthy, the user will be prompted for credentials 48 if none are found from other sources 49 ''' 50 51 try: 52 nrc = netrc.netrc() 53 except (FileNotFoundError, netrc.NetrcParseError): 54 nrc = None 55 56 if nrc is not None: 57 auth = nrc.authenticators('github.com') 58 if auth is not None: 59 return {'login_or_token': auth[0], 'password': auth[2]} 60 61 token = os.environ.get('GITHUB_TOKEN') 62 if token: 63 return {'login_or_token': token} 64 65 if ask: 66 print('Missing GitHub credentials:\n' 67 '~/.netrc file not found or has no github.com credentials, ' 68 'and GITHUB_TOKEN is not set in the environment. ' 69 'Please give your GitHub token.', 70 file=sys.stderr) 71 token = getpass.getpass('token: ') 72 return {'login_or_token': token} 73 74 raise RuntimeError('no credentials found') 75 76def get_github_object(ask: bool = True) -> github.Github: 77 '''Get a github.Github object, created with credentials. 78 79 :param ask: passed to get_github_credentials() 80 ''' 81 return github.Github(**get_github_credentials()) 82