示例#1
0
    def get_flow_from_plan(self,
                           plan: Plan,
                           ctx: WorkableModel,
                           skip: List[str] = None):
        steps = [
            step.to_spec(skip=step.path in skip) for step in plan.steps.all()
        ]

        if isinstance(ctx, PreflightResult):
            flow_config = self.project_config.get_flow(
                plan.preflight_flow_name)
            return FlowCoordinator(
                self.project_config,
                flow_config,
                name=plan.preflight_flow_name,
                callbacks=PreflightFlowCallback(ctx),
            )
        elif isinstance(ctx, Job):
            return FlowCoordinator.from_steps(
                self.project_config,
                steps,
                name="default",
                callbacks=JobFlowCallback(ctx),
            )
        else:  # pragma: no cover
            raise AttributeError(f"ctx must be either a PreflightResult "
                                 f"or Job, but was passed {type(ctx)}.")
示例#2
0
    def test_run__skip_from_init(self):
        """ A flow can receive during init a list of tasks to skip """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "task": "pass_name"
                },
                2: {
                    "task": "name_response",
                    "options": {
                        "response": "^^pass_name.name"
                    },
                },
            },
        })
        flow = FlowCoordinator(self.project_config,
                               flow_config,
                               skip=["name_response"])
        flow.run(self.org_config)

        # the number of results should be 1 instead of 2
        self.assertEqual(1, len(flow.results))
示例#3
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_config = project_config.get_flow(self.flow)

        # If it's a release build, pass the dates in
        options = self._get_flow_options()

        callbacks = None
        if settings.METACI_FLOW_CALLBACK_ENABLED:
            from metaci.build.flows import MetaCIFlowCallback

            callbacks = MetaCIFlowCallback(buildflow_id=self.pk)

        # Create the flow and handle initialization exceptions
        self.flow_instance = FlowCoordinator(
            project_config,
            flow_config,
            name=self.flow,
            options=options,
            callbacks=callbacks,
        )

        # Run the flow
        return self.flow_instance.run(org_config)
    def test_run__no_steps(self):
        """ A flow with no tasks will have no results. """
        flow_config = FlowConfig({"description": "Run no tasks", "steps": {}})
        flow = FlowCoordinator(self.project_config, flow_config)
        flow.run(self.org_config)

        self.assertEqual([], flow.steps)
        self.assertEqual([], flow.results)
示例#5
0
    def test_run__no_steps(self):
        """ A flow with no tasks will have no results. """
        flow_config = FlowConfig({"description": "Run no tasks", "steps": {}})
        flow = FlowCoordinator(self.project_config, flow_config)
        flow.run(self.org_config)

        self.assertEqual([], flow.steps)
        self.assertEqual([], flow.results)
    def test_run__task_raises_exception_fail(self):
        """ A flow aborts when a task raises an exception """

        flow_config = FlowConfig(
            {"description": "Run a task", "steps": {1: {"task": "raise_exception"}}}
        )
        flow = FlowCoordinator(self.project_config, flow_config)
        with self.assertRaises(Exception):
            flow.run(self.org_config)
示例#7
0
 def test_run__skip_conditional_step(self):
     flow_config = FlowConfig(
         {"steps": {
             1: {
                 "task": "pass_name",
                 "when": "False"
             }
         }})
     flow = FlowCoordinator(self.project_config, flow_config)
     flow.run(self.org_config)
     assert len(flow.results) == 0
 def test_run__nested_flow(self):
     """ Flows can run inside other flows """
     flow_config = FlowConfig(
         {
             "description": "Run a task and a flow",
             "steps": {1: {"task": "pass_name"}, 2: {"flow": "nested_flow"}},
         }
     )
     flow = FlowCoordinator(self.project_config, flow_config)
     flow.run(self.org_config)
     self.assertEqual(2, len(flow.steps))
     self.assertEqual(flow.results[0].return_values, flow.results[1].return_values)
 def test_run__skip_flow_None(self):
     flow_config = FlowConfig(
         {
             "description": "A flow that skips its only step",
             "steps": {1: {"task": "None"}},
         }
     )
     callbacks = mock.Mock()
     flow = FlowCoordinator(
         self.project_config, flow_config, name="skip", callbacks=callbacks
     )
     flow.run(self.org_config)
     callbacks.pre_task.assert_not_called()
示例#10
0
    def test_init_org_updates_keychain(self):
        self.org_config.save = save = mock.Mock()

        def change_username(keychain):
            self.org_config.config["username"] = "******"

        self.org_config.refresh_oauth_token = change_username

        flow_config = FlowConfig({"steps": {1: {"task": "pass_name"}}})
        flow = FlowCoordinator(self.project_config, flow_config)
        flow.org_config = self.org_config
        flow._init_org()

        save.assert_called_once()
    def test_run__one_task(self):
        """ A flow with one task will execute the task """
        flow_config = FlowConfig(
            {"description": "Run one task", "steps": {1: {"task": "pass_name"}}}
        )
        flow = FlowCoordinator(self.project_config, flow_config)
        self.assertEqual(1, len(flow.steps))

        flow.run(self.org_config)

        self.assertTrue(
            any(flow_config.description in s for s in self.flow_log["info"])
        )
        self.assertEqual({"name": "supername"}, flow.results[0].return_values)
    def test_run__prints_org_id(self):
        """ A flow with an org prints the org ID """

        flow_config = FlowConfig(
            {
                "description": "Run two tasks",
                "steps": {1: {"task": "pass_name"}, 2: {"task": "sfdc_task"}},
            }
        )
        flow = FlowCoordinator(self.project_config, flow_config)
        flow.run(self.org_config)

        org_id_logs = [s for s in self.flow_log["info"] if ORG_ID in s]

        self.assertEqual(1, len(org_id_logs))
示例#13
0
 def test_step_sorting(self):
     self.project_config.config["flows"] = {
         "test": {
             "steps": {
                 "1": {
                     "flow": "subflow"
                 },
                 "1.1": {
                     "task": "pass_name"
                 }
             }
         },
         "subflow": {
             "steps": {
                 "1": {
                     "task": "pass_name"
                 }
             }
         },
     }
     flow_config = self.project_config.get_flow("test")
     flow = FlowCoordinator(self.project_config,
                            flow_config,
                            name="test_flow")
     assert [str(step.step_num) for step in flow.steps] == ["1/1", "1.1"]
示例#14
0
 def run(self, ctx, plan, steps, org):
     flow_coordinator = FlowCoordinator.from_steps(
         ctx.project_config,
         steps,
         name="default",
         callbacks=JobFlowCallback(self))
     flow_coordinator.run(org)
示例#15
0
 def test_get_summary__multiple_sources(self):
     other_project_config = mock.MagicMock()
     other_project_config.source.__str__.return_value = "other source"
     flow = FlowCoordinator.from_steps(
         self.project_config,
         [
             StepSpec(
                 "1/1",
                 "other:test1",
                 {},
                 None,
                 other_project_config,
                 from_flow="test",
             ),
             StepSpec("1/2",
                      "test2", {},
                      None,
                      self.project_config,
                      from_flow="test"),
         ],
     )
     assert ("1) flow: test" +
             "\n    1) task: other:test1 [from other source]" +
             "\n    2) task: test2 [from current folder]"
             ) == flow.get_summary()
    def test_run__task_raises_exception_ignore(self):
        """ A flow continues when a task configured with ignore_failure raises an exception """

        flow_config = FlowConfig(
            {
                "description": "Run a task",
                "steps": {
                    1: {"task": "raise_exception", "ignore_failure": True},
                    2: {"task": "pass_name"},
                },
            }
        )
        flow = FlowCoordinator(self.project_config, flow_config)
        flow.run(self.org_config)
        self.assertEqual(2, len(flow.results))
        self.assertIsNotNone(flow.results[0].exception)
示例#17
0
    def test_init__options(self):
        """ A flow can accept task options and pass them to the task. """

        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "task": "name_response",
                    "options": {
                        "response": "foo"
                    }
                }
            },
        })

        flow = FlowCoordinator(
            self.project_config,
            flow_config,
            options={"name_response": {
                "response": "bar"
            }},
        )

        # the first step should have the option
        self.assertEqual("bar",
                         flow.steps[0].task_config["options"]["response"])
示例#18
0
    def test_flow_info(self, echo):
        config = mock.Mock()
        flow_config = FlowConfig({"description": "Test Flow", "steps": {}})
        config.get_flow.return_value = FlowCoordinator(None, flow_config)

        run_click_command(cci.flow_info, config=config, flow_name="test")

        echo.assert_called_with("Description: Test Flow")
示例#19
0
    def test_init(self):
        flow_config = FlowConfig({"steps": {"1": {"task": "pass_name"}}})
        flow = FlowCoordinator(self.project_config,
                               flow_config,
                               name="test_flow")

        self.assertEqual(len(flow.steps), 1)
        self.assertEqual(hasattr(flow, "logger"), True)
    def test_run__nested_option_backrefs(self):
        flow_config = FlowConfig(
            {
                "description": "Run two tasks",
                "steps": {
                    1: {"flow": "nested_flow"},
                    2: {
                        "task": "name_response",
                        "options": {"response": "^^nested_flow.pass_name.name"},
                    },
                },
            }
        )

        flow = FlowCoordinator(self.project_config, flow_config)
        flow.run(self.org_config)

        self.assertEqual("supername", flow.results[-1].result)
示例#21
0
 def test_get_summary(self):
     flow_config = FlowConfig({
         "description": "test description",
         "steps": {
             "1": {
                 "flow": "nested_flow_2"
             }
         },
     })
     flow = FlowCoordinator(self.project_config,
                            flow_config,
                            name="test_flow")
     actual_output = flow.get_summary()
     expected_output = ("Description: test description" +
                        "\n1) flow: nested_flow_2" +
                        "\n    1) task: pass_name" +
                        "\n    2) flow: nested_flow" +
                        "\n        1) task: pass_name")
     self.assertEqual(expected_output, actual_output)
示例#22
0
 def test_init_ambiguous_step(self):
     flow_config = FlowConfig(
         {"steps": {
             1: {
                 "task": "None",
                 "flow": "None"
             }
         }})
     with self.assertRaises(FlowConfigError):
         FlowCoordinator(self.project_config, flow_config, name="test")
 def test_init__nested_options(self):
     flow_config = FlowConfig(
         {
             "description": "Run a flow with task options",
             "steps": {
                 1: {"flow": "nested_flow", "options": {"pass_name": {"foo": "bar"}}}
             },
         }
     )
     flow = FlowCoordinator(self.project_config, flow_config)
     self.assertEqual("bar", flow.steps[0].task_config["options"]["foo"])
示例#24
0
 def _freeze_steps(self, project_config, plan_config):
     steps = plan_config["steps"]
     flow_config = FlowConfig(plan_config)
     flow = FlowCoordinator(project_config, flow_config)
     steps = []
     for step in flow.steps:
         task = step.task_class(project_config,
                                TaskConfig(step.task_config),
                                name=step.task_name)
         steps.extend(task.freeze(step))
     return steps
示例#25
0
 def _freeze_steps(self, project_config):
     flow_name = self.options["flow"]
     flow_config = project_config.get_flow(flow_name)
     flow = FlowCoordinator(project_config, flow_config, name=flow_name)
     steps = []
     for step in flow.steps:
         task = step.task_class(project_config,
                                TaskConfig(step.task_config),
                                name=step.task_name)
         steps.extend(task.freeze(step))
     return steps
示例#26
0
 def test_get_summary(self):
     self.project_config.config["flows"]["test"] = {
         "description": "test description",
         "steps": {
             "1": {
                 "flow": "nested_flow_2"
             }
         },
     }
     flow_config = self.project_config.get_flow("test")
     flow = FlowCoordinator(self.project_config,
                            flow_config,
                            name="test_flow")
     actual_output = flow.get_summary()
     expected_output = ("Description: test description" +
                        "\n1) flow: nested_flow_2 [from current folder]" +
                        "\n    1) task: pass_name" +
                        "\n    2) flow: nested_flow" +
                        "\n        1) task: pass_name")
     self.assertEqual(expected_output, actual_output)
示例#27
0
    def test_run__option_backref_not_found(self):
        # instantiate a flow with two tasks
        flow_config = FlowConfig({
            "description": "Run two tasks",
            "steps": {
                1: {
                    "task": "pass_name"
                },
                2: {
                    "task": "name_response",
                    "options": {
                        "response": "^^bogus.name"
                    },
                },
            },
        })

        flow = FlowCoordinator(self.project_config, flow_config)
        with self.assertRaises(NameError):
            flow.run(self.org_config)
    def test_run__option_backrefs(self):
        """ A flow's options reach into return values from other tasks. """

        # instantiate a flow with two tasks
        flow_config = FlowConfig(
            {
                "description": "Run two tasks",
                "steps": {
                    1: {"task": "pass_name"},
                    2: {
                        "task": "name_response",
                        "options": {"response": "^^pass_name.name"},
                    },
                },
            }
        )

        flow = FlowCoordinator(self.project_config, flow_config)
        flow.run(self.org_config)
        # the flow results for the second task should be 'name'
        self.assertEqual("supername", flow.results[1].result)
    def test_run__skip_from_init(self):
        """ A flow can receive during init a list of tasks to skip """

        # instantiate a flow with two tasks
        flow_config = FlowConfig(
            {
                "description": "Run two tasks",
                "steps": {
                    1: {"task": "pass_name"},
                    2: {
                        "task": "name_response",
                        "options": {"response": "^^pass_name.name"},
                    },
                },
            }
        )
        flow = FlowCoordinator(self.project_config, flow_config, skip=["name_response"])
        flow.run(self.org_config)

        # the number of results should be 1 instead of 2
        self.assertEqual(1, len(flow.results))
示例#30
0
 def test_get_flow_steps__for_docs(self):
     self.project_config.config["flows"]["test"] = {
         "description": "test description",
         "steps": {
             "1": {
                 "flow": "nested_flow_2"
             }
         },
     }
     flow_config = self.project_config.get_flow("test")
     flow = FlowCoordinator(self.project_config,
                            flow_config,
                            name="test_flow")
     actual_output = flow.get_flow_steps(for_docs=True)
     expected_output = [
         "1) flow: nested_flow_2",
         "    1) task: pass_name",
         "    2) flow: nested_flow",
         "        1) task: pass_name",
     ]
     self.assertEqual(expected_output, actual_output)
示例#31
0
 def test_run__nested_flow_2(self):
     """ Flows can run inside other flows and call other flows """
     self.project_config.config["flows"]["test"] = {
         "description": "Run a task and a flow",
         "steps": {
             1: {
                 "task": "pass_name"
             },
             2: {
                 "flow": "nested_flow_2"
             }
         },
     }
     flow_config = self.project_config.get_flow("test")
     flow = FlowCoordinator(self.project_config, flow_config)
     flow.run(self.org_config)
     self.assertEqual(3, len(flow.steps))
     self.assertEqual(flow.results[0].return_values,
                      flow.results[1].return_values)
     self.assertEqual(flow.results[1].return_values,
                      flow.results[2].return_values)
示例#32
0
 def test_get_summary__substeps(self):
     flow = FlowCoordinator.from_steps(
         self.project_config,
         [
             StepSpec("1",
                      "test", {},
                      None,
                      self.project_config,
                      from_flow="test")
         ],
     )
     assert flow.get_summary() == ""
 def test_from_steps(self):
     steps = [StepSpec("1", "test", {}, _TaskReturnsStuff)]
     flow = FlowCoordinator.from_steps(self.project_config, steps)
     self.assertEqual(1, len(flow.steps))