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

Adding indications for protected branches #2029

Merged
merged 12 commits into from
Dec 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace GitHub.SampleData
{
public sealed class PullRequestCheckViewModelDesigner : ViewModelBase, IPullRequestCheckViewModel
{
public bool IsRequired { get; } = true;

public string Title { get; set; } = "continuous-integration/appveyor/pr";

public string Description { get; set; } = "AppVeyor build failed";
Expand Down
47 changes: 44 additions & 3 deletions src/GitHub.App/Services/RepositoryService.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading.Tasks;
using GitHub.Api;
using GitHub.Extensions;
using GitHub.Models;
using GitHub.Primitives;
using Octokit.GraphQL;
using static Octokit.GraphQL.Variable;
Expand All @@ -12,9 +14,10 @@ namespace GitHub.Services
{
[Export(typeof(IRepositoryService))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class RepositoryService : IRepositoryService
public class RepositoryService: IRepositoryService
{
static ICompiledQuery<Tuple<string, string>> readParentOwnerLogin;
static ICompiledQuery<List<ProtectedBranch>> queryProtectedBranches;
readonly IGraphQLClientFactory graphqlFactory;

[ImportingConstructor]
Expand Down Expand Up @@ -45,9 +48,47 @@ public RepositoryService(IGraphQLClientFactory graphqlFactory)
{ nameof(name), name },
};

var graphql = await graphqlFactory.CreateConnection(address);
var result = await graphql.Run(readParentOwnerLogin, vars);
var graphql = await graphqlFactory.CreateConnection(address).ConfigureAwait(false);
var result = await graphql.Run(readParentOwnerLogin, vars).ConfigureAwait(false);
return result != null ? (result.Item1, result.Item2) : ((string, string)?)null;
}

public async Task<IList<ProtectedBranch>> GetProtectedBranches(HostAddress address, string owner, string name)
{
Guard.ArgumentNotNull(address, nameof(address));
Guard.ArgumentNotEmptyString(owner, nameof(owner));
Guard.ArgumentNotEmptyString(name, nameof(name));

if (queryProtectedBranches == null)
{
queryProtectedBranches = new Query()
.Repository(Var(nameof(name)), Var(nameof(owner)))
.Select(r =>
r.ProtectedBranches(null, null, null, null)
.AllPages()
.Select(branch => new ProtectedBranch
{
Name = branch.Name,
RequiredStatusCheckContexts = branch.RequiredStatusCheckContexts.ToArray()
}).ToList()
).Compile();
}

var vars = new Dictionary<string, object>
{
{ nameof(owner), owner },
{ nameof(name), name },
};

var graphql = await graphqlFactory.CreateConnection(address).ConfigureAwait(false);
return await graphql.Run(queryProtectedBranches, vars).ConfigureAwait(false);
}

public async Task<ProtectedBranch> GetProtectedBranch(HostAddress address, string owner, string name, string branchName)
{
Guard.ArgumentNotNull(branchName, nameof(branchName));
var protectedBranches = await GetProtectedBranches(address, owner, name).ConfigureAwait(false);
return protectedBranches.FirstOrDefault(branch => branch.Name.Equals(branchName, StringComparison.InvariantCultureIgnoreCase));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static IEnumerable<IPullRequestCheckViewModel> Build(IViewViewModelFactor

var pullRequestCheckViewModel = (PullRequestCheckViewModel) viewViewModelFactory.CreateViewModel<IPullRequestCheckViewModel>();
pullRequestCheckViewModel.CheckType = PullRequestCheckType.StatusApi;
pullRequestCheckViewModel.IsRequired = statusModel.IsRequired;
pullRequestCheckViewModel.Title = statusModel.Context;
pullRequestCheckViewModel.Description = statusModel.Description;
pullRequestCheckViewModel.Status = checkStatus;
Expand Down Expand Up @@ -102,6 +103,7 @@ public static IEnumerable<IPullRequestCheckViewModel> Build(IViewViewModelFactor

var pullRequestCheckViewModel = (PullRequestCheckViewModel)viewViewModelFactory.CreateViewModel<IPullRequestCheckViewModel>();
pullRequestCheckViewModel.CheckType = PullRequestCheckType.ChecksApi;
pullRequestCheckViewModel.IsRequired = arg.checkRun.IsRequired;
pullRequestCheckViewModel.CheckRunId = arg.checkRun.Id;
pullRequestCheckViewModel.HasAnnotations = arg.checkRun.Annotations?.Any() ?? false;
pullRequestCheckViewModel.Title = arg.checkRun.Name;
Expand Down Expand Up @@ -147,6 +149,9 @@ private void DoOpenDetailsUrl()
usageTracker.IncrementCounter(expression).Forget();
}

/// <inheritdoc/>
public bool IsRequired { get; private set; }

/// <inheritdoc/>
public string Title { get; private set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace GitHub.ViewModels.GitHubPane
/// </summary>
public interface IPullRequestCheckViewModel: IViewModel
{
bool IsRequired { get; }

/// <summary>
/// The title of the Status/Check.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/GitHub.Exports/Models/CheckRunModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ public class CheckRunModel
/// </summary>
public string Summary { get; set; }

/// <summary>
/// The flag that denotes if this check is required for the pull request.
/// </summary>
public bool IsRequired { get; set; }

/// <summary>
/// The detail of a Check Run.
/// </summary>
Expand Down
10 changes: 10 additions & 0 deletions src/GitHub.Exports/Models/IPullRequestModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ public enum PullRequestChecksState
Failure
}

public enum PullRequestChecksSummaryState
{
None,
Pending,
Success,
SuccessWithFailure,
SuccessWithPending,
Failure
}

public interface IPullRequestModel : ICopyable<IPullRequestModel>,
IEquatable<IPullRequestModel>, IComparable<IPullRequestModel>
{
Expand Down
8 changes: 8 additions & 0 deletions src/GitHub.Exports/Models/ProtectedBranch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace GitHub.Models
{
public class ProtectedBranch
{
public string Name { get; set; }
public string[] RequiredStatusCheckContexts { get; set; }
}
}
2 changes: 2 additions & 0 deletions src/GitHub.Exports/Models/StatusModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ public class StatusModel
/// The descritption for the Status
/// </summary>
public string Description { get; set; }

public bool IsRequired { get; set; }
}
}
6 changes: 6 additions & 0 deletions src/GitHub.Exports/Services/IRepositoryService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using GitHub.Models;
using GitHub.Primitives;

namespace GitHub.Services
Expand All @@ -17,5 +19,9 @@ public interface IRepositoryService
/// otherwise null.
/// </returns>
Task<(string owner, string name)?> FindParent(HostAddress address, string owner, string name);

Task<IList<ProtectedBranch>> GetProtectedBranches(HostAddress address, string owner, string name);

Task<ProtectedBranch> GetProtectedBranch(HostAddress address, string owner, string name, string branchName);
}
}
30 changes: 26 additions & 4 deletions src/GitHub.InlineReviews/Services/PullRequestSessionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class PullRequestSessionService : IPullRequestSessionService
readonly IDiffService diffService;
readonly IApiClientFactory apiClientFactory;
readonly IGraphQLClientFactory graphqlFactory;
readonly IRepositoryService repositoryService;
readonly IUsageTracker usageTracker;
readonly IDictionary<Tuple<string, string>, string> mergeBaseCache;

Expand All @@ -59,13 +60,15 @@ public PullRequestSessionService(
IDiffService diffService,
IApiClientFactory apiClientFactory,
IGraphQLClientFactory graphqlFactory,
IRepositoryService repositoryService,
IUsageTracker usageTracker)
{
this.gitService = gitService;
this.gitClient = gitClient;
this.diffService = diffService;
this.apiClientFactory = apiClientFactory;
this.graphqlFactory = graphqlFactory;
this.repositoryService = repositoryService;
this.usageTracker = usageTracker;

mergeBaseCache = new Dictionary<Tuple<string, string>, string>();
Expand Down Expand Up @@ -360,9 +363,12 @@ public virtual async Task<PullRequestDetailModel> ReadPullRequestDetail(HostAddr
var connection = await graphqlFactory.CreateConnection(address);
var result = await connection.Run(readPullRequest, vars);

var protectedBranches = await repositoryService.GetProtectedBranch(address, owner, name, result.BaseRefName);
var protectedContexts = protectedBranches != null ? new HashSet<string>(protectedBranches.RequiredStatusCheckContexts) : null;

var apiClient = await apiClientFactory.Create(address);
var files = await apiClient.GetPullRequestFiles(owner, name, number).ToList();
var lastCommitModel = await GetPullRequestLastCommitAdapter(address, owner, name, number);
var lastCommitModel = await GetPullRequestLastCommitAdapter(address, owner, name, number, protectedContexts);

result.Statuses = (IReadOnlyList<StatusModel>) lastCommitModel.Statuses ?? Array.Empty<StatusModel>();

Expand Down Expand Up @@ -773,7 +779,8 @@ Task<IRepository> GetRepository(LocalRepositoryModel repository)
return Task.Factory.StartNew(() => gitService.GetRepository(repository.LocalPath));
}

async Task<LastCommitAdapter> GetPullRequestLastCommitAdapter(HostAddress address, string owner, string name, int number)
async Task<LastCommitAdapter> GetPullRequestLastCommitAdapter(HostAddress address, string owner, string name,
int number, HashSet<string> protectedContexts)
{
ICompiledQuery<IEnumerable<LastCommitAdapter>> query;
if (address.IsGitHubDotCom())
Expand Down Expand Up @@ -867,8 +874,23 @@ async Task<LastCommitAdapter> GetPullRequestLastCommitAdapter(HostAddress addres
};

var connection = await graphqlFactory.CreateConnection(address);
var result = await connection.Run(query, vars);
return result.First();
var results = await connection.Run(query, vars);
var result = results.First();

foreach (var resultCheckSuite in result.CheckSuites)
{
foreach (var checkRunModel in resultCheckSuite.CheckRuns)
{
checkRunModel.IsRequired = protectedContexts?.Contains(checkRunModel.Name) ?? false;
}
}

foreach (var resultStatus in result.Statuses)
{
resultStatus.IsRequired = protectedContexts?.Contains(resultStatus.Context) ?? false;
}

return result;
}

static void BuildPullRequestThreads(PullRequestDetailModel model)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
<TextBlock TextTrimming="CharacterEllipsis" Text="{Binding Description}" ToolTip="{Binding DurationStatus}"/>
</Label>

<StackPanel Grid.Column="3" Grid.Row="0" HorizontalAlignment="Right" Orientation="Horizontal">
<Label Visibility="{Binding IsRequired, Converter={ghfvs:BooleanToVisibilityConverter}}">
Required
</Label>
</StackPanel>

<Label Grid.Column="2" Grid.Row="1" HorizontalContentAlignment="Stretch" Visibility="{Binding HasAnnotations, Converter={ghfvs:BooleanToVisibilityConverter}}">
<Hyperlink ToolTip="View checks"
Command="{Binding Path=DataContext.ShowAnnotations, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type local:PullRequestDetailView}}}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ static PullRequestSessionService CreateTarget(IDiffService diffService)
diffService,
Substitute.For<IApiClientFactory>(),
Substitute.For<IGraphQLClientFactory>(),
Substitute.For<IRepositoryService>(),
Substitute.For<IUsageTracker>());
}

Expand Down