예제 #1
0
 def test_get_github_api_for_repo__not_installed(self, create_token):
     create_token.return_value = "ATOKEN"
     responses.add(
         "GET",
         "https://api.github.com/repos/TestOwner/TestRepo/installation",
         status=404,
     )
     with mock.patch.dict(
         os.environ, {"GITHUB_APP_KEY": "bogus", "GITHUB_APP_ID": "1234"}
     ):
         with pytest.raises(GithubException):
             get_github_api_for_repo(None, "TestOwner", "TestRepo")
예제 #2
0
 def _init_task(self):
     self.github_config = self.project_config.keychain.get_service("github")
     self.github = get_github_api_for_repo(
         self.project_config.keychain,
         self.project_config.repo_owner,
         self.project_config.repo_name,
     )
예제 #3
0
def notify_of_release(owner, name):
    # Dispatch a heroku-release-phase event to the github repository
    gh = get_github_api_for_repo(None, owner, name)
    repo = gh.repository(owner, name)
    url = repo._build_url("dispatches", base_url=repo._api)
    data = {"event_type": "heroku-release-phase"}
    repo._post(url, data=data)
예제 #4
0
    def test_get_github_api_for_repo(self, create_token):
        create_token.return_value = "ATOKEN"
        responses.add(
            "GET",
            "https://api.github.com/repos/TestOwner/TestRepo/installation",
            json={
                "id": 1,
                "access_tokens_url": "",
                "account": "",
                "app_id": "",
                "created_at": "",
                "events": "",
                "html_url": "",
                "permissions": "",
                "repositories_url": "",
                "repository_selection": "",
                "single_file_name": "",
                "target_id": "",
                "target_type": "",
                "updated_at": "",
            },
        )
        responses.add(
            "POST",
            "https://api.github.com/app/installations/1/access_tokens",
            status=201,
            json={"token": "ITOKEN", "expires_at": datetime.now().isoformat()},
        )

        with mock.patch.dict(
            os.environ, {"GITHUB_APP_KEY": "bogus", "GITHUB_APP_ID": "1234"}
        ):
            gh = get_github_api_for_repo(None, "TestOwner", "TestRepo")
            assert isinstance(gh.session.auth, AppInstallationTokenAuth)
예제 #5
0
    def __init__(self, project_config, spec):
        self.project_config = project_config
        self.spec = spec
        self.url = spec["github"]
        if self.url.endswith(".git"):
            self.url = self.url[:-4]

        repo_owner, repo_name = self.url.split("/")[-2:]
        self.repo_owner = repo_owner
        self.repo_name = repo_name

        self.gh = get_github_api_for_repo(project_config.keychain, repo_owner,
                                          repo_name)
        self.repo = self.gh.repository(self.repo_owner, self.repo_name)
        self.resolve()
예제 #6
0
def local_github_checkout(repo_owner, repo_name, commit_ish=None):
    with temporary_dir() as repo_root:
        # pretend it's a git clone to satisfy cci
        os.mkdir(".git")

        repo = get_github_api_for_repo(None, repo_owner, repo_name)
        if commit_ish is None:
            commit_ish = repo.repository(repo_owner, repo_name).default_branch

        zip_file = download_extract_github(repo,
                                           repo_owner,
                                           repo_name,
                                           ref=commit_ish)
        zip_file.extractall(repo_root)

        yield repo_root
예제 #7
0
 def get_github_api(self, owner=None, repo=None):
     return get_github_api_for_repo(self.keychain, owner or self.repo_owner,
                                    repo or self.repo_name)
예제 #8
0
 def get_github_api(self):
     gh = get_github_api_for_repo(GitHubSettingsKeychain(), self.owner,
                                  self.name)
     repo = gh.repository(self.owner, self.name)
     return repo
예제 #9
0
 def test_get_github_api_for_repo__token(self, GitHub):
     with mock.patch.dict(os.environ, {"GITHUB_TOKEN": "token"}):
         gh = get_github_api_for_repo(None, "TestOwner", "TestRepo")
     gh.login.assert_called_once_with(token="token")
예제 #10
0
def run_flows(*, user, plan, skip_steps, organization_url, result_class,
              result_id):
    """
    This operates with side effects; it changes things in a Salesforce
    org, and then records the results of those operations on to a
    `result`.

    Args:
        user (User): The User requesting this flow be run.
        plan (Plan): The Plan instance for the flow you're running.
        skip_steps (List[str]): The strings in the list should be valid
            step_num values for steps in this flow.
        organization_url (str): The URL of the organization, required by
            the OrgConfig.
        result_class (Union[Type[Job], Type[PreflightResult]]): The type
            of the instance onto which to record the results of running
            steps in the flow. Either a PreflightResult or a Job, as
            appropriate.
        result_id (int): the PK of the result instance to get.
    """
    result = result_class.objects.get(pk=result_id)
    token, token_secret = user.token
    repo_url = plan.version.product.repo_url
    commit_ish = plan.commit_ish or plan.version.commit_ish

    with contextlib.ExitStack() as stack:
        stack.enter_context(finalize_result(result))
        stack.enter_context(report_errors_to(user))
        tmpdirname = stack.enter_context(temporary_dir())

        # Get cwd into Python path, so that the tasks below can import
        # from the checked-out repo:
        stack.enter_context(prepend_python_path(os.path.abspath(tmpdirname)))

        # Let's clone the repo locally:
        user, repo_name = extract_user_and_repo(repo_url)
        gh = get_github_api_for_repo(None, user, repo_name)
        repo = gh.repository(user, repo_name)
        # Make sure we have the actual owner/repo name if we were redirected
        user = repo.owner.login
        repo_name = repo.name
        zip_file_name = "archive.zip"
        repo.archive("zipball", path=zip_file_name, ref=commit_ish)
        zip_file = zipfile.ZipFile(zip_file_name)
        if not zip_file_is_safe(zip_file):
            # This is very unlikely, as we get the zipfile from GitHub,
            # but must be considered:
            url = f"https://github.com/{user}/{repo_name}#{commit_ish}"
            logger.error(f"Malformed or malicious zip file from {url}.")
            return
        zip_file.extractall()
        # We know that the zipball contains a root directory named
        # something like this by GitHub's convention. If that ever
        # breaks, this will break:
        zipball_root = glob(f"{user}-{repo_name}-*")[0]
        # It's not unlikely that the zipball root contains a directory
        # with the same name, so we pre-emptively rename it to probably
        # avoid collisions:
        shutil.move(zipball_root, "zipball_root")
        for path in itertools.chain(glob("zipball_root/*"),
                                    glob("zipball_root/.*")):
            shutil.move(path, ".")
        shutil.rmtree("zipball_root")

        # There's a lot of setup to make configs and keychains, link
        # them properly, and then eventually pass them into a flow,
        # which we then run:
        ctx = MetaDeployCCI(repo_root=tmpdirname, plan=plan)

        current_org = "current_org"
        org_config = OrgConfig(
            {
                "access_token": token,
                "instance_url": organization_url,
                "refresh_token": token_secret,
            },
            current_org,
            keychain=ctx.keychain,
        )
        org_config.save()

        # Set up the connected_app:
        connected_app = ServiceConfig({
            "client_secret":
            settings.CONNECTED_APP_CLIENT_SECRET,
            "callback_url":
            settings.CONNECTED_APP_CALLBACK_URL,
            "client_id":
            settings.CONNECTED_APP_CLIENT_ID,
        })
        ctx.keychain.set_service("connected_app", connected_app, True)

        steps = [
            step.to_spec(project_config=ctx.project_config,
                         skip=step.step_num in skip_steps)
            for step in plan.steps.all()
        ]
        org = ctx.keychain.get_org(current_org)
        result.run(ctx, plan, steps, org)