Пример #1
0
def task_info(config, task_name):
    check_project_config(config)
    task_config = getattr(config.project_config, 'tasks__{}'.format(task_name))
    class_path = task_config.get('class_path')
    task_class = import_class(class_path)

    # General task info
    click.echo('Description: {}'.format(task_config.get('description')))
    click.echo('Class: {}'.format(task_config.get('class_path')))

    # Default options
    default_options = task_config.get('options', {})
    if default_options:
        click.echo('')
        click.echo('Default Option Values')
        for key, value in default_options.items():
            click.echo('    {}: {}'.format(key, value))

    # Task options
    task_options = getattr(task_class, 'task_options', {})
    if task_options:
        click.echo('')
        data = []
        headers = ['Option', 'Required', 'Description']
        for key, option in task_options.items():
            if option.get('required'):
                data.append((key, '*', option.get('description')))
            else:
                data.append((key, '', option.get('description')))
        table = Table(data, headers)
        click.echo(table)
Пример #2
0
def doc_task(task_name, task_config, project_config=None, org_config=None):
    """ Document a (project specific) task configuration in RST format. """
    from cumulusci.core.utils import import_class

    doc = []
    doc.append("{}\n==========================================\n".format(task_name))
    doc.append("**Description:** {}\n".format(task_config.description))
    doc.append("**Class::** {}\n".format(task_config.class_path))

    task_class = import_class(task_config.class_path)
    task_docs = textwrap.dedent(task_class.task_docs.strip("\n"))
    if task_docs:
        doc.append(task_docs + "\n")
    if task_class.task_options:
        doc.append("Options:\n------------------------------------------\n")
        defaults = task_config.options or {}
        for name, option in list(task_class.task_options.items()):
            default = defaults.get(name)
            if default:
                default = " **Default: {}**".format(default)
            else:
                default = ""
            if option.get("required"):
                doc.append(
                    "* **{}** *(required)*: {}{}".format(
                        name, option.get("description"), default
                    )
                )
            else:
                doc.append(
                    "* **{}**: {}{}".format(name, option.get("description"), default)
                )

    return "\n".join(doc)
Пример #3
0
def doc_task(task_name, task_config, project_config=None, org_config=None):
    from cumulusci.core.utils import import_class
    doc = []
    doc.append('{}\n==========================================\n'.format(task_name))
    doc.append('**Description:** {}\n'.format(task_config.description))
    doc.append('**Class::** {}\n'.format(task_config.class_path))

    task_class = import_class(task_config.class_path)
    if task_class.task_options:
        doc.append('Options:\n------------------------------------------\n')
        defaults = task_config.options
        if not defaults:
            defaults = {}
        for name, option in task_class.task_options.items():
            default = defaults.get('name')
            if default:
                default = ' **Default: {}**'.format(default)
            else:
                default = ''
            if option.get('required'):
                doc.append('* **{}** *(required)*: {}{}'.format(name, option.get('description'), default))
            else:
                doc.append('* **{}**: {}{}'.format(name, option.get('description'), default))

    return '\n'.join(doc)
Пример #4
0
def flow_run(config, flow_name, org):
    # Check environment
    check_keychain(config)

    # Get necessary configs
    if org:
        org_config = config.project_config.get_org(org)
    else:
        org_config = config.project_config.keychain.get_default_org()
    flow_config = FlowConfig(
        getattr(config.project_config, 'flows__{}'.format(flow_name))
    )
    if not flow_config.config:
        raise click.UsageError('No configuration fould for flow {}'.format(flow_name))

    # Get the class to look up options
    class_path = flow_config.config.get('class_path', 'cumulusci.core.flows.BaseFlow')
    flow_class = import_class(class_path)

    # Create the flow and handle initialization exceptions
    try:
        flow = flow_class(config.project_config, flow_config, org_config)
    except TaskRequiresSalesforceOrg as e:
        raise click.UsageError('This flow requires a salesforce org.  Use org default <name> to set a default org or pass the org name with the --org option')
    except TaskOptionsError as e:
        raise click.UsageError(e.message)

    # Run the flow and handle exceptions
    try:
        flow()
    except TaskOptionsError as e:
        raise click.UsageError(e.message)
    except Exception as e:
        raise click.ClickException('{}: {}'.format(e.__class__.__name__, e.message))
Пример #5
0
 def get_keychain_class(self):
     default_keychain_class = (self.project_config.cumulusci__keychain
                               if not self.is_global_keychain else
                               self.global_config.cumulusci__keychain)
     keychain_class = os.environ.get("CUMULUSCI_KEYCHAIN_CLASS",
                                     default_keychain_class)
     return import_class(keychain_class)
Пример #6
0
def doc_task(task_name, task_config, project_config=None, org_config=None):
    """ Document a (project specific) task configuration in RST format. """
    from cumulusci.core.utils import import_class
    doc = []
    doc.append(
        '{}\n==========================================\n'.format(task_name))
    doc.append('**Description:** {}\n'.format(task_config.description))
    doc.append('**Class::** {}\n'.format(task_config.class_path))

    task_class = import_class(task_config.class_path)
    if task_class.task_options:
        doc.append('Options:\n------------------------------------------\n')
        defaults = task_config.options
        if not defaults:
            defaults = {}
        for name, option in list(task_class.task_options.items()):
            default = defaults.get(name)
            if default:
                default = ' **Default: {}**'.format(default)
            else:
                default = ''
            if option.get('required'):
                doc.append('* **{}** *(required)*: {}{}'.format(
                    name, option.get('description'), default))
            else:
                doc.append('* **{}**: {}{}'.format(name,
                                                   option.get('description'),
                                                   default))

    return '\n'.join(doc)
Пример #7
0
def task_run(config, task_name, org, o, debug, debug_before, debug_after,
             no_prompt):

    # Get necessary configs
    org, org_config = config.get_org(org, fail_if_missing=False)
    task_config = getattr(config.project_config, "tasks__{}".format(task_name))
    if not task_config:
        raise TaskNotFoundError("Task not found: {}".format(task_name))

    # Get the class to look up options
    class_path = task_config.get("class_path")
    task_class = import_class(class_path)

    # Parse command line options and add to task config
    if o:
        if "options" not in task_config:
            task_config["options"] = {}
        for name, value in o:
            # Validate the option
            if name not in task_class.task_options:
                raise click.UsageError(
                    'Option "{}" is not available for task {}'.format(
                        name, task_name))

            # Override the option in the task config
            task_config["options"][name] = value

    task_config = TaskConfig(task_config)

    # Create and run the task
    try:
        task = task_class(config.project_config,
                          task_config,
                          org_config=org_config)

        if debug_before:
            import pdb

            pdb.set_trace()

        task()

        if debug_after:
            import pdb

            pdb.set_trace()

    except CumulusCIUsageError as e:
        # Usage error; report with usage line and no traceback
        exception = click.UsageError(str(e))
        handle_exception_debug(config, debug, throw_exception=exception)
    except (CumulusCIFailure, ScratchOrgException) as e:
        # Expected failure; report without traceback
        exception = click.ClickException(str(e) or e.__class__.__name__)
        handle_exception_debug(config, debug, throw_exception=exception)
    except Exception:
        # Unexpected exception; log to sentry and raise
        handle_exception_debug(config, debug, no_prompt=no_prompt)

    config.alert("Task complete: {}".format(task_name))
Пример #8
0
    def run_flow(self, project_config, org_config):
        # Add the repo root to syspath to allow for custom tasks and flows in
        # the repo
        sys.path.append(project_config.repo_root)

        flow = getattr(project_config, 'flows__{}'.format(self.flow))
        if not flow:
            raise FlowNotFoundError('Flow not found: {}'.format(self.flow))
        flow_config = FlowConfig(flow)

        if settings.METACI_FLOW_SUBCLASS_ENABLED:
            class_path = 'metaci.build.flows.MetaCIFlow'
        else:
            # Get the class to look up options
            class_path = flow_config.config.get(
                'class_path', 'cumulusci.core.flows.BaseFlow')

        flow_class = import_class(class_path)

        # Create the flow and handle initialization exceptions
        self.flow_instance = flow_class(project_config,
                                        flow_config,
                                        org_config,
                                        name=self.flow)

        if settings.METACI_FLOW_SUBCLASS_ENABLED:
            self.flow_instance.buildflow_id = self.pk

        # Run the flow
        res = self.flow_instance()

        return res
Пример #9
0
 def _load_keychain(self):
     self.keychain_key = os.environ.get('CUMULUSCI_KEY')
     if self.project_config:
         keychain_class = os.environ.get(
             'CUMULUSCI_KEYCHAIN_CLASS',
             self.project_config.cumulusci__keychain,
         )
         self.keychain_class = import_class(keychain_class)
         self.keychain = self.keychain_class(self.project_config, self.keychain_key)
         self.project_config.set_keychain(self.keychain)
Пример #10
0
 def _load_keychain(self):
     self.keychain_key = os.environ.get("CUMULUSCI_KEY")
     if self.project_config:
         keychain_class = os.environ.get(
             "CUMULUSCI_KEYCHAIN_CLASS",
             self.project_config.cumulusci__keychain)
         self.keychain_class = import_class(keychain_class)
         self.keychain = self.keychain_class(self.project_config,
                                             self.keychain_key)
         self.project_config.set_keychain(self.keychain)
Пример #11
0
    def _run_task(self, flow_task_config):
        task_config = copy.deepcopy(flow_task_config['task_config'].config)
        task_config = TaskConfig(task_config)

        task_name = flow_task_config['flow_config']['task']

        if 'options' not in task_config.config:
            task_config.config['options'] = {}
        task_config.config['options'].update(
            flow_task_config['flow_config'].get('options', {}))
        # If there were task option overrides passed in, merge them
        if task_name in self.task_options:
            task_config.config['options'].update(self.task_options[task_name])

        # Skip the task if skip was requested
        if task_name in self.skip_tasks:
            self.logger.info('')
            self.logger.info('Skipping task {}'.format(task_name))
            return

        # Handle dynamic value lookups in the format ^^task_name.attr1.attr2
        for option, value in task_config.options.items():
            if unicode(value).startswith('^^'):
                value_parts = value[2:].split('.')
                parent = self._find_task_by_name(value_parts[0])
                for attr in value_parts[1:]:
                    parent = parent.return_values.get(attr)
                task_config.config['options'][option] = parent

        task_class = import_class(task_config.class_path)

        self.logger.info('')
        self.logger.info('Running task: %s', task_name)

        task = task_class(self.project_config,
                          task_config,
                          org_config=self.org_config,
                          flow=self)
        self.tasks.append(task)

        for line in self._render_task_config(task):
            self.logger.info(line)

        try:
            task()
            self.logger.info('Task complete: %s', task_name)
            self.task_results.append(task.result)
            self.task_return_values.append(task.return_values)
        except Exception as e:
            self.logger.error('Task failed: %s', task_name)
            if not flow_task_config['flow_config'].get('ignore_failure'):
                self.logger.error('Failing flow due to exception in task')
                traceback.print_exc()
                raise e
            self.logger.info('Continuing flow')
Пример #12
0
 def to_spec(self, skip: bool = False):
     task_class = import_class(self.task_class)
     assert issubclass(task_class, BaseTask)
     return StepSpec(
         step_num=self.step_num,
         task_name=self.
         path,  # skip from_flow path construction in StepSpec ctr
         task_config=self.task_config or {"options": {}},
         task_class=task_class,
         skip=skip,
     )
Пример #13
0
def task_run(config, task_name, org, o):
    # Check environment
    check_keychain(config)

    # Get necessary configs
    if org:
        org_config = config.project_config.get_org(org)
    else:
        org_config = config.project_config.keychain.get_default_org()
    task_config = getattr(config.project_config, 'tasks__{}'.format(task_name))

    # Get the class to look up options
    class_path = task_config.get('class_path')
    task_class = import_class(class_path)

    # Parse command line options and add to task config
    if o:
        if 'options' not in task_config:
            task_config['options'] = {}
        for option in o:
            name = option[0]
            value = option[1]

            # Validate the option
            if name not in task_class.task_options:
                raise click.UsageError(
                    'Option "{}" is not available for task {}'.format(
                        name,
                        task_name,
                    ),
                )

            # Override the option in the task config
            task_config['options'][name] = value

    task_config = TaskConfig(task_config)

    # Create and run the task
    try:
        task = task_class(config.project_config, task_config, org_config = org_config)
    except TaskRequiresSalesforceOrg as e:
        raise click.UsageError('This task requires a salesforce org.  Use org default <name> to set a default org or pass the org name with the --org option')
    except TaskOptionsError as e:
        raise click.UsageError(e.message)
    except Exception as e:
        raise click.ClickException('{}: {}'.format(e.__class__.__name__, e.message))

    try:
        task()
    except TaskOptionsError as e:
        raise click.UsageError(e.message)
    except Exception as e:
        raise click.ClickException('{}: {}'.format(e.__class__.__name__, unicode(e)))
Пример #14
0
    def _run_task(self, flow_task_config):
        task_config = self.project_config.get_task(flow_task_config['task'])
        task_config = copy.deepcopy(task_config.config)

        task_config = TaskConfig(task_config)

        if flow_task_config:
            if 'options' not in task_config.config:
                task_config.config['options'] = {}
            task_config.config['options'].update(flow_task_config.get('options', {}))

            # Handle dynamic value lookups in the format ^^task_name.attr1.attr2
            for option, value in task_config.options.items():
                if unicode(value).startswith('^^'):
                    value_parts = value[2:].split('.')
                    task_name = value_parts[0]
                    parent = self._find_task_by_name(task_name)
                    for attr in value_parts[1:]:
                        parent = getattr(parent, attr)
                    task_config.config['options'][option] = parent


        task_class = import_class(task_config.class_path)

        self.logger.info('')
        self.logger.info(
            'Running task: {}'.format(
                flow_task_config['task'],
            )
        )

        task = task_class(
            self.project_config,
            task_config,
            org_config = self.org_config,
        )
        self.tasks.append(task)

        for line in self._render_task_config(task):
            self.logger.info(line)

        try:
            response = task()
            self.logger.info('Task complete: {}'.format(flow_task_config['task']))
            self.responses.append(response)
            return response
        except:
            self.logger.error('Task failed: {}'.format(flow_task_config['task']))
            if not flow_task_config.get('ignore_failure'):
                self.logger.info('Aborting flow')
                raise
            self.logger.info('Continuing flow')
Пример #15
0
 def to_spec(self, project_config, skip: bool = False):
     if self.source:
         project_config = project_config.include_source(self.source)
     task_class = import_class(self.task_class)
     assert issubclass(task_class, BaseTask)
     return StepSpec(
         step_num=self.step_num,
         task_name=self.path,  # skip from_flow path construction in StepSpec ctr
         task_config=self.task_config or {"options": {}},
         task_class=task_class,
         skip=skip,
         project_config=project_config,
     )
Пример #16
0
 def _load_keychain(self):
     self.keychain_key = os.environ.get("CUMULUSCI_KEY")
     if self.project_config:
         keychain_class = os.environ.get(
             "CUMULUSCI_KEYCHAIN_CLASS", self.project_config.cumulusci__keychain
         )
         self.keychain_class = import_class(keychain_class)
         try:
             self.keychain = self.keychain_class(
                 self.project_config, self.keychain_key
             )
         except (KeychainKeyNotFound, ConfigError) as e:
             raise click.UsageError("Keychain Error: {}".format(str(e)))
         self.project_config.set_keychain(self.keychain)
Пример #17
0
    def run_flow(self, project_config, org_config):
        flow = getattr(project_config, 'flows__{}'.format(self.flow))
        if not flow:
            raise FlowNotFoundError('Flow not found: {}'.format(flow_name))
        flow_config = FlowConfig(flow)

        # Get the class to look up options
        class_path = flow_config.config.get('class_path',
                                            'cumulusci.core.flows.BaseFlow')
        flow_class = import_class(class_path)

        # Create the flow and handle initialization exceptions
        self.flow_instance = flow_class(project_config, flow_config,
                                        org_config)
        res = self.flow_instance()
Пример #18
0
    def _run_task(self, flow_task_config):
        task_config = copy.deepcopy(flow_task_config['task_config'].config)
        task_config = TaskConfig(task_config)
    
        task_name = flow_task_config['flow_config']['task']

        if 'options' not in task_config.config:
            task_config.config['options'] = {}
        task_config.config['options'].update(flow_task_config['flow_config'].get('options', {}))

        # Handle dynamic value lookups in the format ^^task_name.attr1.attr2
        for option, value in task_config.options.items():
            if unicode(value).startswith('^^'):
                value_parts = value[2:].split('.')
                parent = self._find_task_by_name(value_parts[0])
                for attr in value_parts[1:]:
                    parent = getattr(parent, attr)
                task_config.config['options'][option] = parent


        task_class = import_class(task_config.class_path)

        self.logger.info('')
        self.logger.info(
            'Running task: {}'.format(task_name)
        )

        task = task_class(
            self.project_config,
            task_config,
            org_config = self.org_config,
        )
        self.tasks.append(task)

        for line in self._render_task_config(task):
            self.logger.info(line)

        try:
            response = task()
            self.logger.info('Task complete: {}'.format(task_name))
            self.responses.append(response)
            return response
        except Exception as e:
            self.logger.error('Task failed: {}'.format(task_name))
            if not flow_task_config['flow_config'].get('ignore_failure'):
                self.logger.error('Failing flow due to exception in task')
                raise
            self.logger.info('Continuing flow')
Пример #19
0
 def _run_flow(self, stepnum, flow_task_config):
     class_path = flow_task_config['task_config'].config.get(
         'class_path',
         'cumulusci.core.flows.BaseFlow',
     )
     flow_class = import_class(class_path)
     flow = flow_class(
         self.project_config,
         flow_task_config['task_config'],
         self.org_config,
         options=self.options,
         skip=self.skip,
         nested=True,
     )
     flow()
     self.tasks.append(flow)
     self.task_return_values.append(flow.task_return_values)
Пример #20
0
    def _get_task(self, stepnum, step_config):
        task_config = copy.deepcopy(step_config["task_config"].config)
        task_config = TaskConfig(task_config)

        task_name = step_config["step_config"]["task"]

        if "options" not in task_config.config:
            task_config.config["options"] = {}
        task_config.config["options"].update(step_config["step_config"].get(
            "options", {}))
        # If there were task option overrides passed in, merge them
        if task_name in self.task_options:
            task_config.config["options"].update(self.task_options[task_name])

        # Handle dynamic value lookups in the format ^^task_name.attr1.attr2
        for option, value in list(task_config.options.items()):
            if str(value).startswith("^^"):
                value_parts = value[2:].split(".")
                parent = self._find_step_by_name(value_parts[0])
                n = 0
                while isinstance(parent, BaseFlow):
                    n += 1
                    parent = parent._find_step_by_name(value_parts[n])
                for attr in value_parts[(n + 1):]:
                    if getattr(parent, "nested", None):
                        parent = parent._find_step_by_name()
                    else:
                        parent = parent.return_values.get(attr)
                task_config.config["options"][option] = parent

        task_class = import_class(task_config.class_path)

        task = task_class(
            self.project_config,
            task_config,
            org_config=self.org_config,
            name=task_name,
            stepnum=stepnum,
            flow=self,
        )
        return task
Пример #21
0
    def _run_flow(self, stepnum, step_config):
        class_path = step_config['flow_config'].config.get(
            'class_path',
            'cumulusci.core.flows.BaseFlow',
        )
        flow_options = step_config['step_config'].get(
            'options',
            {},
        )
        if flow_options:
            # Collapse down flow options into task__option format to pass
            options = {}
            for task, task_options in flow_options.items():
                for option, value in task_options.items():
                    options['{}__{}'.format(task, option)] = value
            flow_options = options

        flow_class = import_class(class_path)
        flow = flow_class(self.project_config,
                          step_config['flow_config'],
                          self.org_config,
                          options=flow_options,
                          skip=self.skip,
                          nested=True,
                          parent=self,
                          name=step_config['step_config']['flow'],
                          stepnum=stepnum)
        self._pre_subflow(flow)

        if self._skip_next:
            self._skip_next = False
            return

        flow()
        self._post_subflow(flow)
        self.steps.append(flow)
        self.step_return_values.append(flow.step_return_values)
Пример #22
0
def task_info(config, task_name):
    check_project_config(config)
    task_config = getattr(config.project_config, 'tasks__{}'.format(task_name))
    if not task_config:
        raise TaskNotFoundError('Task not found: {}'.format(task_name))

    task_config = TaskConfig(task_config)
    click.echo(rst2ansi(doc_task(task_name, task_config)))
    return
    class_path = task_config.get('class_path')
    task_class = import_class(class_path)

    # General task info
    click.echo('Description: {}'.format(task_config.get('description')))
    click.echo('Class: {}'.format(task_config.get('class_path')))

    # Default options
    default_options = task_config.get('options', {})
    if default_options:
        click.echo('')
        click.echo('Default Option Values')
        for key, value in default_options.items():
            click.echo('    {}: {}'.format(key, value))

    # Task options
    task_options = getattr(task_class, 'task_options', {})
    if task_options:
        click.echo('')
        data = []
        headers = ['Option', 'Required', 'Description']
        for key, option in task_options.items():
            if option.get('required'):
                data.append((key, '*', option.get('description')))
            else:
                data.append((key, '', option.get('description')))
        table = Table(data, headers)
        click.echo(table)
Пример #23
0
 def _init_parsers(self):
     for cfg in self.parser_config:
         parser_class = import_class(cfg["class_path"])
         self.parsers.append(parser_class(self, cfg["title"]))
Пример #24
0
    def _visit_step(
        self,
        number,
        step_config,
        visited_steps=None,
        parent_options=None,
        from_flow=None,
    ):
        """
        for each step (as defined in the flow YAML), _visit_step is called with only
        the first two parameters. this takes care of validating the step, collating the
        option overrides, and if it is a task, creating a StepSpec for it.

        If it is a flow, we recursively call _visit_step with the rest of the parameters of context.

        :param number: LooseVersion representation of the current step number
        :param step_config: the current step's config (dict from YAML)
        :param visited_steps: used when called recursively for nested steps, becomes the return value
        :param parent_options: used when called recursively for nested steps, options from parent flow
        :param from_flow: used when called recursively for nested steps, name of parent flow
        :return: List[StepSpec] a list of all resolved steps including/under the one passed in
        """
        number = LooseVersion(str(number))

        if visited_steps is None:
            visited_steps = []
        if parent_options is None:
            parent_options = {}

        # Step Validation
        # - A step is either a task OR a flow.
        if all(k in step_config for k in ("flow", "task")):
            raise FlowConfigError(
                "Step {} is configured as both a flow AND a task. \n\t{}.".
                format(number, step_config))

        # Skips
        # - either in YAML (with the None string)
        # - or by providing a skip list to the FlowRunner at initialization.
        if (("flow" in step_config and step_config["flow"] == "None")
                or ("task" in step_config and step_config["task"] == "None") or
            ("task" in step_config and step_config["task"] in self.skip)):
            visited_steps.append(
                StepSpec(
                    number,
                    step_config.get("task", step_config.get("flow")),
                    step_config.get("options", {}),
                    None,
                    from_flow=from_flow,
                    skip=
                    True,  # someday we could use different vals for why skipped
                ))
            return visited_steps

        if "task" in step_config:
            name = step_config["task"]

            # get the base task_config from the project config, as a dict for easier manipulation.
            # will raise if the task doesn't exist / is invalid
            task_config = copy.deepcopy(
                self.project_config.get_task(name).config)
            if "options" not in task_config:
                task_config["options"] = {}

            # merge the options together, from task_config all the way down through parent_options
            step_overrides = copy.deepcopy(parent_options.get(name, {}))
            step_overrides.update(step_config.get("options", {}))
            task_config["options"].update(step_overrides)

            # merge runtime options
            if name in self.runtime_options:
                task_config["options"].update(self.runtime_options[name])

            # get implementation class. raise/fail if it doesn't exist, because why continue
            try:
                task_class = import_class(task_config["class_path"])
            except (ImportError, AttributeError):
                # TODO: clean this up and raise a taskimporterror or something else correcter.
                raise FlowConfigError("Task named {} has bad classpath")

            visited_steps.append(
                StepSpec(
                    number,
                    name,
                    task_config,
                    task_class,
                    step_config.get("ignore_failure", False),
                    from_flow=from_flow,
                ))
            return visited_steps

        if "flow" in step_config:
            name = step_config["flow"]
            if from_flow:
                path = ".".join([from_flow, name])
            else:
                path = name
            step_options = step_config.get("options", {})
            flow_config = self.project_config.get_flow(name)
            for sub_number, sub_stepconf in flow_config.steps.items():
                # append the flow number to the child number, since its a LooseVersion.
                # e.g. if we're in step 2.3 which references a flow with steps 1-5, it
                #   simply ends up as five steps: 2.3.1, 2.3.2, 2.3.3, 2.3.4, 2.3.5
                # TODO: how does this work with nested flowveride? what does defining step 2.3.2 later do?
                num = "{}.{}".format(number, sub_number)
                self._visit_step(
                    num,
                    sub_stepconf,
                    visited_steps,
                    parent_options=step_options,
                    from_flow=path,
                )

        return visited_steps
Пример #25
0
 def get_keychain_class(self):
     keychain_class = os.environ.get(
         "CUMULUSCI_KEYCHAIN_CLASS",
         self.project_config.cumulusci__keychain)
     return import_class(keychain_class)
Пример #26
0
def flow_run(config, flow_name, org, delete_org, debug, o, skip, no_prompt):
    # Check environment
    check_keychain(config)

    # Get necessary configs
    if org:
        org_config = config.project_config.get_org(org)
    else:
        org, org_config = config.project_config.keychain.get_default_org()
        if not org_config:
            raise click.UsageError(
                '`cci flow run` requires an org.'
                ' No org was specified and default org is not set.')

    org_config = check_org_expired(config, org, org_config)

    if delete_org and not org_config.scratch:
        raise click.UsageError(
            '--delete-org can only be used with a scratch org')

    flow = getattr(config.project_config, 'flows__{}'.format(flow_name))
    if not flow:
        raise FlowNotFoundError('Flow not found: {}'.format(flow_name))
    flow_config = FlowConfig(flow)
    if not flow_config.config:
        raise click.UsageError(
            'No configuration found for flow {}'.format(flow_name))

    # Get the class to look up options
    class_path = flow_config.config.get('class_path',
                                        'cumulusci.core.flows.BaseFlow')
    flow_class = import_class(class_path)

    exception = None

    # Parse command line options and add to task config
    options = {}
    if o:
        for option in o:
            options[option[0]] = option[1]

    # Create the flow and handle initialization exceptions
    try:
        flow = flow_class(config.project_config,
                          flow_config,
                          org_config,
                          options,
                          skip,
                          name=flow_name)
    except TaskRequiresSalesforceOrg as e:
        exception = click.UsageError(
            'This flow requires a salesforce org.  Use org default <name> to set a default org or pass the org name with the --org option'
        )
    except TaskOptionsError as e:
        exception = click.UsageError(e.message)
        handle_exception_debug(config, debug, e, throw_exception=exception)
    except Exception as e:
        handle_exception_debug(config, debug, e, no_prompt=no_prompt)

    if not exception:
        # Run the flow and handle exceptions
        try:
            flow()
        except TaskOptionsError as e:
            exception = click.UsageError(e.message)
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except ApexTestException as e:
            exception = click.ClickException('Failed: ApexTestException')
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except BrowserTestFailure as e:
            exception = click.ClickException('Failed: BrowserTestFailure')
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except MetadataComponentFailure as e:
            exception = click.ClickException(
                'Failed: MetadataComponentFailure')
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except MetadataApiError as e:
            exception = click.ClickException('Failed: MetadataApiError')
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except ScratchOrgException as e:
            exception = click.ClickException('ScratchOrgException: {}'.format(
                e.message))
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except Exception as e:
            handle_exception_debug(config, debug, e, no_prompt=no_prompt)

    # Delete the scratch org if --delete-org was set
    if delete_org:
        try:
            org_config.delete_org()
        except Exception as e:
            click.echo(
                'Scratch org deletion failed.  Ignoring the error below to complete the flow:'
            )
            click.echo(e.message)

    if exception:
        handle_sentry_event(config, no_prompt)
        raise exception
Пример #27
0
def task_run(config, task_name, org, o, debug, debug_before, debug_after,
             no_prompt):
    # Check environment
    check_keychain(config)

    # Get necessary configs
    if org:
        org_config = config.project_config.get_org(org)
    else:
        org, org_config = config.project_config.keychain.get_default_org()
    if org_config:
        org_config = check_org_expired(config, org, org_config)
    task_config = getattr(config.project_config, 'tasks__{}'.format(task_name))
    if not task_config:
        raise TaskNotFoundError('Task not found: {}'.format(task_name))

    # Get the class to look up options
    class_path = task_config.get('class_path')
    task_class = import_class(class_path)

    # Parse command line options and add to task config
    if o:
        if 'options' not in task_config:
            task_config['options'] = {}
        for option in o:
            name = option[0]
            value = option[1]

            # Validate the option
            if name not in task_class.task_options:
                raise click.UsageError(
                    'Option "{}" is not available for task {}'.format(
                        name,
                        task_name,
                    ), )

            # Override the option in the task config
            task_config['options'][name] = value

    task_config = TaskConfig(task_config)
    exception = None

    # Create and run the task
    try:
        task = task_class(config.project_config,
                          task_config,
                          org_config=org_config)
    except TaskRequiresSalesforceOrg as e:
        exception = click.UsageError(
            'This task requires a salesforce org.  Use org default <name> to set a default org or pass the org name with the --org option'
        )
    except TaskOptionsError as e:
        exception = click.UsageError(e.message)
        handle_exception_debug(config, debug, e, throw_exception=exception)
    except Exception as e:
        handle_exception_debug(config, debug, e, no_prompt=no_prompt)

    if debug_before:
        import pdb
        pdb.set_trace()

    if not exception:
        try:
            task()
        except TaskOptionsError as e:
            exception = click.UsageError(e.message)
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except ApexTestException as e:
            exception = click.ClickException('Failed: ApexTestFailure')
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except BrowserTestFailure as e:
            exception = click.ClickException('Failed: BrowserTestFailure')
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except MetadataComponentFailure as e:
            exception = click.ClickException(
                'Failed: MetadataComponentFailure')
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except MetadataApiError as e:
            exception = click.ClickException('Failed: MetadataApiError')
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except ScratchOrgException as e:
            exception = click.ClickException('ScratchOrgException: {}'.format(
                e.message))
            handle_exception_debug(config, debug, e, throw_exception=exception)
        except Exception as e:
            handle_exception_debug(config, debug, e, no_prompt=no_prompt)

    if debug_after:
        import pdb
        pdb.set_trace()

    if exception:
        handle_sentry_event(config, no_prompt)
        raise exception
Пример #28
0
def flow_run(config, flow_name, org, delete_org, debug):
    # Check environment
    check_keychain(config)

    # Get necessary configs
    if org:
        org_config = config.project_config.get_org(org)
    else:
        org, org_config = config.project_config.keychain.get_default_org()

    if delete_org and not org_config.scratch:
        raise click.UsageError(
            '--delete-org can only be used with a scratch org')

    flow = getattr(config.project_config, 'flows__{}'.format(flow_name))
    if not flow:
        raise FlowNotFoundError('Flow not found: {}'.format(flow_name))
    flow_config = FlowConfig(flow)
    if not flow_config.config:
        raise click.UsageError(
            'No configuration found for flow {}'.format(flow_name))

    # Get the class to look up options
    class_path = flow_config.config.get('class_path',
                                        'cumulusci.core.flows.BaseFlow')
    flow_class = import_class(class_path)

    exception = None

    # Create the flow and handle initialization exceptions
    try:
        flow = flow_class(config.project_config, flow_config, org_config)
    except TaskRequiresSalesforceOrg as e:
        exception = click.UsageError(
            'This flow requires a salesforce org.  Use org default <name> to set a default org or pass the org name with the --org option'
        )
    except TaskOptionsError as e:
        exception = click.UsageError(e.message)
    except Exception as e:
        if debug:
            import pdb
            import traceback
            traceback.print_exc()
            pdb.post_mortem()
        else:
            raise

    if not exception:
        # Run the flow and handle exceptions
        try:
            flow()
        except TaskOptionsError as e:
            exception = click.UsageError(e.message)
        except ApexTestException as e:
            exception = click.ClickException('Failed: ApexTestException')
        except MetadataComponentFailure as e:
            exception = click.ClickException(
                'Failed: MetadataComponentFailure')
        except MetadataApiError as e:
            exception = click.ClickException('Failed: MetadataApiError')
        except Exception as e:
            if debug:
                import pdb
                import traceback
                traceback.print_exc()
                pdb.post_mortem()
            else:
                raise

    # Delete the scratch org if --delete-org was set
    if delete_org:
        try:
            org_config.delete_org()
        except Exception as e:
            click.echo(
                'Scratch org deletion failed.  Ignoring the error below to complete the flow:'
            )
            click.echo(e.message)

    # Save the org config in case it was modified in a task
    if org and org_config:
        config.keychain.set_org(org, org_config)

    if exception:
        raise exception
Пример #29
0
def flow_run(config, flow_name, org, delete_org, debug):
    # Check environment
    check_keychain(config)

    # Get necessary configs
    if org:
        org_config = config.project_config.get_org(org)
    else:
        org, org_config = config.project_config.keychain.get_default_org()

    if delete_org and not org_config.scratch:
        raise click.UsageError('--delete-org can only be used with a scratch org')

    flow = getattr(config.project_config, 'flows__{}'.format(flow_name))
    if not flow:
        raise FlowNotFoundError('Flow not found: {}'.format(flow_name))
    flow_config = FlowConfig(flow)
    if not flow_config.config:
        raise click.UsageError('No configuration found for flow {}'.format(flow_name))

    # Get the class to look up options
    class_path = flow_config.config.get('class_path', 'cumulusci.core.flows.BaseFlow')
    flow_class = import_class(class_path)

    exception = None

    # Create the flow and handle initialization exceptions
    try:
        flow = flow_class(config.project_config, flow_config, org_config)
    except TaskRequiresSalesforceOrg as e:
        exception = click.UsageError('This flow requires a salesforce org.  Use org default <name> to set a default org or pass the org name with the --org option')
    except TaskOptionsError as e:
        exception = click.UsageError(e.message)
    except Exception as e:
        if debug:
            import pdb
            import traceback
            traceback.print_exc()
            pdb.post_mortem()
        else:
            raise

    if not exception:
        # Run the flow and handle exceptions
        try:
            flow()
        except TaskOptionsError as e:
            exception = click.UsageError(e.message)
        except ApexTestException as e:
            exception = click.ClickException('Failed: ApexTestException')
        except MetadataApiError as e:
            exception = click.ClickException('Failed: MetadataApiError')
        except Exception as e:
            if debug:
                import pdb
                import traceback
                traceback.print_exc()
                pdb.post_mortem()
            else:
                raise

    # Delete the scratch org if --delete-org was set
    if delete_org:
        try:
            org_config.delete_org()
        except Exception as e:
            click.echo('Scratch org deletion failed.  Ignoring the error below to complete the flow:')
            click.echo(e.message)

    # Save the org config in case it was modified in a task
    if org and org_config:
        config.keychain.set_org(org, org_config)

    if exception:
        raise exception
Пример #30
0
def task_run(config, task_name, org, o, debug, debug_before, debug_after,
             no_prompt):
    # Check environment
    config.check_keychain()

    # Get necessary configs
    org, org_config = config.get_org(org, fail_if_missing=False)
    task_config = getattr(config.project_config, "tasks__{}".format(task_name))
    if not task_config:
        raise TaskNotFoundError("Task not found: {}".format(task_name))

    # Get the class to look up options
    class_path = task_config.get("class_path")
    task_class = import_class(class_path)

    # Parse command line options and add to task config
    if o:
        if "options" not in task_config:
            task_config["options"] = {}
        for name, value in o:
            # Validate the option
            if name not in task_class.task_options:
                raise click.UsageError(
                    'Option "{}" is not available for task {}'.format(
                        name, task_name))

            # Override the option in the task config
            task_config["options"][name] = value

    task_config = TaskConfig(task_config)

    # Create and run the task
    try:
        task = task_class(config.project_config,
                          task_config,
                          org_config=org_config)

        if debug_before:
            import pdb

            pdb.set_trace()

        task()

        if debug_after:
            import pdb

            pdb.set_trace()

    except (TaskRequiresSalesforceOrg, TaskOptionsError) as e:
        # Usage error; report with usage line and no traceback
        exception = click.UsageError(e.message)
        handle_exception_debug(config, debug, throw_exception=exception)
    except (
            ApexTestException,
            BrowserTestFailure,
            MetadataComponentFailure,
            MetadataApiError,
            ScratchOrgException,
    ) as e:
        # Expected failure; report without traceback
        exception = click.ClickException("Failed: {}".format(
            e.__class__.__name__))
        handle_exception_debug(config, debug, throw_exception=exception)
    except Exception:
        # Unexpected exception; log to sentry and raise
        handle_exception_debug(config, debug, no_prompt=no_prompt)
Пример #31
0
def task_run(config, task_name, org, o, debug):
    # Check environment
    check_keychain(config)

    # Get necessary configs
    if org:
        org_config = config.project_config.get_org(org)
    else:
        org, org_config = config.project_config.keychain.get_default_org()
    task_config = getattr(config.project_config, 'tasks__{}'.format(task_name))
    if not task_config:
        raise TaskNotFoundError('Task not found: {}'.format(task_name))

    # Get the class to look up options
    class_path = task_config.get('class_path')
    task_class = import_class(class_path)

    # Parse command line options and add to task config
    if o:
        if 'options' not in task_config:
            task_config['options'] = {}
        for option in o:
            name = option[0]
            value = option[1]

            # Validate the option
            if name not in task_class.task_options:
                raise click.UsageError(
                    'Option "{}" is not available for task {}'.format(
                        name,
                        task_name,
                    ),
                )

            # Override the option in the task config
            task_config['options'][name] = value

    task_config = TaskConfig(task_config)
    exception = None

    # Create and run the task
    try:
        task = task_class(config.project_config, task_config, org_config = org_config)
    except TaskRequiresSalesforceOrg as e:
        exception = click.UsageError('This task requires a salesforce org.  Use org default <name> to set a default org or pass the org name with the --org option')
    except TaskOptionsError as e:
        exception = click.UsageError(e.message)
    except Exception as e:
        if debug:
            import pdb
            import traceback
            traceback.print_exc()
            pdb.post_mortem()
        else:
            raise

    if not exception:
        try:
            task()
        except TaskOptionsError as e:
            exception = click.UsageError(e.message)
        except ApexTestException as e:
            exception = click.ClickException('Failed: ApexTestFailure')
        except MetadataApiError as e:
            exception = click.ClickException('Failed: MetadataApiError')
        except Exception as e:
            if debug:
                import pdb
                import traceback
                traceback.print_exc()
                pdb.post_mortem()
            else:
                raise

    # Save the org config in case it was modified in the task
    if org and org_config:
        config.keychain.set_org(org, org_config)

    if exception:
        raise exception
Пример #32
0
 def _init_task(self, class_path, options, task_config):
     task_class = import_class(class_path)
     task_config = self._parse_task_options(options, task_class,
                                            task_config)
     return task_class, task_config
Пример #33
0
def task_run(config, task_name, org, o, debug):
    # Check environment
    check_keychain(config)

    # Get necessary configs
    if org:
        org_config = config.project_config.get_org(org)
    else:
        org, org_config = config.project_config.keychain.get_default_org()
    task_config = getattr(config.project_config, 'tasks__{}'.format(task_name))
    if not task_config:
        raise TaskNotFoundError('Task not found: {}'.format(task_name))

    # Get the class to look up options
    class_path = task_config.get('class_path')
    task_class = import_class(class_path)

    # Parse command line options and add to task config
    if o:
        if 'options' not in task_config:
            task_config['options'] = {}
        for option in o:
            name = option[0]
            value = option[1]

            # Validate the option
            if name not in task_class.task_options:
                raise click.UsageError(
                    'Option "{}" is not available for task {}'.format(
                        name,
                        task_name,
                    ), )

            # Override the option in the task config
            task_config['options'][name] = value

    task_config = TaskConfig(task_config)
    exception = None

    # Create and run the task
    try:
        task = task_class(config.project_config,
                          task_config,
                          org_config=org_config)
    except TaskRequiresSalesforceOrg as e:
        exception = click.UsageError(
            'This task requires a salesforce org.  Use org default <name> to set a default org or pass the org name with the --org option'
        )
    except TaskOptionsError as e:
        exception = click.UsageError(e.message)
    except Exception as e:
        if debug:
            import pdb
            import traceback
            traceback.print_exc()
            pdb.post_mortem()
        else:
            raise

    if not exception:
        try:
            task()
        except TaskOptionsError as e:
            exception = click.UsageError(e.message)
        except ApexTestException as e:
            exception = click.ClickException('Failed: ApexTestFailure')
        except MetadataComponentFailure as e:
            exception = click.ClickException(
                'Failed: MetadataComponentFailure')
        except MetadataApiError as e:
            exception = click.ClickException('Failed: MetadataApiError')
        except Exception as e:
            if debug:
                import pdb
                import traceback
                traceback.print_exc()
                pdb.post_mortem()
            else:
                raise

    # Save the org config in case it was modified in the task
    if org and org_config:
        config.keychain.set_org(org, org_config)

    if exception:
        raise exception