Add conditional workflow connectors based on job artifacts (#505)#561
Conversation
|
I may have already fixed the Wizard Step Skipping in #559 |
There was a problem hiding this comment.
Pull request overview
Adds a new “On Condition” workflow connector type across the backend workflow DAG engine, REST API, and the legacy React workflow visualizer so workflow routing can depend on parent node artifacts (set_stats), and also fixes issues in the Add Node wizard flow/body.
Changes:
- Backend: introduces condition-edge through models, condition evaluation logic, DAG traversal updates, deep-copy/link inheritance support, and migrations.
- API: adds
/condition_nodes/association endpoint for WFJT nodes and exposescondition_nodes/condition_edgesin node serializers. - UI: adds condition link creation/editing (modal + wizard), renders condition edge styling, and updates reducer/link persistence logic.
Reviewed changes
Copilot reviewed 38 out of 54 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/VisualizerLink.js | Colors conditional links with a warning stroke token. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Visualizer.js | Persists condition edges via new associate/disassociate API calls and detects condition updates. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/useWorkflowNodeSteps.js | Prevents wizard nav from skipping blocked steps; persists condition params in query. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/useRunTypeStep.js | Adds condition initial values and blocks Next until artifact key is set for condition links. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/RunStep.js | Adds “On Condition” card and condition-editing fields (trigger/key/operator/value). |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeNextButton.test.js | Updates tests to assert single-advance behavior and disabled state. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeNextButton.js | Simplifies Next behavior to call onNext directly (wizard step advance fix). |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeModal.test.js | Updates wizard mock to avoid double-advance; adds condition defaults. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeModal.js | Removes prior triggerNext plumbing; seeds condition fields in Formik initialValues. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeEditModal.js | Plumbs condition fields through edit modal value extraction. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeAddModal.js | Builds linkCondition payload and strips wizard-only fields from node create POST body. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/LinkModals/LinkModal.test.js | Adds coverage for condition link fields and callback payload shape. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/LinkModals/LinkModal.js | Adds condition option, condition form fields, and passes condition data to callbacks. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/LinkModals/LinkEditModal.test.js | Updates expected reducer payload to include linkCondition: null when not conditional. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/LinkModals/LinkEditModal.js | Dispatches UPDATE_LINK with condition payload. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/LinkModals/LinkAddModal.test.js | Updates expected reducer payload to include linkCondition: null. |
| awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/LinkModals/LinkAddModal.js | Dispatches CREATE_LINK with condition payload. |
| awx/ui/src/screens/Job/WorkflowOutput/WorkflowOutputLink.js | Colors conditional links in workflow output view. |
| awx/ui/src/components/Workflow/workflowReducer.test.js | Adds reducer tests for storing/generating condition links and clearing condition data. |
| awx/ui/src/components/Workflow/workflowReducer.js | Stores linkCondition for conditional links; generates condition links from API node shape. |
| awx/ui/src/components/Workflow/WorkflowLinkHelp.js | Shows trigger + condition expression in tooltip/help panel. |
| awx/ui/src/components/Workflow/WorkflowLegend.js | Adds legend entry for condition links. |
| awx/ui/src/api/models/WorkflowJobTemplateNodes.js | Adds associateConditionNode / disassociateConditionNode client helpers. |
| awx/main/tests/unit/scheduler/test_dag_workflow.py | Adds unit coverage for condition evaluation and DAG traversal/ALL-convergence semantics. |
| awx/main/tests/unit/models/test_workflow_unit.py | Updates mocks to include condition link reverse relation. |
| awx/main/tests/functional/test_copy.py | Verifies WFJT deep copy preserves condition link through data. |
| awx/main/tests/functional/models/test_workflow.py | Updates DAG init query count; tests WFJT→WFJ inheritance of condition links. |
| awx/main/tests/functional/api/test_workflow_node.py | Adds functional tests for WFJT condition link association API. |
| awx/main/tasks/system.py | Extends deep copy relationship reconstruction to clone custom-through M2M rows. |
| awx/main/scheduler/dag_workflow.py | Loads condition links into DAG, evaluates passing edges, and adjusts traversal/DNR/failure semantics. |
| awx/main/models/workflow.py | Adds condition link through models + evaluate_artifact_condition; includes condition parents in parent discovery and inheritance. |
| awx/main/models/init.py | Exports new condition link models. |
| awx/main/migrations/0201_workflowjobnodeconditionlink_and_more.py | Adds DB schema for condition link through models + condition_nodes M2Ms. |
| awx/main/access.py | Prefetches condition relationships; allows attach/unattach for condition_nodes on WFJT nodes. |
| awx/api/views/init.py | Adds WFJT condition_nodes association view with validation and through-row updates; includes condition relationship in cross-rel validation. |
| awx/api/urls/workflow_job_template_node.py | Exposes /condition_nodes/ endpoint for WFJT nodes. |
| awx/api/urls/workflow_job_node.py | Exposes /condition_nodes/ endpoint for WFJ nodes (read-only sublist). |
| awx/api/serializers.py | Exposes condition_nodes and condition_edges on WFJT/WFJ node serializers. |
Comments suppressed due to low confidence (1)
awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/LinkModals/LinkModal.js:10
LinkModal.js's import block uses tab-indented multi-line imports that are inconsistent with the surrounding UI code style (e.g.,LinkAddModal.js:1-3uses standard spaced, single-line imports). This makes the file harder to read and is likely to fight any automated formatting/linting.
Reformat the imports to match the prevailing style (single-line named imports, spaces, trailing commas where applicable).
Implements the backend for ctrliq#505: a fourth workflow connector type that only activates the downstream node when the parent job finishes with the selected outcome AND a condition over its artifacts (set_stats data) evaluates to true. - New condition_nodes m2m on template and job workflow nodes, backed by through models storing trigger (success/failure/always, default success), artifact_key, operator (eq, ne) and expected_value - Workflow DAG engine evaluates conditions against the parent node's ancestor_artifacts merged with its own job artifacts (same semantics as artifact propagation to downstream extra_vars); the edge only fires when the parent outcome matches the trigger; nodes whose unified job template was deleted are treated as failures for condition routing - A condition edge only counts as an error handling path for a failed node when it will actually fire (trigger covers the failure and the condition holds); otherwise the workflow is marked failed, matching failure_nodes semantics - Artifact comparison parses expected_value as JSON with a bool/int cross-type guard (True does not match 1), falling back to string comparison - API sublists /workflow_job_template_nodes/N/condition_nodes/ and /workflow_job_nodes/N/condition_nodes/; association POST accepts trigger, artifact_key, operator and expected_value; re-posting updates the condition; node serializers expose condition_nodes and condition_edges (through rows prefetched to avoid N+1 on node lists) - Condition data is preserved on template-to-job instantiation, relaunch (including relaunch-from-failed carry-forward) and WFJT deep copy; the deep-copy through-row clone is idempotent and direction-aware - RBAC: connection management requires WFJT admin, same as other edges
- Link add/edit modal offers an On Condition run type with an Evaluate on selector (On Success by default, On Failure, Always) plus artifact key, operator (equals / not equals) and expected value fields - Add Node wizard Run step gains an On Condition card with the same fields; the in-flight condition values survive the launch-config resetForm, and wizard nav can no longer jump past a step whose Next button is disabled - Visualizer loads condition edges from condition_nodes/condition_edges, saves them through the condition_nodes association endpoint (re-posting updates the stored condition) and disassociates them like other links - Condition links render in warning color in the visualizer and the workflow job output view; the link tooltip shows the trigger and the condition; the legend documents the new connector - Node-level fields (identifier, nodeType, nodeResource) are stripped from promptValues when adding a node, fixing a pre-existing 400 from posting a blank identifier on node creation - New strings extracted to the i18n catalogs with Spanish translations
Register the condition_nodes endpoints so awx export includes the fourth edge type instead of silently dropping it (an imported workflow would otherwise run condition children unconditionally as root nodes). Each exported edge keeps the target node natural key under 'id' plus its trigger, artifact_key, operator and expected_value, and the import posts the full association. Re-importing an existing link updates its condition in place, so export/import round-trips stay idempotent. Also adds WorkflowJobTemplateNode.add_condition_node for parity with the other add_*_node helpers.
5ab8398 to
05ca813
Compare
|
You did indeed, thanks for the heads up. I rebased the branch on current main and dropped my wizard fix commit since #559 covers the same bug, so the PR is down to the 3 feature commits (backend, UI, awxkit) and is mergeable again. Quick summary of what changed with the rebase:
|
| log.error("endpoint: %s, id: %s", endpoint.endpoint, rel_page['id']) | ||
| self._has_error = True |
There was a problem hiding this comment.
The log.error and self._has_error = True after the successful post are not part of this change, that code is already on main exactly like that. The only new lines here are the post_data.update(extra_fields) and the lookup handling above it. It does look like leftover debugging upstream (a plain 2xx without body raises exc.NoContent, so hitting that branch means the endpoint returned a body), but I'd rather not fold that fix into this PR to keep the scope tight. Happy to send it separately if there's interest.
There was a problem hiding this comment.
Fix this small issue and I think this one is ready to merge.
Summary
Implements #505: a fourth workflow connector type, On Condition, that routes workflow execution based on the artifacts (
set_statsdata) produced by the parent node.A conditional edge stores four properties:
trigger— parent outcome required before evaluating:success(default),failureoralwaysartifact_key— the artifact to inspectoperator—eq/neexpected_value— parsed as JSON when possible (true,3), otherwise compared as a plain stringThe edge activates the downstream node only when the parent finishes with the selected outcome and the condition evaluates to true against the parent's effective artifacts (its
ancestor_artifactsmerged with its own job's artifacts — the same data already passed downstream asextra_vars). A missing key never matches.Design notes
condition_nodesm2m onWorkflowJobTemplateNode/WorkflowJobNode, backed by through models that carry the per-edge condition (backward-compatible migration; existing workflows untouched).bfs_nodes_to_run, DNR marking and ALL-convergence. A condition edge only counts as an error-handling path for a failed node when it will actually fire, keepingfailure_nodessemantics./workflow_job_template_nodes/N/condition_nodes/(and the workflow job node mirror). Association POST accepts the condition fields; re-posting an existing link updates its condition. Node serializers exposecondition_nodes+condition_edges(prefetched, no N+1).awxkitknows the new endpoints, soawx export/awx importround-trips conditional edges together with their condition. Without this an exported workflow would come back with the condition children as unconditional root nodes.Also fixed along the way
identifier(and other wizard-internal fields) in the node create body, which 400s on save.This PR originally also carried a fix for the PF6 Add Node wizard advancing two steps per click, but #559 fixed that same bug upstream, so the branch is now rebased on current main and that commit was dropped.
Screenshots
Editing a conditional link:
Add Node wizard with the new run type:
Visualizer with conditional connectors and the updated legend:
The same workflow routing on its artifacts —
environment: stagingrun vsenvironment: productionrun (the parent playbook publishes the value viaset_stats):Testing
set_statsoutput (screenshots above).awx exportincludes the condition data, the import recreates the edges, and re-importing after editing a condition updates the link in place.Known follow-ups (happy to send separate PRs)
ctrliq.ascendercollection doesn't know about the fourth edge type yet.