コード例 #1
0
        // If set, clear the TR fields conneting the Bug with a TR.
        static public Boolean disconnectBug(Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem)
        {
            Boolean updated = false;

            if (workItem.Fields[TFSMapper.ERICSSON_DEFECT_LINK_FIELD].Value != null &&
                workItem.Fields[TFSMapper.ERICSSON_DEFECT_LINK_FIELD].Value.ToString().Length > 0)
            {
                String trId = workItem.Fields[TFSMapper.ERICSSON_DEFECT_LINK_FIELD].Value.ToString();
                workItem.Fields[TFSMapper.TFS_HISTORY].Value = "Workitem disconnected from TR: " + trId;

                workItem.Fields[TFSMapper.ERICSSON_DEFECT_LINK_FIELD].Value  = null;
                workItem.Fields[TFSMapper.ERICSSON_DEFECT_STATE_FIELD].Value = null;
                workItem.Fields[TFSMapper.ERICSSON_DEFECT_SYNCSTATE].Value   = null;

                updated = true;

                HandlerSettings.LogMessage(
                    String.Format(
                        "Cleared TR connection fields for WorkItem with id {0}.",
                        "" + workItem.Id),
                    HandlerSettings.LoggingLevel.INFO);
            }

            return(updated);
        }
コード例 #2
0
        // Return if Bug is successfully saved or not. Note that Save will cause event that will be
        // triggering our code - but correctly filtered out as done by the functional user.
        public Boolean saveBug(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem)
        {
            try
            {
                workItem.Save();
                HandlerSettings.LogMessage(
                    String.Format("Saved workitem: {0}", workItem.Title),
                    HandlerSettings.LoggingLevel.INFO);
            }
            catch (Exception e)
            {
                // According to doc there are two exceptions that can be thrown:
                //      Microsoft.TeamFoundation.WorkItemTracking.Client.ValidationException
                //      Microsoft.TeamFoundation.WorkItemTracking.Client.DeniedOrNotExistException
                // but at least ValidationException is not recognized as subclass to Exception so compile error
                // See http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.workitemtracking.client.workitem.partialopen.aspx

                HandlerSettings.LogMessage(
                    String.Format("Failed to save workitem, error: {0}", e.Message),
                    HandlerSettings.LoggingLevel.ERROR);
                return(false);
            }

            return(true);
        }
コード例 #3
0
        // Get the Uri for the TR before disconnected assuming disconnect was done in
        // previous save. Preconditions should be checked by caller.
        static public Uri getDisconnectedTRLink(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem,
            WorkItemChangedEvent notification)
        {
            // Apparently we need to check on second last revision to get the correct
            // value for the previous value. This does not show in UI, but is clear when
            // debugging. So check we have > 2 revisions, and then compare.

            if (workItem.Revision < 3)
            {
                return(null);
            }

            Revision lastRev   = workItem.Revisions[workItem.Revision - 2];
            String   oldTrLink = lastRev.Fields[TFSMapper.ERICSSON_DEFECT_LINK_FIELD].Value.ToString();

            if (oldTrLink == null || oldTrLink.Length == 0)
            {
                return(null);
            }

            HandlerSettings.LogMessage(
                String.Format(
                    "Disconnected TR '{0}' from WorkItem with id {1}.",
                    oldTrLink, "" + workItem.Id), HandlerSettings.LoggingLevel.INFO);

            return(new Uri(HandlerSettings.GetUriForTR(oldTrLink)));
        }
コード例 #4
0
        // Return an authenticated oslc client. Throws exception in case not found.
        public OslcClient2 getOslcClient()
        {
            if (oslcClient != null)
            {
                return(oslcClient);
            }

            // Get the Friend info for mhweb
            FriendInfo friend = HandlerSettings.GetFriend("mhweb");

            if (friend == null)
            {
                throw new Exception(String.Format("Failed to get friend info for: {0}", "mhweb"));
            }

            if (friend.UseAccess == FriendInfo.UseAccessType.oauth)
            {
                oslcClient = getOAuthClient(friend);
            }
            else
            {
                oslcClient = getBasicAuthClient(friend);
            }

            if (oslcClient == null)
            {
                throw new Exception(String.Format("Failed to get OSLC client for: {0}", "mhweb"));
            }

            return(oslcClient);
        }
コード例 #5
0
 // For test. Return the Resource as content that would be transmitted over wire.
 public ObjectContent getResourceAsMessage(EnterpriseChangeRequest ecr, String user)
 {
     return(getOslcClient().GetResourceAsMessage(
                ecr,
                OslcMediaType.APPLICATION_RDF_XML,
                OslcMediaType.APPLICATION_RDF_XML,
                HandlerSettings.getRESTHeaders(user)));
 }
コード例 #6
0
        // =============================================================
        // Ignore all changes done by ourselves - i.e. the functional user used to handle save events.
        // Note that IF functional user would be logged in as regular user, events will not be handled.

        private bool ignoreSaveEvent(WorkItemChangedEvent ev)
        {
            bool ignore = HandlerSettings.IgnoreEventByUser(
                getStore().TeamProjectCollection,
                ev.ChangerTeamFoundationId);

            return(ignore);
        }
コード例 #7
0
 public static TfsTeamProjectCollection getTPC()
 {
     if (tpc == null)
     {
         tpc = new TfsTeamProjectCollection(
             new Uri(HandlerSettings.TFSUri),
             HandlerSettings.GetCredentials());
     }
     return(tpc);
 }
コード例 #8
0
        // UC 6: Create a TR based on a Bug.
        // Return if the bug is updated or not.
        private void createTR(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem,
            WorkItemChangedEvent notification,
            String user,
            ref Status status)
        {
            // Create the ECR
            callCreateTR(ECRMapper.mapFromWorkitem(workItem, null, ECRMapper.ACTION_CREATE), user, ref status);
            if (!status.OK)
            {
                return;
            }

            // UC 3 (one case): Update all changed attributes before handling any state change

            // Note: If adding an entry in History on create this should propagate to Progress Info, but
            // this caused Bug to appear dirty after Save, see issue 79. Given almost all fields are used on
            // create, it does not make sense to make extra update as below. TBD if we should re-add in a
            // changed form.

            //EnterpriseChangeRequest updatedEcr = ECRMapper.mapFromUpdatedWorkitem(workItem, status.TRAbout, notification);
            //if (updatedEcr != null)
            //{
            //    // Note: Failure to update will be Warning not Error, so status still OK.
            //    callUpdateTR(updatedEcr, user, null, ref status);
            //}

            // Set the ECR in state Registered
            EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, status.TRAbout, ECRMapper.ACTION_REGISTER_ROUTE);

            callUpdateTR(ecr, user, ECRMapper.TR_STATE_REGISTERED_S, ref status);
            if (!status.OK)
            {
                return;
            }

            // Set the ECR in state Assigned if we have a defined owner
            ecr = ECRMapper.mapFromWorkitem(workItem, status.TRAbout, ECRMapper.ACTION_ASSIGN);
            if (ecr.GetOwner() != null && ecr.GetOwner().Length > 0)
            {
                callUpdateTR(ecr, user, ECRMapper.TR_STATE_ASSIGNED_S, ref status);
                if (!status.OK)
                {
                    return;
                }
            }

            if (status.OK)
            {
                HandlerSettings.LogMessage(
                    String.Format("Created TR based on workitem named: {0}", workItem.Title),
                    HandlerSettings.LoggingLevel.INFO);
            }
        }
コード例 #9
0
        // TODO: This is cheating as we have hardcoded knowledge where release field is.
        // Need to make this fast, but to be correct we should use regular TFSMapper way.
        public bool IsProductInMaintenance(Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem wi)
        {
            String releaseName = wi.Fields[TFSMapper.TFS_FAULTY_PRODUCT].Value.ToString();

            if (releaseName == null || releaseName.Length == 0)
            {
                // Should not happen - Mapping needs to be initialized
                HandlerSettings.LogMessage(
                    "Can not tell if product is in maintenance as the Release name not defined.",
                    HandlerSettings.LoggingLevel.WARN);
                return(false);
            }

            return(releaseToProductMap.ContainsKey(releaseName));
        }
コード例 #10
0
        // =======================================================================
        // Getters

        // Get long TR state name e.g. AS (Assigned) from short e.g. AS.
        public static String getLongTRState(String shortTRState)
        {
            if (mhStateToFullName.ContainsKey(shortTRState))
            {
                return(mhStateToFullName[shortTRState]);
            }
            else
            {
                // Should not happen - unknown state to translate
                HandlerSettings.LogMessage(
                    String.Format("State {0} is not recognized.", shortTRState),
                    HandlerSettings.LoggingLevel.WARN);
                return(shortTRState);
            }
        }
コード例 #11
0
        // Get and initialize a basic auth client
        private OslcClient2 getBasicAuthClient(FriendInfo friend)
        {
            BasicAuthClient basicClient = null;
            String          exMessage   = "";

            try
            {
                JazzRootServicesHelper2 helper = new JazzRootServicesHelper2(
                    HandlerSettings.ClientUri,
                    HandlerSettings.RootservicesUri);

                // Specific code - logging in
                basicClient = new BasicAuthClient(friend.EncodedCredentials);
                HttpClient client = basicClient.GetHttpClient();

                // Get the Creation Factory for mhweb
                String user = friend.GetBasicAuthUser();
                String serviceProviderUrl = basicClient.LookupServiceProviderUrl(
                    helper.GetCatalogUrl(), "mhweb", HandlerSettings.getRESTHeaders(user));
                HandlerSettings.CreationFactoryUri = basicClient.LookupCreationFactory(
                    serviceProviderUrl,
                    Constants.ENTERPRISE_CHANGE_MANAGEMENT_DOMAIN,
                    Constants.TYPE_ENTERPRISE_CHANGE_REQUEST,
                    HandlerSettings.getRESTHeaders(user));
            }
            catch (Exception ex)
            {
                basicClient = null;
                exMessage   = ex.Message;
            }

            if (basicClient == null || exMessage.Length > 0)
            {
                HandlerSettings.LogMessage(
                    String.Format(
                        "Failed to get a httpClient for basic auth." +
                        "\nUsing client uri: {0}" +
                        "\nUsing rootservices uri: {1}" +
                        "\nMessage: {2}",
                        HandlerSettings.ClientUri,
                        HandlerSettings.RootservicesUri,
                        exMessage),
                    HandlerSettings.LoggingLevel.ERROR);
            }

            return(basicClient);
        }
コード例 #12
0
        // Return if the workitem is updated (saved) by the handling code.
        public void handleEvent(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem,
            String user,
            WorkItemChangedEvent notification)
        {
            Status status = new Status();

            // If the user is the OSLC Provider functional user we will only update status
            // message if so needed. This as changes from the OSLC Provider originates from
            // external source = currently: MHWeb. Need revisit to allow multiple clients.
            String aboutStr = AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_ABOUT, workItem);

            if (!user.Equals(HandlerSettings.TFSProviderUser, StringComparison.OrdinalIgnoreCase))
            {
                if (aboutStr.Length == 0)
                {
                    // We do not have a linked TR, we need to create
                    createTR(workItem, notification, user, ref status);
                }
                else
                {
                    Uri    about        = new Uri(aboutStr);
                    Status statusAssign = null;

                    EnterpriseChangeRequest ecr        = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_ASSIGN);
                    TeamFoundationIdentity  assignedTo = HandlerSettings.GetSignumForAssignedTo(workItem);
                    if (user != null && assignedTo != null && !user.Equals(HandlerSettings.GetUserFromSignum(assignedTo.UniqueName), StringComparison.OrdinalIgnoreCase))
                    {
                        statusAssign = new Status();
                        ecr.SetOwner(user);
                        callUpdateTR(ecr, user, ECRMapper.TR_STATE_ASSIGNED_S, ref statusAssign);
                    }

                    // We have a TR linked which might need to be updated
                    updateTR(workItem, notification, user, about, ref status);

                    if (statusAssign != null && statusAssign.OK)
                    {
                        ecr.SetOwner(HandlerSettings.GetUserFromSignum(assignedTo.UniqueName));
                        callUpdateTR(ecr, user, ECRMapper.TR_STATE_ASSIGNED_S, ref statusAssign);
                    }
                }
            }

            // Handle update of Bug
            ECRMapper.updateBug(status, user, workItem);
        }
コード例 #13
0
        public bool Load(String fileName)
        {
            releaseToProductMap = new Dictionary <String, PRIMProduct>();

            try
            {
                XDocument doc     = XDocument.Load(fileName);
                XElement  mapping = doc.Element("mapping");

                // Loop over all entries and add to the dictionary
                foreach (XElement spEntry in mapping.Elements("serviceProvider"))
                {
                    // If the serviceProvider (TFS Project) is defined we only
                    // care about events that are passed to that TFS Project
                    serviceProvider = spEntry.Attribute("name").Value;

                    foreach (XElement productEntry in spEntry.Elements("product"))
                    {
                        // TODO: Check if product info is case-sensitive
                        String      primProdNo = productEntry.Attribute("primProdNo").Value;
                        String      primRState = productEntry.Attribute("primRState").Value;
                        PRIMProduct product    = new PRIMProduct(primProdNo, primRState);

                        String mapTo = productEntry.Attribute("mapTo").Value;

                        // NOTE: We don't care about the team attribute for now.
                        // String team = productEntry.Attribute("team").Value; //.ToLower();;

                        releaseToProductMap.Add(mapTo, product);
                    }
                }
            }
            catch (Exception ex)
            {
                // Error when reading mapping file - assume fatal
                HandlerSettings.LogMessage(
                    "Error when reading the product mapping file: " + fileName +
                    "\nError: " + ex.Message,
                    HandlerSettings.LoggingLevel.ERROR);
                return(false);
            }

            return(true);
        }
コード例 #14
0
        // Get and initialize an oauth client
        private OslcClient2 getOAuthClient(FriendInfo friend)
        {
            JazzOAuthClient2 oauthClient = null;
            String           exMessage   = "";

            try
            {
                JazzRootServicesHelper2 helper = new JazzRootServicesHelper2(
                    HandlerSettings.ClientUri,
                    HandlerSettings.RootservicesUri);

                oauthClient = helper.InitOAuthClient2(friend.ConsumerKey,
                                                      friend.ConsumerSecret,
                                                      friend.AccessToken,
                                                      friend.AccessTokenSecret);

                // Get the Creation Factory for mhweb
                String serviceProviderUrl = oauthClient.LookupServiceProviderUrl(helper.GetCatalogUrl(), "mhweb");
                HandlerSettings.CreationFactoryUri = oauthClient.LookupCreationFactory(
                    serviceProviderUrl, Constants.ENTERPRISE_CHANGE_MANAGEMENT_DOMAIN,
                    Constants.TYPE_ENTERPRISE_CHANGE_REQUEST);
            }
            catch (Exception ex)
            {
                oauthClient = null;
                exMessage   = ex.Message;
            }

            if (oauthClient == null || exMessage.Length > 0)
            {
                HandlerSettings.LogMessage(
                    String.Format(
                        "Failed to get a httpClient for oauth." +
                        "\nUsing client uri: {0}" +
                        "\nUsing rootservices uri: {1}" +
                        "\nMessage: {2}",
                        HandlerSettings.ClientUri,
                        HandlerSettings.RootservicesUri,
                        exMessage),
                    HandlerSettings.LoggingLevel.ERROR);
            }

            return(oauthClient);
        }
コード例 #15
0
        // ===============================================

        static public String GetTfsValueForEcrKey(String propertyName, WorkItem workItem)
        {
            List <String> values = TFSMapper.getInstance().mapToEcr(propertyName, workItem);

            if (values.Count == 0)
            {
                HandlerSettings.LogMessage(
                    "Missing map entry for 'key': " + propertyName,
                    HandlerSettings.LoggingLevel.INFO);
                return("");
            }
            else if (values.Count > 1)
            {
                HandlerSettings.LogMessage(
                    "More than one value for 'key': " + propertyName,
                    HandlerSettings.LoggingLevel.WARN);
            }

            return(values[0]);
        }
コード例 #16
0
        // ===============================================================
        // Utility methods - could be moved elsewhere

        // For call to create TR we need Ericsson user id (also domain?) - seems like we have what we want here.
        // See http://stackoverflow.com/questions/19911368/using-the-tfs-2012-api-how-do-i-get-the-email-address-of-a-user
        static public TeamFoundationIdentity GetSignumForAssignedTo(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem)
        {
            TfsTeamProjectCollection tpc = workItem.Store.TeamProjectCollection;
            String userName = workItem.Fields[TFSMapper.TFS_OWNER].Value.ToString();

            IIdentityManagementService mgmntService = tpc.GetService <IIdentityManagementService>();

            TeamFoundationIdentity member = mgmntService.ReadIdentity(
                IdentitySearchFactor.DisplayName,
                userName,
                MembershipQuery.Direct,
                ReadIdentityOptions.ExtendedProperties);

            if (member == null)
            {
                HandlerSettings.LogMessage(
                    String.Format("Failed to get user identity for user: {0}", userName),
                    HandlerSettings.LoggingLevel.WARN);
            }

            return(member);
        }
コード例 #17
0
        // =========================================================
        // Handle the WorkItemChangedEvent event

        // Disconnect TR if conditions are matching. Return if workitem has been saved.
        public void handleDisconnectEvent(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem,
            String user,
            WorkItemChangedEvent notification)
        {
            Uri about = ECRMapper.getDisconnectedTRLink(workItem, notification);

            if (about == null)
            {
                return;
            }
            EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(
                workItem, about, ECRMapper.ACTION_DISCONNECT);
            Status status = new Status();

            callUpdateTR(ecr, user, null, ref status);
            if (!status.OK)
            {
                HandlerSettings.LogMessage(
                    "Failed to disconnect TR from Bug.",
                    HandlerSettings.LoggingLevel.WARN);
            }
        }
コード例 #18
0
        // Check the Release is or just changed from a maintenance product.
        // TODO: This is cheating as we have hardcoded knowledge where release field is.
        // Need to make this fast, but to be correct we should use regular TFSMapper way.
        public EventType GetEventType(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem wi,
            WorkItemChangedEvent notification,
            String user)
        {
            Field createTR = wi.Fields[TFSMapper.ERICSSON_DEFECT_CREATETR];

            if (createTR == null ||
                createTR.Value.ToString().Length == 0 ||
                createTR.Value.ToString().Equals("No", StringComparison.OrdinalIgnoreCase))
            {
                return(EventType.Ignore);
            }


            // Check project name. If not as defined for product mapping, disregard event.
            // This allows other projects on TFS server to be non-connected to TR system.
            if (serviceProvider.Length > 0 &&
                !wi.Project.Name.Equals(serviceProvider, StringComparison.OrdinalIgnoreCase))
            {
                return(EventType.Ignore);
            }



            bool inMaint = IsProductInMaintenance(wi);

            if (inMaint)
            {
                // Currenty selected release / product is in maintenance
                EventType evType = CheckDisconnect(wi, notification, user);
                if (evType == EventType.Disconnect)
                {
                    return(EventType.Disconnect);
                }
                return(EventType.CreateUpdate);
            }

            // ========================================================================
            // Check if we just changed from having a product in maintenance. Rare case,
            // then need to allow severing links and updating state of the workitem.

            if (notification.ChangeType == ChangeTypes.New)
            {
                // Can only happen for a changed WI, not a new.
                return(EventType.Ignore);
            }

            if (notification.ChangedFields == null || notification.ChangedFields.StringFields == null)
            {
                // No fields of interest are changed
                return(EventType.Ignore);
            }

            StringField[] changedFields = notification.ChangedFields.StringFields;
            for (int i = 0; i < changedFields.Length; i++)
            {
                String name = changedFields[i].ReferenceName;

                // If the release is changed, we need to update the TR product
                // Note: In case we also set to Duplicate, we will disregard product change
                if (name.Equals(TFSMapper.TFS_FAULTY_PRODUCT))
                {
                    String releaseName = changedFields[i].OldValue;
                    if (releaseName == null || releaseName.Length == 0)
                    {
                        // Should not happen - Mapping needs to be initialized
                        HandlerSettings.LogMessage(
                            "Can not tell if product is in maintenance as the Release name not defined.",
                            HandlerSettings.LoggingLevel.WARN);
                        return(EventType.Ignore);
                    }

                    if (releaseToProductMap.ContainsKey(releaseName))
                    {
                        return(EventType.CreateUpdate);
                    }
                    else
                    {
                        return(EventType.Ignore);
                    }
                }
            }

            return(EventType.Ignore);
        }
コード例 #19
0
        // Load attributes from the specified filename. If add is true we append mappings.
        public bool Load(String fileName, bool add)
        {
            // NOTE: Error if not called once first with add = false.
            if (!add)
            {
                forwardMap = new MultiMap <Property>();
                inverseMap = new MultiMap <Property>();

                // TODO: Adding a map to support case when looking up inverse based on TFS key
                // Should this be needed? Also for forward case?
                inverseMapTFSKey = new MultiMap <Property>();

                notifyMap = new MultiMap <Property>();
            }

            try
            {
                XDocument doc     = XDocument.Load(fileName);
                XElement  mapping = doc.Element("mapping");

                // Loop over all entries and add to the dictionary
                foreach (XElement propEntry in mapping.Elements("property"))
                {
                    // In TFS consumer case the serviceProvider (i.e. TFS Project) info is not relevant here
                    // as the workitem (Bug) is in a project context. The serviceProvider info is used when
                    // creating a Bug without the TFS context i.e. through the TFS OSLC Provider.

                    Property property = processProperty(propEntry);

                    foreach (XElement child in propEntry.Elements())
                    {
                        switch (child.Name.LocalName)
                        {
                        case "default":
                            processDefault(child, property);
                            break;

                        case "depends":
                            processDepends(child, property);
                            break;

                        case "map":
                            processMap(child, property);
                            break;

                        case "use":
                            processUse(child, property);
                            break;

                        default:
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // Error when reading mapping file - assume fatal
                HandlerSettings.LogMessage(
                    "Error when reading the attribute mapping file: " + fileName +
                    "\nError: " + ex.Message +
                    "\nStack: " + ex.StackTrace,
                    HandlerSettings.LoggingLevel.ERROR);
                return(false);
            }

            return(true);
        }
コード例 #20
0
        // Update the connected TR.
        private void updateTR(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem,
            WorkItemChangedEvent notification,
            String user,
            Uri about,
            ref Status status)
        {
            String oldState, newState, action;

            ECRMapper.getStatusChange(notification, workItem, out oldState, out newState, out action);

            if (action != null)
            {
                if (action.Equals(ECRMapper.ACTION_IGNORE))
                {
                    // Ignore all changes
                    return;
                }

                if (action.Equals(ECRMapper.ACTION_DUPLICATE))
                {
                    // UC 9.4: Duplicate - Find Bug with duplicate id, get attached TR and send action duplicate

                    // Update needs to be done before setting the Bug as Duplicate as the TR can't change after.
                    updateTRFields(workItem, notification, user, about, ref status);

                    EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_DUPLICATE);

                    if (ecr.GetPrimaryTR() == null || ecr.GetPrimaryTR().Length == 0)
                    {
                        // Failed to find a Bug with a connected TR. Log error and return.
                        String msg = String.Format(
                            "Failed to find duplicate to Bug: {0}, or duplicate Bug had not TR Link set",
                            workItem.Title);
                        HandlerSettings.LogMessage(msg, HandlerSettings.LoggingLevel.ERROR);
                        status.ErrorMessage = msg;
                        return;
                    }

                    callUpdateTR(ecr, user, null, ref status);
                    if (!status.OK)
                    {
                        // Log issue, but continue if e.g. a state change
                        HandlerSettings.LogMessage(
                            String.Format("Failed to set TR as duplicate based on Bug: {0}", workItem.Title),
                            HandlerSettings.LoggingLevel.WARN);
                    }

                    // After setting Bug/TR as Duplicated, no futher changes should be propagated.
                    return;
                }

                if (action.Equals(ECRMapper.ACTION_UNDUPLICATE))
                {
                    // UC 9.4: Unduplicate - Move TR back to Registered by sending action unduplicate
                    EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_UNDUPLICATE);
                    callUpdateTR(ecr, user, null, ref status);
                    if (!status.OK)
                    {
                        // Log issue, but continue if e.g. a state change
                        HandlerSettings.LogMessage(
                            String.Format("Failed to unduplicate TR based on Bug ", workItem.Title),
                            HandlerSettings.LoggingLevel.WARN);
                    }

                    // Update needs to be done after "Unduplicating" the Bug as the TR can't change before.
                    updateTRFields(workItem, notification, user, about, ref status);

                    // Return before handling a possible state change as states can be out of sync
                    // (normal case) when Bug has been Duplicate. Bug then Resolved / Closed, and
                    // TR in an Active state. User needs to set TR state to Active.
                    return;
                }

                else if (action.Equals(ECRMapper.ACTION_CHANGE_PRODUCT))
                {
                    // UC 10.2: Update of the release - propagate info to TR
                    EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_CHANGE_PRODUCT);

                    bool noProduct = ecr.GetProduct().Length == 0;
                    if (noProduct)
                    {
                        // No product found, so value is for internal release - add message in notebook
                        ecr.SetNotebook("The referenced design item was moved to a product internal to Design");
                    }

                    callUpdateTR(ecr, user, null, ref status);
                    if (!status.OK)
                    {
                        // Log issue, but continue if e.g. a state change
                        HandlerSettings.LogMessage(
                            String.Format("Failed to change product on TR based on Bug ", workItem.Title),
                            HandlerSettings.LoggingLevel.WARN);
                    }
                }
            }

            updateTRFields(workItem, notification, user, about, ref status);

            if (newState != null)
            {
                // Handle state change
                updateTRState(workItem, oldState, newState, user, about, ref status);;
            }
        }
コード例 #21
0
        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;

            // TODO: Make impact on performance minimal by optimize logic for understanding if we are interested
            // in this event or not. Also put longer running task in Jobs. For now - do basic checks.

            if (notificationType != NotificationType.Notification)
            {
                return(EventNotificationStatus.ActionPermitted);
            }
            var notification = notificationEventArgs as WorkItemChangedEvent;

            if (notification == null)
            {
                return(EventNotificationStatus.ActionPermitted);
            }

            // Should not thow exception - if so, the code will be disabled by TFS.
            try
            {
                // Init adapter - will only be done once per deployment of plugin
                if (!HandlerSettings.initFromFile())
                {
                    // Fatal error when trying to init - return
                    // TODO: How allow retry without server restart or re-deploy of plugin?
                    return(EventNotificationStatus.ActionPermitted);
                }

                // Handle case where event is fired because of Save we initiated.
                if (ignoreSaveEvent(notification))
                {
                    return(EventNotificationStatus.ActionPermitted);
                }

                int workItemId = notification.CoreFields.IntegerFields[0].NewValue;
                HandlerSettings.LogMessage(
                    String.Format(
                        "WorkItem with id {0} named '{1}' was saved.",
                        "" + workItemId,
                        notification.WorkItemTitle),
                    HandlerSettings.LoggingLevel.INFO);

                // TODO: In examples I have seen you get actual WI by process below, i.e. opening a new connection to TFS.
                // I would expect as we already are in the context of a TFS you somehow could use this. Note: There is a
                // WorkItem class in the namespace Microsoft.TeamFoundation.WorkItemTracking.Server - no documentation found.

                Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem = getStore().GetWorkItem(workItemId);

                // If a new item is based on an existing (copied) we need to reset the connection to any existing TR.
                // Note exception if item is created by the functional user. This to allow test case where TR is set
                // by test case code.
                String user = HandlerSettings.GetSignumForChangeNotification(workItem, notification);
                if (notification.ChangeType == ChangeTypes.New)
                {
                    if (!user.Equals(HandlerSettings.TFSProviderUser, StringComparison.OrdinalIgnoreCase))
                    {
                        // Note: Will not save - done in event handling or at end.
                        ECRMapper.disconnectBug(workItem);
                    }
                }

                ProductMapper.EventType eventType =
                    ProductMapper.getInstance().GetEventType(workItem, notification, user);

                if (eventType == ProductMapper.EventType.CreateUpdate)
                {
                    // Handle the event as the release is for a maintenance product
                    RESTCallHandler.getHandler().handleEvent(workItem, user, notification);
                }
                else if (eventType == ProductMapper.EventType.Disconnect)
                {
                    // Handle the event as the release is for a maintenance product
                    RESTCallHandler.getHandler().handleDisconnectEvent(workItem, user, notification);
                }
                else
                {
                    HandlerSettings.LogMessage(
                        String.Format(
                            "WorkItem with id {0} save event was ignored by integration.",
                            "" + workItemId),
                        HandlerSettings.LoggingLevel.INFO);
                }

                // If updated but not saved, we need to explicitly call save. Very unusual case but will happen
                // e.g. if item is copied with a product value that before was in maintenance but now not. Then
                // code to disconnect bug is called, but event not handled or Bug saved, hence save here.
                if (workItem.IsDirty)
                {
                    RESTCallHandler.getHandler().saveBug(workItem);
                }
            }
            catch (Exception ex)
            {
                // Error when reading mapping file - assume fatal
                HandlerSettings.LogMessage(
                    "Error when handling the change of workitem." +
                    "\nError: " + ex.Message +
                    "\nStack: " + ex.StackTrace,
                    HandlerSettings.LoggingLevel.ERROR);
            }
            return(EventNotificationStatus.ActionPermitted);
        }
コード例 #22
0
        // Update the connected TR State. Return if the bug is updated or not.
        private void updateTRState(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem,
            String oldState, String newState,
            String user,
            Uri about,
            ref Status status)
        {
            status.TRState = ECRMapper.getTRState(workItem);

            if (oldState.Equals(ECRMapper.BUG_STATE_ACTIVE, StringComparison.OrdinalIgnoreCase) &&
                newState.Equals(ECRMapper.BUG_STATE_RESOLVED, StringComparison.OrdinalIgnoreCase))
            {
                // UC 4: Updated TR based on the Bug's Active -> Resolve state change

                EnterpriseChangeRequest ecr = null;
                if (status.TRState.Equals(ECRMapper.TR_STATE_ASSIGNED))
                {
                    ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_PROPOSE);
                    callUpdateTR(ecr, user, ECRMapper.TR_STATE_PROPOSED_S, ref status);
                    if (!status.OK)
                    {
                        return;
                    }
                }

                if (status.TRState.Equals(ECRMapper.TR_STATE_PROPOSED))
                {
                    String answerCode = "";
                    if (ecr != null)
                    {
                        answerCode = ecr.GetAnswerCode();
                    }
                    else
                    {
                        answerCode = AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_ANSWER_CODE, workItem);
                    }

                    if (answerCode.Contains("A") || answerCode.Contains("D") || answerCode.Contains("B11"))
                    {
                        // In case Answer Code = A*, D*, or B11 go directly to Answer
                        callUpdateTR(ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_ANSWER),
                                     user, ECRMapper.TR_STATE_TECH_ANSW_PROV_S, ref status);
                        return;
                    }
                    else
                    {
                        callUpdateTR(ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_APPROVE),
                                     user, ECRMapper.TR_STATE_PROP_APPROV_S, ref status);
                    }
                }

                String expectedState = ECRMapper.TR_STATE_PROP_APPROV;
                if (!status.TRState.Equals(expectedState))
                {
                    // Incorrect pre condition
                    HandlerSettings.LogMessage(
                        String.Format("Expected TR State: {0}, current TR state: {1}", expectedState, status.TRState),
                        HandlerSettings.LoggingLevel.WARN);
                }

                // Note: Here we assume we are in trState PA, as we accepted AS, PP and PA. If we have not failed
                // before, this is where we will fail if any assumption was wrong -> error message.
                if (status.OK)
                {
                    callUpdateTR(ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_VERIFY),
                                 user, ECRMapper.TR_STATE_TECH_ANSW_PROV_S, ref status);
                }
            }

            else if (oldState.Equals(ECRMapper.BUG_STATE_RESOLVED, StringComparison.OrdinalIgnoreCase) &&
                     newState.Equals(ECRMapper.BUG_STATE_CLOSED, StringComparison.OrdinalIgnoreCase))
            {
                // Update a TR based on Close of the Bug's Resolve -> Close state change

                String expectedState = ECRMapper.TR_STATE_TECH_ANSW_PROV;
                if (!status.TRState.Equals(expectedState))
                {
                    // Incorrect pre condition
                    HandlerSettings.LogMessage(
                        String.Format("Expected TR State: {0}, current TR state: {1}", expectedState, status.TRState),
                        HandlerSettings.LoggingLevel.WARN);
                }

                // TODO: Put the condition in configuration file etc.
                String answerCode = AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_ANSWER_CODE, workItem);
                if (answerCode.Equals("D4"))
                {
                    // UC 9.3 - Bug set as Postponed
                    callUpdateTR(ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_ACCEPT),
                                 user, ECRMapper.TR_STATE_POSTPONED_S, ref status);
                }
                else if (answerCode.Equals("Duplicate"))
                {
                    // UC 9.4 - Bug set as Duplicate
                    callUpdateTR(ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_DUPLICATE), user, null, ref status);
                }
                else
                {
                    // UC 9.1 - Close of Bug from TFS
                    callUpdateTR(ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_FINISH), user,
                                 ECRMapper.TR_STATE_FINISHED_S, ref status);
                }
            }

            else if (oldState.Equals(ECRMapper.BUG_STATE_RESOLVED, StringComparison.OrdinalIgnoreCase) &&
                     newState.Equals(ECRMapper.BUG_STATE_ACTIVE, StringComparison.OrdinalIgnoreCase))
            {
                // UC 9.2: Update a TR based the Bug's Resolved -> Active state change

                callUpdateTR(ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_REJECT), user,
                             ECRMapper.TR_STATE_REGISTERED_S, ref status);
                if (!status.OK)
                {
                    return;
                }

                // If Bug is assigned to a user we need to drive change back to Assigned state
                EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_ASSIGN);
                if (ecr.GetOwner() != null && ecr.GetOwner().Length > 0)
                {
                    callUpdateTR(ecr, user, ECRMapper.TR_STATE_ASSIGNED_S, ref status);
                }
            }
            else if (oldState.Equals(ECRMapper.BUG_STATE_CLOSED, StringComparison.OrdinalIgnoreCase) &&
                     newState.Equals(ECRMapper.BUG_STATE_ACTIVE, StringComparison.OrdinalIgnoreCase))
            {
                // UC 9.2: Update a TR based the Bug's Closed -> Active state change

                // In case of Closed -> Active, this is only allowed for the "no action" answer codes
                // in MHWeb, so OK for this to fail if selecting the incorrect answer code.
                // Could block in Bug.xml if we want to prevent some cases.

                callUpdateTR(ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_REACTIVATE), user,
                             ECRMapper.TR_STATE_REGISTERED_S, ref status);
                if (!status.OK)
                {
                    return;
                }

                // If Bug is assigned to a user we need to drive change back to Assigned state
                EnterpriseChangeRequest ecr = ECRMapper.mapFromWorkitem(workItem, about, ECRMapper.ACTION_ASSIGN);
                if (ecr.GetOwner() != null && ecr.GetOwner().Length > 0)
                {
                    callUpdateTR(ecr, user, ECRMapper.TR_STATE_ASSIGNED_S, ref status);
                }
            }

            else if (oldState.Equals(ECRMapper.BUG_STATE_ACTIVE, StringComparison.OrdinalIgnoreCase) &&
                     newState.Equals(ECRMapper.BUG_STATE_ACTIVE, StringComparison.OrdinalIgnoreCase))
            {
                // UC 3 (one case): Handle Assign case - state change for TR, attribute change for Bug

                // Incorrect pre condition
                String expectedState = ECRMapper.TR_STATE_REGISTERED;
                if (!status.TRState.Equals(expectedState))
                {
                    HandlerSettings.LogMessage(
                        String.Format("Expected TR State: {0}, current TR state: {1}", expectedState, status.TRState),
                        HandlerSettings.LoggingLevel.WARN);
                }

                // Handle case when we are in state PR
                if (status.TRState.Equals(ECRMapper.TR_STATE_PRIVATE))
                {
                    callUpdateTR(ECRMapper.mapFromWorkitem(
                                     workItem, about, ECRMapper.ACTION_REGISTER_ROUTE),
                                 user, ECRMapper.TR_STATE_REGISTERED_S, ref status);
                }

                callUpdateTR(ECRMapper.mapFromWorkitem(
                                 workItem, about, ECRMapper.ACTION_ASSIGN), user, ECRMapper.TR_STATE_ASSIGNED_S, ref status);
            }
        }
コード例 #23
0
        // Update the TR State field for the bug based either on incoming ecr, or if this is null
        // get the current TR State from the bug. If missing link for a maintenance product or if
        // having a link for a non-maintenance product, also show this.
        static public void updateBug(Status status, String user,
                                     Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem)
        {
            // Check if we are connected when we should be
            bool   isProdInMaint = ProductMapper.getInstance().IsProductInMaintenance(workItem);
            String currentLink   = HandlerSettings.GetIDFromLink(workItem);
            bool   hasLink       = currentLink.Length > 0;

            if (isProdInMaint && (!hasLink && status.TRAbout == null))
            {
                // Error - should have link and nothing in the status.TRAbout so have not created.
                workItem.Fields[TFSMapper.ERICSSON_DEFECT_STATE_FIELD].Value = trStateToString[TRStateInfo.ErrorMissingTR];
            }
            else if (!isProdInMaint)
            {
                // OK - clear any status fields and return
                ECRMapper.disconnectBug(workItem);
                return;
            }
            else
            {
                // OK - prod is in maint and has link - normal case

                // Check if state is updated
                String newTrState = null;
                if (status.TRState != null)
                {
                    String currentTrState = getTRState(workItem);
                    String updatedTrState = status.TRState;
                    if (!updatedTrState.Equals(currentTrState))
                    {
                        newTrState = updatedTrState;
                        workItem.Fields[TFSMapper.ERICSSON_DEFECT_STATE_FIELD].Value = newTrState;
                    }
                }

                if (status.TRAbout != null)
                {
                    // We will store the relative path of the "Edit TR" link in the bug, reason being that the Link
                    // that we need to define for the UI to allow click to navigate require a non blank UriRoot value,
                    // see http://msdn.microsoft.com/en-us/library/dd936107.aspx.

                    String updatedLink = HandlerSettings.GetIDFromUri(status.TRAbout.ToString());
                    if (updatedLink.Length > 0)
                    {
                        if (!currentLink.Equals(updatedLink))
                        {
                            workItem.Fields[TFSMapper.ERICSSON_DEFECT_LINK_FIELD].Value = updatedLink;
                        }
                    }
                }
            }

            // Put the error and expected state string into system history field
            String message = status.GetMessage();

            // Append any defined guiding message
            TRSyncState newSyncState   = getSyncState(status, workItem);
            String      guidingMessage = "";

            switch (newSyncState)
            {
            case TRSyncState.SyncStateNone:
                guidingMessage = HandlerSettings.SyncNoSyncMessage;
                break;

            case TRSyncState.SyncStateOK:
                guidingMessage = HandlerSettings.SyncSuccessMessage;
                break;

            case TRSyncState.SyncStateWarning:
                guidingMessage = HandlerSettings.SyncWarningMessage;
                break;

            case TRSyncState.SyncStateError:
                guidingMessage = HandlerSettings.SyncErrorMessage;
                break;
            }

            if (message.Length > 0 || guidingMessage.Length > 0)
            {
                workItem.History = message + ((guidingMessage.Length > 0) ? " " + guidingMessage : "");
            }

            // Put the sync state in the Sync State field
            String currentSyncStateStr = workItem.Fields[TFSMapper.ERICSSON_DEFECT_SYNCSTATE].Value.ToString();
            String newSyncStateStr     = trSyncStateToString[newSyncState];

            bool incomingChange = user.Equals(HandlerSettings.TFSProviderUser, StringComparison.OrdinalIgnoreCase);

            newSyncStateStr = String.Format(newSyncStateStr, incomingChange ? "(in)" : "(out)");

            if (!currentSyncStateStr.Equals(trSyncStateToString))
            {
                workItem.Fields[TFSMapper.ERICSSON_DEFECT_SYNCSTATE].Value = newSyncStateStr;
            }
        }
コード例 #24
0
        // ======================================================================================
        // REST calls to create or update

        public void callCreateTR(EnterpriseChangeRequest ecr, String user, ref Status status)
        {
            HttpResponseMessage creationResponse = null;
            String message;

            try
            {
                creationResponse = getOslcClient().CreateResource(
                    HandlerSettings.CreationFactoryUri, ecr,
                    OslcMediaType.APPLICATION_RDF_XML,
                    OslcMediaType.APPLICATION_RDF_XML,
                    HandlerSettings.getRESTHeaders(user));
                message = (creationResponse != null) ?
                          creationResponse.Content.ReadAsStringAsync().Result :
                          "No result when calling " + HandlerSettings.CreationFactoryUri;
            }
            catch (Exception ex)
            {
                HandlerSettings.LogMessage(
                    String.Format("Failed to create ECR: '{0}'", ex.Message),
                    HandlerSettings.LoggingLevel.ERROR);
                status.ErrorMessage = "Failed to create TR from Bug. Error: '" + ex.Message + "'";
                return;
            }

            if (creationResponse == null || creationResponse.StatusCode != HttpStatusCode.Created)
            {
                HandlerSettings.LogMessage(
                    String.Format("Failed to create ECR. Error from MHWeb: '{0}'", message),
                    HandlerSettings.LoggingLevel.ERROR);
                status.ErrorMessage = "Failed to create TR from Bug. Error from MHWeb: '" + message + "'";
                return;
            }
            else
            {
                // Log the incoming rdf
                HandlerSettings.LogMessage(
                    String.Format("Response from create:\n{0}", message),
                    HandlerSettings.LoggingLevel.INFO);
            }

            EnterpriseChangeRequest newEcr = creationResponse.Content.
                                             ReadAsAsync <EnterpriseChangeRequest>(getOslcClient().GetFormatters()).Result;

            status.TRAbout = newEcr.GetAbout();
            String shortState = newEcr.GetStatus();

            status.TRState = ECRMapper.getLongTRState(shortState);

            HandlerSettings.LogMessage(
                String.Format("ECR named {0} created a location: {1}", newEcr.GetTitle(), status.TRAbout),
                HandlerSettings.LoggingLevel.INFO);

            // Verify result
            if (shortState == null || shortState != ECRMapper.TR_STATE_PRIVATE_S)
            {
                status.ExpectedStateMessage =
                    String.Format("Created ECR in wrong state: {0} expected: PR", shortState);
                HandlerSettings.LogMessage(status.ExpectedStateMessage, HandlerSettings.LoggingLevel.WARN);
            }

            return;
        }
コード例 #25
0
        public void callUpdateTR(EnterpriseChangeRequest ecr, String user, String expectedState, ref Status status)
        {
            String message = null;
            HttpResponseMessage updateResponse = null;

            try
            {
                String about = ecr.GetAbout().ToString();
                updateResponse = getOslcClient().UpdateResource(
                    about, ecr,
                    OslcMediaType.APPLICATION_RDF_XML,
                    OslcMediaType.APPLICATION_RDF_XML,
                    HandlerSettings.getRESTHeaders(user));
                message = (updateResponse != null) ?
                          updateResponse.Content.ReadAsStringAsync().Result :
                          "No result when calling " + about;
            }
            catch (Exception ex)
            {
                HandlerSettings.LogMessage(
                    String.Format("Failed to update ECR: '{0}'", ex.Message),
                    HandlerSettings.LoggingLevel.ERROR);
                status.ErrorMessage = "Failed to update TR from Bug. Error: '" + ex.Message + "'";
                return;
            }

            if (updateResponse == null || updateResponse.StatusCode != HttpStatusCode.OK)
            {
                HandlerSettings.LogMessage(
                    String.Format("Failed to update ECR. Error from MHWeb: '{0}'", message),
                    HandlerSettings.LoggingLevel.ERROR);

                // If trying a state change, report as error - otherwise as warning
                if (expectedState != null)
                {
                    status.ErrorMessage = "Failed to update TR from Bug. Error from MHWeb: '" + message + "'";
                }
                else
                {
                    status.WarningMessage = "Warnings when update TR from Bug. Message from MHWeb: '" + message + "'";
                }
                return;
            }
            else
            {
                // Log the incoming rdf
                HandlerSettings.LogMessage(
                    String.Format("Response from update:\n{0}", message),
                    HandlerSettings.LoggingLevel.INFO);
            }

            // NOTE: MHWeb return an updated item. This is convenient, but not by spec.
            // Might need an explicit GET here to make more robust if other clients.
            EnterpriseChangeRequest newEcr = updateResponse.Content.
                                             ReadAsAsync <EnterpriseChangeRequest>(getOslcClient().GetFormatters()).Result;
            String shortState = newEcr.GetStatus();

            status.TRState = ECRMapper.getLongTRState(shortState);

            if (expectedState != null)
            {
                // Verify result if we did a state change

                if (shortState == null || shortState != expectedState)
                {
                    status.ExpectedStateMessage =
                        String.Format("The ECR is in wrong state: {0} expected: {1}", shortState, expectedState);
                    HandlerSettings.LogMessage(status.ExpectedStateMessage, HandlerSettings.LoggingLevel.WARN);
                }
                HandlerSettings.LogMessage(
                    String.Format("The ECR named {0} is updated to state: {1}", newEcr.GetTitle(), status.TRState),
                    HandlerSettings.LoggingLevel.INFO);
            }
            else
            {
                HandlerSettings.LogMessage(
                    String.Format("The ECR named: {0} is updated", newEcr.GetTitle()),
                    HandlerSettings.LoggingLevel.INFO);
            }

            return;
        }
コード例 #26
0
        // Return an EnterpriseChangeRequest with mapped values needed for the state transiton
        // If there is a fail with mapping some values, this will be captured in event log.
        // TODO: This could likely be described in a xml mapping file for configuration
        public static EnterpriseChangeRequest mapFromWorkitem(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem,
            Uri about,
            String action)
        {
            EnterpriseChangeRequest newEcr = new EnterpriseChangeRequest();

            newEcr.SetAbout(about);

            // Create a mapped ECR based on suggested action

            switch (action)
            {
            case ACTION_CREATE:
                newEcr.SetTitle(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_TITLE, workItem));
                newEcr.SetDescription(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_DESCRIPTION, workItem));
                newEcr.SetCurrentMho(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CURRENT_MHO, workItem));
                newEcr.SetCustomer(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CUSTOMER, workItem));
                newEcr.SetProduct(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_PRODUCT, workItem));
                newEcr.SetProductRevision(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_PRODUCT_REVISION, workItem));
                newEcr.SetNodeProduct(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_NODE_PRODUCT, workItem));
                newEcr.SetNodeProductRevision(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_NODE_PRODUCT_REVISION, workItem));

                // Note: The field firstTechnicalContact also is needed for TR creation. This we retrieve from
                // the user in the create notification, and put in the REST call header as required by MHWeb.
                // Formally we have mapping specified in ERICSSON_DEFECT_CREATOR_SIGNUM, but not used.

                // Add the connected Bug as related link
                Uri    relatedBug             = new Uri(HandlerSettings.GetUriForBug(workItem.Id.ToString()));
                String label                  = workItem.Id.ToString() + ": " + workItem.Title;
                OSLC4Net.Core.Model.Link link = new OSLC4Net.Core.Model.Link(relatedBug, label);
                newEcr.AddRelatedChangeRequest(link);

                break;

            case ACTION_REGISTER_ROUTE:
                newEcr.SetAction(ACTION_REGISTER_ROUTE);
                newEcr.SetImpactOnISP(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_IMPACT_ON_ISP, workItem));
                newEcr.SetPriority(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_PRIORITY, workItem));
                newEcr.SetDiddet(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_DIDDET, workItem));
                newEcr.SetActivity(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_ACTIVITY, workItem));
                newEcr.SetFirstTechContactInfo(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_FIRST_TECHNICAL_CONTACT_INFO, workItem));
                newEcr.SetCountry(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_COUNTRY, workItem));
                newEcr.SetSite(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_SITE, workItem));

                break;

            case ACTION_ASSIGN:
                newEcr.SetAction(ACTION_ASSIGN);
                newEcr.SetOwner(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_OWNER, workItem));
                break;

            case ACTION_PROPOSE:
                newEcr.SetAction(ACTION_PROPOSE);
                newEcr.SetDiddet(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_DIDDET, workItem));
                newEcr.SetActivity(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_ACTIVITY, workItem));
                newEcr.SetFirstTechContactInfo(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_FIRST_TECHNICAL_CONTACT_INFO, workItem));
                newEcr.SetExpectedImpactOnISP(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_EXPECTED_IMPACT_ON_ISP, workItem));
                newEcr.SetAnswer(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_ANSWER, workItem));
                newEcr.SetFaultCode(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_FAULTCODE, workItem));
                newEcr.SetAnswerCode(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_ANSWER_CODE, workItem));

                // Corrected Product info is mandatory for some  answerCodes and optional for others. Here
                // we pass in all cases and let the bug.xml handle mandatoryness and mhweb complain if not
                // present.

                newEcr.SetCorrectedProduct(
                    AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CORRECTED_PRODUCT, workItem));
                newEcr.SetCorrectedProductRevision(
                    AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CORRECTED_PRODUCT_REVISION, workItem));
                newEcr.SetCorrectedNodeProduct(
                    AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CORRECTED_NODE_PRODUCT, workItem));
                newEcr.SetCorrectedNodeProductRevision(
                    AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CORRECTED_NODE_PRODUCT_REVISION, workItem));
                break;

            case ACTION_APPROVE:
                newEcr.SetAction(ACTION_APPROVE);
                break;

            case ACTION_VERIFY:
                newEcr.SetAction(ACTION_VERIFY);
                newEcr.SetCorrectedNodeProduct(
                    AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CORRECTED_NODE_PRODUCT, workItem));
                newEcr.SetCorrectedNodeProductRevision(
                    AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CORRECTED_NODE_PRODUCT_REVISION, workItem));
                break;

            case ACTION_ANSWER:
                newEcr.SetAction(ACTION_ANSWER);
                newEcr.SetCorrectedNodeProduct(
                    AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CORRECTED_NODE_PRODUCT, workItem));
                newEcr.SetCorrectedNodeProductRevision(
                    AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_CORRECTED_NODE_PRODUCT_REVISION, workItem));
                break;

            case ACTION_ACCEPT:
                newEcr.SetAction(ACTION_ACCEPT);
                break;

            case ACTION_REJECT:
                newEcr.SetAction(ACTION_REJECT);
                newEcr.SetNotebook(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_NOTEBOOK, workItem));
                break;

            case ACTION_DUPLICATE:
                newEcr.SetAction(ACTION_DUPLICATE);
                newEcr.SetPrimaryTR(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_PRIMARYTR, workItem));
                break;

            case ACTION_UNDUPLICATE:
                newEcr.SetAction(ACTION_UNDUPLICATE);
                break;

            case ACTION_CHANGE_PRODUCT:
                newEcr.SetAction(ACTION_CHANGE_PRODUCT);
                newEcr.SetProduct(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_PRODUCT, workItem));
                newEcr.SetProductRevision(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_PRODUCT_REVISION, workItem));
                newEcr.SetNodeProduct(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_NODE_PRODUCT, workItem));
                newEcr.SetNodeProductRevision(AttributesMapper.GetTfsValueForEcrKey(TFSMapper.ECM_NODE_PRODUCT_REVISION, workItem));
                break;

            case ACTION_REACTIVATE:
                newEcr.SetAction(ACTION_REACTIVATE);
                break;

            case ACTION_FINISH:
                newEcr.SetAction(ACTION_FINISH);
                break;

            case ACTION_DISCONNECT:
                newEcr.SetAction(ACTION_DISCONNECT);
                break;
            }

            return(newEcr);
        }
コード例 #27
0
        // Return an EnterpriseChangeRequest with mapped values for the update
        public static EnterpriseChangeRequest mapFromUpdatedWorkitem(
            Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem,
            Uri about,
            WorkItemChangedEvent notification)
        {
            EnterpriseChangeRequest newEcr = new EnterpriseChangeRequest();

            newEcr.SetAbout(about);

            // The notification contain all changed fields. To understand what to
            // propagate to the client, we need to check which ecm fields that are
            // affected by the changes and are configured for notifyChange

            int noOfMappedChanged = 0;

            if (notification.ChangedFields != null)
            {
                // Most fields are String fields
                StringField[] changedStrFields = notification.ChangedFields.StringFields;
                if (changedStrFields != null)
                {
                    for (int i = 0; i < changedStrFields.Length; i++)
                    {
                        String fieldName = changedStrFields[i].ReferenceName;
                        noOfMappedChanged += mapFromUpdated(workItem, newEcr, fieldName);
                    }
                }

                // For example Priority is an Integer field
                IntegerField[] changedIntFields = notification.ChangedFields.IntegerFields;
                if (changedIntFields != null)
                {
                    for (int i = 0; i < changedIntFields.Length; i++)
                    {
                        String fieldName = changedIntFields[i].ReferenceName;
                        noOfMappedChanged += mapFromUpdated(workItem, newEcr, fieldName);
                    }
                }
            }

            // For example the Description is a Text field
            TextField[] changedTextFields = notification.TextFields;
            if (changedTextFields != null)
            {
                for (int i = 0; i < changedTextFields.Length; i++)
                {
                    String fieldName = changedTextFields[i].ReferenceName;
                    noOfMappedChanged += mapFromUpdated(workItem, newEcr, fieldName);
                }
            }

            // To find a change in the Comment/History one need to look at revision - 1.
            noOfMappedChanged += mapFromUpdated(workItem, newEcr, TFSMapper.TFS_HISTORY);

            // Need to send list of attachments in all cases when we have another update. So if we already have
            // an update (noOfMappedChanged > 0), send - otherwise, check if changed then send.
            if ((noOfMappedChanged > 0 || TFSMapper.getInstance().hasLinksChanged(workItem)))
            {
                noOfMappedChanged += mapFromUpdated(workItem, newEcr, TFSMapper.ERICSSON_DEFECT_HYPERLINK);
            }

            if (noOfMappedChanged > 0)
            {
                // More than 1 field that was mapped changed
                return(newEcr);
            }
            else
            {
                // No field of interest was changed
                HandlerSettings.LogMessage(
                    String.Format("No mapped fields was updated for: {0}", workItem.Title),
                    HandlerSettings.LoggingLevel.INFO);
                return(null);
            }
        }
コード例 #28
0
        // =======================================================================
        // Mapping from workItem to ECR

        // Return the Bug and TR state change if part of update
        public static void getStatusChange(WorkItemChangedEvent notification,
                                           Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem,
                                           out String oldState,
                                           out String newState,
                                           out String action)
        {
            newState = null;
            oldState = null;
            action   = null;

            // If the Bug and TR are in different states, block update from Bug to TR.
            if (ECRMapper.IsSyncError(workItem))
            {
                action = ACTION_IGNORE;
                return;
            }

            bool changedAssignedTo = false;

            // If Bug marked as Duplicate, the only activity to be propagated to TR is Unduplicate.
            String substate           = workItem.Fields[TFSMapper.TFS_SUBSTATE].Value.ToString();
            bool   isDuplicate        = substate.Equals(TFSMapper.TFS_SUBSTATE_DUPLICATE);
            bool   isDuplicateChanged = false;

            if (notification.ChangedFields == null || notification.ChangedFields.StringFields == null)
            {
                // No fields of interest are changed
                return;
            }

            StringField[] changedFields = notification.ChangedFields.StringFields;
            for (int i = 0; i < changedFields.Length; i++)
            {
                String name = changedFields[i].ReferenceName;
                if (name.Equals(TFSMapper.TFS_STATE, StringComparison.OrdinalIgnoreCase))
                {
                    oldState = changedFields[i].OldValue;
                    newState = changedFields[i].NewValue;
                }
                else if (name.Equals(TFSMapper.TFS_OWNER, StringComparison.OrdinalIgnoreCase))
                {
                    changedAssignedTo = true;
                }

                // If TFS_SUBSTATE is changed to/from Duplicate the TR should be set to
                // corresponding state. If marked as Duplicate, the only activity that
                // should be propagated to TR is Unduplicate.
                else if (name.Equals(TFSMapper.TFS_SUBSTATE))
                {
                    if (changedFields[i].NewValue.Equals(TFSMapper.TFS_SUBSTATE_DUPLICATE) ||
                        changedFields[i].OldValue.Equals(TFSMapper.TFS_SUBSTATE_DUPLICATE))
                    {
                        isDuplicateChanged = true;
                    }
                }

                // If the release is changed, we need to update the TR product
                // Note: In case we also set to Duplicate, we will disregard product change
                else if (name.Equals(TFSMapper.TFS_FAULTY_PRODUCT))
                {
                    action = ACTION_CHANGE_PRODUCT;
                }
            }

            if (isDuplicateChanged)
            {
                // If the Duplicate flag is changed we need to act on this. This is a substate flag, so
                // it can happen also during a state transition.
                action = isDuplicate ? ACTION_DUPLICATE : ACTION_UNDUPLICATE;
                return;
            }
            else if (isDuplicate)
            {
                // If Bug is duplicate and there is no change for this state, we should send no
                // updates to TR until unduplicated.
                action = ACTION_IGNORE;
                return;
            }

            // If we have a changed of "Assigned To" this will only be possible to update in specific
            // TR states. So if Assigned To changed at same time as state - likely need to prevent.
            if (changedAssignedTo)
            {
                if (newState == null || oldState == null)
                {
                    // No state change for Bug, but for TR
                    oldState = BUG_STATE_ACTIVE;
                    newState = BUG_STATE_ACTIVE;
                }
                else
                {
                    HandlerSettings.LogMessage(
                        String.Format(
                            "The 'Assigned To' change can not be done for TR: {0} at same time as state change",
                            workItem.Title),
                        HandlerSettings.LoggingLevel.WARN);
                }
            }
        }