Exemple #1
0
        /// <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);
            }
        }
Exemple #2
0
        /// <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);
            }
        }