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

Commit 0c2a3df

Browse files
Merge pull request #2142 from github/fixes/1469-indent-heuristic
Update to use modern version of LibGit2Sharp and use indent heuristic when diffing
2 parents 298af46 + f14b646 commit 0c2a3df

File tree

24 files changed

+410
-272
lines changed

24 files changed

+410
-272
lines changed

src/GitHub.App/GitHub.App.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@
4242
</ItemGroup>
4343

4444
<ItemGroup>
45-
<PackageReference Include="LibGit2Sharp" Version="0.23.1" />
46-
<PackageReference Include="LibGit2Sharp.NativeBinaries" Version="1.0.164" />
45+
<PackageReference Include="LibGit2Sharp" Version="0.26.0" />
4746
<PackageReference Include="Madskristensen.VisualStudio.SDK" Version="14.3.75-pre" />
4847
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.1" />
4948
<PackageReference Include="Microsoft.VisualStudio.StaticReviews.Embeddable" Version="0.1.14-alpha" />

src/GitHub.App/SampleData/GitServiceDesigner.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,8 @@ class GitServiceDesigner : IGitService
1515
public IRepository GetRepository(string path) => null;
1616
public UriString GetUri(string path, string remote = "origin") => null;
1717
public UriString GetUri(IRepository repository, string remote = "origin") => null;
18+
public Task<Patch> Compare(IRepository repository, string sha1, string sha2, string path) => null;
19+
public Task<ContentChanges> CompareWith(IRepository repository, string sha1, string sha2, string path, byte[] contents) => null;
20+
public Task<TreeChanges> Compare(IRepository repository, string sha1, string sha2, bool detectRenames = false) => null;
1821
}
1922
}

src/GitHub.App/Services/GitClient.cs

Lines changed: 42 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ namespace GitHub.Services
1717
[PartCreationPolicy(CreationPolicy.Shared)]
1818
public class GitClient : IGitClient
1919
{
20-
const string defaultOriginName = "origin";
2120
static readonly ILogger log = LogManager.ForContext<GitClient>();
2221
readonly IGitService gitService;
2322
readonly PullOptions pullOptions;
@@ -44,12 +43,17 @@ public GitClient(IGitHubCredentialProvider credentialProvider, IGitService gitSe
4443
public Task Pull(IRepository repository)
4544
{
4645
Guard.ArgumentNotNull(repository, nameof(repository));
47-
return Task.Factory.StartNew(() =>
46+
return Task.Run(() =>
4847
{
4948
var signature = repository.Config.BuildSignature(DateTimeOffset.UtcNow);
50-
#pragma warning disable 0618 // TODO: Replace `Network.Pull` with `Commands.Pull`.
51-
repository.Network.Pull(signature, pullOptions);
52-
#pragma warning restore 0618
49+
if (repository is Repository repo)
50+
{
51+
LibGit2Sharp.Commands.Pull(repo, signature, pullOptions);
52+
}
53+
else
54+
{
55+
log.Error("Couldn't pull because {Variable} isn't an instance of {Type}", nameof(repository), typeof(Repository));
56+
}
5357
});
5458
}
5559

@@ -59,7 +63,7 @@ public Task Push(IRepository repository, string branchName, string remoteName)
5963
Guard.ArgumentNotEmptyString(branchName, nameof(branchName));
6064
Guard.ArgumentNotEmptyString(remoteName, nameof(remoteName));
6165

62-
return Task.Factory.StartNew(() =>
66+
return Task.Run(() =>
6367
{
6468
if (repository.Head?.Commits != null && repository.Head.Commits.Any())
6569
{
@@ -75,14 +79,11 @@ public Task Fetch(IRepository repository, string remoteName)
7579
Guard.ArgumentNotNull(repository, nameof(repository));
7680
Guard.ArgumentNotEmptyString(remoteName, nameof(remoteName));
7781

78-
return Task.Factory.StartNew(() =>
82+
return Task.Run(() =>
7983
{
8084
try
8185
{
82-
var remote = repository.Network.Remotes[remoteName];
83-
#pragma warning disable 0618 // TODO: Replace `Network.Fetch` with `Commands.Fetch`.
84-
repository.Network.Fetch(remote, fetchOptions);
85-
#pragma warning restore 0618
86+
repository.Network.Fetch(remoteName, new[] { "+refs/heads/*:refs/remotes/origin/*" }, fetchOptions);
8687
}
8788
catch (Exception ex)
8889
{
@@ -104,7 +105,7 @@ public Task Fetch(IRepository repo, UriString cloneUrl, params string[] refspecs
104105
}
105106
}
106107

107-
return Task.Factory.StartNew(() =>
108+
return Task.Run(() =>
108109
{
109110
try
110111
{
@@ -114,17 +115,15 @@ public Task Fetch(IRepository repo, UriString cloneUrl, params string[] refspecs
114115
var removeRemote = false;
115116
if (repo.Network.Remotes[remoteName] != null)
116117
{
117-
// If a remote with this neme already exists, use a unique name and remove remote afterwards
118+
// If a remote with this name already exists, use a unique name and remove remote afterwards
118119
remoteName = cloneUrl.Owner + "-" + Guid.NewGuid();
119120
removeRemote = true;
120121
}
121122

122-
var remote = repo.Network.Remotes.Add(remoteName, remoteUri.ToString());
123+
repo.Network.Remotes.Add(remoteName, remoteUri.ToString());
123124
try
124125
{
125-
#pragma warning disable 0618 // TODO: Replace `Network.Fetch` with `Commands.Fetch`.
126-
repo.Network.Fetch(remote, refspecs, fetchOptions);
127-
#pragma warning restore 0618
126+
repo.Network.Fetch(remoteName, refspecs, fetchOptions);
128127
}
129128
finally
130129
{
@@ -149,14 +148,11 @@ public Task Fetch(IRepository repository, string remoteName, params string[] ref
149148
Guard.ArgumentNotNull(repository, nameof(repository));
150149
Guard.ArgumentNotEmptyString(remoteName, nameof(remoteName));
151150

152-
return Task.Factory.StartNew(() =>
151+
return Task.Run(() =>
153152
{
154153
try
155154
{
156-
var remote = repository.Network.Remotes[remoteName];
157-
#pragma warning disable 0618 // TODO: Replace `Network.Fetch` with `Commands.Fetch`.
158-
repository.Network.Fetch(remote, refspecs, fetchOptions);
159-
#pragma warning restore 0618
155+
repository.Network.Fetch(remoteName, refspecs, fetchOptions);
160156
}
161157
catch (Exception ex)
162158
{
@@ -173,117 +169,32 @@ public Task Checkout(IRepository repository, string branchName)
173169
Guard.ArgumentNotNull(repository, nameof(repository));
174170
Guard.ArgumentNotEmptyString(branchName, nameof(branchName));
175171

176-
return Task.Factory.StartNew(() =>
177-
{
178-
#pragma warning disable 0618 // TODO: Replace `IRepository.Checkout` with `Commands.Checkout`.
179-
repository.Checkout(branchName);
180-
#pragma warning restore 0618
181-
});
182-
}
183-
184-
public async Task<bool> CommitExists(IRepository repository, string sha)
185-
{
186-
return await Task.Run(() => repository.Lookup<Commit>(sha) != null).ConfigureAwait(false);
187-
}
188-
189-
public Task CreateBranch(IRepository repository, string branchName)
190-
{
191-
Guard.ArgumentNotNull(repository, nameof(repository));
192-
Guard.ArgumentNotEmptyString(branchName, nameof(branchName));
193-
194-
return Task.Factory.StartNew(() =>
195-
{
196-
repository.CreateBranch(branchName);
197-
});
198-
}
199-
200-
public Task<TreeChanges> Compare(
201-
IRepository repository,
202-
string sha1,
203-
string sha2,
204-
bool detectRenames)
205-
{
206-
Guard.ArgumentNotNull(repository, nameof(repository));
207-
Guard.ArgumentNotEmptyString(sha1, nameof(sha1));
208-
Guard.ArgumentNotEmptyString(sha2, nameof(sha2));
209-
210-
return Task.Factory.StartNew(() =>
172+
return Task.Run(() =>
211173
{
212-
var options = new CompareOptions
174+
if (repository is Repository repo)
213175
{
214-
Similarity = detectRenames ? SimilarityOptions.Renames : SimilarityOptions.None
215-
};
216-
217-
var commit1 = repository.Lookup<Commit>(sha1);
218-
var commit2 = repository.Lookup<Commit>(sha2);
219-
220-
if (commit1 != null && commit2 != null)
221-
{
222-
return repository.Diff.Compare<TreeChanges>(commit1.Tree, commit2.Tree, options);
176+
LibGit2Sharp.Commands.Checkout(repo, branchName);
223177
}
224178
else
225179
{
226-
return null;
180+
log.Error("Couldn't checkout because {Variable} isn't an instance of {Type}", nameof(repository), typeof(Repository));
227181
}
228182
});
229183
}
230184

231-
public Task<Patch> Compare(
232-
IRepository repository,
233-
string sha1,
234-
string sha2,
235-
string path)
185+
public async Task<bool> CommitExists(IRepository repository, string sha)
236186
{
237-
Guard.ArgumentNotNull(repository, nameof(repository));
238-
Guard.ArgumentNotEmptyString(sha1, nameof(sha1));
239-
Guard.ArgumentNotEmptyString(sha2, nameof(sha2));
240-
Guard.ArgumentNotEmptyString(path, nameof(path));
241-
242-
return Task.Factory.StartNew(() =>
243-
{
244-
var commit1 = repository.Lookup<Commit>(sha1);
245-
var commit2 = repository.Lookup<Commit>(sha2);
246-
247-
if (commit1 != null && commit2 != null)
248-
{
249-
return repository.Diff.Compare<Patch>(
250-
commit1.Tree,
251-
commit2.Tree,
252-
new[] { path });
253-
}
254-
else
255-
{
256-
return null;
257-
}
258-
});
187+
return await Task.Run(() => repository.Lookup<Commit>(sha) != null).ConfigureAwait(false);
259188
}
260189

261-
public Task<ContentChanges> CompareWith(IRepository repository, string sha1, string sha2, string path, byte[] contents)
190+
public Task CreateBranch(IRepository repository, string branchName)
262191
{
263192
Guard.ArgumentNotNull(repository, nameof(repository));
264-
Guard.ArgumentNotEmptyString(sha1, nameof(sha1));
265-
Guard.ArgumentNotEmptyString(sha2, nameof(sha1));
266-
Guard.ArgumentNotEmptyString(path, nameof(path));
193+
Guard.ArgumentNotEmptyString(branchName, nameof(branchName));
267194

268-
return Task.Factory.StartNew(() =>
195+
return Task.Run(() =>
269196
{
270-
var commit1 = repository.Lookup<Commit>(sha1);
271-
var commit2 = repository.Lookup<Commit>(sha2);
272-
273-
var treeChanges = repository.Diff.Compare<TreeChanges>(commit1.Tree, commit2.Tree);
274-
var normalizedPath = path.Replace("/", "\\");
275-
var renamed = treeChanges.FirstOrDefault(x => x.Path == normalizedPath);
276-
var oldPath = renamed?.OldPath ?? path;
277-
278-
if (commit1 != null)
279-
{
280-
var contentStream = contents != null ? new MemoryStream(contents) : new MemoryStream();
281-
var blob1 = commit1[oldPath]?.Target as Blob ?? repository.ObjectDatabase.CreateBlob(new MemoryStream());
282-
var blob2 = repository.ObjectDatabase.CreateBlob(contentStream, path);
283-
return repository.Diff.Compare(blob1, blob2);
284-
}
285-
286-
return null;
197+
repository.CreateBranch(branchName);
287198
});
288199
}
289200

@@ -292,7 +203,7 @@ public Task<T> GetConfig<T>(IRepository repository, string key)
292203
Guard.ArgumentNotNull(repository, nameof(repository));
293204
Guard.ArgumentNotEmptyString(key, nameof(key));
294205

295-
return Task.Factory.StartNew(() =>
206+
return Task.Run(() =>
296207
{
297208
var result = repository.Config.Get<T>(key);
298209
return result != null ? result.Value : default(T);
@@ -305,7 +216,7 @@ public Task SetConfig(IRepository repository, string key, string value)
305216
Guard.ArgumentNotEmptyString(key, nameof(key));
306217
Guard.ArgumentNotEmptyString(value, nameof(value));
307218

308-
return Task.Factory.StartNew(() =>
219+
return Task.Run(() =>
309220
{
310221
repository.Config.Set(key, value);
311222
});
@@ -316,7 +227,7 @@ public Task SetRemote(IRepository repository, string remoteName, Uri url)
316227
Guard.ArgumentNotNull(repository, nameof(repository));
317228
Guard.ArgumentNotEmptyString(remoteName, nameof(remoteName));
318229

319-
return Task.Factory.StartNew(() =>
230+
return Task.Run(() =>
320231
{
321232
repository.Config.Set("remote." + remoteName + ".url", url.ToString());
322233
repository.Config.Set("remote." + remoteName + ".fetch", "+refs/heads/*:refs/remotes/" + remoteName + "/*");
@@ -329,7 +240,7 @@ public Task SetTrackingBranch(IRepository repository, string branchName, string
329240
Guard.ArgumentNotEmptyString(branchName, nameof(branchName));
330241
Guard.ArgumentNotEmptyString(remoteName, nameof(remoteName));
331242

332-
return Task.Factory.StartNew(() =>
243+
return Task.Run(() =>
333244
{
334245
var remoteBranchName = IsCanonical(remoteName) ? remoteName : "refs/remotes/" + remoteName + "/" + branchName;
335246
var remoteBranch = repository.Branches[remoteBranchName];
@@ -347,7 +258,7 @@ public Task UnsetConfig(IRepository repository, string key)
347258
{
348259
Guard.ArgumentNotEmptyString(key, nameof(key));
349260

350-
return Task.Factory.StartNew(() =>
261+
return Task.Run(() =>
351262
{
352263
repository.Config.Unset(key);
353264
});
@@ -358,7 +269,7 @@ public Task<Remote> GetHttpRemote(IRepository repo, string remote)
358269
Guard.ArgumentNotNull(repo, nameof(repo));
359270
Guard.ArgumentNotEmptyString(remote, nameof(remote));
360271

361-
return Task.Factory.StartNew(() =>
272+
return Task.Run(() =>
362273
{
363274
var uri = gitService.GetRemoteUri(repo, remote);
364275
var remoteName = uri.IsHypertextTransferProtocol ? remote : remote + "-http";
@@ -373,9 +284,9 @@ public Task<string> ExtractFile(IRepository repository, string commitSha, string
373284
{
374285
Guard.ArgumentNotNull(repository, nameof(repository));
375286
Guard.ArgumentNotEmptyString(commitSha, nameof(commitSha));
376-
Guard.ArgumentNotEmptyString(fileName, nameof(fileName));
287+
Guard.ArgumentIsGitPath(fileName, nameof(fileName));
377288

378-
return Task.Factory.StartNew(() =>
289+
return Task.Run(() =>
379290
{
380291
var commit = repository.Lookup<Commit>(commitSha);
381292
if (commit == null)
@@ -392,9 +303,9 @@ public Task<byte[]> ExtractFileBinary(IRepository repository, string commitSha,
392303
{
393304
Guard.ArgumentNotNull(repository, nameof(repository));
394305
Guard.ArgumentNotEmptyString(commitSha, nameof(commitSha));
395-
Guard.ArgumentNotEmptyString(fileName, nameof(fileName));
306+
Guard.ArgumentIsGitPath(fileName, nameof(fileName));
396307

397-
return Task.Factory.StartNew(() =>
308+
return Task.Run(() =>
398309
{
399310
var commit = repository.Lookup<Commit>(commitSha);
400311
if (commit == null)
@@ -421,9 +332,9 @@ public Task<byte[]> ExtractFileBinary(IRepository repository, string commitSha,
421332
public Task<bool> IsModified(IRepository repository, string path, byte[] contents)
422333
{
423334
Guard.ArgumentNotNull(repository, nameof(repository));
424-
Guard.ArgumentNotEmptyString(path, nameof(path));
335+
Guard.ArgumentIsGitPath(path, nameof(path));
425336

426-
return Task.Factory.StartNew(() =>
337+
return Task.Run(() =>
427338
{
428339
if (repository.RetrieveStatus(path) == FileStatus.Unaltered)
429340
{
@@ -491,7 +402,7 @@ public Task<bool> IsHeadPushed(IRepository repo)
491402
{
492403
Guard.ArgumentNotNull(repo, nameof(repo));
493404

494-
return Task.Factory.StartNew(() =>
405+
return Task.Run(() =>
495406
{
496407
return repo.Head.TrackingDetails.AheadBy == 0;
497408
});
@@ -503,7 +414,7 @@ public Task<IReadOnlyList<CommitMessage>> GetMessagesForUniqueCommits(
503414
string compareBranch,
504415
int maxCommits)
505416
{
506-
return Task.Factory.StartNew(() =>
417+
return Task.Run(() =>
507418
{
508419
var baseCommit = repo.Lookup<Commit>(baseBranch);
509420
var compareCommit = repo.Lookup<Commit>(compareBranch);

src/GitHub.App/Services/GitHubContextService.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,10 @@ public string FindObjectishForTFSTempFile(string tempFile)
406406
/// <inheritdoc/>
407407
public bool HasChangesInWorkingDirectory(string repositoryDir, string commitish, string path)
408408
{
409+
Guard.ArgumentNotNull(path, nameof(repositoryDir));
410+
Guard.ArgumentNotNull(path, nameof(commitish));
411+
Guard.ArgumentIsGitPath(path, nameof(path));
412+
409413
using (var repo = gitService.GetRepository(repositoryDir))
410414
{
411415
var commit = repo.Lookup<Commit>(commitish);

0 commit comments

Comments
 (0)