美文网首页
Rally Python API

Rally Python API

作者: Sank | 来源:发表于2017-01-24 14:47 被阅读188次

    公司采用Rally作为实施敏捷开发的平台和工具,自然少不了自动化。Rally作为大牌敏捷工具其接口也是很丰富的,但baidu上搜到的内容不多,github 上也才是40+ star

    pyral 是其官方支持的python库,底层也是通过封装restful API方式实现。 可以通过pip install pyral 安装
    https://pypi.python.org/pypi/pyral 是其官方文档, 有一个
    https://github.com/RallyTools/RallyRestToolkitForPython 是其gihub的地址,包含了一些基本的操作的例子

    开始code, 一个简单的例子

    文档上给了一些例子:

    import sys
    from pyral import Rally, rallyWorkset
    options = [arg for arg in sys.argv[1:] if arg.startswith('--')]
    args    = [arg for arg in sys.argv[1:] if arg not in options]
    server, user, password, apikey, workspace, project = rallyWorkset(options)
    rally = Rally(server, user, password, apikey=apikey, workspace=workspace, project=project)
    rally.enableLogging('mypyral.log')
    query_criteria = 'FormattedID = "%s"' % args[0]
    response = rally.get('TestCase', fetch=True, query=query_criteria)
    if response.errors:
        sys.stdout.write("\n".join(errors))
        sys.exit(1)
    for testCase in response:  # there should only be one qualifying TestCase
        print "%s %s %s %s" % (testCase.Name, testCase.Type,
                               testCase.DefectStatus, testCase.LastVerdict)
    

    这是个找TestCase 的例子, 很简单,根据Query语句来的'FormattedID = "%s"' % args[0] , 你可以用python gettc.py TC1184 来看TC1184 这个TestCase的信息

    记得query 语句=两边要留有空格,不然会报错。
    有了API Key就可以不用User Name 和 Password了
    在这个网址申请API Key https://rally1.rallydev.com/login/accounts/index.html#/keys

    在pyral中获取object(TestCase, Defect, UserStory,User etc) 的方式一般有两种,一种是FormattedID,另一种是通过ObjectID来获得,上面的例子就是通过FormattedID来query的。 object id 才是真正的id, FormattedID其实就是方便记忆而已,也仅限于一些特定的object才有(US, TC, Feature等), 像TestCaseResult, User等是没有FormattedID的,所以必须要通过object id来获得他们

    再来一个例子

    创建一个新的defect

    proj = rally.getProject()
    
    # get the first (and hopefully only) user whose DisplayName is 'Sally Submitter'
    user = rally.getUserInfo(name='Sally Submitter').pop(0)
    
    defect_data = { "Project" : proj.ref, "SubmittedBy" : user.ref,
                    "Name" : name, "Severity" : severity, "Priority" : priority,
                    "State" : "Open", "ScheduleState" : "Defined",
                    "Description" : description }
    try:
        defect = rally.create('Defect', defect_data)
    except Exception, details:
        sys.stderr.write('ERROR: %s \n' % details)
        sys.exit(1)
    print "Defect created, ObjectID: %s  FormattedID: %s" % (defect.oid, defect.FormattedID)
    

    这个也很简单, 就是用rally.create()的方法去创建一个新的defect,其中可以根据不同公司的要求去创建自己的defect_data,特别是有些custom field 需要自己手动去添加。

    有些entity是需要用ref的,比如上面的user.ref, 可能有些entity没有ref这个变量,你可以试试用_ref

    update 一个defect

     defectID, customer, target_date, notes = args[:4]
     # target_date must be in ISO-8601 format "YYYY-MM-DDThh:mm:ssZ"
    
     defect_data = { "FormattedID" : defectID,
                     "Customer"    : customer,
                     "TargetDate"  : target_date,
                     "Notes"       : notes
                   }
    try:
        defect = rally.update('Defect', defect_data)
    except Exception, details:
        sys.stderr.write('ERROR: %s \n' % details)
        sys.exit(1)
    
    print "Defect %s updated" % defect.FormattedID
    

    这个和之前创建defect的例子比较类似,就是用rally对象的函数来更新rally.update

    获得所有的用户

    all_users = rally.getAllUsers()
        for user in all_users:
            tz   = user.UserProfile.TimeZone or 'default'
            role = user.Role or '-No Role-'
            values = (int(user.oid), user.Name, user.UserName, role, tz)
            print("%12.12d %-24.24s %-30.30s %-12.12s" % values)
    

    以上就是pyral上给出的例子,在github上有更多的例子,简单的功能基本上都可以实现

    Rally.get 函数在restapi.py中可以看到它的详细定义和实现, 建议可以仔细去过一遍代码,粗略看下到底有什么功能, 比如有search, delete这些可能example中并没有很好的使用的例子,需要的话还得自己去挖掘。 国内好像相关的社区也并不发达,要么你去官方发邮件咨询,要么还是自己看代码

    def get(self, entity, fetch=False, query=None, order=None, **kwargs):
    """
     A REST approach has the world seen as resources with the big 4 ops available on them
                (GET, PUT, POST, DELETE). There are other ops but we don't care about them here.
                Each resource _should_ have a unique URI that is used to identify the resource.
                The GET operation is used to specify that we want a representation of that resource.
                For Rally, in order to construct a URI, we need the name of the entity, the attributes
                of the entity (and attributes on any child/parent entity related to the named entity),
                the query (selection criteria) and the order in which the results should be returned.
                The fetch argument (boolean or a comma separated list of attributes) indicates whether 
                we get complete representations of objects back or whether we get "shell" objects with 
                refs to be able to retrieve the full info at some later time.
                An optional instance=True keyword argument will result in returning an instantiated 
                Rally Entity if and only if the resultCount of the get is exactly equal to 1.
                Otherwise, a RallyRESTResponse instance is returned.
    
          All optional keyword args:
                    fetch=True/False or "List,Of,Attributes,We,Are,Interested,In"
                    query='FieldName = "some value"' or ['fld1 = 19', 'fld27 != "Shamu"', etc.]
                    order="fieldName ASC|DESC"
                    instance=False/True
                    pagesize=n
                    start=n
                    limit=n
                    projectScopeUp=True/False
                    projectScopeDown=True/False
    """
    

    这是search 函数的说明

      def search(self, keywords, **kwargs):
            """
                Given a list of keywords or a string with space separated words, issue
                the relevant Rally WSAPI search request to find artifacts within the search
                scope that have any of the keywords in any of the artifact's text fields.
                https://rally1.rallydev.com/slm/webservice/v2.x/search?
                    _slug=%2Fsearch
                    &project=%2Fproject%2F3839949386
                    &projectScopeUp=false
                    &projectScopeDown=true
                    &searchScopeOid=3839949386   # in this case it is the Project ObjectID
                    &searchScopeUp=false
                    &searchScopeDown=true
                    &searchScopeType=project
                    &keywords=wsapi%20documentation
                    &fetch=true
                    &recycledItems=true
                    &includePermissions=true
                    &compact=true
                    &start=1
                    &pagesize=25
                 defaults:
                     projectScopeUp=false
                     projectScopeDown=false
                     includePermissions=true
                     recycledItems=false
                     compact=true
                 A successful search returns SearchObject instances, which have the useful attributes of:
                    ObjectID
                    FormattedID
                    Name
                    Project
                    MatchingText
                    LastUpdateDate
            """
    

    delete 函数的说明

        def delete(self, entityName, itemIdent, workspace='current', project='current', **kwargs):
            """
                Given a Rally entityName, an identification of a specific Rally instnace of that 
                entity (in either OID or FormattedID format), issue the REST DELETE call and 
                return an indication of whether the delete operation was successful.
            """
    

    get allow value:

    from pyral import Rally, rallyWorkset
    import io
    
    RALLY_SERVER='rally1.rallydev.com'
    API_KEY='xxxxxx'
    
    
    class RallyUtil():
    
        def __init__(self):
            self.rally = Rally(server= RALLY_SERVER, apikey=API_KEY,
                          workspace='MicroStrategy Workspace', project='Delivery')
            self.rally.enableLogging('mypyral.log')
    
    
        def get_testset(self):
            criterion = 'FormattedID = TS15992'
            response= self.rally.get('TestSet', fetch='c_ProductionRelease', query=criterion, order="FormattedID", projectScopeDown=True)
            for testset in response:
                print testset.c_ProductionRelease
    
    
    
    
    if __name__ == '__main__':
        rally = RallyUtil()
        rally.get_testset()
    
    
    print self.rally.getAllowedValues('TestSet','c_ProductionRelease')
    

    相关文章

      网友评论

          本文标题:Rally Python API

          本文链接:https://www.haomeiwen.com/subject/haezbttx.html