Share via


Creating Code Review Request in TFS Automation

Code Review Request Automation is for developers and teams that want control their check-ins and create code review requests for specified projects, users and file & path patterns. For example when you checked-in a Java Script file in the specific folder you can create a request to a TFS User. So Request Viewer will be able to check the changes in the source file and interpret them. Solution has 2 project, one contains custom policy source code and other one contains a Visual Studio Installer Package (Vsix). When you build the projects and create the Vsix package you will be able to run it. and When you run it, So you have to add custom policy in this tab and then click Edit button. Here you can select the project, area path, user to be assigned and affected source control paths in Regex format.

The most of Work is done a virtual method Evaluate in the class derived from class PolicyBase. It checks and eveluate checkin operations  in TFS during checkins. So we need write necessary codes here. It needs an extra parameter set outside also.Because we would like to specify the tfs uri, project name , Tfs users and source paths as parametric. Finally I added a form class so that I could pass policy base class to parameter window and I got filled parameters from parameter window.

In the method Evaluate and event PendingChanges_CheckedPendingChangesChanged, I'm determining if check-in operation was completed and then I'm creating a code review request according by parameters filled.

public override  PolicyFailure[] Evaluate() {
            ArrayList changes = new  ArrayList();
 
            try {
                System.Diagnostics.Trace.WriteLine("Method Evaluate entered ....");
 
                if (!checkedItemChanged) {
                    System.Diagnostics.Trace.WriteLine("Method Evaluate  => CheckedItem not Changed....");
                    return (PolicyFailure[])changes.ToArray(typeof(PolicyFailure));
                }
 
                if (this.Disposed) {
                    throw new  ObjectDisposedException("policyType", "policyDisposedMessage");
                }
                  
                #region Parameters
                string workItemTypeName = "Code Review Request";
                string authenticatedUser = string.Empty;
 
                if (string.IsNullOrEmpty(tfsTeamProjectCollectionUrl))
                    return new  PolicyFailure[] { new PolicyFailure("Missing Parameter : Tfs Team Project Collection URL", this) };                
                if (string.IsNullOrEmpty(projectName))
                    return new  PolicyFailure[] { new PolicyFailure("Missing Parameter : Project Name", this) };
                if (string.IsNullOrEmpty(areaPath))
                    return new  PolicyFailure[] { new PolicyFailure("Missing Parameter : Area Path", this) };
                if (string.IsNullOrEmpty(userNameAssignTo))
                    return new  PolicyFailure[] { new PolicyFailure("Missing Parameter : Assign To", this) };
                #endregion
 
                #region Connect to Tfs
                System.Diagnostics.Trace.WriteLine("Method Evaluate  => Connecting to TfsTeamProjectCollection .... " + tfsTeamProjectCollectionUrl);
                TfsTeamProjectCollection tfs = new  TfsTeamProjectCollection(new Uri(tfsTeamProjectCollectionUrl));
                IIdentityManagementService identityManagementService = tfs.GetService<IIdentityManagementService>();
                  
                var versionControl = tfs.GetService<VersionControlServer>();
                versionControl = tfs.GetService<VersionControlServer>();
                authenticatedUser = versionControl.AuthorizedUser;
                #endregion
                                 
                #region Create Code Review Response
                WorkItemStore workitemStore = tfs.GetService<WorkItemStore>();
                var project = workitemStore.Projects[projectName];
 
                var type = project.WorkItemTypes["Code Review Response"];
                var workItem = new  WorkItem(type) { Title = "Code Review Response" };
                workItem.Fields["System.AssignedTo"].Value = userNameAssignTo;
                workItem.Fields["System.State"].Value = "Requested";
                workItem.Fields["System.Reason"].Value = "New";
                var result = workItem.Validate();                
                if (result.Count == 0) {
                    System.Diagnostics.Trace.WriteLine("Method Evaluate  => Saving the WorkItem ....");
                    workItem.Save();
                } else  {
                    System.Diagnostics.Trace.WriteLine("Method Evaluate  => WorkItem is not Validated.... Reasons are listed below ...");
                    foreach (Field item in result) {
                        System.Diagnostics.Trace.WriteLine(string.Format("Method Evaluate => Result.Name : {0}   Result.Value : {1}   Result.Status : {2} ", item.Name, item.Value.ToString(), item.Status.ToString()));
                    }
                    return (PolicyFailure[])changes.ToArray(typeof(PolicyFailure));
                }
                var responseId = workItem.Id;
                #endregion
 
                #region Create Code Review Request
                #region Get Last Changeset
                System.Diagnostics.Trace.WriteLine("Method Evaluate  => Getting the last ChangeSet ....");
                int lastChangesetId = versionControl.GetLatestChangesetId();
                var changeset = versionControl.GetChangeset(lastChangesetId);
                bool pathMatched = false;
                System.Diagnostics.Trace.WriteLine("Method Evaluate  => Matching the files against Regex definitions....");
                foreach (var change in changeset.Changes) {
                    foreach (var pathPattern in sourceControlPathFilters) {
                        if (Regex.IsMatch(change.Item.ServerItem, pathPattern)) {
                            pathMatched = true;
                            break;
                        }
                    }                    
                }
                if (!pathMatched) {
                    System.Diagnostics.Trace.WriteLine("Method Evaluate  => CheckedItem does not match with Regex Path Pattern....");
                    return (PolicyFailure[])changes.ToArray(typeof(PolicyFailure));
                }
                #endregion
 
                type = project.WorkItemTypes[workItemTypeName];
                workItem = new  WorkItem(type) { Title = "Checkin Notification" };                
                workItem.Fields["Microsoft.VSTS.CodeReview.ContextCode"].Value = 0;
                workItem.Fields["Microsoft.VSTS.CodeReview.ContextType"].Value = "Changeset";
                workItem.Fields["Microsoft.VSTS.CodeReview.Context"].Value = changeset.ChangesetId.ToString();
 
                workItem.Fields["System.AreaPath"].Value = areaPath;
                workItem.Fields["System.IterationPath"].Value = areaPath;
                workItem.Fields["System.AssignedTo"].Value = userNameAssignTo;
                workItem.Fields["System.State"].Value = "Requested";
                workItem.Fields["System.Reason"].Value = "New";
                workItem.Fields["System.Description"].Value = "Code Review Request for "  + userNameAssignTo;
                workItem.Fields["System.Title"].Value = "Code Review Request "  + System.DateTime.Now.ToString();
                WorkItemLinkTypeEnd linkTypeEnd = workitemStore.WorkItemLinkTypes.LinkTypeEnds["Child"];
                workItem.Links.Add(new RelatedLink(linkTypeEnd, responseId));
                result = workItem.Validate();
 
                if (result.Count == 0) {
                    System.Diagnostics.Trace.WriteLine("Method Evaluate => Saving the WorkItem ....");
                    workItem.Save();
                } else  {
                    System.Diagnostics.Trace.WriteLine("Method Evaluate => WorkItem is not Validated....");
                    foreach (Field item in result) {
                        System.Diagnostics.Trace.WriteLine(string.Format("Method Evaluate => Result.Name : {0}   Result.Value : {1}   Result.Status : {2} ", item.Name, item.Value.ToString(), item.Status.ToString()));
                    }
                    return (PolicyFailure[])changes.ToArray(typeof(PolicyFailure));
                }
                #endregion
 
                checkedItemChanged = false;
                System.Diagnostics.Trace.WriteLine("Method Evaluate Ended ....");
                return (PolicyFailure[])changes.ToArray(typeof(PolicyFailure));
 
            } catch  (Exception ex) {
                System.Diagnostics.Trace.WriteLine("Method Evaluate Faied ...." + ex.Message);
                System.Diagnostics.Trace.WriteLine("Method Evaluate Faied ...." + ex.StackTrace);
                checkedItemChanged = false;
                return (PolicyFailure[])changes.ToArray(typeof(PolicyFailure));
                //return new PolicyFailure[] { new PolicyFailure(ex.Message, this) };
            }
 
        }
 
 
 /// <summary>
        /// Subscribes to the PendingChanges_CheckedPendingChangesChanged event and reevaluates the policy. 
        /// </summary>
        /// <param name="sender" />The source of the event.</param>
        /// <param name="e" />The <see cref="System.EventArgs" /> instance containing the event data.</param>
        /// 
        void PendingChanges_CheckedPendingChangesChanged(object sender, EventArgs e) {
            //Run it when checkin operation was completed. So lets determine if it has done.
            checkedItemChanged = (_pendingCheckin.PendingChanges.CheckedPendingChanges.Length == 0);
            System.Diagnostics.Trace.WriteLine("Method Evaluate => PendingChanges_CheckedPendingChangesChanged to " + checkedItemChanged.ToString());            
            if (!Disposed && checkedItemChanged) {
                OnPolicyStateChanged(Evaluate());
            }
        }

   

you can download source code Here
https://codereviewrequestautomation.codeplex.com/