Skip to content

Commit dfc9533

Browse files
committed
Account for the possibility of multiple linked issues/PRs
1 parent 435b889 commit dfc9533

File tree

5 files changed

+68
-35
lines changed

5 files changed

+68
-35
lines changed

src/GitReleaseManager.Core/Model/Issue.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ public sealed class Issue
1818

1919
public User User { get; set; }
2020

21-
public Issue LinkedIssue { get; set; }
21+
public IReadOnlyList<Issue> LinkedIssues { get; set; }
2222
}
2323
}

src/GitReleaseManager.Core/Provider/GitHubProvider.cs

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ ... on PullRequest {{
6262
}}
6363
...on DisconnectedEvent {{
6464
createdAt,
65+
id,
66+
source {{
67+
__typename,
68+
... on Issue {{
69+
number
70+
}}
71+
... on PullRequest {{
72+
number,
73+
author {{
74+
avatarUrl,
75+
resourcePath,
76+
}}
77+
}}
78+
}},
79+
subject {{
80+
__typename
81+
... on Issue {{
82+
number
83+
}}
84+
... on PullRequest {{
85+
number
86+
}}
87+
}}
6588
}}
6689
}}
6790
}}
@@ -414,7 +437,7 @@ public string GetIssueType(Issue issue)
414437
return issue.IsPullRequest ? "Pull Request" : "Issue";
415438
}
416439

417-
public async Task<Issue> GetLinkedIssueAsync(string owner, string repository, int issueNumber)
440+
public async Task<IEnumerable<Issue>> GetLinkedIssuesAsync(string owner, string repository, Issue issue)
418441
{
419442
var graphQLQuery = string.Format(CultureInfo.InvariantCulture, CONNECT_AND_DISCONNECT_EVENTS_GRAPHQL_QUERY,
420443
string.Format(CultureInfo.InvariantCulture, CONNECT_AND_DISCONNECT_EVENTS_GRAPHQL_QUERY_FRAGMENT, "issue"),
@@ -428,7 +451,7 @@ public async Task<Issue> GetLinkedIssueAsync(string owner, string repository, in
428451
pageSize = PAGE_SIZE,
429452
repoName = repository,
430453
repoOwner = owner,
431-
issueNumber = issueNumber,
454+
issueNumber = issue.PublicNumber,
432455
},
433456
};
434457

@@ -443,41 +466,45 @@ public async Task<Issue> GetLinkedIssueAsync(string owner, string repository, in
443466

444467
if (issueNode.ValueKind == JsonValueKind.Null || issueNode.ValueKind == JsonValueKind.Undefined)
445468
{
446-
throw new NotFoundException($"Unable to find issue/pull request {issueNumber}");
469+
throw new NotFoundException($"Unable to find issue/pull request {issue.PublicNumber}");
447470
}
448471

449472
var nodes = issueNode.GetJsonElement("timelineItems.nodes");
450-
var sortedNodes = nodes.EnumerateArray().OrderByDescending(n => n.GetJsonElement("createdAt").GetDateTime());
451-
var mostRecentConnectedEvent = sortedNodes.FirstOrDefault(n => n.GetJsonElement("__typename").GetString() == "ConnectedEvent");
452-
var mostRecentDisconnectedEvent = sortedNodes.FirstOrDefault(n => n.GetJsonElement("__typename").GetString() == "DisconnectedEvent");
473+
var sortedNodes = nodes.EnumerateArray().OrderBy(n => n.GetJsonElement("createdAt").GetDateTime());
474+
var connectedEvents = sortedNodes.Where(n => n.GetJsonElement("__typename").GetString() == "ConnectedEvent").ToArray();
475+
var disconnectedEvents = sortedNodes.Where(n => n.GetJsonElement("__typename").GetString() == "DisconnectedEvent").ToArray();
453476

454-
// Make sure we found an event that indicates that an issue/PR was linked to this issue/PR
455-
if (mostRecentConnectedEvent.ValueKind == JsonValueKind.Null || mostRecentConnectedEvent.ValueKind == JsonValueKind.Undefined)
477+
if (!connectedEvents.Any())
456478
{
457-
return null;
479+
return Enumerable.Empty<Issue>();
458480
}
459481

460-
// We found an event indicating that an issue was linked. Make sure it wasn't un-linked
461-
else if (mostRecentDisconnectedEvent.ValueKind == JsonValueKind.Null || mostRecentDisconnectedEvent.ValueKind == JsonValueKind.Undefined)
482+
var linkedIssues = new List<Issue>();
483+
foreach (var connectEvent in connectedEvents)
462484
{
463-
var linkedIssueNumber = mostRecentConnectedEvent.GetJsonElement("subject.number").GetInt32();
464-
var issue = await _gitHubClient.Issue.Get(owner, repository, linkedIssueNumber).ConfigureAwait(false);
465-
return _mapper.Map<Issue>(issue);
466-
}
485+
var linkedIssueNumber = connectEvent.GetJsonElement("subject.number").GetInt32();
486+
var correspondingDisconnectEvent = disconnectedEvents
487+
.FirstOrDefault(e =>
488+
e.GetJsonElement("subject.number").GetInt32() == linkedIssueNumber &&
489+
e.GetJsonElement("createdAt").GetDateTime() >= connectEvent.GetJsonElement("createdAt").GetDateTime());
467490

468-
// We found a linked issue and a disconnection event. Check which one is the most recent
469-
else if (mostRecentDisconnectedEvent.GetJsonElement("createdAt").GetDateTime() >= mostRecentConnectedEvent.GetJsonElement("createdAt").GetDateTime())
470-
{
471-
return null;
491+
if (correspondingDisconnectEvent.ValueKind == JsonValueKind.Null || correspondingDisconnectEvent.ValueKind == JsonValueKind.Undefined)
492+
{
493+
var linkedIssue = await _gitHubClient.Issue.Get(owner, repository, linkedIssueNumber).ConfigureAwait(false);
494+
linkedIssues.Add(_mapper.Map<Issue>(linkedIssue));
495+
}
496+
else if (correspondingDisconnectEvent.GetJsonElement("createdAt").GetDateTime() >= connectEvent.GetJsonElement("createdAt").GetDateTime())
497+
{
498+
continue;
499+
}
500+
else
501+
{
502+
var linkedIssue = await _gitHubClient.Issue.Get(owner, repository, linkedIssueNumber).ConfigureAwait(false);
503+
linkedIssues.Add(_mapper.Map<Issue>(linkedIssue));
504+
}
472505
}
473506

474-
// We found an event indicating that an issue was linked and we determined that it is more recent than any of the "un-link" events
475-
else
476-
{
477-
var linkedIssueNumber = mostRecentConnectedEvent.GetJsonElement("subject.number").GetInt32();
478-
var issue = await _gitHubClient.Issue.Get(owner, repository, linkedIssueNumber).ConfigureAwait(false);
479-
return _mapper.Map<Issue>(issue);
480-
}
507+
return linkedIssues;
481508
}
482509

483510
private async Task ExecuteAsync(Func<Task> action)

src/GitReleaseManager.Core/Provider/IVcsProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ public interface IVcsProvider
5050

5151
string GetIssueType(Issue issue);
5252

53-
Task<Issue> GetLinkedIssueAsync(string owner, string repository, int issueNumber);
53+
Task<IEnumerable<Issue>> GetLinkedIssuesAsync(string owner, string repository, Issue issue);
5454
}
5555
}

src/GitReleaseManager.Core/ReleaseNotes/ReleaseNotesBuilder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ public async Task<string> BuildReleaseNotesAsync(string user, string repository,
7575
{
7676
foreach (var issue in kvp.Value)
7777
{
78-
issue.LinkedIssue = await _vcsProvider.GetLinkedIssueAsync(_user, _repository, issue.PublicNumber).ConfigureAwait(false);
78+
var linkedIssues = await _vcsProvider.GetLinkedIssuesAsync(_user, _repository, issue).ConfigureAwait(false);
79+
issue.LinkedIssues = linkedIssues?.ToList().AsReadOnly() ?? Array.AsReadOnly(Array.Empty<Issue>());
7980
}
8081
}
8182

src/GitReleaseManager.IntegrationTests/GitHubProviderIntegrationTests.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,20 @@ public async Task Should_Get_Commits_Count()
103103
}
104104

105105
[Test]
106-
public async Task GetLinkedIssue()
106+
public async Task GetLinkedIssues()
107107
{
108-
// Assert that issue 43 is linked to pull request 108
109-
var result1 = await _gitHubProvider.GetLinkedIssueAsync("jericho", "_testing", 43).ConfigureAwait(false);
110-
Assert.AreEqual(108, result1.PublicNumber);
108+
// Assert that issue 43 is linked to pull requests 107 and 108
109+
var result1 = await _gitHubProvider.GetLinkedIssuesAsync("jericho", "_testing", new Issue() { PublicNumber = 43 }).ConfigureAwait(false);
110+
Assert.IsNotNull(result1);
111+
Assert.AreEqual(2, result1.Count());
112+
Assert.AreEqual(1, result1.Count(r => r.PublicNumber == 107));
113+
Assert.AreEqual(1, result1.Count(r => r.PublicNumber == 108));
111114

112115
// Assert that pull request 108 is linked to issue 43
113-
var result2 = await _gitHubProvider.GetLinkedIssueAsync("jericho", "_testing", 108).ConfigureAwait(false);
114-
Assert.AreEqual(43, result2.PublicNumber);
116+
var result2 = await _gitHubProvider.GetLinkedIssuesAsync("jericho", "_testing", new Issue() { PublicNumber = 108 }).ConfigureAwait(false);
117+
Assert.IsNotNull(result2);
118+
Assert.AreEqual(1, result2.Count());
119+
Assert.AreEqual(1, result2.Count(r => r.PublicNumber == 43));
115120
}
116121
}
117122
}

0 commit comments

Comments
 (0)