зеркало из https://github.com/github/VisualStudio.git
Parse diffs to get real line numbers for comments.
The `PullRequestReviewComment.Position` field refers to a line number in the diff between the PR `Head` and `Base`. Generate and parse this diff to get the line number in the file at which the comment should be placed.
This commit is contained in:
Родитель
8393f9d1e7
Коммит
bb6aa7ef28
|
@ -1,5 +1,6 @@
|
|||
<ProjectConfiguration>
|
||||
<Settings>
|
||||
<PreventSigningOfAssembly>True</PreventSigningOfAssembly>
|
||||
<PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
|
||||
</Settings>
|
||||
</ProjectConfiguration>
|
|
@ -6,8 +6,11 @@ namespace GitHub.Models
|
|||
[NullGuard(ValidationFlags.None)]
|
||||
public class PullRequestReviewCommentModel : IPullRequestReviewCommentModel
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Path { get; set; }
|
||||
public int? Position { get; set; }
|
||||
public string CommitId { get; set; }
|
||||
public string DiffHunk { get; set; }
|
||||
public IAccount User { get; set; }
|
||||
public string Body { get; set; }
|
||||
public DateTimeOffset UpdatedAt { get; set; }
|
||||
|
|
|
@ -159,6 +159,35 @@ namespace GitHub.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<Patch> Compare(
|
||||
IRepository repository,
|
||||
string sha1,
|
||||
string sha2,
|
||||
string path)
|
||||
{
|
||||
Guard.ArgumentNotNull(repository, nameof(repository));
|
||||
Guard.ArgumentNotEmptyString(sha1, nameof(sha1));
|
||||
Guard.ArgumentNotEmptyString(sha2, nameof(sha2));
|
||||
|
||||
return Task.Factory.StartNew(() =>
|
||||
{
|
||||
var commit1 = repository.Lookup<Commit>(sha1);
|
||||
var commit2 = repository.Lookup<Commit>(sha2);
|
||||
|
||||
if (commit1 != null && commit2 != null)
|
||||
{
|
||||
return repository.Diff.Compare<Patch>(
|
||||
commit1.Tree,
|
||||
commit2.Tree,
|
||||
new[] { path });
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Task<T> GetConfig<T>(IRepository repository, string key)
|
||||
{
|
||||
Guard.ArgumentNotNull(repository, nameof(repository));
|
||||
|
|
|
@ -407,8 +407,11 @@ namespace GitHub.Services
|
|||
Comments = prCacheItem.Comments.Select(x =>
|
||||
(IPullRequestReviewCommentModel)new PullRequestReviewCommentModel
|
||||
{
|
||||
Id = x.Id,
|
||||
Path = x.Path,
|
||||
Position = x.Position,
|
||||
CommitId = x.CommitId,
|
||||
DiffHunk = x.DiffHunk,
|
||||
User = Create(x.User),
|
||||
Body = x.Body,
|
||||
UpdatedAt = x.UpdatedAt,
|
||||
|
@ -623,15 +626,21 @@ namespace GitHub.Services
|
|||
|
||||
public PullRequestReviewCommentCacheItem(PullRequestReviewComment comment)
|
||||
{
|
||||
Id = comment.Id;
|
||||
Path = comment.Path;
|
||||
Position = comment.Position;
|
||||
CommitId = comment.CommitId;
|
||||
DiffHunk = comment.DiffHunk;
|
||||
User = new AccountCacheItem(comment.User);
|
||||
Body = comment.Body;
|
||||
UpdatedAt = comment.UpdatedAt;
|
||||
}
|
||||
|
||||
public int Id { get; }
|
||||
public string Path { get; set; }
|
||||
public int? Position { get; set; }
|
||||
public string CommitId { get; set; }
|
||||
public string DiffHunk { get; set; }
|
||||
public AccountCacheItem User { get; set; }
|
||||
public string Body { get; set; }
|
||||
public DateTimeOffset UpdatedAt { get; set; }
|
||||
|
|
|
@ -12,37 +12,23 @@ namespace GitHub.Services
|
|||
Dictionary<string, List<IPullRequestReviewCommentModel>> comments;
|
||||
|
||||
public PullRequestReviewSession(
|
||||
ILocalRepositoryModel repository,
|
||||
IEnumerable<IPullRequestReviewCommentModel> comments)
|
||||
IPullRequestModel pullRequest,
|
||||
ILocalRepositoryModel repository)
|
||||
{
|
||||
PullRequest = pullRequest;
|
||||
Repository = repository;
|
||||
this.comments = comments.GroupBy(x => x.Path)
|
||||
this.comments = pullRequest.Comments.GroupBy(x => x.Path)
|
||||
.ToDictionary(x => x.Key, x => x.ToList());
|
||||
}
|
||||
|
||||
public IPullRequestModel PullRequest { get; }
|
||||
public ILocalRepositoryModel Repository { get; }
|
||||
|
||||
public IEnumerable<IPullRequestReviewCommentModel> GetCommentsForFile(string filePath)
|
||||
public IReadOnlyList<IPullRequestReviewCommentModel> GetCommentsForFile(string path)
|
||||
{
|
||||
var relativePath = RootedPathToRelativePath(filePath).Replace('\\', '/');
|
||||
var result = Empty;
|
||||
comments.TryGetValue(relativePath, out result);
|
||||
return result ?? Empty;
|
||||
}
|
||||
|
||||
string RootedPathToRelativePath(string path)
|
||||
{
|
||||
if (Path.IsPathRooted(path))
|
||||
{
|
||||
var repoRoot = Repository.LocalPath;
|
||||
|
||||
if (path.StartsWith(repoRoot) && path.Length > repoRoot.Length + 1)
|
||||
{
|
||||
return path.Substring(repoRoot.Length + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
List<IPullRequestReviewCommentModel> result;
|
||||
path = path.Replace('\\', '/');
|
||||
return comments.TryGetValue(path, out result) ? result : Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -486,7 +486,7 @@ namespace GitHub.ViewModels
|
|||
{
|
||||
if (IsCheckedOut)
|
||||
{
|
||||
var session = new PullRequestReviewSession(repository, Model.Comments);
|
||||
var session = new PullRequestReviewSession(Model, repository);
|
||||
sessionManager.NotifySessionChanged(session);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -68,6 +68,18 @@ namespace GitHub.Services
|
|||
/// </returns>
|
||||
Task<TreeChanges> Compare(IRepository repository, string sha1, string sha2, bool detectRenames = false);
|
||||
|
||||
/// <summary>
|
||||
/// Compares a file in two commits.
|
||||
/// </summary>
|
||||
/// <param name="repository">The repository</param>
|
||||
/// <param name="sha1">The SHA of the first commit.</param>
|
||||
/// <param name="sha2">The SHA of the second commit.</param>
|
||||
/// <param name="path">The relative path to the file.</param>
|
||||
/// <returns>
|
||||
/// A <see cref="Patch"/> object or null if one of the commits or the file could not be found in the repository.
|
||||
/// </returns>
|
||||
Task<Patch> Compare(IRepository repository, string sha1, string sha2, string path);
|
||||
|
||||
/// Gets the value of a configuration key.
|
||||
/// </summary>
|
||||
/// <param name="repository">The repository.</param>
|
||||
|
|
|
@ -4,8 +4,11 @@ namespace GitHub.Models
|
|||
{
|
||||
public interface IPullRequestReviewCommentModel
|
||||
{
|
||||
int Id { get; }
|
||||
string Path { get; }
|
||||
int? Position { get; }
|
||||
string CommitId { get; }
|
||||
string DiffHunk { get; }
|
||||
IAccount User { get; }
|
||||
string Body { get; }
|
||||
DateTimeOffset UpdatedAt { get; }
|
||||
|
|
|
@ -6,6 +6,9 @@ namespace GitHub.Services
|
|||
{
|
||||
public interface IPullRequestReviewSession
|
||||
{
|
||||
IEnumerable<IPullRequestReviewCommentModel> GetCommentsForFile(string filePath);
|
||||
IPullRequestModel PullRequest { get; }
|
||||
ILocalRepositoryModel Repository { get; }
|
||||
|
||||
IReadOnlyList<IPullRequestReviewCommentModel> GetCommentsForFile(string path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\packages\LibGit2Sharp.NativeBinaries.1.0.129\build\LibGit2Sharp.NativeBinaries.props" Condition="Exists('..\..\packages\LibGit2Sharp.NativeBinaries.1.0.129\build\LibGit2Sharp.NativeBinaries.props')" />
|
||||
<Import Project="..\..\packages\Microsoft.VSSDK.BuildTools.14.3.25407\build\Microsoft.VSSDK.BuildTools.props" Condition="Exists('..\..\packages\Microsoft.VSSDK.BuildTools.14.3.25407\build\Microsoft.VSSDK.BuildTools.props')" />
|
||||
<PropertyGroup>
|
||||
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||
|
@ -53,7 +54,11 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\common\SolutionInfo.cs">
|
||||
<Link>Properties\SolutionInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="InlineReviewsPackage.cs" />
|
||||
<Compile Include="Models\InlineCommentModel.cs" />
|
||||
<Compile Include="Peek\ReviewPeekableItem.cs" />
|
||||
<Compile Include="Peek\ReviewPeekableItemSource.cs" />
|
||||
<Compile Include="Peek\ReviewPeekableItemSourceProvider.cs" />
|
||||
|
@ -65,6 +70,8 @@
|
|||
<Compile Include="Peek\ReviewPeekSessionCreationOptions.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SampleData\PullRequestReviewCommentDesigner.cs" />
|
||||
<Compile Include="Services\IInlineCommentBuilder.cs" />
|
||||
<Compile Include="Services\InlineCommentBuilder.cs" />
|
||||
<Compile Include="Tags\ReviewGlyph.xaml.cs">
|
||||
<DependentUpon>ReviewGlyph.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -104,6 +111,10 @@
|
|||
<Project>{9aea02db-02b5-409c-b0ca-115d05331a6b}</Project>
|
||||
<Name>GitHub.Exports</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.Extensions\GitHub.Extensions.csproj">
|
||||
<Project>{6AFE2E2D-6DB0-4430-A2EA-F5F5388D2F78}</Project>
|
||||
<Name>GitHub.Extensions</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.UI\GitHub.UI.csproj">
|
||||
<Project>{346384dd-2445-4a28-af22-b45f3957bd89}</Project>
|
||||
<Name>GitHub.UI</Name>
|
||||
|
@ -126,6 +137,10 @@
|
|||
<Reference Include="EnvDTE90, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||
</Reference>
|
||||
<Reference Include="LibGit2Sharp, Version=0.22.0.0, Culture=neutral, PublicKeyToken=7cbde695407f0333, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\LibGit2Sharp.0.22.0\lib\net40\LibGit2Sharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Build.Framework" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.VisualStudio.CommandBars, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
|
@ -279,14 +294,16 @@
|
|||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != '' And '$(NCrunch)' != '1'" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\packages\Microsoft.VSSDK.BuildTools.14.3.25407\build\Microsoft.VSSDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.VSSDK.BuildTools.14.3.25407\build\Microsoft.VSSDK.BuildTools.props'))" />
|
||||
<Error Condition="!Exists('..\..\packages\Microsoft.VSSDK.BuildTools.14.3.25407\build\Microsoft.VSSDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Microsoft.VSSDK.BuildTools.14.3.25407\build\Microsoft.VSSDK.BuildTools.targets'))" />
|
||||
<Error Condition="!Exists('..\..\packages\LibGit2Sharp.NativeBinaries.1.0.129\build\LibGit2Sharp.NativeBinaries.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\LibGit2Sharp.NativeBinaries.1.0.129\build\LibGit2Sharp.NativeBinaries.props'))" />
|
||||
</Target>
|
||||
<Import Project="..\..\packages\Microsoft.VSSDK.BuildTools.14.3.25407\build\Microsoft.VSSDK.BuildTools.targets" Condition="Exists('..\..\packages\Microsoft.VSSDK.BuildTools.14.3.25407\build\Microsoft.VSSDK.BuildTools.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using GitHub.Models;
|
||||
|
||||
namespace GitHub.InlineReviews.Models
|
||||
{
|
||||
public class InlineCommentModel
|
||||
{
|
||||
public InlineCommentModel(int lineNumber, IPullRequestReviewCommentModel original)
|
||||
{
|
||||
LineNumber = lineNumber;
|
||||
Original = original;
|
||||
}
|
||||
|
||||
public int LineNumber { get; private set; }
|
||||
public IPullRequestReviewCommentModel Original { get; }
|
||||
|
||||
public void UpdatePosition(int editLine, int editDelta)
|
||||
{
|
||||
if (LineNumber >= editLine)
|
||||
{
|
||||
LineNumber += editDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +1,6 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("GitHub.InlineReviews")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("GitHub.InlineReviews")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyDescription("Provides inline viewing of PR review comments")]
|
||||
[assembly: Guid("3bf91177-3d16-425d-9c62-50a86cf26298")]
|
||||
|
|
|
@ -6,8 +6,11 @@ namespace GitHub.InlineReviews.SampleData
|
|||
{
|
||||
public class PullRequestReviewCommentDesigner : IPullRequestReviewCommentModel
|
||||
{
|
||||
public int Id => 1;
|
||||
public string Path => string.Empty;
|
||||
public int? Position => 1;
|
||||
public string CommitId => null;
|
||||
public string DiffHunk => null;
|
||||
public DateTimeOffset UpdatedAt => DateTime.Now.Subtract(TimeSpan.FromDays(3));
|
||||
public IAccount User => new AccountDesigner { Login = "shana", IsUser = true };
|
||||
public string 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).";
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.InlineReviews.Models;
|
||||
using GitHub.Services;
|
||||
|
||||
namespace GitHub.InlineReviews.Services
|
||||
{
|
||||
public interface IInlineCommentBuilder
|
||||
{
|
||||
Task<IList<InlineCommentModel>> Build(
|
||||
string path,
|
||||
IPullRequestReviewSession session);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.Extensions;
|
||||
using GitHub.InlineReviews.Models;
|
||||
using GitHub.Services;
|
||||
using LibGit2Sharp;
|
||||
|
||||
namespace GitHub.InlineReviews.Services
|
||||
{
|
||||
[Export(typeof(IInlineCommentBuilder))]
|
||||
[PartCreationPolicy(CreationPolicy.Shared)]
|
||||
public class InlineCommentBuilder : IInlineCommentBuilder
|
||||
{
|
||||
readonly IGitClient gitClient;
|
||||
|
||||
[ImportingConstructor]
|
||||
public InlineCommentBuilder(IGitClient gitClient)
|
||||
{
|
||||
Guard.ArgumentNotNull(gitClient, nameof(gitClient));
|
||||
|
||||
this.gitClient = gitClient;
|
||||
}
|
||||
|
||||
public async Task<IList<InlineCommentModel>> Build(
|
||||
string path,
|
||||
IPullRequestReviewSession session)
|
||||
{
|
||||
Guard.ArgumentNotNull(path, nameof(path));
|
||||
Guard.ArgumentNotNull(session, nameof(session));
|
||||
|
||||
var result = new List<InlineCommentModel>();
|
||||
var repo = GitService.GitServiceHelper.GetRepository(session.Repository.LocalPath);
|
||||
var changes = await gitClient.Compare(
|
||||
repo,
|
||||
session.PullRequest.Head.Sha,
|
||||
session.PullRequest.Base.Sha,
|
||||
path);
|
||||
var comments = session.GetCommentsForFile(path);
|
||||
var diffPositions = comments
|
||||
.Where(x => x.Position.HasValue)
|
||||
.Select(x => x.Position.Value)
|
||||
.OrderBy(x => x)
|
||||
.Distinct();
|
||||
var lineMap = MapDiffPositions(changes.Content, diffPositions);
|
||||
|
||||
foreach (var comment in comments)
|
||||
{
|
||||
int lineNumber;
|
||||
|
||||
if (comment.Position.HasValue && lineMap.TryGetValue(comment.Position.Value, out lineNumber))
|
||||
{
|
||||
result.Add(new InlineCommentModel(lineNumber, comment));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps lines in a diff to lines in the source file.
|
||||
/// </summary>
|
||||
/// <param name="diff">The diff.</param>
|
||||
/// <param name="positions">The diff lines to map.</param>
|
||||
/// <returns>
|
||||
/// A dictionary mapping 1-based diff line numbers to 0-based file line numbers.
|
||||
/// </returns>
|
||||
public IDictionary<int, int> MapDiffPositions(string diff, IEnumerable<int> positions)
|
||||
{
|
||||
Guard.ArgumentNotNull(diff, nameof(diff));
|
||||
Guard.ArgumentNotNull(positions, nameof(positions));
|
||||
|
||||
var diffLine = -1;
|
||||
var sourceLine = -1;
|
||||
var positionEnumerator = positions.GetEnumerator();
|
||||
var result = new Dictionary<int, int>();
|
||||
|
||||
positionEnumerator.MoveNext();
|
||||
|
||||
using (var reader = new StringReader(diff))
|
||||
{
|
||||
string line;
|
||||
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.StartsWith("@@"))
|
||||
{
|
||||
if (sourceLine == -1) diffLine = 0;
|
||||
sourceLine = ReadLineFromHunkHeader(line) - 1;
|
||||
}
|
||||
|
||||
if (positionEnumerator.Current == diffLine)
|
||||
{
|
||||
result.Add(diffLine, sourceLine);
|
||||
if (!positionEnumerator.MoveNext()) break;
|
||||
}
|
||||
|
||||
if (diffLine >= 0)
|
||||
{
|
||||
++diffLine;
|
||||
if (!line.StartsWith('-')) ++sourceLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int ReadLineFromHunkHeader(string line)
|
||||
{
|
||||
int plus = line.IndexOf('+');
|
||||
int comma = line.IndexOf(',', plus);
|
||||
return int.Parse(line.Substring(plus + 1, comma - (plus + 1)));
|
||||
}
|
||||
|
||||
public class ChunkRange
|
||||
{
|
||||
public int DiffLine { get; set; }
|
||||
public int SourceLine { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,11 @@ using Microsoft.VisualStudio.Text;
|
|||
using Microsoft.VisualStudio.Text.Tagging;
|
||||
using GitHub.Services;
|
||||
using GitHub.Models;
|
||||
using System.IO;
|
||||
using LibGit2Sharp;
|
||||
using GitHub.InlineReviews.Models;
|
||||
using GitHub.InlineReviews.Services;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GitHub.InlineReviews.Tags
|
||||
{
|
||||
|
@ -12,13 +17,19 @@ namespace GitHub.InlineReviews.Tags
|
|||
{
|
||||
readonly ITextBuffer buffer;
|
||||
readonly IPullRequestReviewSessionManager sessionManager;
|
||||
readonly IInlineCommentBuilder builder;
|
||||
readonly IDisposable subscription;
|
||||
List<InlineComment> comments;
|
||||
string path;
|
||||
IList<InlineCommentModel> comments;
|
||||
|
||||
public ReviewTagger(ITextBuffer buffer, IPullRequestReviewSessionManager sessionManager)
|
||||
public ReviewTagger(
|
||||
ITextBuffer buffer,
|
||||
IPullRequestReviewSessionManager sessionManager,
|
||||
IInlineCommentBuilder builder)
|
||||
{
|
||||
this.buffer = buffer;
|
||||
this.sessionManager = sessionManager;
|
||||
this.builder = builder;
|
||||
this.buffer.Changed += Buffer_Changed;
|
||||
subscription = sessionManager.SessionChanged.Subscribe(SessionChanged);
|
||||
}
|
||||
|
@ -40,9 +51,9 @@ namespace GitHub.InlineReviews.Tags
|
|||
var endLine = span.End.GetContainingLine().LineNumber;
|
||||
|
||||
var spanComments = comments.Where(x =>
|
||||
x.Position >= startLine &&
|
||||
x.Position <= endLine)
|
||||
.GroupBy(x => x.Position);
|
||||
x.LineNumber >= startLine &&
|
||||
x.LineNumber <= endLine)
|
||||
.GroupBy(x => x.LineNumber);
|
||||
|
||||
foreach (var entry in spanComments)
|
||||
{
|
||||
|
@ -55,35 +66,37 @@ namespace GitHub.InlineReviews.Tags
|
|||
}
|
||||
}
|
||||
|
||||
void SessionChanged(IPullRequestReviewSession session)
|
||||
static string RootedPathToRelativePath(string path, string basePath)
|
||||
{
|
||||
if (session != null)
|
||||
if (Path.IsPathRooted(path))
|
||||
{
|
||||
var document = buffer.Properties.GetProperty<ITextDocument>(typeof(ITextDocument));
|
||||
comments = CreateInlineComments(session.GetCommentsForFile(document.FilePath));
|
||||
|
||||
var entireFile = new SnapshotSpan(buffer.CurrentSnapshot, 0, buffer.CurrentSnapshot.Length);
|
||||
TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(entireFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
comments = null;
|
||||
}
|
||||
}
|
||||
|
||||
List<InlineComment> CreateInlineComments(IEnumerable<IPullRequestReviewCommentModel> comments)
|
||||
{
|
||||
var result = new List<InlineComment>();
|
||||
|
||||
foreach (var comment in comments)
|
||||
{
|
||||
if (comment.Position.HasValue)
|
||||
if (path.StartsWith(basePath) && path.Length > basePath.Length + 1)
|
||||
{
|
||||
result.Add(new InlineComment(comment));
|
||||
return path.Substring(basePath.Length + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return null;
|
||||
}
|
||||
|
||||
void NotifyTagsChanged()
|
||||
{
|
||||
var entireFile = new SnapshotSpan(buffer.CurrentSnapshot, 0, buffer.CurrentSnapshot.Length);
|
||||
TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(entireFile));
|
||||
}
|
||||
|
||||
async void SessionChanged(IPullRequestReviewSession session)
|
||||
{
|
||||
comments = null;
|
||||
NotifyTagsChanged();
|
||||
|
||||
if (session != null)
|
||||
{
|
||||
var document = buffer.Properties.GetProperty<ITextDocument>(typeof(ITextDocument));
|
||||
path = RootedPathToRelativePath(document.FilePath, session.Repository.LocalPath);
|
||||
comments = await builder.Build(path, session);
|
||||
NotifyTagsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Buffer_Changed(object sender, TextContentChangedEventArgs e)
|
||||
|
@ -101,25 +114,5 @@ namespace GitHub.InlineReviews.Tags
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InlineComment
|
||||
{
|
||||
public InlineComment(IPullRequestReviewCommentModel original)
|
||||
{
|
||||
Position = original.Position.Value - 1;
|
||||
Original = original;
|
||||
}
|
||||
|
||||
public int Position { get; private set; }
|
||||
public IPullRequestReviewCommentModel Original { get; }
|
||||
|
||||
public void UpdatePosition(int editLine, int editDelta)
|
||||
{
|
||||
if (Position >= editLine)
|
||||
{
|
||||
Position += editDelta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using GitHub.InlineReviews.Services;
|
||||
using GitHub.Services;
|
||||
using Microsoft.VisualStudio.Text;
|
||||
using Microsoft.VisualStudio.Text.Tagging;
|
||||
|
@ -13,16 +14,20 @@ namespace GitHub.InlineReviews.Tags
|
|||
class ReviewTaggerProvider : ITaggerProvider
|
||||
{
|
||||
readonly IPullRequestReviewSessionManager sessionManager;
|
||||
readonly IInlineCommentBuilder builder;
|
||||
|
||||
[ImportingConstructor]
|
||||
public ReviewTaggerProvider(IPullRequestReviewSessionManager sessionManager)
|
||||
public ReviewTaggerProvider(
|
||||
IPullRequestReviewSessionManager sessionManager,
|
||||
IInlineCommentBuilder builder)
|
||||
{
|
||||
this.sessionManager = sessionManager;
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
|
||||
{
|
||||
return new ReviewTagger(buffer, sessionManager) as ITagger<T>;
|
||||
return new ReviewTagger(buffer, sessionManager, builder) as ITagger<T>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="LibGit2Sharp" version="0.22.0" targetFramework="net461" />
|
||||
<package id="LibGit2Sharp.NativeBinaries" version="1.0.129" targetFramework="net461" />
|
||||
<package id="Microsoft.VisualStudio.CoreUtility" version="14.3.25407" targetFramework="net461" />
|
||||
<package id="Microsoft.VisualStudio.Imaging" version="14.3.25407" targetFramework="net452" />
|
||||
<package id="Microsoft.VisualStudio.Language.Intellisense" version="14.3.25407" targetFramework="net461" />
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using GitHub.InlineReviews.Services;
|
||||
using GitHub.Services;
|
||||
using NSubstitute;
|
||||
using UnitTests.Properties;
|
||||
using Xunit;
|
||||
|
||||
namespace UnitTests.GitHub.InlineReviews
|
||||
{
|
||||
public class InlineCommentBuilderTests
|
||||
{
|
||||
[Fact]
|
||||
public void CorrectlyMapsCommentPositions()
|
||||
{
|
||||
var target = new InlineCommentBuilder(Substitute.For<IGitClient>());
|
||||
var diff = Resources.pr_573_apiclient_diff;
|
||||
var result = target.MapDiffPositions(diff, new[] { 31 });
|
||||
|
||||
Assert.Equal(87, result[31]);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace UnitTests.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("UnitTests.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to diff --git a/src/GitHub.App/Api/ApiClient.cs b/src/GitHub.App/Api/ApiClient.cs
|
||||
///index 6745236..79adcf3 100644
|
||||
///--- a/src/GitHub.App/Api/ApiClient.cs
|
||||
///+++ b/src/GitHub.App/Api/ApiClient.cs
|
||||
///@@ -8,6 +8,7 @@
|
||||
/// using System.Security.Cryptography;
|
||||
/// using System.Text;
|
||||
/// using GitHub.Primitives;
|
||||
///+using NLog;
|
||||
/// using NullGuard;
|
||||
/// using Octokit;
|
||||
/// using Octokit.Reactive;
|
||||
///@@ -18,8 +19,6 @@
|
||||
/// using System.Collections.Generic;
|
||||
/// using GitHub.Models;
|
||||
/// using GitHub.Extensions;
|
||||
///-using GitHub.Infrastructure;
|
||||
///-using S [rest of string was truncated]";.
|
||||
/// </summary>
|
||||
internal static string pr_573_apiclient_diff {
|
||||
get {
|
||||
return ResourceManager.GetString("pr_573_apiclient_diff", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="pr_573_apiclient_diff" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\pr-573-apiclient-diff.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
|
||||
</data>
|
||||
</root>
|
|
@ -0,0 +1,74 @@
|
|||
diff --git a/src/GitHub.App/Api/ApiClient.cs b/src/GitHub.App/Api/ApiClient.cs
|
||||
index 6745236..79adcf3 100644
|
||||
--- a/src/GitHub.App/Api/ApiClient.cs
|
||||
+++ b/src/GitHub.App/Api/ApiClient.cs
|
||||
@@ -8,6 +8,7 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using GitHub.Primitives;
|
||||
+using NLog;
|
||||
using NullGuard;
|
||||
using Octokit;
|
||||
using Octokit.Reactive;
|
||||
@@ -18,8 +19,6 @@
|
||||
using System.Collections.Generic;
|
||||
using GitHub.Models;
|
||||
using GitHub.Extensions;
|
||||
-using GitHub.Infrastructure;
|
||||
-using Serilog;
|
||||
|
||||
namespace GitHub.Api
|
||||
{
|
||||
@@ -27,7 +26,7 @@ public partial class ApiClient : IApiClient
|
||||
{
|
||||
const string ScopesHeader = "X-OAuth-Scopes";
|
||||
const string ProductName = Info.ApplicationInfo.ApplicationDescription;
|
||||
- static readonly ILogger log = LogManager.ForContext<ApiClient>();
|
||||
+ static readonly Logger log = LogManager.GetCurrentClassLogger();
|
||||
static readonly Uri userEndpoint = new Uri("user", UriKind.Relative);
|
||||
|
||||
readonly IObservableGitHubClient gitHubClient;
|
||||
@@ -85,7 +84,7 @@ public IObservable<UserAndScopes> GetUser()
|
||||
}
|
||||
else
|
||||
{
|
||||
- log.Error("Error reading scopes: /user succeeded but {ScopesHeader} was not present.", ScopesHeader);
|
||||
+ log.Error($"Error reading scopes: /user succeeded but {ScopesHeader} was not present.");
|
||||
}
|
||||
|
||||
return new UserAndScopes(response.Body, scopes);
|
||||
@@ -176,7 +175,7 @@ static string GetSha256Hash(string input)
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
- log.Error(e, "IMPOSSIBLE! Generating Sha256 hash caused an exception.");
|
||||
+ log.Error("IMPOSSIBLE! Generating Sha256 hash caused an exception.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -194,14 +193,14 @@ static string GetMachineNameSafe()
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
- log.Information(e, "Failed to retrieve host name using `DNS.GetHostName`.");
|
||||
+ log.Info("Failed to retrieve host name using `DNS.GetHostName`.", e);
|
||||
try
|
||||
{
|
||||
return Environment.MachineName;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
- log.Information(ex, "Failed to retrieve host name using `Environment.MachineName`.");
|
||||
+ log.Info("Failed to retrieve host name using `Environment.MachineName`.", ex);
|
||||
return "(unknown)";
|
||||
}
|
||||
}
|
||||
@@ -222,7 +221,7 @@ static string GetMachineIdentifier()
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
- log.Information(e, "Could not retrieve MAC address. Fallback to using machine name.");
|
||||
+ log.Info("Could not retrieve MAC address. Fallback to using machine name.", e);
|
||||
return GetMachineNameSafe();
|
||||
}
|
||||
}
|
|
@ -246,6 +246,7 @@
|
|||
<Compile Include="GitHub.Exports\LocalRepositoryModelTests.cs" />
|
||||
<Compile Include="GitHub.Extensions\GuardTests.cs" />
|
||||
<Compile Include="GitHub.Extensions\UriExtensionTests.cs" />
|
||||
<Compile Include="GitHub.InlineReviews\InlineCommentBuilderTests.cs" />
|
||||
<Compile Include="GitHub.Primitives\UriStringTests.cs" />
|
||||
<Compile Include="GitHub.UI\Converters.cs" />
|
||||
<Compile Include="GitHub.UI\TestAutomation\ResourceValueTests.cs" />
|
||||
|
@ -260,6 +261,11 @@
|
|||
<Compile Include="Helpers\TestBaseClass.cs" />
|
||||
<Compile Include="Helpers\TestLoginCache.cs" />
|
||||
<Compile Include="Helpers\TestSharedCache.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Substitutes.cs" />
|
||||
<Compile Include="TestDoubles\FakeCommitLog.cs" />
|
||||
<Compile Include="TestDoubles\FakeMenuCommandService.cs" />
|
||||
|
@ -333,6 +339,10 @@
|
|||
<Project>{6afe2e2d-6db0-4430-a2ea-f5f5388d2f78}</Project>
|
||||
<Name>GitHub.Extensions</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.InlineReviews\GitHub.InlineReviews.csproj">
|
||||
<Project>{7f5ed78b-74a3-4406-a299-70cfb5885b8b}</Project>
|
||||
<Name>GitHub.InlineReviews</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.TeamFoundation.14\GitHub.TeamFoundation.14.csproj">
|
||||
<Project>{161DBF01-1DBF-4B00-8551-C5C00F26720D}</Project>
|
||||
<Name>GitHub.TeamFoundation.14</Name>
|
||||
|
@ -363,6 +373,13 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="FodyWeavers.xml" />
|
||||
<None Include="Resources\pr-573-apiclient-diff.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
|
|
Загрузка…
Ссылка в новой задаче