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); }
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; }
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); } }
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)); }