/// <summary>
        /// Tfs returns associated changes from last successful build. That mean, for failed build it can return change that was reported for previous failed build.
        /// This method - clear previously reported changes of previous failed build
        /// </summary>
        private static ICollection <TfsScmChange> GetFilteredBuildChanges(TfsApis tfsManager, TfsBuildInfo buildInfo, TfsBuild build, ICollection <TfsScmChange> changes)
        {
            //put changes in map
            Dictionary <string, TfsScmChange> changesMap = new Dictionary <string, TfsScmChange>();

            foreach (TfsScmChange change in changes)
            {
                changesMap[change.Id] = change;
            }

            //find previous failed build
            IList <TfsBuild> previousBuilds           = tfsManager.GetPreviousFailedBuilds(buildInfo.ProjectId, build.StartTime);
            TfsBuild         foundPreviousFailedBuild = null;

            foreach (TfsBuild previousBuild in previousBuilds)
            {
                //pick only build that done on the same branch
                if (build.SourceBranch.Equals(previousBuild.SourceBranch))
                {
                    foundPreviousFailedBuild = previousBuild;
                    break;
                }
            }

            if (foundPreviousFailedBuild != null)
            {
                //remove changes from previous build
                var previousChanges = tfsManager.GetBuildChanges(buildInfo.ProjectId, foundPreviousFailedBuild.Id.ToString());
                foreach (TfsScmChange previousChange in previousChanges)
                {
                    changesMap.Remove(previousChange.Id);
                }

                int removedCount = changes.Count - changesMap.Count;
                if (removedCount == 0)
                {
                    Log.Debug($"Build {buildInfo} - build {build.Id} contains {changes.Count} associated changes. No one of them was already reported in previous build {foundPreviousFailedBuild.Id}");
                }
                else
                {
                    Log.Debug($"Build {buildInfo} - build {build.Id} contains {changes.Count} associated changes while {removedCount} changes were already reported in build {foundPreviousFailedBuild.Id}");
                }
            }

            return(changesMap.Values);
        }
        public static ScmData GetScmData(TfsApis tfsManager, TfsBuildInfo buildInfo)
        {
            try
            {
                ScmData scmData         = null;
                var     originalChanges = tfsManager.GetBuildChanges(buildInfo.ProjectId, buildInfo.BuildId);
                if (originalChanges.Count > 0)
                {
                    var build = tfsManager.GetBuild(buildInfo.ProjectId, buildInfo.BuildId);
                    ICollection <TfsScmChange> filteredChanges = GetFilteredBuildChanges(tfsManager, buildInfo, build, originalChanges);
                    if (filteredChanges.Count > 0)
                    {
                        scmData = new ScmData();
                        var repository = tfsManager.GetRepositoryById(buildInfo.ProjectId, build.Repository.Id);
                        scmData.Repository        = new ScmRepository();
                        scmData.Repository.Branch = build.SourceBranch;
                        scmData.Repository.Type   = build.Repository.Type;
                        scmData.Repository.Url    = repository.RemoteUrl;

                        scmData.BuiltRevId = build.SourceVersion;
                        scmData.Commits    = new List <ScmCommit>();
                        foreach (TfsScmChange change in filteredChanges)
                        {
                            var       tfsCommit = tfsManager.GetCommitWithChanges(change.Location);
                            ScmCommit scmCommit = new ScmCommit();
                            scmData.Commits.Add(scmCommit);
                            scmCommit.User      = tfsCommit.Committer.Name;
                            scmCommit.UserEmail = tfsCommit.Committer.Email;
                            scmCommit.Time      = OctaneUtils.ConvertToOctaneTime(tfsCommit.Committer.Date);
                            scmCommit.RevId     = tfsCommit.CommitId;
                            if (tfsCommit.Parents.Count > 0)
                            {
                                scmCommit.ParentRevId = tfsCommit.Parents[0];
                            }

                            scmCommit.Comment = tfsCommit.Comment;
                            scmCommit.Changes = new List <ScmCommitFileChange>();

                            foreach (var tfsCommitChange in tfsCommit.Changes)
                            {
                                if (!tfsCommitChange.Item.IsFolder)
                                {
                                    ScmCommitFileChange commitChange = new ScmCommitFileChange();
                                    scmCommit.Changes.Add(commitChange);

                                    string commitChangeType = tfsCommitChange.ChangeType.ToLowerInvariant();
                                    switch (commitChangeType)
                                    {
                                    case "add":
                                    case "edit":
                                    case "delete":
                                        //do nothins
                                        break;

                                    case "delete, sourcerename":
                                        commitChangeType = "delete";
                                        break;

                                    case "rename":
                                    case "edit, rename":
                                        commitChangeType = "add";
                                        break;

                                    default:
                                        Log.Debug($"Build {buildInfo} - Unexpected change type <{commitChangeType}> for file <{tfsCommitChange.Item.Path}>. Setting default to 'edit'.");
                                        commitChangeType = "edit";

                                        break;
                                    }

                                    commitChange.Type = commitChangeType;
                                    commitChange.File = tfsCommitChange.Item.Path;
                                }
                            }
                        }
                    }
                }
                return(scmData);
            }
            catch (Exception e)
            {
                Log.Error($"Build {buildInfo} - failed to create scm data : {e.Message}");
                return(null);
            }
        }