Thursday, January 15, 2015

How to extend TFS and create a bug/workitem from AX 2012 X++!

This is a sample job that shows how to create a bug in TFS from AX by extending Team Foundation Server using the available TFS assemblies.

You need to add two references to the TFS assemblies.

First copy these files to your client bin direcotry (C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin):

  • C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.WorkItemTracking.Client.dll
  • C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Client.dll
Then in the AOT, on the References node, right click and click "Add Reference".  Then choose "Browse" and navigate to these two files.

Then if you have Team Foundation Server setup as your Version Control System in AX, you can just run this job and it'll create a test bug!  If you have TFS somewhere else, you can just adjust the job some.

I also showed how to enumerate allowed fields, validate before saving the bug, etc.  I have a more complicated class that I wrote that does more error handling, but I tried to keep this as simple as possible for demo purposes.

I currently haven't quite figured out how I want to use this yet.  I was thinking of creating a new MenuItemButton on the infolog form that a select set of users would have security to.  And if an error was present in the infolog, the user could click "Submit Bug".  Still thinking of ideas.

Please also note the couple comments as they will explain a little more.

Good luck, happy New Year, and happy DAXing!

static void JobCreateTFSBug(Args _args)
    Microsoft.TeamFoundation.Client.TfsTeamProjectCollection tfs;
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore store;
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemTypeCollection witc;
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType wit;
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project project;
    Microsoft.TeamFoundation.WorkItemTracking.Client.ProjectCollection projectCollection;
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem;
    SysVersionControlParameters parameters = SysVersionControlParameters::find();

    System.Boolean  netBool;
    System.Collections.ArrayList    invalidFields;
    System.Int32    netInt;
    Microsoft.TeamFoundation.WorkItemTracking.Client.Field      field;
    Microsoft.TeamFoundation.WorkItemTracking.Client.AllowedValuesCollection    allowedValues;
    System.String   netStr;
    str             s, s2;
    int             retVal;
    int             i, n;
    int             arrayCount, arrayCount2;

        tfs    = Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory::GetTeamProjectCollection(Microsoft.TeamFoundation.Client.TfsTeamProjectCollection::GetFullyQualifiedUriForName(parameters.TfsServer));
        store = new Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore(tfs);
        projectCollection   = store.get_Projects();
        project             = projectCollection.get_Item(parameters.TfsProject);
        witc                = project.get_WorkItemTypes();
        wit                 = witc.get_Item('Bug');

        workItem = wit.NewWorkItem();

        workItem.set_Title("Bug Title");
        workItem.set_Description("Bug description");

        // This is how you set a custom field
        //workItem.set_Item('CustomField', 'CustomData');

        // These two lines are equivalent
        // workItem.set_Item('Assigned To', 'AlexOnDAX'); // This is the same as the line below
        workItem.set_Item(Microsoft.TeamFoundation.WorkItemTracking.Client.CoreField::AssignedTo, 'AlexOnDAX');

        netBool = workItem.IsValid();
        if (netBool.Equals(false))
            setPrefix("Error creating work item");
            invalidFields = workItem.Validate();

            netInt = invalidFields.get_Count();
            arrayCount = netInt;
            for (i=0; i<arrayCount; i++)
                field = invalidFields.get_Item(i);
                s = field.get_Name();
                s2 = field.get_Value();
                error(strFmt("Error creating work item\tField '%1' with value '%2' is invalid", s, s2));

                allowedValues = field.get_AllowedValues();
                netInt = allowedValues.get_Count();
                arrayCount2 = netInt;

                for (n=0; n<arrayCount2; n++)
                    netStr = allowedValues.get_Item(n);
                    s = netStr;

                    warning(strFmt("Error creating work item\tAllowed values\t %1", s));
            throw Exception::Error;

            netInt = workItem.get_Id();
            retVal = netInt;
        error(strFmt("@SYS343139", parameters.TfsServer));

    info(strFmt("Created bug %1", retVal));