def get_github_uploader(): from agithub.GitHub import GitHub import requests with open(os.path.expanduser("~/.frida-release-github-token"), "r") as f: token = f.read().strip() g = GitHub(token=token) def repo(): return g.repos.frida.frida status, data = repo().releases.tags[tag_name].get() if status != 200: if status == 404: status, data = repo().releases.post( body={ 'tag_name': tag_name, 'name': "Frida {}".format(version), 'body': "See http://www.frida.re/news/ for details.", }) else: raise RuntimeError( "Unexpected error trying to get current release; status={} data={}" .format(status, data)) upload_url = data['upload_url'] upload_url = upload_url[:upload_url.index("{")] def upload(name, mimetype, data): try: r = requests.post(url=upload_url, params={ "name": name, }, headers={ "Authorization": "Token {}".format(token), "Content-Type": mimetype, }, data=data) r.raise_for_status() print("Uploaded", name) except Exception as e: print("Skipping {}: {}".format(name, e)) return upload
def upload_asset_to_github(release_id, asset): gh = GitHub(token=GITHUB_TOKEN, api_url='uploads.github.com') with open(asset, 'rb') as f: file_content = f.read() file_name = os.path.basename(asset) status, r = gh.repos[OWNER][REPO].releases[release_id].assets.post( name=file_name, body=file_content, headers={'content-type': 'application/octet-stream'}) if status == 201: print("Successful upload") else: print("Upload failed with message: {}".format(r)) sys.exit(1)
def get_github_metadata(url, token): info = get_repo_info(url) github = GitHub(token=token) result = github.repos[info['owner']][info['repo']].get() if result[0] == 200: metadata = result[1] elif result[0] == 301: repo = re.match('https://api.github.com/repositories/([0-9]+)', result[1]['url']).group(1) metadata = github.repositories[repo].get()[1] else: raise Exception('Unexpected result: %d', result[0]) npm_name = get_npm_name(info['owner'], info['repo'], github) if not npm_name is None: metadata['npm'] = npm_name return metadata
def get_access_token(inst_id): """ Get application access token for the provided installation. :param inst_id: installation id :return: access token (string) :raises GithubError """ if not settings.GITHUB_APP_PEM: raise GithubError('Github app private key is empty') pem = settings.GITHUB_APP_PEM.decode('unicode-escape').encode() headers = HEADERS.copy() headers['Authorization'] = f"Bearer {create_jwt(settings.GITHUB_APP_ID, pem)}" g = GitHub(paginate=True, sleep_on_ratelimit=False) status, body = g.app.installations[inst_id].access_tokens.post(headers=headers) if status == 201 and 'token' in body: return body['token'] else: raise GithubError(body)
def GetLastReleaseOrTagName(buildSetup): """ Get the name of latest release. If none is found, all releases will be searched for highest number. If there is although no name found, the tags will be searched. """ from agithub.GitHub import GitHub token = buildSetup.gitConfig["token"] user = buildSetup.gitConfig["user"] repo = buildSetup.gitConfig["repo"] branch = buildSetup.gitConfig["branch"] gh = GitHub(token=token) # first try if there's already a latest release lastRelease = '' page = 1 while page > 0: rc, data = gh.repos[user][repo].releases.get(sha=branch, per_page=100, page=page) if rc != 200: break page = NextPage(gh) for release in data: if release["name"] and not release["draft"]: return release["name"].lstrip("v") # ok, no releases, let's check the tags. if lastRelease == '': page = 1 while page > 0: rc, data = gh.repos[user][repo].git.refs.tags.get( sha=branch, per_page=100, page=page ) if rc != 200: break page = NextPage(gh) for tag in data: if tag['ref'][10:] > lastRelease: lastRelease = tag['ref'][10:] return lastRelease
def get_last_release(owner: str = 'shalb', repo: str = 'cluster.dev') -> str: """Get last Github repo release. Args: owner: (str) repo owner name. Default: 'shalb'. repo: (str) repo name. Default: 'cluster.dev'. Returns: realise_version string. """ gh_api = GitHub() status, response = getattr( getattr( gh_api.repos, owner, ), repo, ).releases.latest.get() if status != 200: # noqa: WPS432 sys.exit(f"Can't access Github. Full error: {response}") return response['tag_name']
def get_token_from_code(code, state): """ Get user-to-server token to be used with list_repos(). The user should open https://github.com/login/oauth/authorize?client_id=<...>&redirect_uri=<...>&state=<...> :param code: Code obtained from /login/oauth/authorize redirect. :param state: Random state obtained from /login/oauth/authorize redirect. :return: access token (string) :raises GithubError """ if not settings.GITHUB_APP_CLIENT_ID or not settings.GITHUB_APP_CLIENT_SECRET: raise GithubError('Github credentials not specified') github = GitHub(paginate=True, sleep_on_ratelimit=False, api_url='github.com') status, body = github.login.oauth.access_token.post(client_id=settings.GITHUB_APP_CLIENT_ID, client_secret=settings.GITHUB_APP_CLIENT_SECRET, redirect_uri=settings.GITHUB_APP_REDIRECT_URL, state=state, code=code, headers={'Accept': 'application/json'}) if status == 200 and 'access_token' in body: return body['access_token'] else: raise GithubError(body)
def create_secrets( # noqa: WPS211 creds: Dict[str, Union[str, bool]], cloud: str, owner: str, repo_name: str, git_token: str, ): """Create Github repo secrets for specified Cloud. Args: creds: (Dict[str, Union[str, bool]]) Programmatic access to cloud: `{ 'key': str, 'secret': str, ... }`. cloud: (str) Cloud name. owner: (str) Repository owner (user or organization). repo_name: (str) Repository name. git_token: (str) Git Provider token. """ gh_api = GitHub(token=git_token) # Get public key for encryption public_key = get_repo_public_key(gh_api, owner, repo_name) if cloud == 'AWS': key = 'AWS_ACCESS_KEY_ID' secret = 'AWS_SECRET_ACCESS_KEY' # noqa: S105 # Put secret to repo body = { 'encrypted_value': encrypt(public_key['key'], creds['key']), 'key_id': public_key['key_id'], } add_secret(gh_api, owner, repo_name, key, body) body = { 'encrypted_value': encrypt(public_key['key'], creds['secret']), 'key_id': public_key['key_id'], } add_secret(gh_api, owner, repo_name, secret, body) logger.info('Secrets added to Github repo')
def fork_repo( self, upstream_url: str, github_token: str, organization_name: str = "" ): # https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-scopes-for-oauth-apps/ gh = GitHub(token=github_token) parsed_url = parse(upstream_url) # Fork the repo status, user = gh.user.get() user_name = ( user["login"] if not organization_name else organization_name ) status, forked_repo = gh.repos[user_name][parsed_url.repo].get() if status == 404: status, upstream_repo = gh.repos[parsed_url.owner][ parsed_url.repo ].get() if status == 404: print("Unable to find repo %s" % upstream_url) exit(1) args = {} if organization_name: args["organization"] = organization_name status, forked_repo = gh.repos[parsed_url.owner][ parsed_url.repo ].forks.post(**args) if status == 404: print("Error when forking repo %s" % forked_repo) exit(1) else: print( "Forked %s to %s" % (upstream_url, forked_repo["html_url"]) ) elif status == 202: print("Forked repo %s already exists" % forked_repo["full_name"]) elif status != 200: print("Status not supported: %s - %s" % (status, forked_repo)) exit(1) return forked_repo
def fetch_workflows(config): status, data = ( GitHub(token=GITHUB_TOKEN) .repos[config.github_org][config.github_repo] .actions.workflows.get() ) if status != 200: logger.error("Unable to fetch workflow list from Github") return [] workflow_list = data["workflows"] workflows = {w["name"]: w for w in config.github_workflows} available_names = {w["name"] for w in workflow_list} for workflow in workflows: if workflow not in available_names: raise ConfigError(f"{workflow['name']} is not in a workflow") res = [] for workflow in workflow_list: name = workflow["name"] if name not in workflows: continue res.append(Workflow(config, id=workflow["id"], **workflows[name])) return res
def get_pull_request_repo(self, upstream_url: str, github_token: str, organization_name: str = ""): """ :param upstream_url: :param github_token: :param organization_name: :return: List of url if success, else False """ gh = GitHub(token=github_token) parsed_url = parse(upstream_url) # Fork the repo status, user = gh.user.get() user_name = user['login'] if not organization_name else organization_name status, lst_pull = gh.repos[user_name][parsed_url.repo].pulls.get() if type(lst_pull) is dict: print(f"For url {upstream_url}, got {lst_pull.get('message')}") return False else: for pull in lst_pull: print(pull.get("html_url")) return lst_pull
def create_github_release(version, is_draft, is_prerelease, description, asset): # Create a GitHub object using an access token g = GitHub(token=GITHUB_TOKEN) name = version status, r = g.repos[OWNER][REPO].releases.post( body={ 'tag_name': version, 'target_commitish': 'master', 'name': name, 'body': description, 'draft': is_draft, 'prerelease': is_prerelease, }) if status == 201: print("Created a Github release") if asset != '': print('Uploading an asset ...') upload_asset_to_github(r['id'], asset) else: print("Failed with message: {}".format(r)) sys.exit(1)
def GetCommitCount(buildSetup): """ Get the count of commits for repository. """ from agithub.GitHub import GitHub token = buildSetup.gitConfig["token"] user = buildSetup.gitConfig["user"] repo = buildSetup.gitConfig["repo"] branch = buildSetup.gitConfig["branch"] gh = GitHub(token=token) counter = 0 page = 1 # get the commit count by adding contributions from all contributors while page > 0: rc, data = gh.repos[user][repo].contributors.get(sha=branch, anon='true', per_page=100, page=page) if rc != 200: # print "INFO: couldn't get contributors infos." return None page = NextPage(gh) for contr in data: counter += contr['contributions'] return counter
pr.set_status(pr_data["head"]["sha"], **status) def handle_push(request): data = json.loads(request.body.decode("utf-8")) log.info(json.dumps(data, sort_keys=False, indent=4)) github_handlers = { "pull_request": handle_pull_request, # "push" : handle_push, } github = GitHub(config.github_username, config.github_password) queue = Queue() ShellWorker(queue) def shutdown(): log.info("murdock: shutting down.") tornado.ioloop.IOLoop.instance().stop() def sig_handler(sig, frame): log.warning('Caught signal: %s', sig) shutdown() def startup_load_pull_requests():
def config_github_account(self, username, password): self.g = GitHub(username, password)
def paginate(ag): data = [] links = parse_header_links(ag.getheaders()) for url in [x['url'] for x in links if 'rel' in x and x['rel'] == 'next']: print('Fetching url %s' % url) status, data = ag.client.get(url) data.extend(paginate(ag)) return data if not GITHUB_TOKEN: print('Missing GITHUB_TOKEN') exit(1) g = GitHub(token=GITHUB_TOKEN) repos = [] try: with open(REPOS_FILENAME) as f: repos = json.load(f) except: pass if len(repos) == 0: print('Fetching repos') status, repos = g.orgs[ORG_NAME].repos.get() repos.extend(paginate(g)) with open(REPOS_FILENAME, 'w') as f: json.dump(repos, f)
def DoTask(self): buildSetup = self.buildSetup changelog_path = join(buildSetup.sourceDir, "CHANGELOG.TXT") appVer = buildSetup.appVersion bldDate = time.strftime("%Y-%m-%d", time.gmtime(buildSetup.buildTime)) token = buildSetup.gitConfig["token"] user = buildSetup.gitConfig["user"] repo = buildSetup.gitConfig["repo"] branch = buildSetup.gitConfig["branch"] gh = GitHub(token=token) rc, data = gh.repos[user][repo].releases.latest.get() if rc != 200: # no latest release to_commit = self.get_alternative_release(gh, user, repo) else: to_commit = data['target_commitish'] new_logs = ['**{0} ({1})**\n'.format(appVer, bldDate), '\n'] # get commits since last release page = 1 while page > 0: rc, data = gh.repos[user][repo].commits.get( sha=branch, per_page=100, page=page ) if rc != 200: print "INFO: couldn't get commits." return for item in data: if item['sha'] == to_commit: break author = item['commit']['author']['name'] try: msg = item['commit']['message'].splitlines()[0] if msg.startswith("Merge pull request #"): continue newline = "- {0} ({1})\n".format(msg, author) new_logs.append(newline) except IndexError: pass if item['sha'] == to_commit: break hdr = gh.getheaders() header = {item[0].strip(): item[1].strip() for item in hdr} # NOQA page = NextPage(gh) # read the existing changelog... try: infile = open(changelog_path, "r") except IOError: old_changelog = '' else: old_changelog = infile.read() infile.close() # ... and put the new changelog on top try: outfile = open(changelog_path, "w+") except IOError: import sys import wx parent = wx.GetApp().GetTopWindow() msg = "CHANGELOG.TXT couldn't be written.\n({0})".format( sys.exc_value ) dlg = wx.MessageDialog(parent, msg, caption="Error", style=wx.OK | wx.ICON_ERROR) dlg.ShowModal() else: outfile.writelines(new_logs) if old_changelog: outfile.write('\n\n') outfile.write(old_changelog) outfile.close()
# coding=utf-8 import logging import re from datetime import date from agithub.GitHub import GitHub from . import settings logger = logging.getLogger(__name__) github = GitHub(token=settings.GITHUB_TOKEN) class ValidationError(Exception): pass def get_pr_repo(pull_request): """ Create an agithub repo partial from a pull_request event """ base = pull_request["base"]["repo"] owner = base["owner"]["login"] return github.repos[owner][base["name"]] def create_or_fail(partial, request): status, response = partial.post(body=request) if status not in (200, 201): raise Exception("Creation failed, request: {!r}, " "response: {!r}, code: {}".format( request, response, status))
def fork_and_clone_repo( upstream_url, github_token, repo_dir_root, branch_name=None, upstream_name='upstream'): """Fork a GitHub repo, clone that repo to a local directory, add the upstream remote, create an optional feature branch and checkout that branch :param str upstream_url: GitHub URL of the upstream repo :param str github_token: GitHub auth token :param str repo_dir_root: The local directory path under which clones should be written :param str branch_name: The name of the git feature branch to create :param str upstream_name: The name to use for the remote upstream :return: github3.Head object representing the new feature branch """ # Scope needed is `public_repo` to fork and clone public repos # https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-scopes-for-oauth-apps/ gh = GitHub(token=github_token) parsed_url = parse(upstream_url) # Fork the repo status, user = gh.user.get() status, forked_repo = gh.repos[user['login']][parsed_url.repo].get() if status == 404: status, upstream_repo = ( gh.repos[parsed_url.owner][parsed_url.repo].get()) if status == 404: print("Unable to find repo %s" % upstream_url) exit(1) status, forked_repo = ( gh.repos[parsed_url.owner][parsed_url.repo].forks.post()) print("Forked %s to %s" % (upstream_url, forked_repo['ssh_url'])) else: print("Forked repo %s already exists" % forked_repo['full_name']) # Clone the repo repo_dir = os.path.expanduser(os.path.join(repo_dir_root, parsed_url.repo)) if os.path.isdir(repo_dir): print("Directory %s already exists, assuming it's a clone" % repo_dir) cloned_repo = Repo(repo_dir) else: cloned_repo = retry( wait_exponential_multiplier=1000, stop_max_delay=15000 )(Repo.clone_from)(forked_repo['ssh_url'], repo_dir) print("Cloned %s to %s" % (forked_repo['ssh_url'], repo_dir)) # Create the remote upstream try: upstream_remote = cloned_repo.remote(upstream_name) print('Remote "%s" already exists in %s' % (upstream_name, repo_dir)) except ValueError: upstream_remote = retry( wait_exponential_multiplier=1000, stop_max_delay=15000 )(cloned_repo.create_remote)(upstream_name, upstream_url) print('Remote "%s" created for %s' % (upstream_name, upstream_url)) # Fetch the remote upstream retry(wait_exponential_multiplier=1000, stop_max_delay=15000)( upstream_remote.fetch)() print('Remote "%s" fetched' % upstream_name) # Create and checkout the branch if branch_name is None: return cloned_repo else: if branch_name not in cloned_repo.refs: branch = cloned_repo.create_head(branch_name) print('Branch "%s" created' % branch_name) else: branch = cloned_repo.heads[branch_name] print('Branch "%s" already exists' % branch_name) if branch_name not in cloned_repo.remotes.origin.refs: cloned_repo.remotes.origin.push(refspec='{}:{}'.format( branch.path, branch.path)) print('Branch "%s" pushed to origin' % branch_name) else: print('Branch "%s" already exists in remote origin' % branch_name) if branch.tracking_branch() is None: branch.set_tracking_branch( cloned_repo.remotes.origin.refs[branch_name]) print('Tracking branch "%s" setup for branch "%s"' % ( cloned_repo.remotes.origin.refs[branch_name], branch_name)) else: print('Branch "%s" already setup to track "%s"' % ( branch_name, cloned_repo.remotes.origin.refs[branch_name])) branch.checkout() print('Branch "%s" checked out' % branch_name) return branch
# coding=utf-8 import logging import re from celery import Celery from agithub.GitHub import GitHub import config logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) app = Celery(__name__) app.config_from_object(config.CeleryConfig) github = GitHub(token=config.GITHUB_TOKEN) class ValidationError(Exception): pass def assert_valid_title(pull_request): if not re.match(config.RELEASE_PATTERN, pull_request["title"]): raise ValidationError("Invalid release title") def assert_valid_body(pull_request): if not len(pull_request["body"]): raise ValidationError("Missing description")
def __init__(self, token: str) -> None: self.token = token self.ghub = GitHub(token=token) self.user = None
def GetGitHubConfig(): """ Get GitHub from .gitconfig . """ gitcfg = {} if IsCIBuild(): gitcfg['token'] = os.environ["GITHUB_TOKEN"] user, repo = os.environ["APPVEYOR_REPO_NAME"].split('/') gitcfg['user'] = user gitcfg['repo'] = repo gitcfg['branch'] = os.environ["APPVEYOR_REPO_BRANCH"] return gitcfg from agithub.GitHub import GitHub # read .gitconfig cfg = expanduser('~\.gitconfig') with open(cfg, "rt") as f: cfg = f.readlines() # try to to read github section from .gitconfig idx = cfg.index("[github]\n") for i in range(idx + 1, len(cfg)): if cfg[i].strip().startswith('['): break elif cfg[i].strip() == "": continue key, val = cfg[i].strip().split('=') gitcfg.update({key.strip(): val.strip()}) # no entry for 'token' and/or 'user' found in .gitconfig if "token" not in gitcfg or "user" not in gitcfg: raise KeyError # try to get local active branch try: result = subprocess.check_output(r"git status -b --porcelain") except subprocess.CalledProcessError: local_branch = "" else: local_branch = result.split()[1].split("...")[0] # try to get some defaults for repo and branch gh = GitHub(token=gitcfg["token"]) gitcfg["all_repos"] = {} gitcfg.update({"repo": "", "branch": ""}) page = 1 while page > 0: rc, data = gh.user.repos.get(page=page) page = NextPage(gh) if rc == 200: for repo in data: if repo["name"] == "EventGhost": usr, rep = repo["full_name"].split("/") page2 = 1 branches = [] while page2 > 0: rc2, data2 = gh.repos[usr][rep].branches.get( page=page2) if rc2 == 200: for br in data2: branches.append(br["name"]) page2 = NextPage(gh) gitcfg["all_repos"].update({ repo["full_name"]: { "name": repo["name"], "all_branches": branches, "def_branch": local_branch if local_branch in branches else repo["default_branch"] } }) gitcfg.update({ "repo": repo["name"], "repo_full": repo["full_name"], "branch": local_branch if local_branch in branches else repo["default_branch"] }) else: raise ValueError return gitcfg
def test_token(self): gh = GitHub(username='******', token='deadbeef') self.assertTrue(gh is not None) gh = GitHub(token='deadbeef') self.assertTrue(gh is not None)
def fork_and_clone_repo( upstream_url, github_token, repo_dir_root, branch_name=None, upstream_name="upstream", organization_name=None, fork_only=False, repo_root=None, ): """Fork a GitHub repo, clone that repo to a local directory, add the upstream remote, create an optional feature branch and checkout that branch :param str upstream_url: GitHub URL of the upstream repo :param str github_token: GitHub auth token :param str repo_dir_root: The local directory path under which clones should be written :param str branch_name: The name of the git feature branch to create :param str upstream_name: The name to use for the remote upstream :param str organization_name: The name the organization that replace actual user :param bool fork_only: Stop after forking and don't clone :param obj repo_root: Repo parent, if not None, use submodule with it :return: github3.Head object representing the new feature branch """ # Scope needed is `public_repo` to fork and clone public repos # https://developer.github.com/apps/building-integrations/setting-up-and-registering-oauth-apps/about-scopes-for-oauth-apps/ gh = GitHub(token=github_token) parsed_url = parse(upstream_url) # Fork the repo status, user = gh.user.get() user_name = user["login"] if not organization_name else organization_name status, forked_repo = gh.repos[user_name][parsed_url.repo].get() if status == 404: status, upstream_repo = gh.repos[parsed_url.owner][ parsed_url.repo].get() if status == 404: print("Unable to find repo %s" % upstream_url) exit(1) args = {} if organization_name: args["organization"] = organization_name status, forked_repo = gh.repos[parsed_url.owner][ parsed_url.repo].forks.post(**args) if status == 404: print("Error when forking repo %s" % forked_repo) exit(1) else: print("Forked %s to %s" % (upstream_url, forked_repo["html_url"])) elif status == 202: print("Forked repo %s already exists" % forked_repo["full_name"]) elif status != 200: print("Status not supported: %s - %s" % (status, forked_repo)) exit(1) if fork_only: return True # Clone the repo repo_dir = os.path.expanduser(os.path.join(repo_dir_root, parsed_url.repo)) if repo_root: # TODO validate not already submodule # forked_repo['ssh_url'] http_url = f"https://{(forked_repo['ssh_url'][4:]).replace(':', '/')}" try: if branch_name: submodule_repo = retry(wait_exponential_multiplier=1000, stop_max_delay=15000)( repo_root.create_submodule)( repo_dir_root, repo_dir_root, url=http_url, branch=branch_name, ) else: submodule_repo = retry(wait_exponential_multiplier=1000, stop_max_delay=15000)( repo_root.create_submodule)( repo_dir_root, repo_dir_root, url=http_url) except KeyError as e: if os.path.isdir(repo_dir_root): print(f"Warning, submodule {repo_dir_root} already exist, " "you need to add it in stage.") else: print( f"\nERROR Cannot create submodule {repo_dir_root}." f"Maybe you need to delete .git/modules/{repo_dir_root}\n") return # # Delete appropriate submodule and recreate_submodule # shutil.rmtree(f".git/modules/{repo_dir_root}", ignore_errors=True) # if branch_name: # submodule_repo = retry( # wait_exponential_multiplier=1000, # stop_max_delay=15000 # )(repo_root.create_submodule)(repo_dir_root, repo_dir_root, # url=http_url, # branch=branch_name) # else: # submodule_repo = retry( # wait_exponential_multiplier=1000, # stop_max_delay=15000 # )(repo_root.create_submodule)(repo_dir_root, repo_dir_root, # url=http_url) # Update submodule # print(f"Try to fix submodule {repo_dir_root} with update them all.") # retry( # wait_exponential_multiplier=1000, # stop_max_delay=15000 # )(repo_root.submodule_update)(recursive=False) # if os.path.isdir(repo_dir_root): # print(f"Submodule {repo_dir_root} fixed.") # else: # # TODO remove submodule # print(f"Error, submodule {repo_dir_root} is configured, but not " # f"existing. Do git submodule update") cloned_repo = Repo(repo_dir_root) print("Cloned %s to %s" % (http_url, repo_dir)) # sm = cloned_repo.create_submodule('mysubrepo', 'path/to/subrepo', # url=bare_repo.git_dir, branch='master') else: if os.path.isdir(repo_dir): print("Directory %s already exists, assuming it's a clone" % repo_dir) cloned_repo = Repo(repo_dir) else: cloned_repo = retry(wait_exponential_multiplier=1000, stop_max_delay=15000)(Repo.clone_from)( forked_repo["ssh_url"], repo_dir) print("Cloned %s to %s" % (forked_repo["ssh_url"], repo_dir)) # Create the remote upstream try: upstream_remote = cloned_repo.remote(upstream_name) print('Remote "%s" already exists in %s' % (upstream_name, repo_dir)) except ValueError: upstream_remote = retry(wait_exponential_multiplier=1000, stop_max_delay=15000)( cloned_repo.create_remote)(upstream_name, upstream_url) print('Remote "%s" created for %s' % (upstream_name, upstream_url)) # Fetch the remote upstream retry(wait_exponential_multiplier=1000, stop_max_delay=15000)(upstream_remote.fetch)() print('Remote "%s" fetched' % upstream_name) # Create and checkout the branch if branch_name is None: return cloned_repo else: if branch_name not in cloned_repo.refs: branch = cloned_repo.create_head(branch_name) print('Branch "%s" created' % branch_name) else: branch = cloned_repo.heads[branch_name] print('Branch "%s" already exists' % branch_name) if branch_name not in cloned_repo.remotes.origin.refs: cloned_repo.remotes.origin.push( refspec="{}:{}".format(branch.path, branch.path)) print('Branch "%s" pushed to origin' % branch_name) else: print('Branch "%s" already exists in remote origin' % branch_name) if branch.tracking_branch() is None: branch.set_tracking_branch( cloned_repo.remotes.origin.refs[branch_name]) print('Tracking branch "%s" setup for branch "%s"' % (cloned_repo.remotes.origin.refs[branch_name], branch_name)) else: print('Branch "%s" already setup to track "%s"' % (branch_name, cloned_repo.remotes.origin.refs[branch_name])) branch.checkout() print('Branch "%s" checked out' % branch_name) return branch
import os from agithub.GitHub import GitHub from ..common.values import Status try: GITHUB_TOKEN = open('/run/secrets/github_token').read().rstrip() except FileNotFoundError: GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN') if not GITHUB_TOKEN: raise CLIENT = GitHub(token=GITHUB_TOKEN) def get_status_for_count(count): if count < 1: return Status.GREEN if count < 6: return Status.YELLOW return Status.RED def get_github_data(username, repo): code, body = CLIENT.repos[username][repo].get() if code != 200: return { 'issues': { 'count': float('inf'), 'status': Status.UNKNOWN
def main(): keyfile = os.path.join(os.environ['HOME'], GITHUBTOKEN_FILE) parser = argparse.ArgumentParser() parser.add_argument("-k", "--keyfile", type=argparse.FileType('r'), default=keyfile, help="File containing github token") parser.add_argument("-c", "--comment", action="store_true", help="Put a comment with a reference under" "the original PR") parser.add_argument("-n", "--noop", action="store_true", help="Limited noop mode, creates branch, but doesn't" "push and create the PR") parser.add_argument("-r", "--release-branch", type=str, help="Base the backport on this branch, " "default is the latest") parser.add_argument("--backport-branch-fmt", type=str, default=BACKPORT_BRANCH, help="Backport branch format. " "Fields '{release}' and '{origbranch} will be " "replaced by the release name and remote branch " "name.") parser.add_argument('-d', '--gitdir', type=str, default=os.getcwd(), help="Base git repo to work from") parser.add_argument("PR", type=int, help="Pull request number to backport") args = parser.parse_args() gittoken = args.keyfile.read().strip() g = GitHub(token=gittoken) # TODO: exception handling status, user = g.user.get() if status != 200: print("Could not retrieve user: {}".format(user['message'])) exit(1) username = user['login'] status, pulldata = g.repos[ORG][REPO].pulls[args.PR].get() if status != 200: print("Commit #{} not found: {}".format(args.PR, pulldata['message'])) sys.exit(2) if not pulldata['merged']: print("Original PR not yet merged") exit(0) print("Fetching for commit: #{}: {}".format(args.PR, pulldata['title'])) orig_branch = pulldata['head']['ref'] status, commits = g.repos[ORG][REPO].pulls[args.PR].commits.get() if status != 200: print("No commits found for #{}: {}".format(args.PR, commits['message'])) sys.exit(3) for commit in commits: print("found {} : {}".format(commit['sha'], commit['commit']['message'])) # Find latest release branch if args.release_branch: release_fullname = args.release_branch release_shortname = _branch_name_strip(args.release_branch) else: status, branches = g.repos[ORG][REPO].branches.get() if status != 200: print("Could not retrieve branches for {}/{}: {}" .format(ORG, REPO, branches['message'])) sys.exit(4) release_shortname, release_fullname = _get_latest_release(branches) if not release_fullname: print("No release branch found, exiting") sys.exit(5) print("Backport based on branch {}".format(release_fullname)) repo = git.Repo(args.gitdir) # Fetch current upstream upstream_remote = _get_upstream(repo) if not upstream_remote: print("No upstream remote found, can't fetch") exit(6) print("Fetching {} remote".format(upstream_remote)) upstream_remote.fetch() # Build topic branch in temp dir new_branch = args.backport_branch_fmt.format(release=release_shortname, origbranch=orig_branch) if new_branch in repo.branches: print("ERROR: Branch {} already exists".format(new_branch)) sys.exit(1) worktree_dir = os.path.join(args.gitdir, WORKTREE_SUBDIR) repo.git.worktree("add", "-b", new_branch, WORKTREE_SUBDIR, "{}/{}".format(upstream_remote, release_fullname)) try: bp_repo = git.Repo(worktree_dir) # Apply commits for commit in commits: bp_repo.git.cherry_pick('-x', commit['sha']) # Push to github origin = _find_remote(repo, username, REPO) print("Pushing branch {} to {}".format(new_branch, origin)) if not args.noop: repo.git.push(origin, '{0}:{0}'.format(new_branch)) except Exception as exc: # Delete worktree print("Pruning temporary workdir at {}".format(worktree_dir)) _delete_worktree(repo, worktree_dir) # also delete branch created by worktree; this is only possible after # the worktree was deleted repo.delete_head(new_branch) raise exc else: # Delete worktree print("Pruning temporary workdir at {}".format(worktree_dir)) _delete_worktree(repo, worktree_dir) labels = _get_labels(pulldata) merger = pulldata['merged_by']['login'] if not args.noop: # Open new PR on github pr = { 'title': "{} [backport {}]".format(pulldata['title'], release_shortname), 'head': '{}:{}'.format(username, new_branch), 'base': release_fullname, 'body': "# Backport of #{}\n\n{}".format(args.PR, pulldata['body']), 'maintainer_can_modify': True, } status, new_pr = g.repos[ORG][REPO].pulls.post(body=pr) if status != 201: print("Error creating the new pr: \"{}\". Is \"Public Repo\"" " access enabled for the token" .format(new_pr['message'])) pr_number = new_pr['number'] print("Create PR number #{} for backport".format(pr_number)) g.repos[ORG][REPO].issues[pr_number].labels.post(body=labels) review_request = {"reviewers": [merger]} g.repos[ORG][REPO].pulls[pr_number].\ requested_reviewers.post(body=review_request) # Put commit under old PR if args.comment and not args.noop: comment = {"body": "Backport provided in #{}".format(pr_number)} status, res = g.repos[ORG][REPO].\ issues[args.PR].comments.post(body=comment) if status != 201: print("Something went wrong adding the comment: {}" .format(res['message'])) print("Added comment to #{}".format(args.PR))
def DoTask(self): buildSetup = self.buildSetup appVer = buildSetup.appVersion gitConfig = buildSetup.gitConfig token = gitConfig["token"] user = gitConfig["user"] repo = gitConfig["repo"] branch = gitConfig["branch"] ref = 'heads/{0}'.format(branch) setupFile = 'EventGhost_{0}_Setup.exe'.format(appVer) setupPath = join(buildSetup.outputDir, setupFile) chglogFile = "CHANGELOG.md" chglogPath = join(buildSetup.outputDir, chglogFile) print "reading changelog" try: f = open(chglogPath, 'r') except IOError: print "ERROR: couldn't read changelog file ({0}).".format(chglogFile) return else: changelog = f.read() f.close() print "loading setup file" try: f = open(setupPath, 'rb') except IOError: print "ERROR: '{0}' not found.".format(setupFile) return else: setupFileContent = f.read() f.close() gh = GitHub(token=token) print "getting release info" releaseExists = False page = 1 while page > 0: rc, data = gh.repos[user][repo].releases.get( sha=branch, per_page=100, page=page ) page = NextPage(gh) if rc == 200: for rel in data: if rel['name'][1:] == appVer: app = wx.GetApp() win = app.GetTopWindow() dlg = wx.MessageDialog( win, caption="Information", message="Found an existing GitHub release matching" " 'v{0}'\nOverwrite it?".format(appVer), style=wx.YES_NO ) if dlg.ShowModal() == wx.ID_NO: return releaseId = rel["id"] uploadUrl = str(rel['upload_url'][:-13]) releaseExists = True print "getting branch info" rc, data = gh.repos[user][repo].branches[branch].get() if rc != 200: print "ERROR: couldn't get branch info." return commitSha = data['commit']['sha'] rc, data = gh.repos[user][repo].contents[chglogFile].get(ref=branch) if rc == 200: remoteChangelog = base64.decodestring(data["content"]) else: remoteChangelog = None if changelog != remoteChangelog: print "getting commit referenced by branch" rc, data = gh.repos[user][repo].git.commits[commitSha].get() if rc != 200: print "ERROR: couldn't get commit info." return treeSha = data['tree']['sha'] print "getting tree" rc, data = gh.repos[user][repo].git.trees[treeSha].get() if rc != 200: print "ERROR: couldn't get tree info." return blob = None print "getting blob for {0}".format(chglogFile) for entry in data['tree']: if entry['path'] == chglogFile and entry['type'] == 'blob': blob = entry break if blob is None: print "ERROR: couldn't get blob info." return print "posting new changelog" body = { 'content': changelog, 'encoding': 'utf-8' } rc, data = gh.repos[user][repo].git.blobs.post(body=body) if rc != 201: print "ERROR: couldn't post new changelog contents." return print "posting tree" newblob = { 'path': blob['path'], 'mode': blob['mode'], 'type': blob['type'], 'sha': data['sha'] } body = { 'tree': [newblob], 'base_tree': treeSha } rc, data = gh.repos[user][repo].git.trees.post(body=body) if rc != 201: print "ERROR: couldn't post new tree." return newTreeSha = data['sha'] print "creating commit for changelog update" body = { 'message': "Add changelog for v{0}".format(appVer), 'tree': newTreeSha, 'parents': [commitSha] } rc, data = gh.repos[user][repo].git.commits.post(body=body) if rc != 201: print "ERROR: couldn't create commit for changelog update." return newCommitSha = data['sha'] print "updating reference for branch to new commit" body = {'sha': newCommitSha} rc, data = gh.repos[user][repo].git.refs[ref].patch(body=body) if rc != 200: print "ERROR: couldn't update reference ({0}) with new commit.".format(ref) return if not releaseExists: print "extracting changelog for this release" relChglog = '' chgLines = changelog.splitlines(True) try: for i in range(1, len(chgLines)): if chgLines[i].startswith("## "): break else: relChglog += chgLines[i] except IndexError: pass relChglog = relChglog.strip() print "creating release" body = {'tag_name': 'v{0}'.format(appVer), 'target_commitish': newCommitSha, 'name': 'v{0}'.format(appVer), 'body': relChglog, #'draft': False, 'prerelease': ("-" in self.buildSetup.appVersion) } rc, data = gh.repos[user][repo].releases.post(body=body) if rc != 201: print "ERROR: couldn't create a release on GitHub." return uploadUrl = str(data['upload_url'][:-13]) else: print 'deleting existing asset' rc, data = gh.repos[user][repo].releases[releaseId].assets.get() if rc == 200: for asset in data: if asset["name"] == setupFile: rc, data = gh.repos[user][repo].releases.\ assets[asset["id"]].delete() if rc != 204: print "ERROR: couldn't delete existing asset." return break print "uploading setup file" url = uploadUrl + '?name={0}'.format(setupFile) headers = {'content-type': 'application/octet-stream', 'authorization': 'Token {0}'.format(token), 'accept': 'application/vnd.github.v3+json', 'user-agent': 'agithub/v2.0'} conn = http.client.HTTPSConnection('uploads.github.com') conn.request('POST', url, setupFileContent, headers) response = conn.getresponse() status = response.status conn.close() if status != 201: print "ERROR: couldn't upload installer file to GitHub." return
def test_user_pw(self): gh = GitHub('korfuri', '1234') self.assertTrue(gh is not None) gh = GitHub(username='******', password='******') self.assertTrue(gh is not None)
def main(): parser = argparse.ArgumentParser() parser.add_argument('--input', type=argparse.FileType('r'), help='Input file to parse') parser.add_argument('--token', type=str, help='GitHub token') parser.add_argument('--pr', type=str, help='GitHub PR') parser.add_argument('--sha', type=str, help='GitHub SHA') args = parser.parse_args() file = args.input my_body_dedupe = "Produced by binaryCompatability.py" body = f"Binary incompatibility detected for commit {args.sha}.\n" \ f" See the uploaded artifacts from the action for details. You must bump the version number.\n\n" incompatible = False tree = ET.parse(file) for clazz in tree.getroot().findall("./classes/class"): any_incompatible = False body += f"{clazz.attrib['fullyQualifiedName']} is " if clazz.attrib['binaryCompatible'] == "false": body += "binary incompatible" incompatible = True any_incompatible = True if clazz.attrib['sourceCompatible'] == "false": if any_incompatible: body += " and is " body += "source incompatible" any_incompatible = True if any_incompatible: body += f" because of " \ f"{', '.join({x.text for x in findall_recursive(clazz, 'compatibilityChanges/compatibilityChange')})}" else: body += "fully compatible" body += "\n" body += "\n" + my_body_dedupe token = args.token pr = args.pr gh = GitHub(token=token) existing_comments = gh.repos[os.getenv( "GITHUB_REPOSITORY")].issues[pr].comments.get() if existing_comments[0] == 200: existing_comments = list( filter(lambda i: my_body_dedupe in i["body"], existing_comments[1])) else: existing_comments = [] if existing_comments: comment_id = existing_comments[0]["id"] if incompatible: updated_issue = gh.repos[os.getenv( "GITHUB_REPOSITORY")].issues.comments[comment_id].patch( body={"body": body}) print(updated_issue, flush=True) else: gh.repos[os.getenv( "GITHUB_REPOSITORY")].issues.comments[comment_id].delete() elif incompatible: issue = gh.repos[os.getenv( "GITHUB_REPOSITORY")].issues[pr].comments.post(body={"body": body}) print(issue, flush=True)
def test_token_password(self): with self.assertRaises(TypeError): GitHub(username='******', password='******', token='deadbeef')
def agithub_client(monkeypatch): token = os.environ["GITHUB_TOKEN"] monkeypatch.setenv("INPUT_GITHUB-TOKEN", token) yield GitHub(token=token)