feat(LAB-4291): add copy_workflow_from_project SDK method#2033
Conversation
Add a high-level method to copy a workflow from one project to another, including step configurations (consensus, coverage, sendBackStepId). - Add `copy_workflow_from_project` to presentation client and use cases - Add `send_back_step_id` field to WorkflowStepCreate and WorkflowStepUpdate - Add `sendBackStepId` mapping in the GraphQL step mapper - Validate destination project has no labels before copying - Remap sendBackStepId references to new step IDs after creation - Don't copy assignees per specification - Add unit tests for all scenarios Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Guard against self-copy (source == destination project ID) - Validate source step names are unique before name-based remapping - Log warning when fetching destination steps fails instead of silent swallow - Preserve original result when sendBackStepId remap produces no updates - Add tests for self-copy and duplicate step name edge cases Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… project is not wv2
86b8e63 to
f83a12a
Compare
baptiste-olivier
left a comment
There was a problem hiding this comment.
Can you add a notebook, and add it to our e2e stack ? 🙏
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
0ab4fce to
2e62b1f
Compare
baptiste-olivier
left a comment
There was a problem hiding this comment.
Auto Review Summary
Verdict: Needs discussion (already merged)
| Severity | Count |
|---|---|
| Blocker | 0 |
| Required | 1 |
| Suggestion | 3 |
| Question | 2 |
| Praise | 2 |
Well-structured feature with good validations and test coverage, but one potential bug in the first-step update and some architectural concerns.
[PRAISE] Comprehensive validations
Good defensive checks: same project ID guard, destination has no labels, duplicate step names detection, and labeler count for consensus. These prevent confusing runtime errors.
[PRAISE] Thorough test coverage
11 test cases covering happy path, error conditions, sendBackStepId remapping, assignee routing, and edge cases (no existing workflow, extra dest steps). Well-structured test helpers (_make_source_steps, _setup_happy_path).
| ) | ||
|
|
||
| delete_steps = [str(step["id"]) for step in dest_steps[1:]] or None | ||
|
|
There was a problem hiding this comment.
[REQUIRED] _build_step_update doesn't copy stepCoverage or type for the first step
When updating the first destination step to match the first source step, only name, consensusCoverage, and numberOfExpectedLabelsForConsensus are set. The stepCoverage and type fields from the source step are not copied. If the first source step has a stepCoverage value, or a different type than the existing destination step, those properties will be silently lost.
# Current - missing stepCoverage and type
def _build_step_update(dest_step_id, source_step):
update = {"id": dest_step_id, "name": ...}
# only sets consensusCoverage, numberOfExpectedLabelsForConsensus
# Missing: stepCoverage, type
return update| create_steps: Optional[list[WorkflowStepCreate]] | ||
| update_steps: Optional[list[WorkflowStepUpdate]] | ||
| delete_steps: Optional[list[str]] | ||
| for_copy: bool = False |
There was a problem hiding this comment.
[SUGGESTION] for_copy flag leaks through the architecture
This flag is threaded from the use case through ProjectWorkflowDataKiliAPIGatewayInput into the mapper, just to change serialization behavior (keeping None for consensus fields). The adapter layer shouldn't know about "copy" semantics. A cleaner approach would be to explicitly set consensusCoverage=0 or have the use case pass a sentinel to signal "include this field even if None", keeping the mapper stateless.
|
|
||
|
|
||
| def update_step_mapper(data: Union[WorkflowStepCreate, WorkflowStepUpdate]) -> dict: | ||
| def update_step_mapper( |
There was a problem hiding this comment.
[SUGGESTION] Typo: "worklow" → "workflow". Also ## is unusual for a Python comment — typically single #.
| ] | ||
| } | ||
| ], | ||
| "source": [ |
There was a problem hiding this comment.
[SUGGESTION] Notebook outputs contain real-looking test environment emails (test+edouard@kili-technology.com, test+max@kili-technology.com) and internal IDs. Consider clearing outputs or using placeholder data to avoid leaking internal information.
| # 1. Fetch source workflow steps and settings | ||
| logger.info("Fetching workflow steps from source project %s", source_project_id) | ||
| source_steps = self._kili_api_gateway.get_steps(source_project_id, _SOURCE_STEP_FIELDS) | ||
|
|
There was a problem hiding this comment.
[QUESTION] Consensus validation only checks the first step
_validate_consensus_labelers is only called for source_steps[0]. Is it guaranteed that only the first step can have consensus settings? If a later step could also have numberOfExpectedLabelsForConsensus, the copy would succeed but the destination workflow might be misconfigured.
| """ | ||
| if source_project_id == destination_project_id: | ||
| raise ValueError( | ||
| "Source and destination project IDs must be different." |
There was a problem hiding this comment.
[QUESTION] No source project workflow V2 validation
The code validates the destination project is V2 but does not check the source project. If the source uses V1, get_steps might return unexpected data. Is this intentional because V1 projects can't have multi-step workflows anyway?
Add a high-level method to copy a workflow from one project to another, including step configurations (consensus, coverage, sendBackStepId).
copy_workflow_from_projectto presentation client and use casessend_back_step_idfield to WorkflowStepCreate and WorkflowStepUpdatesendBackStepIdmapping in the GraphQL step mapper