What's wrong
GitIntegration/Hosting/AzureDevOpsProvider.cs, ToGitPullRequestState(string? status):
private static GitPullRequestState ToGitPullRequestState(string? status) => status switch
{
"active" => GitPullRequestState.Open,
"completed" => GitPullRequestState.Merged,
"abandoned" => GitPullRequestState.Closed,
_ => throw new NotSupportedException($"Azure DevOps reported an unrecognised pull request status '{status}'."),
};
status comes from a raw JSON string field on a live external API (AzureDevOpsPullRequest.Status), not a closed local enum. Any pull request whose status is something other than the three known values — a future Azure DevOps status, a casing/locale variant, a service preview value, or null/empty on a malformed record — makes GetPullRequestsAsync throw an unhandled NotSupportedException.
This violates the invariant this repo's own design (and CLAUDE.md) states: a field a host reports must not escape as anything but a GitHostingException, specifically so the two providers (GitHubProvider/AzureDevOpsProvider) stay interchangeable behind a catch (GitHostingException). GitHubProvider.ToGitPullRequestState has an identically-shaped default arm, but there it's genuinely unreachable because Octokit's ItemState is a closed two-value enum mirroring GitHub's own closed open/closed field — Azure DevOps's status is an open string from the wire, so the same code shape is not equally safe there.
This is distinct from already-open issue #104 (which covers Number, Title, SourceBranch/TargetBranch, Author, WebURI bypassing ToHostValue) — #104 doesn't mention Status, and the fix belongs in the same method family, so it's worth fixing alongside #104 if convenient.
Why it matters
A caller who wrote the documented catch (GitHostingException) around both providers, expecting them to be interchangeable, will have this one specific exception type escape that catch — an availability bug on a code path meant to be exception-safe.
Suggested fix
Route the fallback through the GitHostingException hierarchy (e.g. throw GitHostingRequestException carrying the raw status and response body) instead of NotSupportedException, or add an Unknown state to GitPullRequestState the way GitChangeKind.Unknown and GitRefUpdateKind.Unknown already handle open-ended git output elsewhere in this codebase.
Acceptance criteria
- An Azure DevOps pull request with an unrecognized
status value surfaces as a GitHostingException (or maps to an Unknown state), not an unhandled NotSupportedException.
What's wrong
GitIntegration/Hosting/AzureDevOpsProvider.cs,ToGitPullRequestState(string? status):statuscomes from a raw JSON string field on a live external API (AzureDevOpsPullRequest.Status), not a closed local enum. Any pull request whose status is something other than the three known values — a future Azure DevOps status, a casing/locale variant, a service preview value, ornull/empty on a malformed record — makesGetPullRequestsAsyncthrow an unhandledNotSupportedException.This violates the invariant this repo's own design (and CLAUDE.md) states: a field a host reports must not escape as anything but a
GitHostingException, specifically so the two providers (GitHubProvider/AzureDevOpsProvider) stay interchangeable behind acatch (GitHostingException).GitHubProvider.ToGitPullRequestStatehas an identically-shaped default arm, but there it's genuinely unreachable because Octokit'sItemStateis a closed two-value enum mirroring GitHub's own closedopen/closedfield — Azure DevOps'sstatusis an open string from the wire, so the same code shape is not equally safe there.This is distinct from already-open issue #104 (which covers
Number,Title,SourceBranch/TargetBranch,Author,WebURIbypassingToHostValue) — #104 doesn't mentionStatus, and the fix belongs in the same method family, so it's worth fixing alongside #104 if convenient.Why it matters
A caller who wrote the documented
catch (GitHostingException)around both providers, expecting them to be interchangeable, will have this one specific exception type escape that catch — an availability bug on a code path meant to be exception-safe.Suggested fix
Route the fallback through the
GitHostingExceptionhierarchy (e.g. throwGitHostingRequestExceptioncarrying the raw status and response body) instead ofNotSupportedException, or add anUnknownstate toGitPullRequestStatethe wayGitChangeKind.UnknownandGitRefUpdateKind.Unknownalready handle open-ended git output elsewhere in this codebase.Acceptance criteria
statusvalue surfaces as aGitHostingException(or maps to anUnknownstate), not an unhandledNotSupportedException.