def getworkitemtitle(wrkitemid):
    # HTTP Basic Auth with personal access token
    client = TFSAPI("TFS URL HERE", project="TFS PROJECT", pat='patid')
    # For single Workitem
    workitem = client.get_workitem(int(wrkitemid))

    # Get all fields
    # Case insensitive. Remove space in field name
    return workitem['Title']
def getacptnccriteria(wrkitemid):
    # HTTP Basic Auth with personal access token
    client = TFSAPI("TFS URL HERE", project="TFS PROJECT", pat='patid')
    # For single Workitem

    workitem = client.get_workitem(int(wrkitemid))
    actnccrit = html2text.html2text(
        workitem['Microsoft.VSTS.Common.AcceptanceCriteria'])
    # Get all fields
    # Case insensitive. Remove space in field name
    return actnccrit
Exemple #3
0
def getquerydetails():
    # HTTP Basic Auth with personal access token
    client = TFSAPI("http://tfs2.dell.com:8080/tfs/eDell/",
                    project="eDellPrograms",
                    pat='dgi5cehn7jg3rpn5enmovn2xj47thnx77vsg5uyv7wiz227ckpaa')
    query = client.run_query('c03cebf1-1bb2-4c8a-9e75-76ba65ef4020')
    # Get all found workitems
    result = query.result
    workitems = result.workItemRelations
    a = workitems[0].target
    wrkitemlist = []
    lstkeys = []
    lstvalues = []
    openwith = {}
    for wrktimid in workitems:
        trgt = wrktimid.target
        wrkitemlist.append(int(trgt.id))

    for b in workitems:
        strchanges = []
        stre2estrtchanges = []
        trgt = b.target
        sit_strt = False
        e2e_strt = False
        ttltimeelapsed = ''
        applicatn = ''
        # expctdappln =sys.argv[1]
        wrkitm = client.get_workitem(int(trgt.id))
        wrkitmfields = wrkitm.fields
        if ('Dell.SDLC.Application' in wrkitmfields.keys()):
            applicatn = wrkitmfields['Dell.SDLC.Application']

        if ('OSC' in applicatn):
            if (str(wrkitm['System.WorkItemType']) == "Story"
                    or str(wrkitm['System.WorkItemType']) == "Feature"):
                rev = wrkitm.revisions
                for re in rev:
                    fieldacss = re.data
                    for key, value in fieldacss.items():
                        if (key == 'fields'):
                            allfields = fieldacss[key]
                            if ('Dell.SDLC.Application' in allfields.keys()):
                                applicatn = fieldacss[key][
                                    'Dell.SDLC.Application']

                            revstate = fieldacss[key]['System.State']
                            strchngdby = fieldacss[key]['System.ChangedBy']
                            # stre2ereqd = fieldacss[key]['Dell.SDLC.QERequired']

                            if ('OSC' in applicatn):
                                if (revstate == 'Ready for E2E testing'):
                                    sit_strt = True
                                    changedate = fieldacss[key][
                                        'System.ChangedDate']
                                    if (trgt.id in wrkitemlist):
                                        wrkitemlist.remove(trgt.id)

                                    stre2estrtchanges.append(changedate)
                                    # strchanges.append(strchngdby)
                                    # strchanges.append(stre2ereqd)
                                if (revstate == 'E2E Testing Started'):
                                    e2e_strt = True
                                    e2echangedate = fieldacss[key][
                                        'System.ChangedDate']
                                    if (trgt.id in wrkitemlist):
                                        wrkitemlist.remove(trgt.id)
                                    strchanges.append(e2echangedate)
                                    strchanges.append(strchngdby)
                                    # strchanges.append(stre2ereqd)
                            if (sit_strt == True and e2e_strt == True):
                                e2eprpdate = parser.parse(stre2estrtchanges[0])
                                e2estrtpdate = parser.parse(strchanges[-2])
                                ttltimeelapsed = e2estrtpdate - e2eprpdate
                                openwith[trgt.id] = [
                                    str(trgt.id),
                                    str(ttltimeelapsed.days),
                                    stre2estrtchanges[0], strchanges[-2],
                                    strchanges[-1]
                                ]

    for key, value in openwith.items():
        print(key, ' --> ', value)
        lstkeys.append(key)
        lstvalues.append(value)

    dfObj = pd.DataFrame(
        lstvalues,
        columns=['id', 'totaltime', 'readyfor2e', 'e2estarted', 'owner'])
    # name_dict = {
    #     'Name': lstkeys,
    #     'changeby': lstvalues[0][2],
    #     'totaltimeelapsed': lstvalues[0]
    # }
    dfObj.to_csv('OSC.csv')
Exemple #4
0
#!/usr/bin/env python3

from tfs import TFSAPI

user = "******"
password = "******"

# Use DefaultCollection
#client = TFSAPI("https://http://tfs02.corp.tsafe.systems:8080/tfs/Viableware", user=user, password=password)

# Use CustomCollection
client = TFSAPI("https://http://tfs02.corp.tsafe.systems:8080/tfs/Viableware",
                project="Software Development",
                user=user,
                password=password)

# Set path to ProjectName in project parameter
#client = TFSAPI("https://tfs.tfs.ru/tfs/", project="DefaultCollection/ProjectName", user=user, password=password)

workitem = client.get_workitem(12870)  # Test connection with Workitem id

print(workitem)
Exemple #5
0
class TfsService:
    """
    TFS Service class
    """

    def __init__(self, tfs_server, tfs_project='DefaultCollection'):
        self.__tfs_server = tfs_server
        self.__tfs_project = tfs_project

        self.__is_connected = False
        self.__tfs_client = None
        
        return

    @property 
    def is_connected(self):
        return self.__is_connected

    def connect(self, user_name, user_password, connection_test_item_id):
        '''Connect to TFS Service function
        Using HttpNtlmAuth authication

        Parameters:
            user_name (str): user name
            user_password (str): user password
            connection_test_item_id (int): id of test workitem for connection test
        
        Returns:
            is_connected (Boolean): True if successfully connected. False owerwise.
        '''
        self.__tfs_client = TFSAPI(self.__tfs_server, project=self.__tfs_project,
            user=user_name, password=user_password, auth_type=HttpNtlmAuth)
        
        try:
            wi = self.__tfs_client.get_workitem(int(connection_test_item_id))
            self.__is_connected = True if wi else False
        except:
            self.__is_connected = False

        return self.__is_connected
    
    def get_workitem(self, item_id):
        '''Get workitem and load properties

        Parameters:
            item_id (int): workitem id

        Returns:
            workitem (TfsWorkitem): Workitem with properties. None owerwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        wi = self.__tfs_client.get_workitem(item_id)
        if wi:
            return TfsWorkitem(wi)
        else:
            return None
        
    def get_workitems(self, item_ids):
        '''Get workitems and load properties

        Parameters:
            item_ids (list of int): workitem ids list

        Returns:
            workitems (list of TfsWorkitem): List of workitems with properties. None owerwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        if not isinstance(item_ids, list):
            raise NameError('item_ids should be list')

        ids = [int(id) for id in item_ids]
        workitems = self.__tfs_client.get_workitems(ids)

        if workitems:
            res = [TfsWorkitem(wi) for wi in workitems]
            return res
        else:
            return None

    def save_raw_workitem(self, item_id, props):
        '''Save workitem with given properties

        Parameters:
            item_id (int): workitem id
            props (dict(str, str)): dictionary of properties
        
        Returns:
            result (Boolean): True if saved, False owerwise
        '''
        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        if not isinstance(props, dict):
            raise NameError('props should be dictonary')

        wi = self.__tfs_client.get_workitem(int(item_id))
        if wi:
            for prop_name, prop_value in props.items():
                wi[prop_name] = prop_value

            return True
        else:
            return False
    
    def create_workitem(self, workitem_type, required_fields, props=None):
        '''Create new tfs workitem with given type

        Parameters:
            workitem_type (str): workitem type
            required_fields (dict(str, str)): Required. Dictonary of setted fields.
            props (dict(str, str)): additional dictionary of properties which will be setted after creating item
        
        Returns:
            workitem (TfsWorkitem): Workitem with properties. None overwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        if (required_fields != None) and (not isinstance(required_fields, dict)):
            raise NameError('required_fields should be dictonary')

        if (props != None) and (not isinstance(props, dict)):
            raise NameError('props should be dictonary')

        workitem = self.__tfs_client.create_workitem(workitem_type, fields=required_fields)
        if workitem:
            wi = TfsWorkitem(workitem)
            
            if props != None:
                for prop_name, prop_value in props.items():
                    wi[prop_name] = prop_value
            
            return wi
        else:
            return None

    def copy_workitem(self, 
        workitem, with_links_and_attachments=True,
        suppress_notifications=True, props=None):
        '''Create copy of tfs workitem and set properties

        Parameters:
            workitem (TfsWorkitem or int): workitem or workitem ID
            with_links_and_attachments (Boolean): create copy with links and attachments
            suppress_notifications (Boolean): suppress notifications
            props (dict(str, str)): dictionary of properties
        
        Returns:
            workitem (TfsWorkitem): Copy of given Workitem with properties. None overwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        if (props != None) and (not isinstance(props, dict)):
            raise NameError('props should be dictonary')

        id = workitem.id if workitem is TfsWorkitem else workitem
        source_wi = self.__tfs_client.get_workitem(id)
        if source_wi:
            copy_wi = self.__tfs_client.copy_workitem(source_wi, 
                with_links_and_attachments=with_links_and_attachments,
                suppress_notifications=suppress_notifications)
            
            if copy_wi:
                wi = TfsWorkitem(copy_wi)
                
                if props != None:
                    for prop_name, prop_value in props.items():
                        wi[prop_name] = prop_value
                
                return wi
            else:
                return None
        else:
            raise NameError('Source workitem is None')
    
    def run_query(self, query):
        '''Runs tfs query and return list of workitems

        Parameters:
            query (str): Query string. Named query in folder or query GUID
        
        Returns:
            workitem (list of TfsWorkitem): List of workitems. None overwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        query = self.__tfs_client.run_query(query)
        if query:
            workitems = [TfsWorkitem(wi) for wi in query.workitems] # Lazy generator
            
            return workitems
        else:
            return None

    # uri_params: https://docs.microsoft.com/en-us/rest/api/azure/devops/wit/Wiql/Query%2520By%2520Wiql?view=azure-devops-rest-5.0&viewFallbackFrom=vsts-rest-4.1#uri-parameters
    def run_wiql(self, wiql, uri_params=None):
        '''Runs tfs wiql and return list of workitems

        Parameters:
            wiql (str): wiql query string.
            uri_params (dict (str, str)): extra URI parameters as a dictionary (only works for parameters that come at the end of the link)
        
        Returns:
            workitem (list of TfsWorkitem): List of workitems. None overwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        if (uri_params != None) and (not isinstance(uri_params, dict)):
            raise NameError('URI params should be dictonary. Search \'Wiql - Query By Wiql\' URI Parameters web page')

        query = self.__tfs_client.run_wiql(wiql) if uri_params == None else self.__tfs_client.run_wiql(wiql, params=uri_params)
        if query:
            workitems = [TfsWorkitem(wi) for wi in query.workitems] # Lazy generator
            
            return workitems
        else:
            return None
    
    def find_items(self, search_string,
        wi_fields = ['Id', 'State', 'Title', 'Description']):
        '''
        Search items in TFS. Execute WIQL query.

        Parameters:
            search_string (str): what to search.
            wi_fields (list of str): list of string where to search
        
        Returns:
            workitem (list of TfsWorkitem): List of workitems. None overwise
        '''
        if not wi_fields:
            raise NameError('Workitem fields is empty')

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        fields_str = ', '.join(['[{}]'.format(field) for field in wi_fields])
        conditionals = ('({field} CONTAINS \'{search})\''.format(field=field, search=search_string) for field in wi_fields)
        conditional = ' OR '.join(conditionals)

        wiql = '''
        SELECT {fields}
        FROM Worktitems
        WHERE {conditional}
        ORDER BY [System.Id]
        '''.format(fields=fields_str, conditional=conditional)

        return self.run_wiql(wiql)

    #### https://devopshq.github.io/tfs/advanced.html ####
    ##### https://docs.microsoft.com/ru-ru/rest/api/azure/devops/wit/?view=azure-devops-rest-5.0 ######

    # System.LinkTypes.Hierarchy-Reverse
    def add_parent_link(self, source_workitem, dest_workitem):
        '''Add parent link from source workitem to destination workitem

        Parameters:
            source_workitem (TfsWorkitem): Source workitem
            dest_workitem (TfsWorkitem): Destination workitem
        
        Returns:
            Result (Boolean): True if parent link was added, False overwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')
        
        if source_workitem.add_parent_link(dest_workitem):
            return True
        else:
            return False

    # System.LinkTypes.Hierarchy-Forward
    def add_child_link(self, source_workitem, dest_workitem):
        '''Add child link from source workitem to destination workitem

        Parameters:
            source_workitem (TfsWorkitem): Source workitem
            dest_workitem (TfsWorkitem): Destination workitem
        
        Returns:
            Result (Boolean): True if child link was added, False overwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        if source_workitem.add_child_link(dest_workitem):
            return True
        else:
            return False

    # Microsoft.VSTS.Common.Affects-Forward
    def add_affect_link(self, source_workitem, dest_workitem):
        '''Add affects link from source workitem to destination workitem

        Parameters:
            source_workitem (TfsWorkitem): Source workitem
            dest_workitem (TfsWorkitem): Destination workitem
        
        Returns:
            Result (Boolean): True if affects link was added, False overwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        if source_workitem.add_affect_link(dest_workitem):
            return True
        else:
            return False

    # Microsoft.VSTS.Common.Affects-Reverse
    def add_affected_by_link(self, source_workitem, dest_workitem):
        '''Add affected by link from source workitem to destination workitem

        Parameters:
            source_workitem (TfsWorkitem): Source workitem
            dest_workitem (TfsWorkitem): Destination workitem
        
        Returns:
            Result (Boolean): True if affected by link was added, False overwise
        '''

        if not self.__is_connected:
            raise NameError('Disconnected from TFS Service')

        if source_workitem.add_affected_by_link(dest_workitem):
            return True
        else:
            return False
Exemple #6
0
class TfsIntegration:
    def __init__(self, tfs_url, project, user, password):
        self.project = project
        self.client = TFSAPI(tfs_url,
                             project=project,
                             user=user,
                             password=password,
                             auth_type=HttpNtlmAuth)
        # connect_timeout=10, read_timeout=30

    def get_workitem(self, workitem_id):
        return self.client.get_workitem(workitem_id)

    def get_workitems(self):
        # NOTE: Fields in SELECT really ignored, wiql return Work Items with all fields
        query = """SELECT
            [System.Id],
            [System.WorkItemType],
            [System.Title],
            [System.ChangedDate]
        FROM workitems
        WHERE
            [System.AreaPath] = '{}'
        ORDER BY [System.Title]""".format(self.project)
        # ORDER BY [System.ChangedDate]""".format(self.project)

        wiql = self.client.run_wiql(query)

        # Get founded Work Item ids
        # ids = wiql.workitem_ids

        return wiql.workitems

    def get_testcases(self):
        query = """SELECT
            [System.Id],
            [System.WorkItemType],
            [System.Title],
            [System.ChangedDate]
        FROM workitems
        WHERE
            [System.WorkItemType] = 'Test Case' AND
            [System.AreaPath] = '{}'
        ORDER BY [System.Title]""".format(self.project)

        wiql = self.client.run_wiql(query)
        return wiql.workitems

    def get_testcases_from_testsuite(self, test_suite_id):
        test_suite = self.get_workitem(test_suite_id)
        assert test_suite['WorkItemType'] == 'User Story'

        testcases = []
        for relation in test_suite.data['relations']:
            if relation['rel'] == 'Microsoft.VSTS.Common.TestedBy-Forward':
                workitem_id = self.__get_workitem_id_from_url(relation['url'])
                testcases.append(self.get_workitem(workitem_id))

        # Order by title
        testcases = sorted(testcases, key=lambda testcase: testcase['Title'])
        return testcases

    def get_work_item_by_title(self, title):
        query = """SELECT
            [System.Id],
            [System.WorkItemType],
            [System.Title],
            [System.ChangedDate]
        FROM workitems
        WHERE
            [System.AreaPath] = '{}' AND
            [System.Title] = '{}'""".format(self.project, title)

        workitems = self.client.run_wiql(query).workitems
        assert len(workitems) <= 1
        if len(workitems) == 0:
            return None

        return workitems[0]

    @staticmethod
    def __get_workitem_id_from_url(url):
        # Example:
        # 'url':'https://tfs.e-unicred.com.br/Unicred/70711659-4c4f-4ac0-965c-ae87fbae6d49/_apis/wit/workItems/45327'
        workitem_id = int(url.split('/')[-1])
        return workitem_id

    def get_testcases_from_current_sprint(self):
        query = """SELECT
            [System.Id],
            [System.WorkItemType],
            [System.Title],
            [System.ChangedDate]
        FROM workitems
        WHERE
            [System.WorkItemType] = 'Test Case' AND
            [System.AreaPath] = '{}' AND
            [System.IterationPath] = @CurrentIteration
        ORDER BY [System.Title]""".format(self.project)

        wiql = self.client.run_wiql(query)
        return wiql.workitems

    def get_testsuites(self):
        query = """
        SELECT
            *
        FROM
            workitems
        WHERE
            [System.WorkItemType] = 'User Story' AND
            [System.AreaPath] = '{}' AND
            [Related Link Count] >= 1
        ORDER BY
            [System.Title]""".format(self.project)

        wiql = self.client.run_wiql(query)
        workitems = wiql.workitems

        # Filter for relations.rel = Microsoft.VSTS.Common.TestedBy-Forward
        filtered = set()
        for workitem in workitems:
            for relation in workitem.data['relations']:
                if relation['rel'] == 'Microsoft.VSTS.Common.TestedBy-Forward':
                    filtered.add(workitem)

        return list(filtered)