Skip to content

jira provider _find_issue_link_id: directional removes miss links populated on the opposite side #131

Description

@studykit

Description

_find_issue_link_id (plugins/workflow/scripts/issue/jira/provider.py:1475-1495) locates the issuelinks entry to delete by selecting one of outwardIssue / inwardIssue based on the mapping direction:

direction_field = "outwardIssue" if operation.mapping.direction == "outward" else "inwardIssue"
target_issue = link.get(direction_field)

The Jira REST API populates only one of those two fields per link entry — the side that is not the current issue. So from the source issue's perspective, looking for the target on the field matching operation.mapping.direction can miss: when the target is on the opposite side from what the mapping nominally says, the populated field is the other one and the lookup returns None.

Practical effect: when a directional link (related, blocked_by, blocking, etc.) was created in a way that places the target on the inward side from the current issue's perspective, _find_issue_link_id returns None, and --remove-related <target> (or the other directional removes) fails with:

Jira issue link not found for <relationship> <target>

The link is visible in the issue's issuelinks payload, but the find function looks at the wrong direction field. The user has to remove the link manually in the Jira UI.

The bug affects every directional relationship that routes through _find_issue_link_id, not only related. The exact reproduction depends on which side of the link the source issue lives on at remove-time.

Reproduction

  1. Configure providers.issues.relationship_mappings.related with a fixed direction (e.g., direction: outward).
  2. Add a related link between two issues A and B (any creation path).
  3. From whichever of A / B ends up on the opposite side of the link from the mapping direction, run:
    "$WORKFLOW" jira_issue_relationships.py <that issue> --remove-related <other issue>
  4. Observe the error: Jira issue link not found for related <other issue> — even though the link is present in the issue's issuelinks payload.

A regression repro does not require live Jira: invoke _find_issue_link_id directly with a synthesized issue payload that mirrors a real Jira response (single populated direction field per link entry).

Unit Test Strategy

Unit test _find_issue_link_id directly. Cover the four combinations of (mapping.direction, populated field):

mapping.direction populated field in link should match
outward outwardIssue (target on outward side from source) yes
outward inwardIssue (target on inward side from source) yes
inward outwardIssue yes
inward inwardIssue yes

The function should match the target when either populated field's key equals the target and the link type matches, regardless of mapping direction.

Acceptance Criteria

  • _find_issue_link_id matches links whose target appears in either outwardIssue or inwardIssue, not only the field tied to operation.mapping.direction.
  • --remove-related, --remove-blocked-by, --remove-blocking, and any other directional removes succeed regardless of which side of the link the source issue was on at create time.
  • Regression test covers all four (direction, populated field) combinations using synthesized payloads.

Affected Paths

  • plugins/workflow/scripts/issue/jira/provider.py:1475-1495 (_find_issue_link_id)
  • plugins/workflow/tests/ (new regression coverage)

Resume

  • Approach. _find_issue_link_id now inspects both outwardIssue and inwardIssue after the type.name check and returns the link id for whichever side carries the target. operation.mapping.direction is preserved on the create path; only the read filter on remove changed. Regression coverage in plugins/workflow/tests/test_workflow_jira_issue_link_lookup.py exercises all four (direction, populated field) combinations plus link-type and target-key negative cases — the two cross-direction cases failed on the unfixed code and pass on the fix; full workflow suite (508 tests) green.
  • Waiting for.
  • Open questions. None.
  • Next.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions