예제 #1
0
    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
예제 #2
0
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
예제 #4
0
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)
예제 #5
0
파일: Utils.py 프로젝트: WoLpH/EventGhost
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
예제 #6
0
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']
예제 #7
0
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)
예제 #8
0
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')
예제 #9
0
    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
예제 #10
0
 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
예제 #11
0
    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
예제 #12
0
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)
예제 #13
0
파일: Utils.py 프로젝트: WoLpH/EventGhost
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
예제 #14
0
            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)
예제 #16
0
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)
예제 #17
0
    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()
예제 #18
0
# 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))
예제 #19
0
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
예제 #20
0
# 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")
예제 #21
0
 def __init__(self, token: str) -> None:
     self.token = token
     self.ghub = GitHub(token=token)
     self.user = None
예제 #22
0
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
예제 #23
0
    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)
예제 #24
0
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
예제 #25
0
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
예제 #26
0
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))
예제 #27
0
    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
예제 #28
0
    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)
예제 #30
0
 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)