/// <summary> /// Generate map diffs for a given <paramref name="pullRequest"/> /// </summary> /// <param name="pullRequest">The <see cref="PullRequest"/></param> /// <param name="installationId">The <see cref="InstallationId.Id"/></param> /// <param name="checkRunId">The <see cref="CheckRun.Id"/></param> /// <param name="changedDmis">Paths to changed .dmm files</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param> /// <returns>A <see cref="Task"/> representing the running operation</returns> async Task GenerateDiffs(PullRequest pullRequest, long installationId, long checkRunId, IReadOnlyList <string> changedDmis, CancellationToken cancellationToken) { using (logger.BeginScope("Generating {0} diffs for pull request #{1} in {2}/{3}", changedDmis.Count, pullRequest.Number, pullRequest.Base.Repository.Owner.Login, pullRequest.Base.Repository.Name)) { var gitHubManager = serviceProvider.GetRequiredService <IGitHubManager>(); var checkRunDequeueUpdate = gitHubManager.UpdateCheckRun(pullRequest.Base.Repository.Id, installationId, checkRunId, new CheckRunUpdate { Status = CheckStatus.InProgress, Output = new CheckRunOutput(stringLocalizer["Generating Diffs"], stringLocalizer["Aww geez rick, I should eventually put some progress message here"], null, null), }, cancellationToken); var results = new List <IconDiff>(); async Task DiffDmi(string path) { async Task <Bitmap> GetImageFor(string commit) { var data = await gitHubManager.GetFileAtCommit(pullRequest.Base.Repository.Id, installationId, path, commit, cancellationToken).ConfigureAwait(false); return(new Bitmap(new MemoryStream(data))); } var beforeTask = GetImageFor(pullRequest.Base.Sha); using (var after = await GetImageFor(pullRequest.Head.Sha).ConfigureAwait(false)) using (var before = await beforeTask.ConfigureAwait(false)) { var diffs = await diffGenerator.GenerateDiffs(before, after, cancellationToken).ConfigureAwait(false); lock (results) { var baseCount = results.Count; results.AddRange(diffs.Select(x => { x.CheckRunId = checkRunId; x.DmiPath = path; x.FileId = ++baseCount; x.RepositoryId = pullRequest.Base.Repository.Id; return(x); })); } } }; await Task.WhenAll(changedDmis.Select(x => DiffDmi(x))).ConfigureAwait(false); await checkRunDequeueUpdate.ConfigureAwait(false); await HandleResults(pullRequest, installationId, checkRunId, results, cancellationToken).ConfigureAwait(false); } }
/// <summary> /// Generate map diffs for a given <paramref name="pullRequest"/> /// </summary> /// <param name="pullRequest">The <see cref="PullRequest"/></param> /// <param name="installationId">The <see cref="InstallationId.Id"/></param> /// <param name="checkRunId">The <see cref="CheckRun.Id"/></param> /// <param name="changedDmis"><see cref="IReadOnlyList{T}"/> of <see cref="PullRequestFile"/>s for changed .dmis</param> /// <param name="scope">The <see cref="IServiceScope"/> for the operation</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param> /// <returns>A <see cref="Task"/> representing the running operation</returns> async Task GenerateDiffs(PullRequest pullRequest, long installationId, long checkRunId, IReadOnlyList <PullRequestFile> changedDmis, IServiceScope scope, CancellationToken cancellationToken) { using (logger.BeginScope("Generating {0} diffs for pull request #{1} in {2}/{3}", changedDmis.Count, pullRequest.Number, pullRequest.Base.Repository.Owner.Login, pullRequest.Base.Repository.Name)) { var gitHubManager = scope.ServiceProvider.GetRequiredService <IGitHubManager>(); var checkRunDequeueUpdate = gitHubManager.UpdateCheckRun(pullRequest.Base.Repository.Id, installationId, checkRunId, new CheckRunUpdate { Status = CheckStatus.InProgress, Output = new NewCheckRunOutput(stringLocalizer["Generating Diffs"], stringLocalizer["Aww geez rick, I should eventually put some progress message here"]), }, cancellationToken); var results = new List <IconDiff>(); int fileIdCounter = 0; var finalImageDictionary = new Dictionary <string, Image>(); async Task DiffDmi(PullRequestFile file) { async Task <MemoryStream> GetImageFor(string commit, bool before) { var data = await gitHubManager.GetFileAtCommit(pullRequest.Base.Repository.Id, installationId, before?(file.PreviousFileName ?? file.FileName) : file.FileName, commit, cancellationToken).ConfigureAwait(false); return(new MemoryStream(data)); } Task <MemoryStream> beforeTask; if (file.Status == "added") { beforeTask = Task.FromResult <MemoryStream>(null); } else { beforeTask = GetImageFor(pullRequest.Base.Sha, true); } Task <MemoryStream> afterTask; if (file.Status == "removed") { afterTask = Task.FromResult <MemoryStream>(null); } else { afterTask = GetImageFor(pullRequest.Head.Sha, false); } using (var after = await afterTask.ConfigureAwait(false)) using (var before = await beforeTask.ConfigureAwait(false)) { List <IconDiff> diffs; try { diffs = diffGenerator.GenerateDiffs(before, after); } catch (Exception e) { //image conversion issue lock (results) results.Add(new IconDiff { DmiPath = file.FileName ?? file.PreviousFileName, CheckRunId = checkRunId, FileId = ++fileIdCounter, RepositoryId = pullRequest.Base.Repository.Id, Error = e.ToString() }); return; } int baseFileId; lock (results) { baseFileId = fileIdCounter; fileIdCounter += diffs.Count; } //populate metadata lock (finalImageDictionary) foreach (var I in diffs) { I.CheckRunId = checkRunId; I.DmiPath = file.FileName ?? file.PreviousFileName; I.RepositoryId = pullRequest.Base.Repository.Id; I.FileId = ++baseFileId; if (I.Before != null) { if (finalImageDictionary.TryGetValue(I.Before.Sha1, out Image cachedImage)) { I.Before = cachedImage; } else { finalImageDictionary.Add(I.Before.Sha1, I.Before); } } if (I.After != null) { if (finalImageDictionary.TryGetValue(I.After.Sha1, out Image cachedImage)) { I.After = cachedImage; } else { finalImageDictionary.Add(I.After.Sha1, I.After); } } } lock (results) results.AddRange(diffs); } }; await Task.WhenAll(changedDmis.Select(x => DiffDmi(x))).ConfigureAwait(false); var databaseContext = scope.ServiceProvider.GetRequiredService <IDatabaseContext>(); //decide whether to attach or add images var keysToSearch = finalImageDictionary.Keys; var dbImages = await databaseContext.Images.Where(x => keysToSearch.Contains(x.Sha1)).Select(x => new Image { Id = x.Id, Sha1 = x.Sha1 }).ToListAsync(cancellationToken).ConfigureAwait(false); foreach (var I in dbImages) { var image = finalImageDictionary[I.Sha1]; image.Id = I.Id; databaseContext.Images.Attach(image); finalImageDictionary.Remove(I.Sha1); } foreach (var I in finalImageDictionary.Select(x => x.Value)) { databaseContext.Images.Add(I); } await checkRunDequeueUpdate.ConfigureAwait(false); await HandleResults(pullRequest, installationId, checkRunId, results, scope, databaseContext, cancellationToken).ConfigureAwait(false); } }
/// <summary> /// Generate map diffs for a given <paramref name="pullRequest"/> /// </summary> /// <param name="pullRequest">The <see cref="PullRequest"/></param> /// <param name="installationId">The <see cref="InstallationId.Id"/></param> /// <param name="checkRunId">The <see cref="CheckRun.Id"/></param> /// <param name="changedDmis">Paths to changed .dmm files</param> /// <param name="scope">The <see cref="IServiceScope"/> for the operation</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation</param> /// <returns>A <see cref="Task"/> representing the running operation</returns> async Task GenerateDiffs(PullRequest pullRequest, long installationId, long checkRunId, IReadOnlyList <string> changedDmis, IServiceScope scope, CancellationToken cancellationToken) { using (logger.BeginScope("Generating {0} diffs for pull request #{1} in {2}/{3}", changedDmis.Count, pullRequest.Number, pullRequest.Base.Repository.Owner.Login, pullRequest.Base.Repository.Name)) { var gitHubManager = scope.ServiceProvider.GetRequiredService <IGitHubManager>(); var checkRunDequeueUpdate = gitHubManager.UpdateCheckRun(pullRequest.Base.Repository.Id, installationId, checkRunId, new CheckRunUpdate { Status = CheckStatus.InProgress, Output = new CheckRunOutput(stringLocalizer["Generating Diffs"], stringLocalizer["Aww geez rick, I should eventually put some progress message here"], null, null, null), }, cancellationToken); var databaseContext = scope.ServiceProvider.GetRequiredService <IDatabaseContext>(); var results = new List <IconDiff>(); int fileIdCounter = 0; async Task DiffDmi(string path) { async Task <MemoryStream> GetImageFor(string commit) { var data = await gitHubManager.GetFileAtCommit(pullRequest.Base.Repository.Id, installationId, path, commit, cancellationToken).ConfigureAwait(false); return(new MemoryStream(data)); } var beforeTask = GetImageFor(pullRequest.Base.Sha); using (var after = await GetImageFor(pullRequest.Head.Sha).ConfigureAwait(false)) using (var before = await beforeTask.ConfigureAwait(false)) { var diffs = diffGenerator.GenerateDiffs(before, after); async Task <IconDiff> CheckDiffImages(IconDiff iconDiff) { IQueryable <Models.Image> query; if (iconDiff.Before == null || iconDiff.After == null) { query = databaseContext.Images.Where(x => x.Sha1 == (iconDiff.Before == null ? iconDiff.After.Sha1 : iconDiff.Before.Sha1)); } else { query = databaseContext.Images.Where(x => x.Sha1 == iconDiff.Before.Sha1 || x.Sha1 == iconDiff.After.Sha1); } var matchingImages = await query.Select(x => new Image { Id = x.Id }).ToListAsync(cancellationToken).ConfigureAwait(false); var beforeQueryResult = matchingImages.FirstOrDefault(x => x.Sha1 == iconDiff.Before?.Sha1); var afterQueryResult = matchingImages.FirstOrDefault(x => x.Sha1 == iconDiff.Before?.Sha1); lock (databaseContext) { if (beforeQueryResult != default(Models.Image)) { databaseContext.Images.Attach((Models.Image)beforeQueryResult); iconDiff.Before = beforeQueryResult; } else if (iconDiff.Before != null) { databaseContext.Images.Add(iconDiff.Before); } if (afterQueryResult != default(Models.Image)) { databaseContext.Images.Attach((Models.Image)afterQueryResult); iconDiff.Before = afterQueryResult; } else if (iconDiff.Before != null) { databaseContext.Images.Add(iconDiff.Before); } } return(iconDiff); }; var tasks = diffs.Select(x => { x.CheckRunId = checkRunId; x.DmiPath = path; lock (results) x.FileId = ++fileIdCounter; x.RepositoryId = pullRequest.Base.Repository.Id; return(CheckDiffImages(x)); }); await Task.WhenAll(tasks).ConfigureAwait(false); lock (results) results.AddRange(tasks.Select(x => x.Result)); } }; await Task.WhenAll(changedDmis.Select(x => DiffDmi(x))).ConfigureAwait(false); await checkRunDequeueUpdate.ConfigureAwait(false); await HandleResults(pullRequest, installationId, checkRunId, results, scope, databaseContext, cancellationToken).ConfigureAwait(false); } }