Exemple #1
0
        public async Task FilesWithoutExt_ShowFullPathInSummary()
        {
            // Arrange
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake.cs", 2);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake2", 4);
            gitRepoHelpers.CommitFilesToRepo();
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake.cs", 5);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake2", 2);
            var quantifierInput = new QuantifierInput();

            quantifierInput.Changes.AddRange(gitEngine.GetGitChanges(gitRepoHelpers.RepoPath));
            var quantifyClient = new QuantifyClient(string.Empty);

            // Act
            var quantifierResult = await quantifyClient.Compute(quantifierInput);

            var comment = await quantifierResult.ToMarkdownCommentAsync(
                RepositoryLink,
                ContextFileLink,
                PullRequestLink,
                AuthorName);

            // Assert
            Assert.True(comment.IndexOf("fake2 : +0 -2", StringComparison.Ordinal) > -1);
            Assert.True(comment.IndexOf(".cs : +3 -0", StringComparison.Ordinal) > -1);
        }
Exemple #2
0
        public async Task ToMarkdownCommentAsync_Successful()
        {
            // Arrange
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake.cs", 2);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake2.cs", 4);
            gitRepoHelpers.CommitFilesToRepo();
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake.cs", 5);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake2.cs", 2);
            var quantifierInput = new QuantifierInput();

            quantifierInput.Changes.AddRange(gitEngine.GetGitChanges(gitRepoHelpers.RepoPath));
            var quantifyClient = new QuantifyClient(string.Empty);

            // Act
            var quantifierResult = await quantifyClient.Compute(quantifierInput);

            var comment = await quantifierResult.ToMarkdownCommentAsync(
                RepositoryLink,
                ContextFileLink,
                PullRequestLink,
                AuthorName);

            // Assert
            Assert.True(!string.IsNullOrWhiteSpace(comment));
            Assert.StartsWith("### Pull Request Quantified", comment);
        }
Exemple #3
0
        public async Task QuantifyClient_AgainstCommit()
        {
            // Arrange
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake.cs", 2);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake2.cs", 4);
            gitRepoHelpers.CommitFilesToRepo();
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake3.cs", 5);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake4.cs", 2);
            var commit = gitRepoHelpers.CommitFilesToRepo();

            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake6.cs", 3);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake5.cs", 6);
            gitRepoHelpers.CommitFilesToRepo();
            var quantifyClient = new QuantifyClient(string.Empty);

            // Act
            var quantifierResult = await quantifyClient.Compute(
                gitRepoHelpers.RepoPath,
                commit.Sha);

            // Assert
            Assert.True(!string.IsNullOrEmpty(quantifierResult.Label));
            Assert.Equal(7, quantifierResult.QuantifiedLinesAdded);
            Assert.Equal(0, quantifierResult.QuantifiedLinesDeleted);
            Assert.Equal(2, (int)quantifierResult.PercentileAddition);
            Assert.Equal(0, quantifierResult.PercentileDeletion);
            Assert.Equal(2, (int)quantifierResult.FormulaPercentile);
        }
        private async Task <QuantifierResult> QuantifyPullRequest(PullRequestEventPayload payload)
        {
            var gitHubClientAdapter =
                await gitHubClientAdapterFactory.GetGitHubClientAdapterAsync(
                    payload.Installation.Id,
                    new Uri(payload.PullRequest.HtmlUrl).DnsSafeHost);

            var quantifierInput = await GetQuantifierInputFromPullRequest(payload, gitHubClientAdapter);

            var context = await GetContextFromRepoIfPresent(payload, gitHubClientAdapter);

            var quantifyClient         = new QuantifyClient(context);
            var quantifierClientResult = await quantifyClient.Compute(quantifierInput);

            await ApplyLabelToPullRequest(
                payload,
                gitHubClientAdapter,
                quantifierClientResult,
                quantifyClient.Context.Thresholds.Select(t => t.Label));

            var quantifierContextLink = !string.IsNullOrWhiteSpace(context)
                ? $"{payload.Repository.HtmlUrl}/blob/{payload.Repository.DefaultBranch}/prquantifier.yaml"
                : string.Empty;

            await UpdateCommentOnPullRequest(
                payload,
                gitHubClientAdapter,
                quantifierClientResult,
                quantifierContextLink);

            return(quantifierClientResult);
        }
Exemple #5
0
        public async Task QuantifyClient_AgainstCommitNotFound()
        {
            var quantifyClient = new QuantifyClient(string.Empty);

            // Act
            var quantifierResult = await quantifyClient.Compute(
                gitRepoHelpers.RepoPath,
                nameof(string.Empty));

            // Assert
            Assert.Equal("No Changes", quantifierResult.Label);
            Assert.Equal(0, quantifierResult.QuantifiedLinesAdded);
            Assert.Equal(0, quantifierResult.QuantifiedLinesDeleted);
            Assert.Equal(0, quantifierResult.PercentileAddition);
            Assert.Equal(0, quantifierResult.PercentileDeletion);
            Assert.Equal(0, quantifierResult.FormulaPercentile);
        }
Exemple #6
0
        private static async Task Quantify(
            IEnumerable <Organization> organizations,
            string clonePath)
        {
            var repositories = organizations.Select(o =>
                                                    o.Projects.Select(p =>
                                                                      p.Repositories.Select(r => new
            {
                Organization = o.Name,
                Project      = p.Name,
                Repository   = r.Name
            })))
                               .SelectMany(a => a)
                               .SelectMany(a => a);

            var gitEngine      = new GitEngine();
            var quantifyClient = new QuantifyClient(string.Empty);

            foreach (var repository in repositories)
            {
                var saveResultsToDatabase = new Dictionary <string, QuantifierResult>();

                var repoPath    = Path.Combine(clonePath, repository.Repository);
                var commitsSha1 = gitEngine.GetAllCommits(repoPath).Select(c => c.Sha).ToArray();
                Console.WriteLine($"Total commits to evaluate : {commitsSha1.Length}. Repo name {repository.Repository}.");

                foreach (var commitSha1 in commitsSha1)
                {
                    try
                    {
                        var quantifierResult = await quantifyClient.Compute(repoPath, commitSha1);

                        saveResultsToDatabase[commitSha1] = quantifierResult;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                }

                await SaveToCsv(
                    saveResultsToDatabase,
                    Path.Combine(clonePath, $"{repository.Repository}_QuantifierResults.csv"));
            }
        }
Exemple #7
0
        public async Task ToMarkdownCommentAsync_Options_CollapseChangesSummarySection(
            bool collapseChangesSummarySection)
        {
            // Arrange
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake.cs", 2);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake2.cs", 4);
            gitRepoHelpers.CommitFilesToRepo();
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake.cs", 5);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake2.cs", 2);
            var quantifierInput = new QuantifierInput();

            quantifierInput.Changes.AddRange(gitEngine.GetGitChanges(gitRepoHelpers.RepoPath));
            var quantifyClient = new QuantifyClient(string.Empty);

            // Act
            var quantifierResult = await quantifyClient.Compute(quantifierInput);

            var comment = await quantifierResult.ToMarkdownCommentAsync(
                RepositoryLink,
                ContextFileLink,
                PullRequestLink,
                AuthorName,
                new MarkdownCommentOptions
            {
                CollapseChangesSummarySection = collapseChangesSummarySection
            });

            // Assert
            Assert.True(!string.IsNullOrWhiteSpace(comment));
            Assert.StartsWith("### Pull Request Quantified", comment);
            if (collapseChangesSummarySection)
            {
                Assert.True(comment.IndexOf(
                                await File.ReadAllTextAsync(@"Data/AssertCommentSummaryCollapsed.txt"),
                                StringComparison.Ordinal) > -1);
            }
            else
            {
                Assert.True(comment.IndexOf(
                                await File.ReadAllTextAsync(@"Data/AssertCommentSummaryNotCollapsed.txt"),
                                StringComparison.Ordinal) > -1);
            }
        }
Exemple #8
0
        public async Task ToMarkdownCommentAsync_Successful()
        {
            // Arrange
            var quantifierInput = new QuantifierInput();

            quantifierInput.Changes.AddRange(gitEngine.GetGitChanges(gitRepoHelpers.RepoPath));
            var quantifyClient = new QuantifyClient(string.Empty);

            // Act
            var quantifierResult = await quantifyClient.Compute(quantifierInput);

            var comment = await quantifierResult.ToMarkdownCommentAsync(
                RepositoryLink,
                ContextFileLink,
                PullRequestLink,
                AuthorName);

            // Assert
            Assert.True(!string.IsNullOrWhiteSpace(comment));
            Assert.StartsWith("### ![](https://img.shields.io/static/v1?label=Quantified&message=Extra%20Small&color=green)", comment);
        }
Exemple #9
0
        public async Task ToMarkdownCommentAsync_Options_CollapseQuantificationDetailsSection(bool collapseQuantifiedDetailsSection)
        {
            // Arrange
            var quantifierInput = new QuantifierInput();

            quantifierInput.Changes.AddRange(gitEngine.GetGitChanges(gitRepoHelpers.RepoPath));
            var quantifyClient = new QuantifyClient(string.Empty);

            // Act
            var quantifierResult = await quantifyClient.Compute(quantifierInput);

            var comment = await quantifierResult.ToMarkdownCommentAsync(
                RepositoryLink,
                ContextFileLink,
                PullRequestLink,
                AuthorName,
                false,
                new MarkdownCommentOptions
            {
                CollapsePullRequestQuantifiedSection = collapseQuantifiedDetailsSection
            });

            // Assert
            Assert.True(!string.IsNullOrWhiteSpace(comment));
            Assert.StartsWith("### ![](https://img.shields.io/static/v1?label=Quantified&message=Extra%20Small&color=green)", comment);
            if (collapseQuantifiedDetailsSection)
            {
                Assert.True(
                    comment.IndexOf(
                        await File.ReadAllTextAsync(@"Data/AssertCommentSummaryCollapsed.txt"),
                        StringComparison.Ordinal) > -1);
            }
            else
            {
                Assert.True(
                    comment.IndexOf(
                        await File.ReadAllTextAsync(@"Data/AssertCommentSummaryNotCollapsed.txt"),
                        StringComparison.Ordinal) > -1);
            }
        }
        public async Task ToMarkdownCommentAsync_IdealSizeCheck(int formulaLinesChanged, bool isIdeal)
        {
            // Arrange
            var quantifierInput = new QuantifierInput();

            quantifierInput.Changes.AddRange(gitEngine.GetGitChanges(gitRepoHelpers.RepoPath));
            var quantifyClient   = new QuantifyClient(string.Empty);
            var quantifierResult = await quantifyClient.Compute(quantifierInput);

            quantifierResult.FormulaLinesChanged = formulaLinesChanged;

            var comment = await quantifierResult.ToMarkdownCommentAsync(
                RepositoryLink,
                ContextFileLink,
                PullRequestLink,
                AuthorName);

            // Assert
            var idealJobIndex = comment.IndexOf("Great job", StringComparison.Ordinal);

            Assert.True((isIdeal && idealJobIndex > -1) || (!isIdeal && idealJobIndex == -1));
        }
Exemple #11
0
        public async Task QuantifyClient_MissingFormulaPercentileContext()
        {
            // Arrange
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake.cs", 2);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake2.cs", 4);
            gitRepoHelpers.CommitFilesToRepo();
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake.cs", 5);
            gitRepoHelpers.AddUntrackedFileToRepoWithNumLines("fake2.cs", 2);
            var quantifierInput = new QuantifierInput();

            quantifierInput.Changes.AddRange(gitEngine.GetGitChanges(gitRepoHelpers.RepoPath));
            var quantifyClient = new QuantifyClient(@"Data/MissingFormulaPercentileContext.prquantifier.yaml");

            // Act
            var quantifierResult = await quantifyClient.Compute(quantifierInput);

            // Assert
            Assert.True(!string.IsNullOrEmpty(quantifierResult.Label));
            Assert.Equal(3, quantifierResult.QuantifiedLinesAdded);
            Assert.Equal(2, quantifierResult.QuantifiedLinesDeleted);
            Assert.Equal(0, quantifierResult.PercentileAddition);
            Assert.Equal(0, quantifierResult.PercentileDeletion);
            Assert.Equal(0, quantifierResult.FormulaPercentile);
        }
        private static async Task RunQuantifier(
            QuantifyClient quantifyClient,
            string resultFile,
            string repoPath)
        {
            var repoRoot = LibGit2Sharp.Repository.Discover(repoPath);

            if (repoRoot == null)
            {
                Console.WriteLine($"No repo found at {repoPath}");
                return;
            }

            using var repo = new LibGit2Sharp.Repository(repoRoot);
            var commits = repo.Commits.QueryBy(
                new CommitFilter
            {
                FirstParentOnly = true
            });

            Console.WriteLine($"Total commits to evaluate : {commits.Count()}. Repository path {repoPath}.");
            var sw = new Stopwatch();

            sw.Reset();
            sw.Start();
            var batchSize         = 100;
            var quantifierResults = new ConcurrentDictionary <string, QuantifierResult>();

            for (int page = 0; page < (commits.Count() / batchSize) + 1; page++)
            {
                var commitBatch   = commits.Skip(batchSize * page).Take(batchSize);
                var quantifyTasks = commitBatch.Select(
                    async commit =>
                {
                    try
                    {
                        var quantifierInput = new QuantifierInput();
                        var firstParent     = commit.Parents.FirstOrDefault();
                        if (firstParent != null)
                        {
                            var patch = repo.Diff.Compare <Patch>(firstParent.Tree, commit.Tree);

                            foreach (var gitFilePatch in patch.GetGitFilePatch())
                            {
                                quantifierInput.Changes.Add(gitFilePatch);
                            }
                        }

                        var quantifierResult = await quantifyClient.Compute(quantifierInput);
                        quantifierResults.TryAdd(commit.Sha, quantifierResult);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                    }
                });
                await Task.WhenAll(quantifyTasks);
                await AddResultsToFile(quantifierResults, resultFile);

                quantifierResults = new ConcurrentDictionary <string, QuantifierResult>();
                Console.WriteLine($"{page * batchSize}/{commits.Count()} {sw.Elapsed}");
            }

            Console.WriteLine("Completed!");
        }
        private async Task <QuantifierResult> QuantifyPullRequest(PullRequestEventPayload payload)
        {
            var gitHubClientAdapter =
                await gitHubClientAdapterFactory.GetGitHubClientAdapterAsync(
                    payload.Installation.Id,
                    new Uri(payload.PullRequest.HtmlUrl).DnsSafeHost);

            // get pull request
            var pullRequest = await gitHubClientAdapter.GetPullRequestAsync(
                payload.Repository.Id,
                payload.PullRequest.Number);

            // get pull request files
            var pullRequestFiles = await gitHubClientAdapter.GetPullRequestFilesAsync(
                payload.Repository.Id,
                payload.PullRequest.Number);

            // convert to quantifier input
            var quantifierInput = new QuantifierInput();

            foreach (var pullRequestFile in pullRequestFiles)
            {
                if (pullRequestFile.Patch == null)
                {
                    continue;
                }

                var changeType = GitChangeType.Modified;
                switch (pullRequestFile.Status)
                {
                case "modified":
                    break;

                case "added":
                    changeType = GitChangeType.Added;
                    break;

                case "deleted":
                    changeType = GitChangeType.Deleted;
                    break;
                }

                var fileExtension = !string.IsNullOrWhiteSpace(pullRequestFile.FileName)
                    ? new FileInfo(pullRequestFile.FileName).Extension
                    : string.Empty;
                var gitFilePatch = new GitFilePatch(
                    pullRequestFile.FileName,
                    fileExtension)
                {
                    ChangeType           = changeType,
                    AbsoluteLinesAdded   = pullRequestFile.Additions,
                    AbsoluteLinesDeleted = pullRequestFile.Deletions,
                    DiffContent          = pullRequestFile.Patch,
                };
                quantifierInput.Changes.Add(gitFilePatch);
            }

            // get context if present
            string context = null;

            try
            {
                var rawContext = await gitHubClientAdapter.GetRawFileAsync(
                    payload.Repository.Owner.Login,
                    payload.Repository.Name,
                    "/prquantifier.yaml");

                context = Encoding.UTF8.GetString(rawContext);
            }
            catch (NotFoundException)
            {
            }
            catch
            {
                // ignored
            }

            var quantifyClient         = new QuantifyClient(context);
            var quantifierClientResult = await quantifyClient.Compute(quantifierInput);

            // create a new label in the repository if doesn't exist
            try
            {
                var existingLabel = await gitHubClientAdapter.GetLabelAsync(
                    payload.Repository.Id,
                    quantifierClientResult.Label);
            }
            catch (NotFoundException)
            {
                // create new label
                var color = Color.FromName(quantifierClientResult.Color);
                await gitHubClientAdapter.CreateLabelAsync(
                    payload.Repository.Id,
                    new NewLabel(quantifierClientResult.Label, ConvertToHex(color)));
            }

            // apply label to pull request
            await gitHubClientAdapter.ApplyLabelAsync(
                payload.Repository.Id,
                payload.PullRequest.Number,
                new[] { quantifierClientResult.Label });

            // create a comment on the issue
            var defaultBranch         = payload.Repository.DefaultBranch;
            var quantifierContextLink = $"{payload.Repository.HtmlUrl}/blob/{defaultBranch}/prquantifier.yaml";
            var comment = await quantifierClientResult.ToMarkdownCommentAsync(
                payload.Repository.HtmlUrl,
                quantifierContextLink,
                payload.PullRequest.HtmlUrl,
                payload.PullRequest.User.Login);

            await gitHubClientAdapter.CreateIssueCommentAsync(
                payload.Repository.Id,
                payload.PullRequest.Number,
                comment);

            return(quantifierClientResult);
        }