예제 #1
0
        public static bool IsForceRequired(this PushNotification pushNotification, IVssRequestContext requestContext, ITfsGitRepository repository)
        {
            foreach (var refUpdateResult in pushNotification.RefUpdateResults.Where(r => r.Succeeded))
            {
                // Don't bother with new or deleted refs
                if (refUpdateResult.OldObjectId.IsEmpty || refUpdateResult.NewObjectId.IsEmpty)
                {
                    continue;
                }

                TfsGitObject gitObject = repository.LookupObject(refUpdateResult.NewObjectId);
                if (gitObject.ObjectType != GitObjectType.Commit)
                {
                    continue;
                }
                TfsGitCommit gitCommit = (TfsGitCommit)gitObject;

                if (!gitCommit.IsDescendantOf(requestContext, refUpdateResult.OldObjectId))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #2
0
        public static bool IsForceRequired(this PushNotification pushNotification, IVssRequestContext requestContext, ITfsGitRepository repository)
        {
            foreach (var refUpdateResult in pushNotification.RefUpdateResults.Where(r => r.Succeeded))
            {
                // Don't bother with new or deleted refs
                if (refUpdateResult.OldObjectId.IsEmpty || refUpdateResult.NewObjectId.IsEmpty) continue;

                TfsGitObject gitObject = repository.LookupObject(refUpdateResult.NewObjectId);
                if (gitObject.ObjectType != GitObjectType.Commit) continue;
                TfsGitCommit gitCommit = (TfsGitCommit)gitObject;

                if (!gitCommit.IsDescendantOf(requestContext, refUpdateResult.OldObjectId))
                    return true;
            }

            return false;
        }
예제 #3
0
        protected override IEnumerable <INotification> CreateNotifications(IVssRequestContext requestContext, PushNotification pushNotification, int maxLines)
        {
            var repositoryService = requestContext.GetService <ITeamFoundationGitRepositoryService>();
            var commonService     = requestContext.GetService <CommonStructureService>();
            var commitService     = requestContext.GetService <ITeamFoundationGitCommitService>();
            var identityService   = requestContext.GetService <TeamFoundationIdentityService>();

            var identity  = identityService.ReadIdentity(requestContext, IdentitySearchFactor.Identifier, pushNotification.Pusher.Identifier);
            var teamNames = GetUserTeamsByProjectUri(requestContext, pushNotification.TeamProjectUri, pushNotification.Pusher);

            using (ITfsGitRepository repository = repositoryService.FindRepositoryById(requestContext, pushNotification.RepositoryId))
            {
                var pushRow = new PushRow()
                {
                    UniqueName  = pushNotification.AuthenticatedUserName,
                    DisplayName = identity.DisplayName,
                    RepoName    = pushNotification.RepositoryName,
                    RepoUri     = repository.GetRepositoryUri(),
                    ProjectName = commonService.GetProject(requestContext, pushNotification.TeamProjectUri).Name,
                    IsForcePush = Settings.IdentifyForcePush && pushNotification.IsForceRequired(requestContext, repository)
                };
                var notification = new GitPushNotification(requestContext.ServiceHost.Name, pushRow.ProjectName,
                                                           pushRow.RepoName, pushNotification.AuthenticatedUserName, teamNames,
                                                           pushNotification.RefUpdateResults.Where(r => r.Succeeded).Select(r => new GitRef(r)));
                notification.Add(pushRow);
                notification.TotalLineCount++;

                var refLookup   = new Dictionary <Sha1Id, List <GitRef> >();
                var deletedRefs = new List <GitRef>();
                var oldCommits  = new HashSet <TfsGitCommit>(new TfsGitObjectEqualityComparer());
                var unknowns    = new List <TfsGitRefUpdateResult>();

                // Associate refs (branch, lightweight and annotated tag) with corresponding commit
                foreach (var refUpdateResult in pushNotification.RefUpdateResults.Where(r => r.Succeeded))
                {
                    var          newObjectId = refUpdateResult.NewObjectId;
                    TfsGitCommit commit      = null;

                    if (newObjectId.IsEmpty)
                    {
                        deletedRefs.Add(new GitRef(refUpdateResult));
                        continue;
                    }

                    TfsGitObject gitObject = repository.LookupObject(newObjectId);

                    if (gitObject.ObjectType == WebApi.GitObjectType.Commit)
                    {
                        commit = gitObject as TfsGitCommit;
                    }
                    else if (gitObject.ObjectType == WebApi.GitObjectType.Tag)
                    {
                        var tag = (TfsGitTag)gitObject;
                        commit = tag.TryResolveToCommit();
                    }

                    if (commit != null)
                    {
                        List <GitRef> refs;
                        if (!refLookup.TryGetValue(commit.ObjectId, out refs))
                        {
                            refs = new List <GitRef>();
                            refLookup.Add(commit.ObjectId, refs);
                        }
                        refs.Add(new GitRef(refUpdateResult));

                        if (!pushNotification.IncludedCommits.Contains(commit.ObjectId))
                        {
                            oldCommits.Add(commit);
                        }
                    }
                    else
                    {
                        unknowns.Add(refUpdateResult);
                    }
                }

                notification.TotalLineCount += pushNotification.IncludedCommits.Count() + oldCommits.Count + unknowns.Count;

                // Add new commits with refs
                var pushCommits = pushNotification.IncludedCommits.Select(commitId => (TfsGitCommit)repository.LookupObject(commitId)).OrderByDescending(c => c.GetCommitter().Time);
                foreach (var commit in pushCommits.TakeWhile(c => notification.Count < maxLines))
                {
                    notification.Add(CreateCommitRow(requestContext, commitService, repository, commit, CommitRowType.Commit, pushNotification, refLookup));
                }

                // Add updated refs to old commits
                foreach (TfsGitCommit gitCommit in oldCommits.OrderByDescending(c => c.GetCommitter().Time).TakeWhile(c => notification.Count < maxLines))
                {
                    notification.Add(CreateCommitRow(requestContext, commitService, repository, gitCommit, CommitRowType.RefUpdate, pushNotification, refLookup));
                }

                // Add deleted refs if any
                if (deletedRefs.Any() && notification.Count < maxLines)
                {
                    notification.Add(new DeleteRow()
                    {
                        Refs = deletedRefs
                    });
                }

                // Add "unknown" refs
                foreach (var refUpdateResult in unknowns.TakeWhile(c => notification.Count < maxLines))
                {
                    var          newObjectId = refUpdateResult.NewObjectId;
                    TfsGitObject gitObject   = repository.LookupObject(newObjectId);
                    notification.Add(new RefUpdateRow()
                    {
                        NewObjectId = newObjectId,
                        ObjectType  = gitObject.ObjectType,
                        Refs        = new[] { new GitRef(refUpdateResult) }
                    });
                }

                yield return(notification);
            }
        }
예제 #4
0
        protected override PolicyEvaluationResult EvaluateInternal(IVssRequestContext requestContext, PushNotification push)
        {
            var repositoryService = requestContext.GetService <ITeamFoundationGitRepositoryService>();

            var newBranches = push.RefUpdateResults.Where(r => r.OldObjectId == Sha1Id.Empty && r.Name.StartsWith(Constants.BranchPrefix));
            var branch      = newBranches.SingleOrDefault(b => b.Name == Constants.BranchPrefix + "master");

            if (branch != null)
            {
                using (ITfsGitRepository repository = repositoryService.FindRepositoryById(requestContext, push.RepositoryId))
                {
                    TfsGitCommit commit = (TfsGitCommit)repository.LookupObject(branch.NewObjectId);
                    if (commit != null)
                    {
                        var tree        = commit.GetTree();
                        var treeEntries = tree.GetTreeEntries();
                        if (treeEntries.Any())
                        {
                            bool includesGitignore     = false;
                            bool includesGitattributes = false;
                            foreach (var entry in treeEntries)
                            {
                                if (entry.ObjectType == GitObjectType.Blob && entry.Name.Equals(".gitignore", StringComparison.OrdinalIgnoreCase))
                                {
                                    includesGitignore = true;
                                }

                                if (entry.ObjectType == GitObjectType.Blob && entry.Name.Equals(".gitattributes", StringComparison.OrdinalIgnoreCase))
                                {
                                    using (var reader = new StreamReader(entry.Object.GetContent()))
                                    {
                                        var gitattributesContents = reader.ReadToEnd();
                                        // Make sure .gitattributes file has a '* text=auto' line for eol normalization
                                        if (!Regex.IsMatch(gitattributesContents, @"^\*\s+text=auto\s*$", RegexOptions.Multiline))
                                        {
                                            Logger.Log("pushNotification:", push);
                                            var statusMessage = $".gitattributes is missing '* text=auto'. See {Settings.DocsBaseUrl}/guidelines/scm/git-conventions/#mandatory-files.";
                                            Logger.Log(statusMessage);
                                            return(new PolicyEvaluationResult(false, push.Pusher, statusMessage));
                                        }

                                        includesGitattributes = true;
                                    }
                                }
                            }

                            if (!includesGitignore || !includesGitattributes)
                            {
                                Logger.Log("pushNotification:", push);
                                var statusMessage = $"Mandatory files missing. See {Settings.DocsBaseUrl}/guidelines/scm/git-conventions/#mandatory-files.";
                                Logger.Log(statusMessage);
                                return(new PolicyEvaluationResult(false, push.Pusher, statusMessage));
                            }
                        }
                        else
                        {
                            Logger.Log("Commit without tree entries: " + branch.NewObjectId);
                        }
                    }
                    else
                    {
                        Logger.Log("Unable to find commit " + branch.NewObjectId);
                    }
                }
            }

            return(new PolicyEvaluationResult(true));
        }