Example #1
0
        private static CommitRow CreateCommitRow(TeamFoundationRequestContext requestContext, TeamFoundationGitCommitService commitService,
                                                 TfsGitRepository repository, TfsGitCommit gitCommit, CommitRowType rowType, PushNotification pushNotification, Dictionary <Sha1Id, List <GitRef> > refLookup)
        {
            var    commitManifest = commitService.GetCommitManifest(requestContext, repository, gitCommit.ObjectId);
            string repoUri        = repository.GetRepositoryUri(requestContext);

            var commitRow = new CommitRow()
            {
                CommitId     = gitCommit.ObjectId,
                Type         = rowType,
                CommitUri    = repoUri + "/commit/" + gitCommit.ObjectId.ToHexString(),
                AuthorTime   = gitCommit.GetLocalAuthorTime(requestContext),
                Author       = gitCommit.GetAuthor(requestContext),
                AuthorName   = gitCommit.GetAuthorName(requestContext),
                AuthorEmail  = gitCommit.GetAuthorEmail(requestContext),
                Comment      = gitCommit.GetComment(requestContext),
                ChangeCounts = commitManifest.ChangeCounts
            };
            List <GitRef> refs;

            refLookup.TryGetValue(gitCommit.ObjectId, out refs);
            commitRow.Refs = refs;

            return(commitRow);
        }
        protected override IEnumerable <Notifications.INotification> CreateNotifications(TeamFoundationRequestContext requestContext, RepositoryCreatedNotification ev, int maxLines)
        {
            var repositoryService = requestContext.GetService <TeamFoundationGitRepositoryService>();
            var identityService   = requestContext.GetService <ITeamFoundationIdentityService>();
            var commonService     = requestContext.GetService <CommonStructureService>();

            var identity = identityService.ReadIdentity(requestContext, IdentitySearchFactor.Identifier, ev.Creator.Identifier);

            using (TfsGitRepository repository = repositoryService.FindRepositoryById(requestContext, ev.RepositoryId))
            {
                string repoUri = repository.GetRepositoryUri(requestContext);

                var notification = new Notifications.RepositoryCreatedNotification()
                {
                    TeamProjectCollection = requestContext.ServiceHost.Name,
                    UniqueName            = identity.UniqueName,
                    DisplayName           = identity.DisplayName,
                    ProjectName           = commonService.GetProject(requestContext, ev.TeamProjectUri).Name,
                    RepoUri   = repoUri,
                    RepoName  = ev.RepositoryName,
                    TeamNames = GetUserTeamsByProjectUri(requestContext, ev.TeamProjectUri, identity.Descriptor)
                };
                yield return(notification);
            }
        }
Example #3
0
        internal static void LogRequest(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            if (!PluginConfiguration.Instance.HasLog)
                return;

            var lines = new List<string>();

            lines.Add(string.Format("Request from {0} for {1}"
                , requestContext.GetNameToDisplay()
                , requestContext.ServiceName
                ));
            lines.Add("Summary for " + requestContext.GetSummary());

            lines.Add(string.Format("{6} #{0} on {1} repo {2} at {3} by {5} ({4})"
                , pushNotification.PushId
                , pushNotification.TeamProjectUri
                , pushNotification.RepositoryName
                , pushNotification.PushTime
                , pushNotification.AuthenticatedUserName
                , pushNotification.Pusher
                , requestContext.Method.Name
                ));

            lines.Add("- Included Commits:");
            foreach (var commitHash in pushNotification.IncludedCommits)
            {
                var commit = repository.TryLookupObject(requestContext, commitHash) as TfsGitCommit;
                lines.Add(string.Format("   Commit {0}: {1} '{2}'"
                    , commit.ObjectId.DisplayHash()
                    , commit.GetCommitterName(requestContext)
                    , commit.GetComment(requestContext)
                    ));

                foreach (var parentCommit in commit.GetParents(requestContext))
                {
                    lines.Add(string.Format("      Parent {0}: {1} '{2}'"
                        , parentCommit.ObjectId.DisplayHash()
                        , parentCommit.GetCommitterName(requestContext)
                        , parentCommit.GetComment(requestContext)
                        ));
                }
            }

            lines.Add("- Ref Update Results:");
            foreach (var refUpdate in pushNotification.RefUpdateResults)
            {
                lines.Add(string.Format("   on {0} {1}..{2} is {3} (succeeded: {4}) rejecter '{5}' message '{6}'"
                    , refUpdate.Name
                    , refUpdate.NewObjectId.DisplayHash()
                    , refUpdate.OldObjectId.DisplayHash()
                    , refUpdate.Status
                    , refUpdate.Succeeded
                    , refUpdate.RejectedBy
                    , refUpdate.CustomMessage
                    ));
            }//for

            File.AppendAllLines(PluginConfiguration.Instance.LogFile, lines);
        }
Example #4
0
 public List<Validation> CheckRules(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
 {
     var res = new List<Validation>();
     foreach (var rule in this.Rules)
     {
         res.Add(rule.CheckRule(requestContext, pushNotification, repository));
     }//for
     return res;
 }
        public override Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            var result = new Validation();

            // refuse any push
            result.Fails = true;
            result.ReasonCode = 99;
            result.ReasonMessage = string.Format(
                "Repository '{0}' is in read-only mode",
                pushNotification.RepositoryName);

            return result;
        }
        public static bool IsForceRequired(this PushNotification pushNotification, TeamFoundationRequestContext requestContext, TfsGitRepository repository)
        {
            foreach (var refUpdateResult in pushNotification.RefUpdateResults.Where(r => r.Succeeded))
            {
                // Don't bother with new or deleted refs
                if (refUpdateResult.OldObjectId.IsZero() || refUpdateResult.NewObjectId.IsZero()) continue;

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

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

            return false;
        }
        public override Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            var result = new Validation();

            long totalSize = 0;
            foreach (var commitId in pushNotification.IncludedCommits)
            {
                TfsGitCommit gitCommit = repository.LookupObject(requestContext, commitId) as TfsGitCommit;
                if (gitCommit == null)
                    continue;

                long size = GetCommitSize(gitCommit, requestContext);
                totalSize += size;
            }//for

            // convert to MB
            totalSize = totalSize / (1024 * 1024);

            if (totalSize < this.Megabytes)
            {
                Logger.Log(string.Format(
                    "Push request is {0} MB, below the {1} MB limit."
                    , totalSize, this.Megabytes
                    , "Limit Size"));
            }
            else
            {
                if (IsUserExempted(requestContext, pushNotification))
                {
                    Logger.Log(string.Format(
                        "Push request is {0} MB, above or equal to the {1} MB limit, but user is exempted."
                        , totalSize, this.Megabytes
                        , "Limit Size"));
                }
                else
                {
                    result.Fails = true;
                    result.ReasonCode = 2;
                    result.ReasonMessage = string.Format(
                        "Push request is {0} MB, above or equal to the {1} MB limit: refused."
                        , totalSize, this.Megabytes);
                }
            }//if

            return result;
        }
        protected override IEnumerable <Notifications.INotification> CreateNotifications(TeamFoundationRequestContext requestContext, ReviewerVoteNotification ev, int maxLines)
        {
            var repositoryService = requestContext.GetService <TeamFoundationGitRepositoryService>();
            var identityService   = requestContext.GetService <ITeamFoundationIdentityService>();
            var commonService     = requestContext.GetService <ICommonStructureService>();

            var identity = identityService.ReadIdentity(requestContext, IdentitySearchFactor.Identifier, ev.Reviewer.Identifier);

            using (TfsGitRepository repository = repositoryService.FindRepositoryById(requestContext, ev.RepositoryId))
            {
                var pullRequestService = requestContext.GetService <ITeamFoundationGitPullRequestService>();
                TfsGitPullRequest pullRequest;
                if (pullRequestService.TryGetPullRequestDetails(requestContext, repository, ev.PullRequestId, out pullRequest))
                {
                    string repoUri      = repository.GetRepositoryUri(requestContext);
                    var    creator      = identityService.ReadIdentities(requestContext, new[] { pullRequest.Creator }).First();
                    var    reviewers    = identityService.ReadIdentities(requestContext, pullRequest.Reviewers.Select(r => r.Reviewer).ToArray());
                    var    notification = new Notifications.PullRequestReviewerVoteNotification()
                    {
                        TeamProjectCollection = requestContext.ServiceHost.Name,
                        CreatorUserName       = creator.UniqueName,
                        Vote              = ev.ReviewerVote,
                        UniqueName        = identity.UniqueName,
                        DisplayName       = identity.DisplayName,
                        ProjectName       = commonService.GetProject(requestContext, ev.TeamProjectUri).Name,
                        RepoUri           = repoUri,
                        RepoName          = ev.RepositoryName,
                        PrId              = pullRequest.PullRequestId,
                        PrUrl             = string.Format("{0}/pullrequest/{1}#view=discussion", repoUri, ev.PullRequestId),
                        PrTitle           = pullRequest.Title,
                        TeamNames         = GetUserTeamsByProjectUri(requestContext, ev.TeamProjectUri, ev.Reviewer),
                        SourceBranch      = new Notifications.GitRef(pullRequest.SourceBranchName),
                        TargetBranch      = new Notifications.GitRef(pullRequest.TargetBranchName),
                        ReviewerUserNames = reviewers.Select(r => r.UniqueName)
                    };
                    yield return(notification);
                }
                else
                {
                    throw new TfsNotificationRelayException("Unable to get pull request " + ev.PullRequestId);
                }
            }
        }
        public override Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            var result = new Validation();

            foreach (var refUpdateResult in pushNotification.RefUpdateResults)
            {
                // new or deleted refs have id==0
                if (IsNullHash(refUpdateResult.OldObjectId)
                    || IsNullHash(refUpdateResult.NewObjectId))
                    continue;

                TfsGitCommit gitCommit = repository.LookupObject(requestContext, refUpdateResult.NewObjectId) as TfsGitCommit;
                if (gitCommit == null)
                    continue;

                string authorEmail = gitCommit.GetAuthorEmail(requestContext);
                if (!AuthorEmail.Any(pattern => Regex.IsMatch(authorEmail, pattern)))
                {
                    result.Fails = true;
                    result.ReasonCode = 2;
                    result.ReasonMessage = string.Format(
                        "Author email '{0}' on commit {1} is not admitted",
                        authorEmail,
                        gitCommit.ObjectId.DisplayHash());
                    break;
                }

                string committerEmail = gitCommit.GetCommitterEmail(requestContext);
                if (!CommitterEmail.Any(pattern => Regex.IsMatch(committerEmail, pattern)))
                {
                    result.Fails = true;
                    result.ReasonCode = 3;
                    result.ReasonMessage = string.Format(
                        "Committer email '{0}' on commit {1} is not admitted",
                        authorEmail,
                        gitCommit.ObjectId.DisplayHash());
                    break;
                }//if
            }//for changes

            return result;
        }
        protected override Notifications.INotification CreateNotification(TeamFoundationRequestContext requestContext, ReviewerVoteNotification ev, int maxLines)
        {
            var repositoryService = requestContext.GetService <TeamFoundationGitRepositoryService>();
            var identityService   = requestContext.GetService <ITeamFoundationIdentityService>();
            var commonService     = requestContext.GetService <ICommonStructureService>();

            var identity = identityService.ReadIdentity(requestContext, IdentitySearchFactor.Identifier, ev.Reviewer.Identifier);

            using (TfsGitRepository repository = repositoryService.FindRepositoryById(requestContext, ev.RepositoryId))
            {
                var pullRequestService = requestContext.GetService <ITeamFoundationGitPullRequestService>();
                TfsGitPullRequest pullRequest;
                if (pullRequestService.TryGetPullRequestDetails(requestContext, repository, ev.PullRequestId, out pullRequest))
                {
                    string repoUri      = repository.GetRepositoryUri(requestContext);
                    var    notification = new Notifications.PullRequestReviewerVoteNotification()
                    {
                        TeamProjectCollection = requestContext.ServiceHost.Name,
                        Vote        = ev.ReviewerVote,
                        UniqueName  = identity.UniqueName,
                        DisplayName = identity.DisplayName,
                        ProjectName = commonService.GetProject(requestContext, ev.TeamProjectUri).Name,
                        RepoUri     = repoUri,
                        RepoName    = ev.RepositoryName,
                        PrId        = pullRequest.PullRequestId,
                        PrUrl       = string.Format("{0}/pullrequest/{1}#view=discussion", repoUri, ev.PullRequestId),
                        PrTitle     = pullRequest.Title
                    };
                    return(notification);
                }
                else
                {
                    throw new TfsNotificationRelayException("Unable to get pull request " + ev.PullRequestId);
                }
            }
        }
Example #11
0
        protected bool RequiresForcePush(PushNotification pushNotification, TeamFoundationRequestContext requestContext, TfsGitRepository repository)
        {
            foreach (var refUpdateResult in pushNotification.RefUpdateResults)
            {
                // new or deleted refs have id==0
                if (IsNullHash(refUpdateResult.OldObjectId) ||
                    IsNullHash(refUpdateResult.NewObjectId))
                {
                    continue;
                }

                TfsGitCommit gitCommit = repository.LookupObject(requestContext, refUpdateResult.NewObjectId) as TfsGitCommit;
                if (gitCommit == null)
                {
                    continue;
                }

                if (!DescendsFrom(gitCommit, refUpdateResult.OldObjectId, requestContext))
                {
                    // aha! no common node
                    return(true);
                }
            }
            return(false);
        }
Example #12
0
        public List <Validation> CheckRules(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            var res = new List <Validation>();

            foreach (var rule in this.Rules)
            {
                res.Add(rule.CheckRule(requestContext, pushNotification, repository));
            }//for
            return(res);
        }
Example #13
0
        protected override IEnumerable <INotification> CreateNotifications(TeamFoundationRequestContext requestContext, PushNotification pushNotification, int maxLines)
        {
            var repositoryService = requestContext.GetService <TeamFoundationGitRepositoryService>();
            var commonService     = requestContext.GetService <CommonStructureService>();
            var commitService     = requestContext.GetService <TeamFoundationGitCommitService>();
            var identityService   = requestContext.GetService <TeamFoundationIdentityService>();

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

            using (TfsGitRepository repository = repositoryService.FindRepositoryById(requestContext, pushNotification.RepositoryId))
            {
                var pushRow = new PushRow()
                {
                    UniqueName  = pushNotification.AuthenticatedUserName,
                    DisplayName = identity.DisplayName,
                    RepoName    = pushNotification.RepositoryName,
                    RepoUri     = repository.GetRepositoryUri(requestContext),
                    ProjectName = commonService.GetProject(requestContext, pushNotification.TeamProjectUri).Name,
                    IsForcePush = settings.IdentifyForcePush ? pushNotification.IsForceRequired(requestContext, repository) : false
                };
                var notification = new GitPushNotification(requestContext.ServiceHost.Name, pushRow.ProjectName, pushRow.RepoName, teamNames);
                notification.Add(pushRow);
                notification.TotalLineCount++;

                var refNames   = new Dictionary <byte[], List <string> >(new ByteArrayComparer());
                var oldCommits = new HashSet <byte[]>(new ByteArrayComparer());
                var unknowns   = new List <RefUpdateResultGroup>();

                // Associate refs (branch, lightweight and annotated tag) with corresponding commit
                var refUpdateResultGroups = pushNotification.RefUpdateResults
                                            .Where(r => r.Succeeded)
                                            .GroupBy(r => r.NewObjectId, (key, items) => new RefUpdateResultGroup(key, items), new ByteArrayComparer());

                foreach (var refUpdateResultGroup in refUpdateResultGroups)
                {
                    byte[] newObjectId = refUpdateResultGroup.NewObjectId;
                    byte[] commitId    = null;

                    if (newObjectId.IsZero())
                    {
                        commitId = newObjectId;
                    }
                    else
                    {
                        TfsGitObject gitObject = repository.LookupObject(requestContext, newObjectId);

                        if (gitObject.ObjectType == TfsGitObjectType.Commit)
                        {
                            commitId = newObjectId;
                        }
                        else if (gitObject.ObjectType == TfsGitObjectType.Tag)
                        {
                            var tag    = (TfsGitTag)gitObject;
                            var commit = tag.TryResolveToCommit(requestContext);
                            if (commit != null)
                            {
                                commitId = commit.ObjectId;
                            }
                        }
                    }

                    if (commitId != null)
                    {
                        List <string> names;
                        if (!refNames.TryGetValue(commitId, out names))
                        {
                            names = new List <string>();
                            refNames.Add(commitId, names);
                        }
                        names.AddRange(RefsToStrings(refUpdateResultGroup.RefUpdateResults));

                        if (commitId.IsZero() || !pushNotification.IncludedCommits.Any(r => r.SequenceEqual(commitId)))
                        {
                            oldCommits.Add(commitId);
                        }
                    }
                    else
                    {
                        unknowns.Add(refUpdateResultGroup);
                    }
                }

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

                // Add new commits with refs
                foreach (byte[] commitId in pushNotification.IncludedCommits.TakeWhile(c => notification.Count < maxLines))
                {
                    TfsGitCommit gitCommit = (TfsGitCommit)repository.LookupObject(requestContext, commitId);
                    notification.Add(CreateCommitRow(requestContext, commitService, gitCommit, CommitRowType.Commit, pushNotification, refNames));
                }

                // Add updated refs to old commits
                foreach (byte[] commitId in oldCommits.TakeWhile(c => notification.Count < maxLines))
                {
                    if (commitId.IsZero())
                    {
                        notification.Add(new DeleteRow()
                        {
                            RefNames = refNames[commitId]
                        });
                    }
                    else
                    {
                        TfsGitCommit gitCommit = (TfsGitCommit)repository.LookupObject(requestContext, commitId);
                        notification.Add(CreateCommitRow(requestContext, commitService, gitCommit, CommitRowType.RefUpdate, pushNotification, refNames));
                    }
                }

                // Add "unknown" refs
                foreach (var refUpdateResultGroup in unknowns.TakeWhile(c => notification.Count < maxLines))
                {
                    byte[]       newObjectId = refUpdateResultGroup.NewObjectId;
                    TfsGitObject gitObject   = repository.LookupObject(requestContext, newObjectId);
                    notification.Add(new RefUpdateRow()
                    {
                        NewObjectId = newObjectId,
                        ObjectType  = gitObject.ObjectType,
                        RefNames    = RefsToStrings(refUpdateResultGroup.RefUpdateResults)
                    });
                }

                yield return(notification);
            }
        }
Example #14
0
        protected override IEnumerable <INotification> CreateNotifications(TeamFoundationRequestContext requestContext,
                                                                           DiscussionsNotification args, int maxLines)
        {
            var locationService   = requestContext.GetService <ILocationService>();
            var linkingService    = requestContext.GetService <TeamFoundationLinkingService>();
            var hyperlinkService  = requestContext.GetService <TswaServerHyperlinkService>();
            var identityService   = requestContext.GetService <ITeamFoundationIdentityService>();
            var commonService     = requestContext.GetService <ICommonStructureService>();
            var discussionService = requestContext.GetService <ITeamFoundationDiscussionService>();

            var notifications = new List <INotification>();

            foreach (var thread in args.Threads)
            {
                if (thread.Comments == null)
                {
                    continue;                          // e.g. when a comment is deleted
                }
                var artifactId = LinkingUtilities.DecodeUri(thread.ArtifactUri);

                int discussionId = thread.DiscussionId <= 0 ? thread.Comments[0].DiscussionId : thread.DiscussionId;

                if (artifactId.ArtifactType.Equals("Commit", StringComparison.OrdinalIgnoreCase))
                {
                    var repositoryService = requestContext.GetService <TeamFoundationGitRepositoryService>();
                    var commitService     = requestContext.GetService <TeamFoundationGitCommitService>();

                    Guid   projectGuid;
                    Guid   repositoryId;
                    Sha1Id commitId;
                    GitCommitArtifactId.Decode(artifactId, out projectGuid, out repositoryId, out commitId);

                    using (TfsGitRepository repository = repositoryService.FindRepositoryById(requestContext, repositoryId))
                    {
                        var    project   = commonService.GetProject(requestContext, projectGuid);
                        var    repoUri   = repository.GetRepositoryUri(requestContext);
                        var    commitUri = repoUri + "/commit/" + commitId.ToHexString();
                        string itemPath;
                        if (thread.Properties.TryGetValue <string>("Microsoft.TeamFoundation.Discussion.ItemPath", out itemPath))
                        {
                            commitUri += string.Format("#path={0}&discussionId={1}&_a=contents", Uri.EscapeDataString(itemPath), discussionId);
                        }

                        var commitManifest = commitService.GetCommitManifest(requestContext, repository, commitId);

                        var pusher = identityService.ReadIdentities(requestContext, new[] { commitManifest.PusherId }).FirstOrDefault();

                        foreach (var comment in thread.Comments)
                        {
                            var commenter = identityService.ReadIdentities(requestContext, new[] { comment.Author }).First();

                            var notification = new Notifications.CommitCommentNotification()
                            {
                                TeamProjectCollection = requestContext.ServiceHost.Name,
                                PusherUniqueName      = pusher?.UniqueName,
                                UniqueName            = commenter.UniqueName,
                                DisplayName           = comment.AuthorDisplayName,
                                ProjectName           = project.Name,
                                RepoUri   = repoUri,
                                RepoName  = repository.Name,
                                CommitId  = commitId,
                                CommitUri = commitUri,
                                Comment   = TextHelper.Truncate(comment.Content, Settings.DiscussionCommentMaxLength),
                                TeamNames = GetUserTeamsByProjectUri(requestContext, project.Uri, commenter.Descriptor),
                            };

                            notifications.Add(notification);
                        }
                    }
                }
                else if (artifactId.ArtifactType.Equals("CodeReviewId", StringComparison.OrdinalIgnoreCase))
                {
                    Guid projectGuid;
                    int  pullRequestId;
                    LegacyCodeReviewArtifactId.Decode(artifactId, out projectGuid, out pullRequestId);

                    var pullRequestService = requestContext.GetService <ITeamFoundationGitPullRequestService>();
                    var pullRequest        = pullRequestService.GetPullRequestDetails(requestContext, pullRequestId);

                    var repositoryService = requestContext.GetService <TeamFoundationGitRepositoryService>();

                    using (TfsGitRepository repository = repositoryService.FindRepositoryById(requestContext, pullRequest.RepositoryId))
                    {
                        var    project = commonService.GetProject(requestContext, projectGuid);
                        string repoUri = repository.GetRepositoryUri(requestContext);
                        var    creator = identityService.ReadIdentities(requestContext, new[] { pullRequest.Creator }).FirstOrDefault();

                        foreach (var comment in thread.Comments)
                        {
                            var commenter = identityService.ReadIdentities(requestContext, new[] { comment.Author }).First();

                            var notification = new Notifications.PullRequestCommentNotification()
                            {
                                TeamProjectCollection = requestContext.ServiceHost.Name,
                                CreatorUniqueName     = creator?.UniqueName,
                                UniqueName            = commenter.UniqueName,
                                DisplayName           = commenter.DisplayName,
                                ProjectName           = project.Name,
                                RepoUri      = repoUri,
                                RepoName     = repository.Name,
                                PrId         = pullRequest.PullRequestId,
                                PrUrl        = $"{repoUri}/pullrequest/{pullRequest.PullRequestId}#view=discussion",
                                PrTitle      = pullRequest.Title,
                                TeamNames    = GetUserTeamsByProjectUri(requestContext, project.Uri, commenter.Descriptor),
                                SourceBranch = new GitRef(pullRequest.SourceBranchName),
                                TargetBranch = new GitRef(pullRequest.TargetBranchName),
                                Comment      = TextHelper.Truncate(comment.Content, Settings.DiscussionCommentMaxLength)
                            };

                            notifications.Add(notification);
                        }
                    }
                }
                else if (artifactId.ArtifactType.Equals("Changeset", StringComparison.OrdinalIgnoreCase))
                {
                    var versionControlService = requestContext.GetService <TeamFoundationVersionControlService>();

                    var uri         = new VersionControlIntegrationUri(thread.ArtifactUri);
                    var changesetId = int.Parse(uri.ArtifactName);
                    var reader      = versionControlService.QueryChangeset(requestContext, changesetId, true, false, false);
                    var changeset   = reader.Current <Changeset>();

                    var    changesetUrl = hyperlinkService.GetChangesetDetailsUrl(changesetId).AbsoluteUri;
                    string baseUrl      = String.Format("{0}/{1}/",
                                                        locationService.GetAccessMapping(requestContext, "PublicAccessMapping").AccessPoint,
                                                        requestContext.ServiceHost.Name);

                    string       itemPath           = string.Empty;
                    string       projectName        = string.Empty;
                    const string projectNamePattern = @"^\$\/([^\/]*)\/";

                    if (thread.Properties != null && thread.Properties.TryGetValue <string>("Microsoft.TeamFoundation.Discussion.ItemPath", out itemPath))
                    {
                        changesetUrl += string.Format("#path={0}&discussionId={1}&_a=contents", Uri.EscapeDataString(itemPath), discussionId);
                        Match match = Regex.Match(itemPath, projectNamePattern);
                        if (match.Success)
                        {
                            projectName = match.Groups[1].Value;
                        }
                    }
                    else
                    {
                        // This assumes changeset doesn't span multiple projects.
                        var serverItem = changeset.Changes.FirstOrDefault()?.Item.ServerItem;
                        if (serverItem != null)
                        {
                            Match match = Regex.Match(serverItem, projectNamePattern);
                            if (match.Success)
                            {
                                projectName = match.Groups[1].Value;
                            }
                        }
                    }

                    var commiter = identityService.ReadIdentity(requestContext, IdentitySearchFactor.AccountName, changeset.Committer);

                    foreach (var comment in thread.Comments)
                    {
                        var commenter = identityService.ReadIdentities(requestContext, new[] { comment.Author }).First();

                        var notification = new Notifications.ChangesetCommentNotification()
                        {
                            TeamProjectCollection = requestContext.ServiceHost.Name,
                            CreatorUniqueName     = commiter?.UniqueName,
                            UniqueName            = commenter.UniqueName,
                            DisplayName           = commenter.DisplayName,
                            ProjectUrl            = baseUrl + projectName,
                            ProjectName           = projectName,
                            ChangesetId           = changesetId,
                            ChangesetUrl          = changesetUrl,
                            TeamNames             = GetUserTeamsByProjectName(requestContext, projectName, commenter.Descriptor),
                            SourcePath            = itemPath,
                            Comment = TextHelper.Truncate(comment.Content, Settings.DiscussionCommentMaxLength)
                        };

                        notifications.Add(notification);
                    }
                }
            }

            return(notifications);
        }
Example #15
0
        internal static void LogRequest(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            if (!PluginConfiguration.Instance.HasLog)
            {
                return;
            }

            var lines = new List <string>();

            lines.Add(string.Format("Request from {0} for {1}"
                                    , requestContext.GetNameToDisplay()
                                    , requestContext.ServiceName
                                    ));
            lines.Add("Summary for " + requestContext.GetSummary());

            lines.Add(string.Format("{6} #{0} on {1} repo {2} at {3} by {5} ({4})"
                                    , pushNotification.PushId
                                    , pushNotification.TeamProjectUri
                                    , pushNotification.RepositoryName
                                    , pushNotification.PushTime
                                    , pushNotification.AuthenticatedUserName
                                    , pushNotification.Pusher
                                    , requestContext.Method.Name
                                    ));

            lines.Add("- Included Commits:");
            foreach (var commitHash in pushNotification.IncludedCommits)
            {
                var commit = repository.TryLookupObject(requestContext, commitHash) as TfsGitCommit;
                lines.Add(string.Format("   Commit {0}: {1} '{2}'"
                                        , commit.ObjectId.DisplayHash()
                                        , commit.GetCommitterName(requestContext)
                                        , commit.GetComment(requestContext)
                                        ));

                foreach (var parentCommit in commit.GetParents(requestContext))
                {
                    lines.Add(string.Format("      Parent {0}: {1} '{2}'"
                                            , parentCommit.ObjectId.DisplayHash()
                                            , parentCommit.GetCommitterName(requestContext)
                                            , parentCommit.GetComment(requestContext)
                                            ));
                }
            }

            lines.Add("- Ref Update Results:");
            foreach (var refUpdate in pushNotification.RefUpdateResults)
            {
                lines.Add(string.Format("   on {0} {1}..{2} is {3} (succeeded: {4}) rejecter '{5}' message '{6}'"
                                        , refUpdate.Name
                                        , refUpdate.NewObjectId.DisplayHash()
                                        , refUpdate.OldObjectId.DisplayHash()
                                        , refUpdate.Status
                                        , refUpdate.Succeeded
                                        , refUpdate.RejectedBy
                                        , refUpdate.CustomMessage
                                        ));
            }//for

            File.AppendAllLines(PluginConfiguration.Instance.LogFile, lines);
        }
Example #16
0
 public abstract Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository);
Example #17
0
        public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType,
                                                    object notificationEventArgs, out int statusCode, out string statusMessage, out Microsoft.TeamFoundation.Common.ExceptionPropertyCollection properties)
        {
            statusCode    = 0;
            statusMessage = string.Empty;
            properties    = null;

            try
            {
                if (notificationType == NotificationType.Notification && notificationEventArgs is PushNotification)
                {
                    Stopwatch timer = new Stopwatch();
                    timer.Start();

                    PushNotification pushNotification = notificationEventArgs as PushNotification;
                    var repositoryService             = requestContext.GetService <TeamFoundationGitRepositoryService>();
                    var commonService = requestContext.GetService <CommonStructureService>();

                    using (TfsGitRepository repository = repositoryService.FindRepositoryById(requestContext, pushNotification.RepositoryId))
                    {
                        string repoName    = pushNotification.RepositoryName;
                        string projectName = commonService.GetProject(requestContext, pushNotification.TeamProjectUri).Name;
                        string userName    = pushNotification.AuthenticatedUserName.Replace(DOMAIN_PREFIX, "");

                        var lines = new List <string>();

                        string pushText = pushNotification.IsForceRequired(requestContext, repository) ? "FORCE push" : "push";
                        lines.Add(String.Format("{0} by {1} to {2}/{3}", pushText, userName, projectName, repoName));

                        var refNames   = new Dictionary <byte[], List <string> >(new ByteArrayComparer());
                        var oldCommits = new HashSet <byte[]>(new ByteArrayComparer());
                        var unknowns   = new List <RefUpdateResultGroup>();

                        // Associate refs (branch, ligtweight and annotated tag) with corresponding commit
                        var refUpdateResultGroups = pushNotification.RefUpdateResults
                                                    .Where(r => r.Succeeded)
                                                    .GroupBy(r => r.NewObjectId, (key, items) => new RefUpdateResultGroup(key, items), new ByteArrayComparer());

                        foreach (var refUpdateResultGroup in refUpdateResultGroups)
                        {
                            byte[] newObjectId = refUpdateResultGroup.NewObjectId;
                            byte[] commitId    = null;

                            if (newObjectId.IsZero())
                            {
                                commitId = newObjectId;
                            }
                            else
                            {
                                TfsGitObject gitObject = repository.LookupObject(requestContext, newObjectId);

                                if (gitObject.ObjectType == TfsGitObjectType.Commit)
                                {
                                    commitId = newObjectId;
                                }
                                else if (gitObject.ObjectType == TfsGitObjectType.Tag)
                                {
                                    var tag    = (TfsGitTag)gitObject;
                                    var commit = tag.TryResolveToCommit(requestContext);
                                    if (commit != null)
                                    {
                                        commitId = commit.ObjectId;
                                    }
                                }
                            }

                            if (commitId != null)
                            {
                                List <string> names;
                                if (!refNames.TryGetValue(commitId, out names))
                                {
                                    names = new List <string>();
                                    refNames.Add(commitId, names);
                                }
                                names.AddRange(RefsToStrings(refUpdateResultGroup.RefUpdateResults));

                                if (commitId.IsZero() || !pushNotification.IncludedCommits.Any(r => r.SequenceEqual(commitId)))
                                {
                                    oldCommits.Add(commitId);
                                }
                            }
                            else
                            {
                                unknowns.Add(refUpdateResultGroup);
                            }
                        }

                        // Display new commits with refs
                        foreach (byte[] commitId in pushNotification.IncludedCommits)
                        {
                            TfsGitCommit gitCommit = (TfsGitCommit)repository.LookupObject(requestContext, commitId);
                            string       line      = CommitToString(requestContext, gitCommit, "commit", pushNotification, refNames);
                            lines.Add(line);
                        }

                        // Display updated refs to old commits
                        foreach (byte[] commitId in oldCommits)
                        {
                            string line = null;

                            if (commitId.IsZero())
                            {
                                line = String.Format("{0} deleted", String.Join("", refNames[commitId]));
                            }
                            else
                            {
                                TfsGitCommit gitCommit = (TfsGitCommit)repository.LookupObject(requestContext, commitId);
                                line = CommitToString(requestContext, gitCommit, "->", pushNotification, refNames);
                            }
                            lines.Add(line);
                        }

                        // Display "unknown" refs
                        foreach (var refUpdateResultGroup in unknowns)
                        {
                            byte[]       newObjectId = refUpdateResultGroup.NewObjectId;
                            TfsGitObject gitObject   = repository.LookupObject(requestContext, newObjectId);
                            string       line        = String.Format("{0} -> {1} {2}", RefsToString(refUpdateResultGroup.RefUpdateResults), gitObject.ObjectType, newObjectId.ToHexString());

                            lines.Add(line);
                        }

                        //Log(lines);

                        List <string> sendLines = lines;
                        if (lines.Count > MAX_LINES)
                        {
                            sendLines = lines.Take(MAX_LINES).ToList();
                            sendLines.Add(String.Format("{0} more line(s) suppressed.", lines.Count - MAX_LINES));
                        }

                        Task.Run(() => SendToBot(sendLines));
                    }

                    timer.Stop();
                    //Log("Time spent in ProcessEvent: " + timer.Elapsed);
                }
            }
            catch (Exception ex)
            {
                Log(ex.Message);
                Log(ex.StackTrace);
            }

            return(EventNotificationStatus.ActionPermitted);
        }
Example #18
0
 public abstract Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository);
        protected override IEnumerable <INotification> CreateNotifications(TeamFoundationRequestContext requestContext, PushNotification pushNotification, int maxLines)
        {
            var repositoryService = requestContext.GetService <TeamFoundationGitRepositoryService>();
            var commonService     = requestContext.GetService <CommonStructureService>();
            var commitService     = requestContext.GetService <TeamFoundationGitCommitService>();
            var identityService   = requestContext.GetService <TeamFoundationIdentityService>();

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

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

                var refLookup   = new Dictionary <byte[], List <GitRef> >(new ByteArrayComparer());
                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.IsZero())
                    {
                        deletedRefs.Add(new GitRef(refUpdateResult));
                        continue;
                    }

                    TfsGitObject gitObject = repository.LookupObject(requestContext, newObjectId);

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

                    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.Any(r => r.SequenceEqual(commit.ObjectId)))
                        {
                            oldCommits.Add(commit);
                        }
                    }
                    else
                    {
                        unknowns.Add(refUpdateResult);
                    }
                }

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

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

                // Add updated refs to old commits
                foreach (TfsGitCommit gitCommit in oldCommits.OrderByDescending(c => c.GetCommitTime(requestContext)).TakeWhile(c => notification.Count < maxLines))
                {
                    notification.Add(CreateCommitRow(requestContext, commitService, 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(requestContext, newObjectId);
                    notification.Add(new RefUpdateRow()
                    {
                        NewObjectId = newObjectId,
                        ObjectType  = gitObject.ObjectType,
                        Refs        = new[] { new GitRef(refUpdateResult) }
                    });
                }

                yield return(notification);
            }
        }
        public override Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            var result = new Validation();

            foreach (var refUpdateResult in pushNotification.RefUpdateResults)
            {
                // new or deleted refs have id==0
                if (IsNullHash(refUpdateResult.OldObjectId) ||
                    IsNullHash(refUpdateResult.NewObjectId))
                {
                    continue;
                }

                TfsGitCommit gitCommit = repository.LookupObject(requestContext, refUpdateResult.NewObjectId) as TfsGitCommit;
                if (gitCommit == null)
                {
                    continue;
                }

                string authorEmail = gitCommit.GetAuthorEmail(requestContext);
                if (!AuthorEmail.Any(pattern => Regex.IsMatch(authorEmail, pattern)))
                {
                    result.Fails         = true;
                    result.ReasonCode    = 2;
                    result.ReasonMessage = string.Format(
                        "Author email '{0}' on commit {1} is not admitted",
                        authorEmail,
                        gitCommit.ObjectId.DisplayHash());
                    break;
                }

                string committerEmail = gitCommit.GetCommitterEmail(requestContext);
                if (!CommitterEmail.Any(pattern => Regex.IsMatch(committerEmail, pattern)))
                {
                    result.Fails         = true;
                    result.ReasonCode    = 3;
                    result.ReasonMessage = string.Format(
                        "Committer email '{0}' on commit {1} is not admitted",
                        authorEmail,
                        gitCommit.ObjectId.DisplayHash());
                    break;
                } //if
            }     //for changes

            return(result);
        }
Example #21
0
        public override Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            var result = new Validation();

            long totalSize = 0;

            foreach (var commitId in pushNotification.IncludedCommits)
            {
                TfsGitCommit gitCommit = repository.LookupObject(requestContext, commitId) as TfsGitCommit;
                if (gitCommit == null)
                {
                    continue;
                }

                long size = GetCommitSize(gitCommit, requestContext);
                totalSize += size;
            }//for

            // convert to MB
            totalSize = totalSize / (1024 * 1024);

            if (totalSize < this.Megabytes)
            {
                Logger.Log(string.Format(
                               "Push request is {0} MB, below the {1} MB limit."
                               , totalSize, this.Megabytes
                               , "Limit Size"));
            }
            else
            {
                if (IsUserExempted(requestContext, pushNotification))
                {
                    Logger.Log(string.Format(
                                   "Push request is {0} MB, above or equal to the {1} MB limit, but user is exempted."
                                   , totalSize, this.Megabytes
                                   , "Limit Size"));
                }
                else
                {
                    result.Fails         = true;
                    result.ReasonCode    = 2;
                    result.ReasonMessage = string.Format(
                        "Push request is {0} MB, above or equal to the {1} MB limit: refused."
                        , totalSize, this.Megabytes);
                }
            }//if

            return(result);
        }
        public override Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            var result = new Validation();

            // refuse any push
            result.Fails         = true;
            result.ReasonCode    = 99;
            result.ReasonMessage = string.Format(
                "Repository '{0}' is in read-only mode",
                pushNotification.RepositoryName);

            return(result);
        }
Example #23
0
        public override Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository)
        {
            var result = new Validation();

            bool force = RequiresForcePush(pushNotification, requestContext, repository);

            if (force)
            {
                if (IsUserExempted(requestContext, pushNotification))
                {
                    Logger.Log(string.Format(
                                   "User {0} has explicit permission for {1}"
                                   , pushNotification.AuthenticatedUserName
                                   , "Forced Push"));
                }
                else
                {
                    result.Fails         = true;
                    result.ReasonCode    = 1;
                    result.ReasonMessage = "Force Push policy fails for user " + pushNotification.AuthenticatedUserName + ".";
                } //if
            }     //if

            return(result);
        }
Example #24
0
        public static bool IsForceRequired(this PushNotification pushNotification, TeamFoundationRequestContext requestContext, TfsGitRepository 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(requestContext, refUpdateResult.NewObjectId);
                if (gitObject.ObjectType != GitObjectType.Commit)
                {
                    continue;
                }
                TfsGitCommit gitCommit = (TfsGitCommit)gitObject;

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

            return(false);
        }