feat: replace work item relations with dedicated dependency and custom relation tools#148
feat: replace work item relations with dedicated dependency and custom relation tools#148akhil-vamshi-konam wants to merge 8 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a new ChangesWork Item Relation Definitions and Dual-Mode Relation Tools
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
plane_mcp/tools/work_item_relation_definitions.py (1)
138-142:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd missing
Returnssections to tool docstrings.Both modified tool docstrings include
Argsbut omitReturns, which violates the tool docstring standard.
plane_mcp/tools/work_item_relation_definitions.py#L138-L142: add aReturnssection (even if it is explicitNone/ack behavior).plane_mcp/tools/work_item_relations.py#L136-L150: add aReturnssection documenting the remove tool’s output contract.
As per coding guidelines, “Tool docstrings must include Args and Returns sections.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plane_mcp/tools/work_item_relation_definitions.py` around lines 138 - 142, Add missing `Returns` sections to both tool docstrings to comply with the tool docstring standard. In `plane_mcp/tools/work_item_relation_definitions.py` lines 138-142, add a `Returns` section to the docstring for the delete method documenting what it returns (e.g., None or acknowledgment behavior). In `plane_mcp/tools/work_item_relations.py` lines 136-150, add a `Returns` section to the docstring for the remove tool documenting its output contract. Both sections should clearly describe the return value or behavior to ensure complete documentation per coding guidelines.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plane_mcp/tools/work_item_relations.py`:
- Around line 96-127: The function currently silently chooses dependency
creation if relation_type is provided, even if custom relation fields
(relation_definition_id and relation_definition_label) are also passed. Since
these modes are mutually exclusive per the API contract, add early validation
before the existing if statements to check if both relation_type and the custom
relation fields are provided together. If this ambiguous combination is
detected, raise a ValueError explaining that these parameters are mutually
exclusive and the caller must choose only one mode.
In `@tests/test_integration.py`:
- Around line 193-200: The extract_result call for the epics_result is
incorrectly assuming the payload is wrapped in a dict with a "results" key, but
list_work_items returns the item list directly. Remove the ["results"] indexing
from the epics assignment where extract_result(epics_result) is called, so that
epics is assigned the extracted list directly rather than attempting to access a
non-existent "results" key within it.
- Around line 142-158: Before creating a new workspace-level Epic type via the
create_work_item_type call, first check if an Epic type already exists in the
workspace_types list that was just retrieved. After extracting the
workspace_types from the result, search through that list for an existing type
with the name "Epic". If found, use that existing type for epic_type instead of
creating a duplicate. Only call create_work_item_type if no Epic type already
exists in the workspace_types. This prevents duplicate-name errors and avoids
unnecessary type creation when the type is already available.
---
Outside diff comments:
In `@plane_mcp/tools/work_item_relation_definitions.py`:
- Around line 138-142: Add missing `Returns` sections to both tool docstrings to
comply with the tool docstring standard. In
`plane_mcp/tools/work_item_relation_definitions.py` lines 138-142, add a
`Returns` section to the docstring for the delete method documenting what it
returns (e.g., None or acknowledgment behavior). In
`plane_mcp/tools/work_item_relations.py` lines 136-150, add a `Returns` section
to the docstring for the remove tool documenting its output contract. Both
sections should clearly describe the return value or behavior to ensure complete
documentation per coding guidelines.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f03418e5-4715-4273-8d89-b804cb6dc997
📒 Files selected for processing (9)
README.mdplane_mcp/instructions.pyplane_mcp/tools/__init__.pyplane_mcp/tools/initiatives.pyplane_mcp/tools/work_item_relation_definitions.pyplane_mcp/tools/work_item_relations.pyplane_mcp/tools/work_item_types.pyplane_mcp/tools/work_items.pytests/test_integration.py
✅ Files skipped from review due to trivial changes (2)
- plane_mcp/tools/work_item_types.py
- README.md
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
plane_mcp/tools/work_item_relation_definitions.py (1)
138-142:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd missing
Returnssections to tool docstrings.Both modified tool docstrings include
Argsbut omitReturns, which violates the tool docstring standard.
plane_mcp/tools/work_item_relation_definitions.py#L138-L142: add aReturnssection (even if it is explicitNone/ack behavior).plane_mcp/tools/work_item_relations.py#L136-L150: add aReturnssection documenting the remove tool’s output contract.
As per coding guidelines, “Tool docstrings must include Args and Returns sections.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plane_mcp/tools/work_item_relation_definitions.py` around lines 138 - 142, Add missing `Returns` sections to both tool docstrings to comply with the tool docstring standard. In `plane_mcp/tools/work_item_relation_definitions.py` lines 138-142, add a `Returns` section to the docstring for the delete method documenting what it returns (e.g., None or acknowledgment behavior). In `plane_mcp/tools/work_item_relations.py` lines 136-150, add a `Returns` section to the docstring for the remove tool documenting its output contract. Both sections should clearly describe the return value or behavior to ensure complete documentation per coding guidelines.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plane_mcp/tools/work_item_relations.py`:
- Around line 96-127: The function currently silently chooses dependency
creation if relation_type is provided, even if custom relation fields
(relation_definition_id and relation_definition_label) are also passed. Since
these modes are mutually exclusive per the API contract, add early validation
before the existing if statements to check if both relation_type and the custom
relation fields are provided together. If this ambiguous combination is
detected, raise a ValueError explaining that these parameters are mutually
exclusive and the caller must choose only one mode.
In `@tests/test_integration.py`:
- Around line 193-200: The extract_result call for the epics_result is
incorrectly assuming the payload is wrapped in a dict with a "results" key, but
list_work_items returns the item list directly. Remove the ["results"] indexing
from the epics assignment where extract_result(epics_result) is called, so that
epics is assigned the extracted list directly rather than attempting to access a
non-existent "results" key within it.
- Around line 142-158: Before creating a new workspace-level Epic type via the
create_work_item_type call, first check if an Epic type already exists in the
workspace_types list that was just retrieved. After extracting the
workspace_types from the result, search through that list for an existing type
with the name "Epic". If found, use that existing type for epic_type instead of
creating a duplicate. Only call create_work_item_type if no Epic type already
exists in the workspace_types. This prevents duplicate-name errors and avoids
unnecessary type creation when the type is already available.
---
Outside diff comments:
In `@plane_mcp/tools/work_item_relation_definitions.py`:
- Around line 138-142: Add missing `Returns` sections to both tool docstrings to
comply with the tool docstring standard. In
`plane_mcp/tools/work_item_relation_definitions.py` lines 138-142, add a
`Returns` section to the docstring for the delete method documenting what it
returns (e.g., None or acknowledgment behavior). In
`plane_mcp/tools/work_item_relations.py` lines 136-150, add a `Returns` section
to the docstring for the remove tool documenting its output contract. Both
sections should clearly describe the return value or behavior to ensure complete
documentation per coding guidelines.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f03418e5-4715-4273-8d89-b804cb6dc997
📒 Files selected for processing (9)
README.mdplane_mcp/instructions.pyplane_mcp/tools/__init__.pyplane_mcp/tools/initiatives.pyplane_mcp/tools/work_item_relation_definitions.pyplane_mcp/tools/work_item_relations.pyplane_mcp/tools/work_item_types.pyplane_mcp/tools/work_items.pytests/test_integration.py
✅ Files skipped from review due to trivial changes (2)
- plane_mcp/tools/work_item_types.py
- README.md
🛑 Comments failed to post (3)
plane_mcp/tools/work_item_relations.py (1)
96-127:
⚠️ Potential issue | 🟠 Major | ⚡ Quick winReject ambiguous create mode inputs.
If callers pass
relation_typeand custom relation fields together, dependency creation is chosen silently. This should fail fast because the API contract is mutually exclusive.Suggested fix
client, workspace_slug = get_plane_client_context() + if relation_type and (relation_definition_id or relation_definition_label): + raise ValueError( + "Use either relation_type (dependency) or relation_definition_id + " + "relation_definition_label (custom), not both." + ) if relation_type: if relation_type not in _DEPENDENCY_TYPES: raise ValueError(📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.if relation_type and (relation_definition_id or relation_definition_label): raise ValueError( "Use either relation_type (dependency) or relation_definition_id + " "relation_definition_label (custom), not both." ) if relation_type: if relation_type not in _DEPENDENCY_TYPES: raise ValueError( f"relation_type must be one of {list(_DEPENDENCY_TYPES)}. For any " "other relationship, pass relation_definition_id + " "relation_definition_label from list_work_item_relation_definitions." ) return client.work_items.dependencies.create( workspace_slug=workspace_slug, project_id=project_id, work_item_id=work_item_id, data=CreateWorkItemDependency( relation_type=relation_type, # type: ignore[arg-type] work_item_ids=work_item_ids, ), ) if relation_definition_id and relation_definition_label: return client.work_items.custom_relations.create( workspace_slug=workspace_slug, project_id=project_id, work_item_id=work_item_id, data=CreateWorkItemCustomRelation( relation_definition_id=relation_definition_id, relation_definition_type=relation_definition_label, work_item_ids=work_item_ids, ), ) raise ValueError( "Provide relation_type for a built-in dependency, or " "relation_definition_id + relation_definition_label for a custom " "relation (call list_work_item_relation_definitions to find one)." )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@plane_mcp/tools/work_item_relations.py` around lines 96 - 127, The function currently silently chooses dependency creation if relation_type is provided, even if custom relation fields (relation_definition_id and relation_definition_label) are also passed. Since these modes are mutually exclusive per the API contract, add early validation before the existing if statements to check if both relation_type and the custom relation fields are provided together. If this ambiguous combination is detected, raise a ValueError explaining that these parameters are mutually exclusive and the caller must choose only one mode.tests/test_integration.py (2)
142-158:
⚠️ Potential issue | 🟠 Major | ⚡ Quick winAvoid duplicate “Epic” type creation in workspace scope.
The fallback path creates a new workspace-level
Epicwheneverworkspace_typesis non-empty, without first checking whetherEpicalready exists there. That can trigger duplicate-name errors or unnecessary type churn.Suggested fix
- if workspace_types: - new_type_result = await client.call_tool("create_work_item_type", {"name": "Epic"}) - epic_type = extract_result(new_type_result) - created_workspace_epic_type = True - await client.call_tool( - "import_work_item_types_to_project", - {"project_id": project_id, "work_item_type_ids": [epic_type["id"]]}, - ) + if workspace_types: + epic_type = next((t for t in workspace_types if t.get("name", "").lower() == "epic"), None) + if epic_type is None: + new_type_result = await client.call_tool("create_work_item_type", {"name": "Epic"}) + epic_type = extract_result(new_type_result) + created_workspace_epic_type = True + await client.call_tool( + "import_work_item_types_to_project", + {"project_id": project_id, "work_item_type_ids": [epic_type["id"]]}, + )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.if epic_type is None: workspace_types_result = await client.call_tool("list_work_item_types", {}) workspace_types = extract_result(workspace_types_result) if workspace_types: epic_type = next((t for t in workspace_types if t.get("name", "").lower() == "epic"), None) if epic_type is None: new_type_result = await client.call_tool("create_work_item_type", {"name": "Epic"}) epic_type = extract_result(new_type_result) created_workspace_epic_type = True await client.call_tool( "import_work_item_types_to_project", {"project_id": project_id, "work_item_type_ids": [epic_type["id"]]}, ) else: new_type_result = await client.call_tool( "create_work_item_type", {"name": "Epic", "project_id": project_id} ) epic_type = extract_result(new_type_result)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_integration.py` around lines 142 - 158, Before creating a new workspace-level Epic type via the create_work_item_type call, first check if an Epic type already exists in the workspace_types list that was just retrieved. After extracting the workspace_types from the result, search through that list for an existing type with the name "Epic". If found, use that existing type for epic_type instead of creating a duplicate. Only call create_work_item_type if no Epic type already exists in the workspace_types. This prevents duplicate-name errors and avoids unnecessary type creation when the type is already available.
193-200:
⚠️ Potential issue | 🟠 Major | ⚡ Quick winUse
list_work_itemsresult as a list, not["results"].Line 199 assumes a wrapped payload shape and can fail with
TypeError/KeyErrorwhen the tool returns the list directly.
Based on learnings, list endpoints should return onlyresponse.results(the item list), not pagination metadata wrappers.Suggested fix
- epics = extract_result(epics_result)["results"] + epics = extract_result(epics_result)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_integration.py` around lines 193 - 200, The extract_result call for the epics_result is incorrectly assuming the payload is wrapped in a dict with a "results" key, but list_work_items returns the item list directly. Remove the ["results"] indexing from the epics assignment where extract_result(epics_result) is called, so that epics is assigned the extracted list directly rather than attempting to access a non-existent "results" key within it.Source: Learnings
…into chore-custom-relations
Description:
Summary
Replaces the legacy
work_item_relationstools with three purpose-built modules that map to the new dedicated API endpoints:work_item_relation_definitions(4 tools) — CRUD for workspace-level relation definitions; these define the outward/inward labels used by custom relationswork_item_dependencies(3 tools) — list, create, remove across all six hardcoded directions (blocking / blocked_by / start_before / start_after / finish_before / finish_after); uses/relation-dependencies/work_item_custom_relations(3 tools) — list, create, remove definition-based relations with directionality viarelation_definition_type; uses/work-item-relations/Removes
work_item_relations.py— the legacy/relations/endpoint it wrapped is broken for custom types and superseded by the above.Type of Change
Test Scenarios
list_work_item_relation_definitions— returns all definitions (default + custom)create_work_item_dependencywith each of the six relation typeslist_work_item_dependencies— verifies grouping by direction and reverse-side visibilityremove_work_item_dependency— confirms removal from both sidescreate_work_item_custom_relationoutward + inward directionslist_work_item_custom_relations— verifies dict keyed by definition labelsremove_work_item_custom_relation— confirms clearing from both sidesSummary by CodeRabbit
New Features
Documentation
Improvements