Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit 9124705

Browse files
authored
Merge pull request #1864 from github/features/check-suite-annotations
Check Run Annotations
2 parents a0d556e + 6bbb1ae commit 9124705

File tree

69 files changed

+1819
-427
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1819
-427
lines changed

lib/Octokit.GraphQL.0.1.1-beta.nupkg

-194 KB
Binary file not shown.

src/GitHub.Api/GitHub.Api.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@
3030
<ItemGroup>
3131
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.1" />
3232
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
33-
<PackageReference Include="Octokit.GraphQL" Version="0.1.1-beta" />
33+
<PackageReference Include="Octokit.GraphQL" Version="0.1.2-beta" />
3434
</ItemGroup>
3535
</Project>

src/GitHub.App/GitHub.App.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@
4949
<PackageReference Include="Microsoft.VisualStudio.SDK.EmbedInteropTypes" Version="15.0.17" />
5050
<PackageReference Include="Microsoft.VisualStudio.Shell.14.0" Version="14.3.25407" />
5151
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
52-
<PackageReference Include="Octokit.GraphQL" Version="0.1.1-beta" />
52+
<PackageReference Include="Octokit.GraphQL" Version="0.1.2-beta" />
5353
<PackageReference Include="Rothko" Version="0.0.3-ghfvs" />
5454
<PackageReference Include="Serilog" Version="2.5.0" />
5555
<PackageReference Include="SerilogAnalyzer" Version="0.12.0.0" />
5656
<PackageReference Include="Stateless" Version="2.5.56.0" targetFramework="net45" />
5757
</ItemGroup>
58-
</Project>
58+
</Project>

src/GitHub.App/SampleData/CommentThreadViewModelDesigner.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using System.Diagnostics.CodeAnalysis;
1+
using System.Collections.Generic;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.Threading.Tasks;
4+
using GitHub.Models;
35
using GitHub.ViewModels;
46
using ReactiveUI;
57

@@ -8,6 +10,16 @@ namespace GitHub.SampleData
810
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")]
911
public class CommentThreadViewModelDesigner : ViewModelBase, ICommentThreadViewModel
1012
{
13+
public CommentThreadViewModelDesigner()
14+
{
15+
Comments = new ReactiveList<ICommentViewModel>(){new CommentViewModelDesigner()
16+
{
17+
Author = new ActorViewModel{ Login = "shana"},
18+
Body = "You can use a `CompositeDisposable` type here, it's designed to handle disposables in an optimal way (you can just call `Dispose()` on it and it will handle disposing everything it holds)."
19+
}};
20+
21+
}
22+
1123
public IReadOnlyReactiveList<ICommentViewModel> Comments { get; }
1224
= new ReactiveList<ICommentViewModel>();
1325

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System.Collections.Generic;
2+
using GitHub.Models;
3+
using GitHub.ViewModels;
4+
5+
namespace GitHub.SampleData
6+
{
7+
public class InlineAnnotationViewModelDesigner : IInlineAnnotationViewModel
8+
{
9+
public InlineAnnotationViewModelDesigner()
10+
{
11+
var checkRunAnnotationModel = new CheckRunAnnotationModel
12+
{
13+
AnnotationLevel = CheckAnnotationLevel.Failure,
14+
Path = "SomeFile.cs",
15+
EndLine = 12,
16+
StartLine = 12,
17+
Message = "Some Error Message",
18+
Title = "CS12345"
19+
};
20+
21+
var checkRunModel =
22+
new CheckRunModel
23+
{
24+
Annotations = new List<CheckRunAnnotationModel> {checkRunAnnotationModel},
25+
Name = "Fake Check Run"
26+
};
27+
28+
var checkSuiteModel = new CheckSuiteModel()
29+
{
30+
ApplicationName = "Fake Check Suite",
31+
HeadSha = "ed6198c37b13638e902716252b0a17d54bd59e4a",
32+
CheckRuns = new List<CheckRunModel> { checkRunModel}
33+
};
34+
35+
Model= new InlineAnnotationModel(checkSuiteModel, checkRunModel, checkRunAnnotationModel);
36+
}
37+
38+
public InlineAnnotationModel Model { get; }
39+
}
40+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.Reactive;
3+
using GitHub.Models;
4+
using GitHub.ViewModels.GitHubPane;
5+
using ReactiveUI;
6+
7+
namespace GitHub.SampleData
8+
{
9+
[ExcludeFromCodeCoverage]
10+
public sealed class PullRequestAnnotationItemViewModelDesigner : IPullRequestAnnotationItemViewModel
11+
{
12+
public CheckRunAnnotationModel Annotation { get; set; }
13+
public bool IsExpanded { get; set; }
14+
public string LineDescription => $"{Annotation.StartLine}:{Annotation.EndLine}";
15+
public bool IsFileInPullRequest { get; set; }
16+
public ReactiveCommand<Unit, Unit> OpenAnnotation { get; }
17+
}
18+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using System.Collections.Generic;
2+
using System.Diagnostics.CodeAnalysis;
3+
using System.Reactive;
4+
using System.Threading.Tasks;
5+
using GitHub.Models;
6+
using GitHub.ViewModels.GitHubPane;
7+
using ReactiveUI;
8+
9+
namespace GitHub.SampleData
10+
{
11+
[ExcludeFromCodeCoverage]
12+
public sealed class PullRequestAnnotationsViewModelDesigner : PanePageViewModelBase, IPullRequestAnnotationsViewModel
13+
{
14+
public LocalRepositoryModel LocalRepository { get; set; }
15+
public string RemoteRepositoryOwner { get; set; }
16+
public int PullRequestNumber { get; set; } = 123;
17+
public string CheckRunId { get; set; }
18+
public ReactiveCommand<Unit, Unit> NavigateToPullRequest { get; }
19+
public string PullRequestTitle { get; } = "Fixing stuff in this PR";
20+
public string CheckSuiteName { get; } = "Awesome Check Suite";
21+
public string CheckRunSummary { get; } = "Awesome Check Run Summary";
22+
public string CheckRunText { get; } = "Awesome Check Run Text";
23+
24+
public IReadOnlyDictionary<string, IPullRequestAnnotationItemViewModel[]> AnnotationsDictionary { get; }
25+
= new Dictionary<string, IPullRequestAnnotationItemViewModel[]>
26+
{
27+
{
28+
"asdf/asdf.cs",
29+
new IPullRequestAnnotationItemViewModel[]
30+
{
31+
new PullRequestAnnotationItemViewModelDesigner
32+
{
33+
Annotation = new CheckRunAnnotationModel
34+
{
35+
AnnotationLevel = CheckAnnotationLevel.Warning,
36+
StartLine = 3,
37+
EndLine = 4,
38+
Path = "asdf/asdf.cs",
39+
Message = "; is expected",
40+
Title = "CS 12345"
41+
},
42+
IsExpanded = true,
43+
IsFileInPullRequest = true
44+
},
45+
new PullRequestAnnotationItemViewModelDesigner
46+
{
47+
Annotation = new CheckRunAnnotationModel
48+
{
49+
AnnotationLevel = CheckAnnotationLevel.Failure,
50+
StartLine = 3,
51+
EndLine = 4,
52+
Path = "asdf/asdf.cs",
53+
Message = "; is expected",
54+
Title = "CS 12345"
55+
},
56+
IsExpanded = true,
57+
IsFileInPullRequest = true
58+
},
59+
}
60+
},
61+
{
62+
"blah.cs",
63+
new IPullRequestAnnotationItemViewModel[]
64+
{
65+
new PullRequestAnnotationItemViewModelDesigner
66+
{
67+
Annotation = new CheckRunAnnotationModel
68+
{
69+
AnnotationLevel = CheckAnnotationLevel.Notice,
70+
StartLine = 3,
71+
EndLine = 4,
72+
Path = "blah.cs",
73+
Message = "; is expected",
74+
Title = "CS 12345"
75+
},
76+
IsExpanded = true,
77+
}
78+
}
79+
},
80+
};
81+
82+
public string CheckRunName { get; } = "Psuedo Check Run";
83+
84+
public Task InitializeAsync(LocalRepositoryModel localRepository, IConnection connection, string owner,
85+
string repo,
86+
int pullRequestNumber, string checkRunId)
87+
{
88+
return Task.CompletedTask;
89+
}
90+
}
91+
}

src/GitHub.App/SampleData/PullRequestCheckViewModelDesigner.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
22
using System.Reactive;
3-
using System.Windows.Media.Imaging;
3+
using GitHub.Models;
44
using GitHub.ViewModels;
55
using GitHub.ViewModels.GitHubPane;
66
using ReactiveUI;
@@ -18,5 +18,11 @@ public sealed class PullRequestCheckViewModelDesigner : ViewModelBase, IPullRequ
1818
public Uri DetailsUrl { get; set; } = new Uri("http://github.com");
1919

2020
public ReactiveCommand<Unit, Unit> OpenDetailsUrl { get; set; } = null;
21+
22+
public PullRequestCheckType CheckType { get; set; } = PullRequestCheckType.ChecksApi;
23+
24+
public string CheckRunId { get; set; }
25+
26+
public bool HasAnnotations { get; } = true;
2127
}
2228
}

src/GitHub.App/SampleData/PullRequestDetailViewModelDesigner.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Reactive;
1010
using System.Threading.Tasks;
1111
using GitHub.SampleData;
12+
using ReactiveUI.Legacy;
1213

1314
namespace GitHub.SampleData
1415
{
@@ -122,8 +123,10 @@ public PullRequestDetailViewModelDesigner()
122123
public ReactiveCommand<Unit, Unit> Checkout { get; }
123124
public ReactiveCommand<Unit, Unit> Pull { get; }
124125
public ReactiveCommand<Unit, Unit> Push { get; }
126+
public ReactiveCommand<Unit, Unit> SyncSubmodules { get; }
125127
public ReactiveCommand<Unit, Unit> OpenOnGitHub { get; }
126128
public ReactiveCommand<IPullRequestReviewSummaryViewModel, Unit> ShowReview { get; }
129+
public ReactiveCommand<IPullRequestCheckViewModel, Unit> ShowAnnotations { get; }
127130

128131
public IReadOnlyList<IPullRequestCheckViewModel> Checks { get; }
129132

src/GitHub.App/SampleData/PullRequestFilesViewModelDesigner.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ public PullRequestFilesViewModelDesigner()
3636
public ReactiveCommand<IPullRequestFileNode, Unit> DiffFileWithWorkingDirectory { get; }
3737
public ReactiveCommand<IPullRequestFileNode, Unit> OpenFileInWorkingDirectory { get; }
3838
public ReactiveCommand<IPullRequestFileNode, Unit> OpenFirstComment { get; }
39+
public ReactiveCommand<IPullRequestFileNode, Unit> OpenFirstAnnotationNotice { get; }
40+
public ReactiveCommand<IPullRequestFileNode, Unit> OpenFirstAnnotationWarning { get; }
41+
public ReactiveCommand<IPullRequestFileNode, Unit> OpenFirstAnnotationFailure { get; }
3942

4043
public Task InitializeAsync(
4144
IPullRequestSession session,

src/GitHub.App/Services/FromGraphQlExtensions.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using GitHub.Models;
33
using Octokit.GraphQL.Model;
4+
using CheckAnnotationLevel = GitHub.Models.CheckAnnotationLevel;
45
using CheckConclusionState = GitHub.Models.CheckConclusionState;
56
using CheckStatusState = GitHub.Models.CheckStatusState;
67
using PullRequestReviewState = GitHub.Models.PullRequestReviewState;
@@ -84,7 +85,7 @@ public static CheckStatusState FromGraphQl(this Octokit.GraphQL.Model.CheckStatu
8485
}
8586
}
8687

87-
public static GitHub.Models.PullRequestReviewState FromGraphQl(this Octokit.GraphQL.Model.PullRequestReviewState value)
88+
public static PullRequestReviewState FromGraphQl(this Octokit.GraphQL.Model.PullRequestReviewState value)
8889
{
8990
switch (value) {
9091
case Octokit.GraphQL.Model.PullRequestReviewState.Pending:
@@ -101,5 +102,20 @@ public static GitHub.Models.PullRequestReviewState FromGraphQl(this Octokit.Grap
101102
throw new ArgumentOutOfRangeException(nameof(value), value, null);
102103
}
103104
}
105+
106+
public static CheckAnnotationLevel FromGraphQl(this Octokit.GraphQL.Model.CheckAnnotationLevel value)
107+
{
108+
switch (value)
109+
{
110+
case Octokit.GraphQL.Model.CheckAnnotationLevel.Failure:
111+
return CheckAnnotationLevel.Failure;
112+
case Octokit.GraphQL.Model.CheckAnnotationLevel.Notice:
113+
return CheckAnnotationLevel.Notice;
114+
case Octokit.GraphQL.Model.CheckAnnotationLevel.Warning:
115+
return CheckAnnotationLevel.Warning;
116+
default:
117+
throw new ArgumentOutOfRangeException(nameof(value), value, null);
118+
}
119+
}
104120
}
105121
}

src/GitHub.App/Services/PullRequestEditorService.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ await pullRequestService.ExtractToTempFile(
285285
}
286286

287287
/// <inheritdoc/>
288-
public async Task<IDifferenceViewer> OpenDiff(
288+
public Task<IDifferenceViewer> OpenDiff(
289289
IPullRequestSession session,
290290
string relativePath,
291291
IInlineCommentThreadModel thread)
@@ -294,11 +294,17 @@ public async Task<IDifferenceViewer> OpenDiff(
294294
Guard.ArgumentNotEmptyString(relativePath, nameof(relativePath));
295295
Guard.ArgumentNotNull(thread, nameof(thread));
296296

297-
var diffViewer = await OpenDiff(session, relativePath, thread.CommitSha, scrollToFirstDraftOrDiff: false);
297+
return OpenDiff(session, relativePath, thread.CommitSha, thread.LineNumber - 1);
298+
}
299+
300+
/// <inheritdoc/>
301+
public async Task<IDifferenceViewer> OpenDiff(IPullRequestSession session, string relativePath, string headSha, int fromLine)
302+
{
303+
var diffViewer = await OpenDiff(session, relativePath, headSha, scrollToFirstDraftOrDiff: false);
298304

299-
var param = (object)new InlineCommentNavigationParams
305+
var param = (object) new InlineCommentNavigationParams
300306
{
301-
FromLine = thread.LineNumber - 1,
307+
FromLine = fromLine,
302308
};
303309

304310
// HACK: We need to wait here for the inline comment tags to initialize so we can find the next inline comment.

src/GitHub.App/Services/PullRequestService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public async Task<Page<PullRequestListItemModel>> ReadPullRequests(
115115
{
116116
Conclusion = run.Conclusion.FromGraphQl(),
117117
Status = run.Status.FromGraphQl()
118-
}).ToList()
118+
}).ToList(),
119119
}).ToList(),
120120
Statuses = commit.Commit.Status
121121
.Select(context =>

src/GitHub.App/ViewModels/GitHubPane/GitHubPaneViewModel.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public sealed class GitHubPaneViewModel : ViewModelBase, IGitHubPaneViewModel, I
3535
static readonly Regex pullUri = CreateRoute("/:owner/:repo/pull/:number");
3636
static readonly Regex pullNewReviewUri = CreateRoute("/:owner/:repo/pull/:number/review/new");
3737
static readonly Regex pullUserReviewsUri = CreateRoute("/:owner/:repo/pull/:number/reviews/:login");
38+
static readonly Regex pullCheckRunsUri = CreateRoute("/:owner/:repo/pull/:number/checkruns/:id");
3839

3940
readonly IViewViewModelFactory viewModelFactory;
4041
readonly ISimpleApiClientFactory apiClientFactory;
@@ -266,6 +267,15 @@ public async Task NavigateTo(Uri uri)
266267
var login = match.Groups["login"].Value;
267268
await ShowPullRequestReviews(owner, repo, number, login);
268269
}
270+
else if ((match = pullCheckRunsUri.Match(uri.AbsolutePath))?.Success == true)
271+
{
272+
var owner = match.Groups["owner"].Value;
273+
var repo = match.Groups["repo"].Value;
274+
var number = int.Parse(match.Groups["number"].Value);
275+
var id = match.Groups["id"].Value;
276+
277+
await ShowPullRequestCheckRun(owner, repo, number, id);
278+
}
269279
else
270280
{
271281
throw new NotSupportedException("Unrecognised GitHub pane URL: " + uri.AbsolutePath);
@@ -319,6 +329,20 @@ public Task ShowPullRequestReviews(string owner, string repo, int number, string
319329
x.User.Login == login);
320330
}
321331

332+
/// <inheritdoc/>
333+
public Task ShowPullRequestCheckRun(string owner, string repo, int number, string checkRunId)
334+
{
335+
Guard.ArgumentNotNull(owner, nameof(owner));
336+
Guard.ArgumentNotNull(repo, nameof(repo));
337+
338+
return NavigateTo<IPullRequestAnnotationsViewModel>(
339+
x => x.InitializeAsync(LocalRepository, Connection, owner, repo, number, checkRunId),
340+
x => x.RemoteRepositoryOwner == owner &&
341+
x.LocalRepository.Name == repo &&
342+
x.PullRequestNumber == number &&
343+
x.CheckRunId == checkRunId);
344+
}
345+
322346
/// <inheritdoc/>
323347
public Task ShowPullRequestReviewAuthoring(string owner, string repo, int number)
324348
{
@@ -489,8 +513,8 @@ static async Task<bool> IsValidRepository(ISimpleApiClient client)
489513

490514
static Regex CreateRoute(string route)
491515
{
492-
// Build RegEx from route (:foo to named group (?<foo>[\w_.-]+)).
493-
var routeFormat = "^" + new Regex("(:([a-z]+))\\b").Replace(route, @"(?<$2>[\w_.-]+)") + "$";
516+
// Build RegEx from route (:foo to named group (?<foo>[\w_.\-=]+)).
517+
var routeFormat = "^" + new Regex("(:([a-z]+))\\b").Replace(route, @"(?<$2>[\w_.\-=]+)") + "$";
494518
return new Regex(routeFormat, RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
495519
}
496520
}

0 commit comments

Comments
 (0)