Issue sprint/iteration is never surfaced: Azure's IterationPath is commented out and Jira's sprints are dropped in fromProviderIssue
Summary
An issue's sprint/iteration never reaches a consumer of @gitkraken/core-gitlens. Two separate gaps: Azure's System.IterationPath is commented out of the WorkItem model, and the sprints array that @gitkraken/provider-apis already populates for Jira is silently dropped by fromProviderIssue.
This is the middle layer of three needed for a sprint filter in Kepler (gitkraken/kepler#2272). It is blocked by the provider-apis side (GKDEV-3614) for Azure, but the Jira half can ship independently — that data is already there and being thrown away.
Current state (verified on core, v0.6.0)
Azure
'System.IterationPath': string;is present but commented out inWorkItem.fields—packages/core/src/plus/integrations/providers/azure/models.ts:133.- Azure's account-wide issue read goes through
fromProviderIssue(azureDevOps.ts:1078), so once provider-apis exposes the value it only needs plumbing here, not a new request.
Jira (the free win)
- provider-apis already returns
sprints?: IssueSprint[]on its exportedIssue, populated bynormalizeIssueinjiraHelpers.ts— with id, name,isActive, and start/end/completed dates. fromProviderIssue(packages/core/src/plus/integrations/providers/models.ts:1711) never readsissue.sprints. The whole array is discarded at the mapper.
The model
- Neither
IssueShape(packages/core/src/git/models/issue.ts:164) nor theIssueclass (:180) has any sprint or iteration field.
Scope
Carry the sprint/iteration from the provider-apis Issue onto IssueShape / Issue, and populate it in fromProviderIssue. Read-only plumbing, no new requests, no change to any query.
Decision
The shape was an open question across this issue and GKDEV-3614. It is now settled, in both places, as follows.
Upstream (GKDEV-3614): Azure gets its own field, sprints is untouched
Reusing provider-apis' IssueSprint for Azure would be a silent behaviour change in a shipped product. gitkraken.dev's Launchpad renders a Sprint filter off that exact field (src/features/launchpad/components/shared/filters/sprint-filter.tsx), collecting sprints with a structural if ('sprints' in issue) check, keying on sprint.id, sorting on startDate, and using isActive to pick its default selection. Azure has none of those three values, so a synthesized isActive would silently move every Azure item in or out of that default. provider-apis therefore adds iteration?: { path, name } and leaves sprints alone.
Here: one normalized iterations array, with honestly-optional metadata
Two upstream shapes (Jira's rich object, Azure's path) should not become two fields that every consumer has to handle separately. Normalize once, here, into the axis both providers actually share — an identity and a name — and keep the richer metadata as optional fields that are absent when the provider does not report them.
In packages/core/src/git/models/issue.ts:
/**
* A sprint/iteration an issue belongs to.
*
* `isActive` and the dates are optional because only some providers report them:
* Jira does, Azure does not. Absent means "the provider did not say", which is NOT
* the same as `false` — a consumer defaulting to the active sprints must be able to
* tell "not active" from "unknown", or it will silently drop every Azure item.
*/
export interface IssueIteration {
/** Stable within the provider's project: Jira's sprint id, Azure's iteration path. */
id: string;
/** What the team calls it. Jira's sprint name, the leaf segment of Azure's path. */
name: string;
isActive?: boolean;
startDate?: Date;
endDate?: Date;
}and on IssueShape:
/**
* The sprint(s) this issue is in. An array because Jira can carry an item across
* several; Azure reports exactly one, so a single entry there means one iteration,
* not a truncation.
*/
iterations?: IssueIteration[];Mapping in fromProviderIssue
- Jira — from the existing
issue.sprints:id,name,isActiveand the dates map straight across (dropcompletedDate, which no consumer here needs; add it later if one does). - Azure — from
issue.iterationonce GKDEV-3614 ships:idis the path (unique within the project),nameis the leaf segment.isActiveand the dates stay absent. - Absent stays absent: an issue with no sprint gets no
iterationsat all, not[].
Rationale for optional-over-fabricated is the one already documented on IssueMember.name in this repo: a value invented in a mapper is indistinguishable downstream from one the provider reported, and cannot be undone by a consumer.
Acceptance criteria
IssueShape/Issueexposeiterations.fromProviderIssuepopulates it for Jira fromissue.sprints, and for Azure fromissue.iterationonce GKDEV-3614 ships.- Azure entries carry no
isActiveand no dates — verified by a test, not just by inspection. - An issue with no sprint carries no
iterations, rather than an empty array. - Uncomment
'System.IterationPath'in the AzureWorkItemmodel if that path ends up being the one used. - Released so Kepler can consume it.
Depends on
- GKDEV-3614 (provider-apis, Azure side) — https://gitkraken.atlassian.net/browse/GKDEV-3614. The Jira half has no dependency and can land first.
Blocks
- gitkraken/kepler#2272 — Azure DevOps: multi-select filter on Iteration (sprint)
Context
Requested by a user through Kepler in-app feedback: they work in sprints on Azure DevOps and want to filter their board by Iteration. There is an internal ask to cover the other providers too, which is what makes the dropped Jira sprints worth fixing in the same change.
Source: gitkraken/vscode-gitlens