Пример #1
0
    def get_org_config(self):
        org_config = json.loads(self.json)

        return OrgConfig(org_config, self.name)
Пример #2
0
 def test_refresh_oauth_token_no_connected_app(self):
     config = OrgConfig({}, "test")
     with self.assertRaises(AttributeError):
         config.refresh_oauth_token(None)
Пример #3
0
 def test_user_id(self):
     config = OrgConfig({"id": "org/user"}, "test")
     self.assertEqual("user", config.user_id)
Пример #4
0
 def test_can_delete(self):
     config = OrgConfig({}, "test")
     self.assertFalse(config.can_delete())
Пример #5
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)
Пример #6
0
 def test_lightning_base_url(self):
     config = OrgConfig({"instance_url": "https://na01.salesforce.com"},
                        "test")
     self.assertEqual("https://na01.lightning.force.com",
                      config.lightning_base_url)
Пример #7
0
    def test_org_list(self, cli_tbl):
        config = mock.Mock()
        config.global_config.cli__plain_output = None
        config.project_config.keychain.list_orgs.return_value = [
            "test0",
            "test1",
            "test2",
        ]
        config.project_config.keychain.get_org.side_effect = [
            ScratchOrgConfig(
                {
                    "default": True,
                    "scratch": True,
                    "date_created": datetime.now() - timedelta(days=8),
                    "days": 7,
                    "config_name": "dev",
                    "username": "******",
                },
                "test0",
            ),
            ScratchOrgConfig(
                {
                    "default":
                    False,
                    "scratch":
                    True,
                    "date_created":
                    datetime.now(),
                    "days":
                    7,
                    "config_name":
                    "dev",
                    "username":
                    "******",
                    "instance_url":
                    "https://sneaky-master-2330-dev-ed.cs22.my.salesforce.com",
                },
                "test1",
            ),
            OrgConfig(
                {
                    "default":
                    False,
                    "scratch":
                    False,
                    "expired":
                    False,
                    "config_name":
                    "dev",
                    "username":
                    "******",
                    "instance_url":
                    "https://dude-chillin-2330-dev-ed.cs22.my.salesforce.com",
                },
                "test2",
            ),
        ]

        run_click_command(cci.org_list, config=config, plain=False)

        scratch_table_call = mock.call(
            [
                ["Name", "Default", "Days", "Expired", "Config", "Domain"],
                ["test0", True, "7", True, "dev", ""],
                [
                    "test1", False, "1/7", False, "dev",
                    "sneaky-master-2330-dev-ed.cs22"
                ],
            ],
            bool_cols=["Default"],
            title="Scratch Orgs",
            dim_rows=[0, 1],
        )
        persistent_table_call = mock.call(
            [["Name", "Default", "Username"],
             ["test2", False, "*****@*****.**"]],
            bool_cols=["Default"],
            title="Persistent Orgs",
            wrap_cols=["Username"],
        )

        self.assertIn(scratch_table_call, cli_tbl.call_args_list)
        self.assertIn(persistent_table_call, cli_tbl.call_args_list)
Пример #8
0
 def setUp(self):
     self.project_config = create_project_config()
     self.project_config.keychain = mock.Mock()
     self.project_config.keychain.get_service.side_effect = ServiceNotConfigured
     self.task_config = TaskConfig()
     self.org_config = OrgConfig({}, "test")
Пример #9
0
def create_scratch_org(org_pk):
    """
    Takes our local ScratchOrg model instance and creates the actual org on Salesforce
    """
    org = ScratchOrg.objects.get(pk=org_pk)
    plan = org.plan
    email = org.email
    org.email = None
    org.save()
    repo_url = plan.version.product.repo_url
    repo_owner, repo_name = extract_user_and_repo(repo_url)
    commit_ish = plan.commit_ish

    if settings.METADEPLOY_FAST_FORWARD:  # pragma: no cover
        fake_org_id = str(uuid.uuid4())[:18]
        scratch_org_config = OrgConfig({"org_id": fake_org_id}, "scratch")
    else:
        try:
            with local_github_checkout(repo_owner,
                                       repo_name,
                                       commit_ish=commit_ish) as repo_root:
                scratch_org_config, _, org_config = create_scratch_org_on_sf(
                    repo_owner=repo_owner,
                    repo_name=repo_name,
                    repo_url=repo_url,
                    repo_branch=commit_ish,
                    email=email,
                    project_path=repo_root,
                    scratch_org=org,
                    org_name=plan.org_config_name,
                    duration=plan.scratch_org_duration,
                )
        except Exception as e:
            org.fail(e)
            return

    org.complete(scratch_org_config)

    if plan.requires_preflight:
        preflight_result = PreflightResult.objects.create(
            user=None,
            plan=plan,
            org_id=org.org_id,  # Set by org.complete()
        )
        async_to_sync(preflight_started)(org, preflight_result)
        preflight(preflight_result.pk)
    elif plan.required_step_ids.count() == plan.steps.count():
        # Start installation job automatically if both:
        # - Plan has no preflight
        # - All plan steps are required
        with transaction.atomic():
            job = Job.objects.create(
                user=None,
                plan=plan,
                org_id=org.org_id,  # Set by org.complete()
                full_org_type=ORG_TYPES.Scratch,
            )
            job.steps.set(plan.steps.all())
        # This is already called on `save()`, but the new Job isn't in the
        # database yet because it's in an atomic transaction.
        job.push_to_org_subscribers(is_new=True, changed={})
        async_to_sync(job_started)(org, job)
Пример #10
0
def run_flows(*, plan, skip_steps, 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:
        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.
        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)
    scratch_org = None
    if not result.user:
        # This means we're in a ScratchOrg.
        scratch_org = ScratchOrg.objects.get(org_id=result.org_id)

    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))
        if result.user:
            stack.enter_context(report_errors_to(result.user))
        if scratch_org:
            stack.enter_context(delete_org_on_error(scratch_org))

        # Let's clone the repo locally:
        repo_user, repo_name = extract_user_and_repo(repo_url)
        repo_root = stack.enter_context(
            local_github_checkout(repo_user, repo_name, commit_ish))

        # 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(repo_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=repo_root, plan=plan)

        current_org = "current_org"
        if settings.METADEPLOY_FAST_FORWARD:  # pragma: no cover
            org_config = OrgConfig({}, name=current_org, keychain=ctx.keychain)
        elif scratch_org:
            org_config = scratch_org.get_refreshed_org_config(
                org_name=current_org, keychain=ctx.keychain)
        else:
            token, token_secret = result.user.token
            org_config = OrgConfig(
                {
                    "access_token": token,
                    "instance_url": result.user.instance_url,
                    "refresh_token": token_secret,
                    "username": result.user.sf_username,
                    # 'id' is used by CumulusCI to pick the right 'aud' for JWT auth
                    "id": result.user.oauth_id,
                },
                current_org,
                keychain=ctx.keychain,
            )
        org_config.save()

        # Set up the connected_app:
        connected_app = ServiceConfig({
            "client_secret": settings.SFDX_CLIENT_SECRET,
            "callback_url": settings.SFDX_CLIENT_CALLBACK_URL,
            "client_id": settings.SFDX_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)
        if not settings.METADEPLOY_FAST_FORWARD:
            result.run(ctx, plan, steps, org)
Пример #11
0
 def setUp(self):
     self.global_config = BaseGlobalConfig()
     self.project_config = BaseProjectConfig(self.global_config,
                                             config={"noyaml": True})
     self.task_config = TaskConfig({"options": {"version": "1.0"}})
     self.org_config = OrgConfig({}, "test")