public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { statusCode = 0; properties = null; statusMessage = string.Empty; try { if (notificationType == NotificationType.Notification && notificationEventArgs is CheckinNotification) { var checkinNotification = notificationEventArgs as CheckinNotification; if (ShouldMergeItemsIfNecessary(requestContext, checkinNotification)) { var changeset = requestContext.GetChangeset(checkinNotification.Changeset); if (changeset != null) { TfsTeamProjectCollection impersonatedCollection = requestContext.GetImpersonatedCollection(changeset.Committer); MergeWorkItems(impersonatedCollection, changeset.ChangesetId); } } } } catch (Exception ex) { TeamFoundationApplicationCore.LogException("Inmeta.TFS.MergeWorkItemEventHandler encountered an exception", ex); } return EventNotificationStatus.ActionPermitted; }
/// <summary> /// TFS Main Event Handler /// </summary> /// <param name="requestContext">Event context passed in by TFS</param> /// <param name="notificationType">DecisionPoint or Notification</param> /// <param name="notificationEventArgs">Object that was published</param> /// <param name="statusCode">Code to return to the user when a decision point fails</param> /// <param name="statusMessage">Message to return to the user when a decision point fails</param> /// <param name="properties">Properties to return to the user when a decision point fails</param> /// <returns></returns> public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { #region method outputs EventNotificationStatus returnStatus = EventNotificationStatus.ActionPermitted; //allows the action if no other subscribers reject statusCode = 0; properties = null; statusMessage = String.Empty; #endregion try { var ev = notificationEventArgs as WorkItemChangedEvent; if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent) { int thisWorkItemID = getWorkItemID(ev); if (ev.ChangeType == ChangeTypes.New) { //new TFS Work Item created returnStatus = TfsEvent_WorkItemCreated(requestContext, notificationEventArgs, ev.PortfolioProject, thisWorkItemID); } } } catch (Exception exception) { TeamFoundationApplicationCore.LogException("Error processing event", exception); } return returnStatus; }
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { statusCode = 0; properties = null; statusMessage = string.Empty; try { if (notificationType == NotificationType.DecisionPoint && notificationEventArgs is CheckinNotification) { var args = notificationEventArgs as CheckinNotification; if (args.PolicyOverrideInfo.PolicyFailures.Length > 0) { statusMessage = "Policy Overriding is not allowed."; return EventNotificationStatus.ActionDenied; } } return EventNotificationStatus.ActionPermitted; } catch (Exception ex) { // log the error and fail the check in statusMessage = "Error in plugin '" + this.Name + "', error details: " + ex; EventLog.WriteEntry("TFS Service", statusMessage, EventLogEntryType.Error); return EventNotificationStatus.ActionDenied; } }
internal static void InformUserOfFailure(string email , TeamFoundationRequestContext requestContext, PushNotification pushNotification , List<Validation> validationResults) { var buf = new StringBuilder(); buf.AppendFormat("{0}'s {1} request was refused for the following reasons:" , requestContext.GetNameToDisplay() , requestContext.ServiceName ); buf.AppendLine(); buf.AppendLine(); foreach (var res in validationResults.Where(res => res.Fails)) { buf.Append(" - "); buf.AppendLine(res.ReasonMessage); } buf.AppendLine(); buf.AppendLine("Additional information:"); buf.Append(requestContext.GetSummary()); buf.AppendLine(); var message = new MailMessage(); message.From = new MailAddress(PluginConfiguration.Instance.EmailSender); message.To.Add(new MailAddress(email)); message.Subject = "Push refused"; message.Body = buf.ToString(); var smtp = new SmtpClient(PluginConfiguration.Instance.EmailSmtpServer); smtp.Send(message); }
public override async Task NotifyAsync(TeamFoundationRequestContext requestContext, INotification notification, BotElement bot, EventRuleElement matchingRule) { var token = bot.GetSetting("token"); if (string.IsNullOrEmpty(token)) throw new ArgumentException("Missing token!"); var tasks = new List<Task>(); var slackClient = new SlackClient(); foreach (string tfsUserName in notification.TargetUserNames) { var userId = bot.GetMappedUser(tfsUserName); if (userId != null) { Message slackMessage = ToSlackMessage((dynamic)notification, bot, null, true); if (slackMessage != null) { slackMessage.AsUser = true; var t = Task.Run(async () => { var response = await slackClient.SendApiMessageAsync(slackMessage, token, userId); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); }); tasks.Add(t); } } } await Task.WhenAll(tasks); }
public TFSHelper(TeamFoundationRequestContext requestContext, string projectName) { TFSCollection = getTeamProjectCollectionFromRequestContext(requestContext); // TFSCollection.EnsureAuthenticated(); workItemStore = TFSCollection.GetService<WorkItemStore>(); teamProject = workItemStore.Projects[projectName]; }
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); }
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; }
long GetCommitSize(TfsGitCommit gitCommit, TeamFoundationRequestContext requestContext) { var tree = gitCommit.GetTree(requestContext); if (tree == null) return 0; long totalSize = tree.GetBlobs(requestContext).Aggregate( 0L, (size, blob) => size + blob.GetLength(requestContext)); return totalSize; }
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 void LeaveMethod(TeamFoundationRequestContext requestContext) { //Log(String.Format("LeaveMethod: {0} ({1})", requestContext.Method.Name, requestContext.Method.MethodType)); //Log("Status: " + requestContext.Status.GetType()); //foreach (var key in requestContext.Method.Parameters.AllKeys) //{ // Log(String.Format("{0} : {1}", key, requestContext.Method.Parameters[key])); //} //foreach (var key in requestContext.Items.Keys) //{ // Log(String.Format("{0} :: {1}", key, requestContext.Items[key].GetType())); //} }
protected bool IsUserExempted(TeamFoundationRequestContext requestContext, PushNotification pushNotification) { string collectionUrl = requestContext.GetCollectionUri(); // client API TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri(collectionUrl)); var identityManagement = tfs.GetService<IIdentityManagementService>(); var requestIdentity = identityManagement.ReadIdentity(IdentitySearchFactor.AccountName, pushNotification.AuthenticatedUserName, MembershipQuery.Direct, ReadIdentityOptions.None); bool exempted = false; foreach (var groupName in this.Groups) { var groupIdentity = identityManagement.ReadIdentity(IdentitySearchFactor.AccountName, groupName, MembershipQuery.Direct, ReadIdentityOptions.None); exempted |= identityManagement.IsMember(groupIdentity.Descriptor, requestIdentity.Descriptor); }//for return exempted; }
public async Task NotifyAsync(TeamFoundationRequestContext requestContext, INotification notification, BotElement bot, EventRuleElement matchingRule) { string room = bot.GetSetting("room"); string baseUrl = bot.GetSetting("apiBaseUrl"); string authToken = bot.GetSetting("roomNotificationToken"); var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken); string json = ToJson((dynamic)notification, bot); var content = new StringContent(json, Encoding.UTF8, "application/json"); string url = baseUrl + "/room/" + room + "/notification"; requestContext.Trace(0, TraceLevel.Verbose, Constants.TraceArea, "HipChatNotifier", "Sending notification to {0}\n{1}", url, json); await httpClient.PostAsync(url, content).ContinueWith(t => t.Result.EnsureSuccessStatusCode()); }
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 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 EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out Microsoft.TeamFoundation.Common.ExceptionPropertyCollection properties) { statusCode = 0; properties = null; statusMessage = string.Empty; try { if (notificationType == NotificationType.Notification && notificationEventArgs is CheckinNotification) { CheckinNotification args = notificationEventArgs as CheckinNotification; NumberParser numberParser = new NumberParser(); WorkItemStore workItemStore = WorkItemStoreFactory.GetWorkItemStore(GetTFSUri(requestContext)); VersionControlServer service = workItemStore.TeamProjectCollection.GetService<VersionControlServer>(); Changeset changeset = service.GetChangeset(args.Changeset); foreach (int workItemID in numberParser.Parse(args.Comment)) { var workItem = workItemStore.GetWorkItem(workItemID); if (workItem != null) { //now create the link ExternalLink changesetLink = new ExternalLink( workItemStore.RegisteredLinkTypes[ArtifactLinkIds.Changeset], changeset.ArtifactUri.AbsoluteUri); //you should verify if such a link already exists if (!workItem.Links.OfType<ExternalLink>() .Any(l => l.LinkedArtifactUri == changeset.ArtifactUri.AbsoluteUri)) { workItem.Links.Add(changesetLink); workItem.Save(); } } } } return EventNotificationStatus.ActionPermitted; } catch (Exception ex) { // log the error and fail the check in statusMessage = "Error in plugin '" + Name + "', error details: " + ex.ToString(); EventLog.WriteEntry("TFS Service", statusMessage, EventLogEntryType.Error); return EventNotificationStatus.ActionDenied; } }
internal static void LogEvent(TeamFoundationRequestContext requestContext, string message, LogEventInformationLevel informationLevel) { switch (informationLevel) { case LogEventInformationLevel.Information: TeamFoundationTrace.Info(message); break; case LogEventInformationLevel.Warning: TeamFoundationTrace.Warning(message); TeamFoundationApplicationCore.Log(requestContext, message, TeamFoundationEventId.WarehouseErrorsBaseEventId, System.Diagnostics.EventLogEntryType.Warning); break; case LogEventInformationLevel.Error: TeamFoundationTrace.Error(message); TeamFoundationApplicationCore.Log(requestContext, message, TeamFoundationEventId.WarehouseErrorsBaseEventId, System.Diagnostics.EventLogEntryType.Error); break; } }
public async Task NotifyAsync(TeamFoundationRequestContext requestContext, INotification notification, BotElement bot, EventRuleElement matchingRule) { var channels = bot.GetCsvSetting("channels"); var tasks = new List<Task>(); var slackClient = new SlackClient(); foreach (string channel in channels) { Message slackMessage = ToSlackMessage((dynamic)notification, bot, channel); if (slackMessage != null) { tasks.Add(slackClient.SendMessageAsync(slackMessage, bot.GetSetting("webhookUrl")).ContinueWith(t => t.Result.EnsureSuccessStatusCode())); } } await Task.WhenAll(tasks); }
protected EventNotificationStatus TfsEvent_WorkItemCreated(TeamFoundationRequestContext requestContext, object notificationEventArgs, string TFSProjectName,int TFSworkItemID) { TFSHelper tfs = new TFSHelper(requestContext, TFSProjectName); if (TFSworkItemID > 0) { Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem thisWorkItem = tfs.getWorkItem(TFSworkItemID); if ((thisWorkItem != null)) { if (tfs.isWorkItemEligibleForClone(thisWorkItem)) { Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem templateWorkItem = tfs.getTemplateForWorkItem(thisWorkItem); if (templateWorkItem != null) tfs.createChildWorkItems(thisWorkItem, templateWorkItem); } } else { throw new System.Exception(string.Format(Resources.errorMessages.UNABLETOGET_WORKITEM, TFSworkItemID.ToString())); } } else {throw new System.ArgumentException(String.Format(Resources.errorMessages.ERROR_INVALID_WORK_ITEMID, TFSworkItemID.ToString()));} return EventNotificationStatus.ActionPermitted; //allows the action if no other subscribers reject. }
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; }
public static bool IsDescendantOf(this TfsGitCommit commit, TeamFoundationRequestContext requestContext, byte[] ancestorId) { Queue<TfsGitCommit> q = new Queue<TfsGitCommit>(); HashSet<byte[]> visited = new HashSet<byte[]>(new ByteArrayComparer()); q.Enqueue(commit); while (q.Count > 0) { TfsGitCommit current = q.Dequeue(); if (!visited.Add(current.ObjectId)) continue; if (current.ObjectId.SequenceEqual(ancestorId)) return true; foreach (var c in current.GetParents(requestContext)) q.Enqueue(c); } return false; }
/// <summary> /// This is the one where all the magic starts. Main() so to speak. I will load the settings, connect to tfs and apply the aggregation rules. /// </summary> public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { statusCode = 0; properties = null; statusMessage = String.Empty; int currentAggregationId = 0; int workItemId = 0; string currentAggregationName = string.Empty; try { if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent) { // Change this object to be a type we can easily get into WorkItemChangedEvent ev = notificationEventArgs as WorkItemChangedEvent; // Connect to the setting file and load the location of the TFS server string tfsUri = TFSAggregatorSettings.TFSUri; // Connect to TFS so we are ready to get and send data. Store store = new Store(tfsUri); // Get the id of the work item that was just changed by the user. workItemId = ev.CoreFields.IntegerFields[0].NewValue; // Download the work item so we can update it (if needed) WorkItem eventWorkItem = store.Access.GetWorkItem(workItemId); string workItemTypeName = eventWorkItem.Type.Name; List <WorkItem> workItemsToSave = new List <WorkItem>(); if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("Change detected to {0} [{1}]", workItemTypeName, workItemId)); MiscHelpers.LogMessage(String.Format("{0}Processing {1} AggregationItems", " ", TFSAggregatorSettings.ConfigAggregatorItems.Count.ToString())); } // Apply the aggregation rules to the work item foreach (ConfigAggregatorItem configAggregatorItem in TFSAggregatorSettings.ConfigAggregatorItems) { IEnumerable <WorkItem> sourceWorkItems = null; WorkItem targetWorkItem = null; currentAggregationName = configAggregatorItem.Name; // Check to make sure that the rule applies to the work item type we have if (eventWorkItem.Type.Name == configAggregatorItem.WorkItemType) { if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}[Entry {2}] Aggregation '{3}' applies to {1} work items", " ", workItemTypeName, currentAggregationId, currentAggregationName)); } // Use the link type to see what the work item we are updating is if (configAggregatorItem.LinkType == ConfigLinkTypeEnum.Self) { // We are updating the same workitem that was sent in the event. sourceWorkItems = new List <WorkItem> { eventWorkItem }; targetWorkItem = eventWorkItem; if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}{0}{0}Aggregation applies to SELF. ({1} {2})", " ", workItemTypeName, workItemId)); } // Make sure that all conditions are true before we do the aggregation // If any fail then we don't do this aggregation. if (!configAggregatorItem.Conditions.AreAllConditionsMet(targetWorkItem)) { if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for aggregation are not met.", " ")); } currentAggregationId++; continue; } if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for aggregation are met.", " ")); } } // We are aggregating to the parent else if (configAggregatorItem.LinkType == ConfigLinkTypeEnum.Parent) { bool parentLevelFound = true; // Go up the tree till we find the level of parent that we are looking for. WorkItem iterateToParent = eventWorkItem; for (int i = 0; i < configAggregatorItem.LinkLevel; i++) { // Load the parent from the saved list (if we have it in there) or just load it from the store. WorkItem nullCheck = iterateToParent.GetParentFromListOrStore(workItemsToSave, store); // if (nullCheck != null) { iterateToParent = nullCheck; } else { parentLevelFound = false; } } // If we did not find the correct parent then we are done with this aggregation. if (!parentLevelFound) { if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}{0}{0}Couldn't find a PARENT {2} {4} up from {3} [{1}]. This aggregation will not continue.", " ", workItemId, configAggregatorItem.LinkLevel, workItemTypeName, configAggregatorItem.LinkLevel > 1 ? "levels" : "level")); } currentAggregationId++; continue; } if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}{0}{0}Found {1} [{2}] {3} {4} up from {5} [{6}]. Aggregation continues.", " ", iterateToParent.Type.Name, iterateToParent.Id, configAggregatorItem.LinkLevel, configAggregatorItem.LinkLevel > 1 ? "levels" : "level", workItemTypeName, workItemId)); } targetWorkItem = iterateToParent; // Make sure that all conditions are true before we do the aggregation // If any fail then we don't do this aggregation. if (!configAggregatorItem.Conditions.AreAllConditionsMet(targetWorkItem)) { if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for parent aggregation are not met", " ")); } currentAggregationId++; continue; } if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for parent aggregation are met", " ")); } // Get the children down how ever many link levels were specified. List <WorkItem> iterateFromParents = new List <WorkItem> { targetWorkItem }; for (int i = 0; i < configAggregatorItem.LinkLevel; i++) { List <WorkItem> thisLevelOfKids = new List <WorkItem>(); // Iterate all the parents to find the children of current set of parents foreach (WorkItem iterateFromParent in iterateFromParents) { thisLevelOfKids.AddRange(iterateFromParent.GetChildrenFromListOrStore(workItemsToSave, store)); } iterateFromParents = thisLevelOfKids; } // remove the kids that are not the right type that we are working with ConfigAggregatorItem configAggregatorItemClosure = configAggregatorItem; iterateFromParents.RemoveAll(x => x.Type.Name != configAggregatorItemClosure.WorkItemType); sourceWorkItems = iterateFromParents; } // Do the actual aggregation now bool changeMade = Aggregator.Aggregate(sourceWorkItems, targetWorkItem, configAggregatorItem); // If we made a change then add this work item to the list of items to save. if (changeMade) { // Add the target work item to the list of work items to save. workItemsToSave.AddIfUnique(targetWorkItem); } } else { if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}[Entry {2}] Aggregation '{3}' does not apply to {1} work items", " ", workItemTypeName, currentAggregationId, currentAggregationName)); } } currentAggregationId++; } // Save any changes to the target work items. workItemsToSave.ForEach(x => { bool isValid = x.IsValid(); if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}{0}{0}{1} [{2}] {3} valid to save. {4}", " ", x.Type.Name, x.Id, isValid ? "IS" : "IS NOT", String.Format("\n{0}{0}{0}{0}Invalid fields: {1}", " ", MiscHelpers.GetInvalidWorkItemFieldsList(x).ToString()))); } if (isValid) { x.PartialOpen(); x.Save(); } }); MiscHelpers.AddRunSeparatorToLog(); } } catch (Exception e) { string message = String.Format("Exception encountered processing Work Item [{2}]: {0} \nStack Trace:{1}", e.Message, e.StackTrace, workItemId); if (e.InnerException != null) { message += String.Format("\n Inner Exception: {0} \nStack Trace:{1}", e.InnerException.Message, e.InnerException.StackTrace); } MiscHelpers.LogMessage(message, true); } return(EventNotificationStatus.ActionPermitted); }
/// <summary> /// Shortcut for tracing - could be refactored further /// </summary> /// <param name="requestContext"></param> /// <param name="message"></param> /// <param name="args"></param> private void Trace(TeamFoundationRequestContext requestContext, string message, params object[] args) { requestContext.Trace(0, TraceLevel.Verbose, Constants.TraceArea, this.GetType().Name, message, args); }
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, CreatorUniqueName = 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 = $"{repoUri}/pullrequest/{ev.PullRequestId}#view=discussion", 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 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); }
protected abstract IEnumerable <INotification> CreateNotifications(TeamFoundationRequestContext requestContext, T notificationEventArgs, int maxLines);
public void BeginRequest(TeamFoundationRequestContext requestContext) { }
public void EndRequest(TeamFoundationRequestContext requestContext) { }
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 void RequestReady(TeamFoundationRequestContext requestContext) { }
public abstract Validation CheckRule(TeamFoundationRequestContext requestContext, PushNotification pushNotification, TfsGitRepository repository);
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.DecisionPoint && notificationEventArgs is PushNotification) { PushNotification pushNotification = notificationEventArgs as PushNotification; // validation applies? var policy = GetPolicy(requestContext, pushNotification); if (policy != null) { Logger.LogStart("Request controlled by policy"); var gitRepoService = requestContext.GetService<TeamFoundationGitRepositoryService>(); using (var repository = gitRepoService.FindRepositoryById(requestContext, pushNotification.RepositoryId)) { Logger.LogRequest(requestContext, pushNotification, repository); var validationResults = policy.CheckRules(requestContext, pushNotification, repository); //TODO accumulate failures var failsAt = validationResults.FirstOrDefault(v => v.Fails); if (failsAt != null) { if (PluginConfiguration.Instance.ShouldSendEmail) { try { string email = GetEmailAddress(requestContext, pushNotification); if (string.IsNullOrWhiteSpace(email)) // no email for user -> notify admin email = PluginConfiguration.Instance.AdministratorEmail; UserAlerter.InformUserOfFailure(email, requestContext, pushNotification, validationResults); } catch (Exception e) { Logger.Log(string.Format("Error: failed to notify user {0}, reason {1}", pushNotification.AuthenticatedUserName, e.Message)); }//try }//if Logger.LogDenied(failsAt.ReasonMessage); statusCode = failsAt.ReasonCode; statusMessage = failsAt.ReasonMessage; return EventNotificationStatus.ActionDenied; }//if }//using }//if }//if } catch (Exception ex) { Logger.LogException(ex); throw; // TFS will disable plugin }//try /* * from https://msdn.microsoft.com/en-us/library/Gg214903%28v=vs.120%29.aspx * ActionDenied Action denied; do not notify other subscribers. * ActionPermitted Action permitted; continue with subscriber notification. * ActionApproved Like ActionPermitted, but do not notify other subscribers. */ return EventNotificationStatus.ActionPermitted; }
private bool ShouldMergeItemsIfNecessary( TeamFoundationRequestContext requestContext, CheckinNotification checkinNotification) { if (checkinNotification.Comment != null && checkinNotification.Comment.IndexOf("***NO_PBI***", StringComparison.OrdinalIgnoreCase) >= 0) { return false; } return true; }
public RequestContextWrapper(TeamFoundationRequestContext context) { this.context = context; }
protected override IEnumerable <INotification> CreateNotifications(TeamFoundationRequestContext requestContext, object notificationEventArgs, int maxLines) { return(CreateNotifications(requestContext, (T)notificationEventArgs, maxLines)); }
public static string GetCollectionUri(this TeamFoundationRequestContext requestContext) { TeamFoundationLocationService service = requestContext.GetService <TeamFoundationLocationService>(); return(service.GetHostLocation(requestContext, service.GetPublicAccessMapping(requestContext, service.CurrentServiceOwner))); }
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); }
protected override IEnumerable <INotification> CreateNotifications(TeamFoundationRequestContext requestContext, WorkItemChangedEvent ev, int maxLines) { var notifications = new List <INotification>(); var identityService = requestContext.GetService <TeamFoundationIdentityService>(); var identity = identityService.ReadIdentity(requestContext, IdentitySearchFactor.Identifier, ev.ChangerSid); if (ev.CoreFields == null) { throw new TfsNotificationRelayException("ev.CoreFields is null"); } if (ev.CoreFields.StringFields == null) { throw new TfsNotificationRelayException("ev.CoreFields.StringFields is null"); } if (ev.CoreFields.IntegerFields == null) { throw new TfsNotificationRelayException("ev.CoreFields.IntegerFields is null"); } var typeField = ev.CoreFields.StringFields.SingleOrDefault(f => f.ReferenceName == "System.WorkItemType"); if (typeField == null) { throw new TfsNotificationRelayException("missing System.WorkItemType"); } string type = typeField.NewValue; var idField = ev.CoreFields.IntegerFields.Single(f => f.ReferenceName == "System.Id"); if (idField == null) { throw new TfsNotificationRelayException("missing System.Id"); } int id = idField.NewValue; var assignedTo = ev.CoreFields.StringFields.GetFieldValue("System.AssignedTo", f => f.NewValue); string assignedToUserName = null; if (!string.IsNullOrEmpty(assignedTo)) { var assignedToIdentity = identityService.ReadIdentity(requestContext, IdentitySearchFactor.DisplayName, assignedTo); if (assignedToIdentity != null) { assignedToUserName = assignedToIdentity.UniqueName; } } var teamNames = GetUserTeamsByProjectUri(requestContext, ev.ProjectNodeId, identity.Descriptor); if (ev.TextFields != null) { var comment = ev.TextFields.FirstOrDefault(f => f.ReferenceName == "System.History" && !String.IsNullOrEmpty(f.Value)); if (comment != null) { var commentNotification = new WorkItemCommentNotification() { TeamProjectCollection = requestContext.ServiceHost.Name, UniqueName = identity.UniqueName, DisplayName = identity.DisplayName, WiUrl = ev.DisplayUrl, WiType = type, WiId = id, WiTitle = ev.WorkItemTitle, ProjectName = ev.PortfolioProject, AreaPath = ev.AreaPath, AssignedTo = assignedTo, AssignedToUserName = assignedToUserName, CommentHtml = comment.Value, Comment = TextHelper.HtmlToText(comment.Value), TeamNames = teamNames }; notifications.Add(commentNotification); } } var changeNotification = new WorkItemChangedNotification() { TeamProjectCollection = requestContext.ServiceHost.Name, IsNew = ev.ChangeType == ChangeTypes.New, UniqueName = identity.UniqueName, DisplayName = identity.DisplayName, WiUrl = ev.DisplayUrl, WiType = type, WiId = id, WiTitle = ev.WorkItemTitle, ProjectName = ev.PortfolioProject, AreaPath = ev.AreaPath, IsStateChanged = ev.ChangedFields != null && ev.ChangedFields.StringFields != null && ev.ChangedFields.StringFields.Any(f => f.ReferenceName == "System.State"), IsAssignmentChanged = ev.ChangedFields != null && ev.ChangedFields.StringFields != null && ev.ChangedFields.StringFields.Any(f => f.ReferenceName == "System.AssignedTo"), State = ev.CoreFields.StringFields.GetFieldValue("System.State", f => f.NewValue), AssignedTo = assignedTo, AssignedToUserName = assignedToUserName, CoreFields = ev.CoreFields, ChangedFields = ev.ChangedFields, TeamNames = teamNames }; notifications.Add(changeNotification); return(notifications); }
protected override void Execute(CodeActivityContext context) { TeamFoundationRequestContext requestContextCollection = context.GetValue(this.RequestContext); string argToAdress = context.GetValue(this.ToAdress); string argSubject = context.GetValue(this.Subject); bool argIsBodyHtml = context.GetValue(this.IsBodyHtml); string argBody = context.GetValue(this.Body); // services on the configuration #if UsingOrganizationServiceHost TeamFoundationRequestContext requestContextConfiguration = requestContextCollection.ServiceHost.OrganizationServiceHost.CreateServicingContext(); #else TeamFoundationRequestContext requestContextConfiguration = requestContextCollection.ServiceHost.ApplicationServiceHost.CreateServicingContext(); #endif TeamFoundationRegistryService srvRegistryConfiguration = requestContextConfiguration.GetService <TeamFoundationRegistryService>(); // read the parameters from TFS registry var arrRegEntries = srvRegistryConfiguration.ReadEntries(requestContextConfiguration, "/Service/Integration/Settings/*").ToArray(); var keyvalues = new List <string>() { "EmailEnabled", "EmailNotificationFromAddress", // "SmtpAnonymousAuth", "SmtpCertThumbprint", "SmtpEnableSsl", "SmtpPassword", "SmtpPort", "SmtpServer", "SmtpUser" }.Select(name => { string path = "/Service/Integration/Settings/" + name; string value = null; try { // value = srvRegistryConfiguration.ReadEntries(requestContextConfiguration, path).First().Value; value = arrRegEntries.Where(regEntry => regEntry.Name == name).Select(regEntry => regEntry.Value).FirstOrDefault(); } catch (Exception e) { this.LogInfo(string.Format("registry value '{0}' not found", path)); this.LogInfo(e.Message); } return(new { key = name, value = value }); }); // dispose the request context requestContextConfiguration.Dispose(); foreach (var keyvalue in keyvalues) { if (keyvalue.value == null) { this.LogInfo(string.Format("registry value '{0}' not found", keyvalue.key)); } } bool TfsEmailEnabled = bool.Parse(keyvalues.Where(kv => kv.key == "EmailEnabled").First().value); if (!TfsEmailEnabled) { this.LogInfo(string.Format("TFS Email Alter Settings are disabled")); return; } string TfsSmtpServer = keyvalues.Where(kv => kv.key == "SmtpServer").First().value; int TfsSmtpPort = int.Parse(keyvalues.Where(kv => kv.key == "SmtpPort").First().value); string TfsEmailNotificationFromAddress = keyvalues.Where(kv => kv.key == "EmailNotificationFromAddress").First().value; string TfsSmtpUser = keyvalues.Where(kv => kv.key == "SmtpUser").First().value; string TfsSmtpPassword = keyvalues.Where(kv => kv.key == "SmtpPassword").First().value; this.LogInfo(string.Format("TFS SmptServer: {0}:{1}", TfsSmtpServer, TfsSmtpPort)); this.LogInfo(string.Format("TFS SmptUser: {0} (from address: {1})", TfsSmtpUser, TfsEmailNotificationFromAddress)); // setup connection to the SMTP host. SmtpClient client = new SmtpClient(TfsSmtpServer, TfsSmtpPort); if (string.IsNullOrWhiteSpace(TfsSmtpUser)) { client.UseDefaultCredentials = true; } else { client.Credentials = new System.Net.NetworkCredential(TfsSmtpUser, TfsSmtpPassword); } // Specify the e-mail sender. // Create a mailing address that includes a UTF8 character // in the display name. MailAddress from = new MailAddress(TfsEmailNotificationFromAddress, TfsEmailNotificationFromAddress); // Set destinations for the e-mail message. MailAddress to = new MailAddress(argToAdress); // Specify the message content. MailMessage message = new MailMessage(from, to); message.Subject = argSubject; message.SubjectEncoding = System.Text.Encoding.UTF8; message.Body = argBody; message.BodyEncoding = System.Text.Encoding.UTF8; message.IsBodyHtml = argIsBodyHtml; // send the mail client.Send(message); }
protected override IEnumerable <Notifications.INotification> CreateNotifications(TeamFoundationRequestContext requestContext, PullRequestCreatedNotification 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.Creator.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.PullRequestCreatedNotification() { TeamProjectCollection = requestContext.ServiceHost.Name, 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.Creator) }; yield return(notification); } else { throw new TfsNotificationRelayException("Unable to get pull request " + ev.PullRequestId); } } }
protected override Notifications.INotification CreateNotification(TeamFoundationRequestContext requestContext, object eventargs, int maxLines) { Logger.Log("eventargs: " + JObject.FromObject(eventargs).ToString()); throw new Tfs2SlackException("DebugHandler"); }
private string GetEmailAddress(TeamFoundationRequestContext requestContext, PushNotification pushNotification) { var collectionUrl = new Uri(requestContext.GetCollectionUri()); var collection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(collectionUrl); var managementService = collection.GetService<IIdentityManagementService>(); TeamFoundationIdentity teamFoundationIdentity = managementService.ReadIdentity( IdentitySearchFactor.AccountName, pushNotification.AuthenticatedUserName, MembershipQuery.None, ReadIdentityOptions.None); return teamFoundationIdentity.GetAttribute("Mail", null); }
TfsTeamProjectCollection getTeamProjectCollectionFromRequestContext(TeamFoundationRequestContext requestContext) { //todo: Avoid hardcoding credentials. System.Net.ICredentials cred = new System.Net.NetworkCredential("John", "cheese"); IdentityDescriptor id; requestContext.GetAuthenticatedIdentity(out id); //ICredentialsProvider c = requestContext.GetAuthenticatedIdentity TeamFoundationLocationService service = requestContext.GetService<TeamFoundationLocationService>(); Uri selfReferenceUri = service.GetSelfReferenceUri(requestContext, service.GetDefaultAccessMapping(requestContext)); return new TfsTeamProjectCollection(selfReferenceUri, cred); }
private Policy GetPolicy(TeamFoundationRequestContext requestContext, PushNotification pushNotification) { // HACK string collectionName = requestContext.ServiceHost.VirtualDirectory.Replace("/tfs/", "").Replace("/", ""); // HACK is this cheap? var commonService = requestContext.GetService<CommonStructureService>(); string projectName = commonService.GetProject(requestContext, pushNotification.TeamProjectUri).Name; string repositoryName = pushNotification.RepositoryName; foreach (var policy in PluginConfiguration.Instance.Policies) { if (policy.AppliesTo(collectionName, projectName, repositoryName)) return policy; }//for return null; }
public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { properties = null; statusCode = 0; statusMessage = null; if (notificationType != NotificationType.DecisionPoint) { return(EventNotificationStatus.ActionApproved); } var notification = notificationEventArgs as PullRequestNotification; if (notification != null) { var gitPullRequestService = requestContext.GetService <TeamFoundationGitPullRequestService>(); var gitrepositoryService = requestContext.GetService <TeamFoundationGitRepositoryService>(); var pullRequest = gitPullRequestService.GetPullRequestDetails(requestContext, notification.PullRequestId); var repository = gitrepositoryService.FindRepositoryById(requestContext, pullRequest.RepositoryId); var reviews = pullRequest.Reviewers.ToList(); reviews.Add(new TfsGitPullRequest.ReviewerWithVote(new Guid(), 4, ReviewerVoteStatus.Rejected)); gitPullRequestService.UpdatePullRequest(requestContext, repository, pullRequest.PullRequestId, pullRequest.Status, pullRequest.Title, pullRequest.Description, reviews); var messageBuilder = new StringBuilder(); messageBuilder.AppendFormat(DateTime.Now.ToShortTimeString()); messageBuilder.Append(" : "); messageBuilder.AppendFormat(@"PullRequestId = {0}", pullRequest.PullRequestId); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"MergeId = {0}", pullRequest.MergeId); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"PullRequestId = {0}", pullRequest.SourceBranchName); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"SourceBranchName = {0}", pullRequest.TargetBranchName); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"LastMergeCommit = {0}", pullRequest.LastMergeCommit); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"LastMergeSourceCommit = {0}", pullRequest.LastMergeSourceCommit); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"LastMergeTargetCommit = {0}", pullRequest.LastMergeTargetCommit); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"Status = {0}", pullRequest.Status); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"Title = {0}", pullRequest.Title); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"MergeStatus = {0}", pullRequest.MergeStatus); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"CompleteWhenMergedAuthority = {0}", pullRequest.CompleteWhenMergedAuthority); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"Description = {0}", pullRequest.Description); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"Creator = {0}", pullRequest.Creator); messageBuilder.AppendLine(); messageBuilder.AppendFormat(@"CreationDate = {0}", pullRequest.CreationDate); messageBuilder.AppendLine(); messageBuilder.AppendLine("=========================================================="); File.AppendAllText(@"C:\TMP\NPTV_TEST_LOG.txt", messageBuilder.ToString()); } return(EventNotificationStatus.ActionApproved); }
protected override INotification CreateNotification(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); 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); 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) }); } return(notification); } }
/// <summary> /// This is the one where all the magic starts. Main() so to speak. I will load the settings, connect to tfs and apply the aggregation rules. /// </summary> public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties) { statusCode = 0; properties = null; statusMessage = String.Empty; int currentAggregationId = 0; int workItemId = 0; string currentAggregationName = string.Empty; try { if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent) { // Change this object to be a type we can easily get into WorkItemChangedEvent ev = notificationEventArgs as WorkItemChangedEvent; // Connect to the setting file and load the location of the TFS server string tfsUri = TFSAggregatorSettings.TFSUri; // Connect to TFS so we are ready to get and send data. Store store = new Store(tfsUri); // Get the id of the work item that was just changed by the user. workItemId = ev.CoreFields.IntegerFields[0].NewValue; // Download the work item so we can update it (if needed) WorkItem eventWorkItem = store.Access.GetWorkItem(workItemId); string workItemTypeName = eventWorkItem.Type.Name; List<WorkItem> workItemsToSave = new List<WorkItem>(); if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("Change detected to {0} [{1}]", workItemTypeName, workItemId)); MiscHelpers.LogMessage(String.Format("{0}Processing {1} AggregationItems", " ", TFSAggregatorSettings.ConfigAggregatorItems.Count.ToString())); } // Apply the aggregation rules to the work item foreach (ConfigAggregatorItem configAggregatorItem in TFSAggregatorSettings.ConfigAggregatorItems) { IEnumerable<WorkItem> sourceWorkItems = null; WorkItem targetWorkItem = null; currentAggregationName = configAggregatorItem.Name; // Check to make sure that the rule applies to the work item type we have if (eventWorkItem.Type.Name == configAggregatorItem.WorkItemType) { if (TFSAggregatorSettings.LoggingIsEnabled) MiscHelpers.LogMessage(String.Format("{0}[Entry {2}] Aggregation '{3}' applies to {1} work items", " ", workItemTypeName, currentAggregationId, currentAggregationName)); // Use the link type to see what the work item we are updating is if (configAggregatorItem.LinkType == ConfigLinkTypeEnum.Self) { // We are updating the same workitem that was sent in the event. sourceWorkItems = new List<WorkItem> {eventWorkItem}; targetWorkItem = eventWorkItem; if (TFSAggregatorSettings.LoggingIsEnabled) MiscHelpers.LogMessage(String.Format("{0}{0}{0}Aggregation applies to SELF. ({1} {2})", " ", workItemTypeName, workItemId)); // Make sure that all conditions are true before we do the aggregation // If any fail then we don't do this aggregation. if (!configAggregatorItem.Conditions.AreAllConditionsMet(targetWorkItem)) { if (TFSAggregatorSettings.LoggingIsEnabled) MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for aggregation are not met.", " ")); currentAggregationId++; continue; } if (TFSAggregatorSettings.LoggingIsEnabled) MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for aggregation are met.", " ")); } // We are aggregating to the parent else if (configAggregatorItem.LinkType == ConfigLinkTypeEnum.Parent) { bool parentLevelFound = true; // Go up the tree till we find the level of parent that we are looking for. WorkItem iterateToParent = eventWorkItem; for (int i = 0; i < configAggregatorItem.LinkLevel; i++) { // Load the parent from the saved list (if we have it in there) or just load it from the store. WorkItem nullCheck = iterateToParent.GetParentFromListOrStore(workItemsToSave, store); // if (nullCheck != null) { iterateToParent = nullCheck; } else parentLevelFound = false; } // If we did not find the correct parent then we are done with this aggregation. if (!parentLevelFound) { if (TFSAggregatorSettings.LoggingIsEnabled) MiscHelpers.LogMessage(String.Format("{0}{0}{0}Couldn't find a PARENT {2} {4} up from {3} [{1}]. This aggregation will not continue.", " ", workItemId, configAggregatorItem.LinkLevel, workItemTypeName, configAggregatorItem.LinkLevel > 1 ? "levels" : "level")); currentAggregationId++; continue; } if (TFSAggregatorSettings.LoggingIsEnabled) MiscHelpers.LogMessage(String.Format("{0}{0}{0}Found {1} [{2}] {3} {4} up from {5} [{6}]. Aggregation continues.", " ", iterateToParent.Type.Name, iterateToParent.Id, configAggregatorItem.LinkLevel, configAggregatorItem.LinkLevel > 1 ? "levels" : "level", workItemTypeName, workItemId)); targetWorkItem = iterateToParent; // Make sure that all conditions are true before we do the aggregation // If any fail then we don't do this aggregation. if (!configAggregatorItem.Conditions.AreAllConditionsMet(targetWorkItem)) { if (TFSAggregatorSettings.LoggingIsEnabled) MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for parent aggregation are not met", " ")); currentAggregationId++; continue; } if (TFSAggregatorSettings.LoggingIsEnabled) MiscHelpers.LogMessage(String.Format("{0}{0}All conditions for parent aggregation are met", " ")); // Get the children down how ever many link levels were specified. List<WorkItem> iterateFromParents = new List<WorkItem> {targetWorkItem}; for (int i = 0; i < configAggregatorItem.LinkLevel; i++) { List<WorkItem> thisLevelOfKids = new List<WorkItem>(); // Iterate all the parents to find the children of current set of parents foreach (WorkItem iterateFromParent in iterateFromParents) { thisLevelOfKids.AddRange(iterateFromParent.GetChildrenFromListOrStore(workItemsToSave, store)); } iterateFromParents = thisLevelOfKids; } // remove the kids that are not the right type that we are working with ConfigAggregatorItem configAggregatorItemClosure = configAggregatorItem; iterateFromParents.RemoveAll(x => x.Type.Name != configAggregatorItemClosure.WorkItemType); sourceWorkItems = iterateFromParents; } // Do the actual aggregation now bool changeMade = Aggregator.Aggregate(sourceWorkItems, targetWorkItem, configAggregatorItem); // If we made a change then add this work item to the list of items to save. if (changeMade) { // Add the target work item to the list of work items to save. workItemsToSave.AddIfUnique(targetWorkItem); } } else { if (TFSAggregatorSettings.LoggingIsEnabled) MiscHelpers.LogMessage(String.Format("{0}[Entry {2}] Aggregation '{3}' does not apply to {1} work items", " ", workItemTypeName, currentAggregationId, currentAggregationName)); } currentAggregationId++; } // Save any changes to the target work items. workItemsToSave.ForEach(x => { bool isValid = x.IsValid(); if (TFSAggregatorSettings.LoggingIsEnabled) { MiscHelpers.LogMessage(String.Format("{0}{0}{0}{1} [{2}] {3} valid to save. {4}", " ", x.Type.Name, x.Id, isValid ? "IS" : "IS NOT", String.Format("\n{0}{0}{0}{0}Invalid fields: {1}", " ", MiscHelpers.GetInvalidWorkItemFieldsList(x).ToString()))); } if (isValid) { x.PartialOpen(); x.Save(); } }); MiscHelpers.AddRunSeparatorToLog(); } } catch (Exception e) { string message = String.Format("Exception encountered processing Work Item [{2}]: {0} \nStack Trace:{1}", e.Message, e.StackTrace, workItemId); if (e.InnerException != null) { message += String.Format("\n Inner Exception: {0} \nStack Trace:{1}", e.InnerException.Message, e.InnerException.StackTrace); } MiscHelpers.LogMessage(message, true); } return EventNotificationStatus.ActionPermitted; }
public static Uri GetTFSUri(TeamFoundationRequestContext requestContext) { return new Uri(requestContext.GetService<TeamFoundationLocationService>().GetServerAccessMapping(requestContext).AccessPoint.Replace("localhost", Environment.MachineName) + "/" + requestContext.ServiceHost.Name); }
protected abstract INotification CreateNotification(TeamFoundationRequestContext requestContext, T notificationEventArgs, int maxLines);