Example #1
0
        private bool CheckLinesContent(IRepository repository, IScmData scmData, string testRevision, ProjectFile file, bool resultOnly)
        {
            IBlame fileBlame = null;
            try
            {
                fileBlame = scmData.Blame(testRevision, file.Path);
            }
            catch
            {
            }
            if (fileBlame == null)
            {
                if (! resultOnly)
                {
                    Console.WriteLine("File {0} does not exist.", file.Path);
                }
                return false;
            }

            double currentLOC = repository.SelectionDSL()
                    .Commits().TillRevision(testRevision)
                    .Files().IdIs(file.ID)
                    .Modifications().InCommits().InFiles()
                    .CodeBlocks().InModifications()
                    .CalculateLOC();

            bool correct = currentLOC == fileBlame.Count;

            if (! correct)
            {
                if (! resultOnly)
                {
                    Console.WriteLine("Incorrect number of lines in file {0}. {1} should be {2}",
                        file.Path, currentLOC, fileBlame.Count
                    );
                }
                else
                {
                    return false;
                }
            }

            SmartDictionary<string, int> linesByRevision = new SmartDictionary<string, int>(x => 0);
            foreach (var line in fileBlame)
            {
                linesByRevision[line.Value]++;
            }

            var codeBySourceRevision =
            (
                from f in repository.Queryable<ProjectFile>()
                join m in repository.Queryable<Modification>() on f.ID equals m.FileID
                join cb in repository.Queryable<CodeBlock>() on m.ID equals cb.ModificationID
                join c in repository.Queryable<Commit>() on m.CommitID equals c.ID
                let addedCodeBlock = repository.Queryable<CodeBlock>()
                    .Single(x => x.ID == (cb.Size < 0 ? cb.TargetCodeBlockID : cb.ID))
                let codeAddedInitiallyInRevision = repository.Queryable<Commit>()
                    .Single(x => x.ID == addedCodeBlock.AddedInitiallyInCommitID)
                    .Revision
                let testRevisionNumber = repository.Queryable<Commit>()
                    .Single(x => x.Revision == testRevision)
                    .OrderedNumber
                where
                    f.ID == file.ID
                    &&
                    c.OrderedNumber <= testRevisionNumber
                group cb.Size by codeAddedInitiallyInRevision into g
                select new
                {
                    FromRevision = g.Key,
                    CodeSize = g.Sum()
                }
            ).Where(x => x.CodeSize != 0).ToList();

            var errorCode =
                (
                    from codeFromRevision in codeBySourceRevision
                    where
                        codeFromRevision.CodeSize != linesByRevision[codeFromRevision.FromRevision]
                    select new
                    {
                        SourceRevision = codeFromRevision.FromRevision,
                        CodeSize = codeFromRevision.CodeSize,
                        RealCodeSize = linesByRevision[codeFromRevision.FromRevision]
                    }
                ).ToList();

            correct =
                correct
                &&
                codeBySourceRevision.Count() == linesByRevision.Count
                &&
                errorCode.Count == 0;

            if (! resultOnly)
            {
                if (codeBySourceRevision.Count() != linesByRevision.Count)
                {
                    Console.WriteLine("Number of revisions file {0} contains code from is incorrect. {1} should be {2}",
                        file.Path, codeBySourceRevision.Count(), linesByRevision.Count
                    );
                }
                foreach (var error in errorCode)
                {
                    Console.WriteLine("Incorrect number of lines in file {0} from revision {1}. {2} should be {3}",
                        file.Path,
                        error.SourceRevision,
                        error.CodeSize,
                        error.RealCodeSize
                    );
                }
                if ((! correct) && (errorCode.Count > 0))
                {
                    string latestCodeRevision = repository.LastRevision(errorCode.Select(x => x.SourceRevision));

                    var commitsFileTouchedIn = repository.SelectionDSL()
                        .Files().IdIs(file.ID)
                        .Commits().FromRevision(latestCodeRevision).TouchFiles()
                        .OrderBy(c => c.OrderedNumber);

                    foreach (var commit in commitsFileTouchedIn)
                    {
                        if (!CheckLinesContent(repository, scmData, commit.Revision, file, true))
                        {
                            Console.WriteLine("{0} - incorrectly mapped commit.", commit.Revision);
                            if ((automaticallyFixDiffErrors) && (errorCode.Sum(x => x.CodeSize - x.RealCodeSize) == 0))
                            {
                                var incorrectDeleteCodeBlocks =
                                    from cb in repository.SelectionDSL()
                                        .Commits().RevisionIs(commit.Revision)
                                        .Files().PathIs(file.Path)
                                        .Modifications().InCommits().InFiles()
                                        .CodeBlocks().InModifications().Deleted()
                                    join tcb in repository.Queryable<CodeBlock>() on cb.TargetCodeBlockID equals tcb.ID
                                    join m in repository.Queryable<Modification>() on tcb.ModificationID equals m.ID
                                    join c in repository.Queryable<Commit>() on m.CommitID equals c.ID
                                    where
                                        errorCode.Select(x => x.SourceRevision).Contains(c.Revision)
                                    select new
                                    {
                                        Code = cb,
                                        TargetRevision = c.Revision
                                    };

                                foreach (var error in errorCode)
                                {
                                    var incorrectDeleteCodeBlock = incorrectDeleteCodeBlocks.SingleOrDefault(x => x.TargetRevision == error.SourceRevision);
                                    var codeBlock = incorrectDeleteCodeBlock == null ? null : incorrectDeleteCodeBlock.Code;
                                    double difference = error.CodeSize - error.RealCodeSize;
                                    if (codeBlock == null)
                                    {
                                        codeBlock = new CodeBlock()
                                        {
                                            Size = 0,
                                            Modification = repository.SelectionDSL()
                                                .Commits().RevisionIs(commit.Revision)
                                                .Files().PathIs(file.Path)
                                                .Modifications().InCommits().InFiles().Single(),
                                        };
                                        repository.Add(codeBlock);
                                    }
                                    Console.WriteLine("Fix code block size for file {0} in revision {1}:", file.Path, commit.Revision);
                                    Console.Write("Was {0}", codeBlock.Size);
                                    codeBlock.Size -= difference;
                                    if (codeBlock.Size == 0)
                                    {
                                        repository.Delete(codeBlock);
                                    }
                                    else if ((codeBlock.Size > 0) && (codeBlock.AddedInitiallyInCommitID == null))
                                    {
                                        codeBlock.AddedInitiallyInCommit = commit;
                                    }
                                    else if ((codeBlock.Size < 0) && (codeBlock.TargetCodeBlockID == null))
                                    {
                                        codeBlock.TargetCodeBlock = repository.SelectionDSL()
                                            .Commits().RevisionIs(error.SourceRevision)
                                            .Files().PathIs(file.Path)
                                            .Modifications().InFiles()
                                            .CodeBlocks().InModifications().AddedInitiallyInCommits().Single();
                                    }
                                    Console.WriteLine(", now {0}", codeBlock.Size);
                                }
                            }
                            break;
                        }
                    }
                }
            }

            return correct;
        }
        public override IDictionary<string, object> BuildData(IRepository repository)
        {
            Dictionary<string,object> result = new Dictionary<string,object>();

            double totalLoc = repository.SelectionDSL()
                .Files().InDirectory(TargetDir)
                .Modifications().InFiles()
                .CodeBlocks().InModifications().CalculateLOC();

            List<object> releaseObjects = new List<object>();

            var releases = repository.AllReleases();
            releases.Add(repository.LastRevision(), "upcoming");

            DateTime statFrom = repository.Queryable<Commit>().Min(x => x.Date);

            string prevRelease = null;
            foreach (var release in releases)
            {
                var releaseCommits = repository.SelectionDSL()
                    .Commits()
                        .AfterRevision(prevRelease)
                        .TillRevision(release.Key)
                    .Fixed();
                var releaseCode = releaseCommits
                    .Files()
                        .InDirectory(TargetDir)
                    .Modifications()
                        .InCommits()
                        .InFiles()
                    .CodeBlocks()
                        .InModifications()
                    .Fixed();
                var totalReleaseCommits = repository.SelectionDSL()
                    .Commits()
                        .TillRevision(release.Key)
                    .Fixed();
                var totalReleaseCode = totalReleaseCommits
                    .Files()
                        .InDirectory(TargetDir)
                    .Modifications()
                        .InCommits()
                        .InFiles()
                    .CodeBlocks()
                        .InModifications()
                    .Fixed();

                DateTime releaseStatFrom = releaseCommits.Min(x => x.Date);
                DateTime releaseStatTo = releaseCommits.Max(x => x.Date);

                int releaseCommitsCount = releaseCommits.Count();
                int releaseAuthorsCount = releaseCommits.Select(c => c.Author).Distinct().Count();
                int releaseFixesCount = releaseCommits.AreBugFixes().Count();
                int releaseFilesCount = repository.SelectionDSL()
                    .Files().ExistInRevision(release.Key).Count();
                int releaseTouchedFilesCount = releaseCommits
                    .Files()
                        .ExistInRevision(release.Key)
                        .TouchedInCommits()
                    .Count();
                int releaseDefectiveFilesCount = releaseCode
                    .DefectiveFiles(prevRelease, null)
                        .ExistInRevision(release.Key)
                    .Count();
                int totalReleaseCommitsCount = totalReleaseCommits.Count();
                int totalReleaseAuthorsCount = totalReleaseCommits.Select(c => c.Author).Distinct().Count();
                int totalReleaseFixesCount = totalReleaseCommits.AreBugFixes().Count();

                var totalReleaseLoc = totalReleaseCode.CalculateLOC();
                var releaseRemainLoc = releaseCode.Added().CalculateLOC() + releaseCode.ModifiedBy().CalculateLOC();
                var totalReleaseAddedLoc = totalReleaseCode.Added().CalculateLOC();
                var releaseAddedLoc = releaseCode.Added().CalculateLOC();

                double releaseDD = releaseCode.CalculateDefectDensity();
                double totalReleaseDD = totalReleaseCode.CalculateDefectDensity();
                double postReleaseDD = releaseDD - releaseCode.CalculateDefectDensity(release.Key);

                releaseObjects.Add(new
                {
                    tag = release.Value,
                    commits = string.Format("{0} ({1})",
                        releaseCommitsCount,
                        totalReleaseCommitsCount
                    ),
                    days = string.Format("{0} ({1})",
                        (releaseStatTo - releaseStatFrom).Days,
                        (releaseStatTo - statFrom).Days
                    ),
                    authors = string.Format("{0} ({1})",
                        releaseAuthorsCount,
                        totalReleaseAuthorsCount
                    ),
                    files = releaseFilesCount,
                    files_changed = string.Format(
                        "{0} ({1}%)",
                        releaseTouchedFilesCount,
                        (((double)releaseTouchedFilesCount / releaseFilesCount) * 100).ToString("F02")
                    ),
                    files_defective = string.Format(
                        "{0} ({1}%)",
                        releaseDefectiveFilesCount,
                        (((double)releaseDefectiveFilesCount / releaseFilesCount) * 100).ToString("F02")
                    ),
                    dd = string.Format("{0} ({1})",
                        releaseDD.ToString("F03"),
                        totalReleaseDD.ToString("F03")
                    ),
                    post_release_dd = string.Format(
                        "{0} ({1}%)",
                        postReleaseDD.ToString("F02"),
                        ((releaseDD > 0 ? postReleaseDD / releaseDD : 0) * 100).ToString("F02")
                    ),
                    fixed_defects = string.Format("{0} ({1})",
                        releaseFixesCount,
                        totalReleaseFixesCount
                    ),
                    added_loc = string.Format("{0} ({1})",
                        releaseAddedLoc,
                        totalReleaseAddedLoc
                    ),
                    removed_loc = string.Format("{0} ({1})",
                        - releaseCode.Deleted().CalculateLOC(),
                        - totalReleaseCode.Deleted().CalculateLOC()
                    ),
                    loc = totalReleaseLoc,
                    remain_loc = releaseRemainLoc,
                    contribution = ((releaseRemainLoc / totalLoc) * 100).ToString("F02") + "%",
                    demand_for_code = (releaseAddedLoc > 0 ?
                        ((releaseRemainLoc / releaseAddedLoc) * 100)
                        :
                        0).ToString("F02") + "%"
                });

                prevRelease = release.Key;
            }

            result.Add("releases", releaseObjects);
            return result;
        }