diff --git a/cmd.py b/cmd.py new file mode 100644 index 0000000..fc8ae44 --- /dev/null +++ b/cmd.py @@ -0,0 +1,329 @@ +# -*- coding: utf8 -*- +import datetime +from pylarion.document import Document +from pylarion.work_item import TestCase +from pylarion.work_item import Requirement +from pylarion.test_run import TestRun +from pylarion.plan import Plan + + +class CmdList(object): + ''' An object to manage the command of list''' + + def list_documents_by_query(self, + query): + fields = ['document_id', + 'document_name', + 'author', + 'created', + 'updated', + 'updated_by'] + doc_list = Document.query(query, False, fields) + + return doc_list + + def print_documents(self, docs): + print 'Created%7sAuthor%7sDocument' % ('', '') + print '-------%7s------%7s--------' % ('', '') + + for doc in docs: + print '%-14s %-11s %s' % (doc.created.strftime('%Y-%m-%d'), + doc.author, + doc.document_id) + + def list_workitems_in_doc(self, doc_name_with_space): + if doc_name_with_space.find('/') < 0: + print "Document format should be: 'space/document'" + exit(1) + + doc = Document(Document.default_project, doc_name_with_space) + fields = ['work_item_id', + 'author', + 'title', + 'type', + 'status', + 'assignee', + 'categories', + 'comments', + 'created', + 'approvals', + 'updated'] + self.workitem_list = doc.get_work_items(None, True, fields) + return self.workitem_list + + def print_workitems(self, workitems): + print 'Type%10sID%12sDescription' % ('', '') + print '-------%7s-----%9s--------' % ('', '') + + for wi in workitems: + print '%-13s %-13s %s' % (wi.type, wi.work_item_id, wi.title) + + def print_steps_for_testcase(self, case_id): + tc = TestCase(TestCase.default_project, case_id) + steps = tc.get_test_steps() + + for step in steps.steps: + stp = step.values[0].content + exp = step.values[1].content + print 'TestStep = %s' % stp + print 'ExpectedResult = %s\n' % exp + + if steps.steps is None: + print 'No step for this tesecase!' + + def print_links_for_requirement(self, req_id): + req = Requirement(Requirement.default_project, req_id) + print 'ID%-12sRole' % ('') + print '-------%7s------' % ('') + + for linked in req.linked_work_items_derived: + print '%-13s %-13s' % (linked.work_item_id, + linked.role) + + def print_links_for_testcase(self, case_id): + tc = TestCase(TestCase.default_project, case_id) + print 'ID%-12sRole' % ('') + print '-------%7s------' % ('') + + for linked in tc.linked_work_items: + print '%-13s %-13s' % (linked.work_item_id, + linked.role) + + def print_runs_by_query(self, query, is_template=False): + query_ful = 'project.id:%s AND %s' % (TestRun.default_project, query) + fields = ['query', + 'created', + 'test_run_id', + 'select_test_cases_by', + 'status', + 'plannedin', + 'assignee', + 'author'] + + st = TestRun.search(query_ful, + fields, + 'created', + -1, + is_template) + Object = '' + if is_template: + Object = 'Template' + + prestr = 'Created Time %8sAuthor %3sAssignee' % ('', '') + latstr = '%sStatus %3sPlanID%10s%s' % ('', '', '', Object) + preln = '------------%9s------%4s------' % ('', '') + latln = '%2s--------%2s-------%9s--------' % ('', '', '') + + print '%s %s' % (prestr, latstr) + print '%s %s' % (preln, latln) + + for tp in st: + created_time = str(tp.created).split('.')[0] + print '%-20s %-9s %-8s %-10s%-15s %s' % (created_time, + tp.author, + tp.assignee, + tp.status, + tp.plannedin, + tp.test_run_id) + + def print_templates_by_query(self, query): + self.print_runs_by_query(query, True) + + def print_testcases_from_run(self, run): + tr = TestRun(run, None, TestRun.default_project) + print '(Only CaseID can be displayed when --run=$template)' + print('List cases for: %s\n' % run) + ttstr = ('Created Time %8sStatus %1sExecutedBy %2sCaseID' % ('', + '', + '')) + lnstr = ('------------%9s------%2s----------%3s------' % ('', '', '')) + print ttstr + print lnstr + + for rec in tr.records: + time = str(rec.executed).split('.')[0] + print('%-21s%-9s%-12s%-10s' % (time, + rec.result, + rec.executed_by, + rec.test_case_id)) + + def print_plan_ids(self, query): + pls = Plan.search(query, + sort='due_date', + limit=-1, + fields=['due_date', + 'name', + 'plan_id']) + + ttstr = ('Due Date%-5sPlan ID%-24sPlan Name' % ('', '')) + lnstr = ('----------- ---------- %-20s---------' % '') + print ttstr + print lnstr + + for pl in pls: + print '%-12s %-30s %s' % (pl.due_date, pl.plan_id, pl.name) + + +class CmdUpdate(object): + ''' An object to manage the command of update''' + + def update_all_case_results_for_run(self, run, result, user, comment): + + run = run.strip() + tr = TestRun(run, None, TestRun.default_project) + print '\nUpdate %s:' % run + + if not comment: + comment = '' + + print 'Total records: %d' % len(tr.records) + print 'Updated Date Time Result CaseID' + print '------------------- ------ -----------' + + if user == 'None': + user = TestRun.logged_in_user_id + + for rec in tr.records: + rec.executed = datetime.datetime.now() + rec.executed_by = user + executed_str = str(rec.executed).split('.')[0] + rec.result = result + rec.comment = comment + + print '%-20s %-7s %s' % (executed_str, + result, + rec.test_case_id) + tr.update_test_record_by_object(rec.test_case_id, + rec) + print 'Done!' + + def update_all_case_results_for_runs(self, runs, result, user, comment): + if runs.find(','): + for run in runs.split(','): + self.update_all_case_results_for_run(run, result, + user, comment) + else: + print "Please use comma ',' to seperate your runs!" + + def update_1_case_result_for_run(self, + run, + testcase, + result, + user, + comment): + + if not comment: + comment = '' + + tr = TestRun(run.strip(), None, TestRun.default_project) + print 'Update %s:' % run + + if user == 'None': + user = TestRun.logged_in_user_id + + is_found = False + for rec in tr.records: + if rec.test_case_id == testcase: + is_found = True + rec.executed = datetime.datetime.now() + rec.executed_by = user + rec.result = result + rec.comment = comment + + tr.update_test_record_by_object(testcase, rec) + print "%4sSet %s to %s (verdict comment: '%s')" % ('', + testcase, + result, + comment) + return 0 + + if not is_found: + print 'Test case %s is not found in run.' % testcase + + def update_run(self, + run, + template=None, + plannedin=None, + assignee=None, + status=None, + description=None, + is_template=False): + + run = run.strip() + query_ful = 'project.id:%s AND id:%s' % (TestRun.default_project, + run) + + fields = ['query', + 'created', + 'test_run_id', + 'select_test_cases_by', + 'status', + 'plannedin', + 'assignee', + 'author'] + st = TestRun.search(query_ful, + fields, + 'created', + -1, + is_template) + + # Update run if exists, otherwise create it. + if st: + print 'Update the existing run: %s' % run + tr = TestRun(run, + None, + TestRun.default_project) + + # set fields + if assignee != 'None': + tr.assignee = assignee + print '%4sSet Assignee to %s' % ('', assignee) + if plannedin is not None: + tr.plannedin = plannedin + print '%4sSet Plannedin to %s' % ('', plannedin) + if status is not None: + tr.status = status + print '%4sSet Status to %s' % ('', status) + if description is not None: + tr.description = description + print '%4sSet Description to %s' % ('', description) + tr.update() + + else: + tr = TestRun.create(TestRun.default_project, + run, + template, + assignee=assignee, + plannedin=plannedin, + status=status, + description=description) + # display fields + if assignee != 'None': + print '%4sSet Assignee to %s' % ('', assignee) + if plannedin is not None: + print '%4sSet Plannedin to %s' % ('', plannedin) + if status is not None: + print '%4sSet Status to %s' % ('', status) + if description is not None: + print '%4sSet Description to %s' % ('', description) + print 'Created %s:' % run + + def update_runs(self, + runs, + template=None, + plannedin=None, + assignee=None, + status=None, + description=None): + + if runs.find(','): + for run in runs.split(','): + self.update_run(run, + template, + plannedin, + assignee, + status, + description) + print 'Done!' + else: + print "Please use comma ',' to seperate your runs!" diff --git a/scripts/pylarion-cmd b/scripts/pylarion-cmd index 9192292..64e1895 100755 --- a/scripts/pylarion-cmd +++ b/scripts/pylarion-cmd @@ -1,8 +1,6 @@ #!/usr/bin/env python import os -from pylarion.cli.cmd import Repo -from pylarion.cli.cmd import Config from pylarion.cli.cmd import CmdList from pylarion.cli.cmd import CmdUpdate import click @@ -15,23 +13,23 @@ def cli(): @cli.command() @click.option('-d', '--document', - help='document name.') + help="document with space e.g. 'space/document'") @click.option('-e', '--query', - help='query items') + help="query items e.g. --query='author.id:xhe'") @click.option('-D', '--is_document', default=False, is_flag=True, - help='flag of document') + help='flag indicating that the action will reference a document') @click.option('-i', '--testcase', help='testcase id') @click.option('-l', '--links', default=False, is_flag=True, - help='links of workitem') + help='flag indicating that the action will reference the links') @click.option('-m', '--template', default=False, is_flag=True, - help='test run template') + help='flag indicating that the action will reference a template') @click.option('-p', '--plan_ids', help='plan ids in project') @click.option('-q', '--requirement', @@ -41,14 +39,12 @@ def cli(): @click.option('-s', '--steps', default=False, is_flag=True, - help='steps of testcase') + help='flag indicating that the action will reference the steps') @click.option('-t', '--workitem', default=False, is_flag=True, - help='the flag of workitem') -@click.pass_context -def list(ctx, - document, + help='flag indicating that the action will reference workitem') +def list(document, query, is_document, testcase, @@ -59,82 +55,47 @@ def list(ctx, run, steps, workitem): - '''list documents, testcases, steps of testcase, - links of workitems, runs, templates''' - ctx.obj = Repo(None, # assignee - None, # comment - document, - query, - None, # debug - is_document, - testcase, - links, - template, - None, # plannedin, - None, # result - plan_ids, - requirement, - run, - steps, - workitem, - None, # status - ) - - # read config - LOCAL_CONFIG = os.path.expanduser("~") + "/.pylarion" - condict = Config().getconf(LOCAL_CONFIG) - - # instance list object - list_obj = CmdList(condict['con_space']) - - # get all documents in space - if (not query) and is_document: - docs = list_obj.list_all_documents_under_space() - list_obj.print_documents(docs, - fields=['document_id', - 'document_name', - 'author', - 'updated', - 'updated_by']) - # query document - elif is_document and query: - docs = list_obj.list_documents_by_query(query) - list_obj.print_documents(docs, - fields=['document_id', - 'document_name', - 'author', - 'updated', - 'updated_by']) - # get workitems in doc - elif document and workitem: - wis = list_obj.list_workitems_in_doc('%s/%s' % (condict['con_space'], - document)) - list_obj.print_workitems(wis) - - # get links of testcase - elif links and testcase: - list_obj.print_links_for_testcase(testcase) - - # get links of requirement - elif links and requirement: - list_obj.print_links_for_requirement(requirement) - - # get runs by query - elif (not is_document) and (not template) and query: - list_obj.print_runs_by_query(query) + """list documents, testcases, steps of testcase, links of workitems, runs, + templates. For more info and examples: + https://docs.engineering.redhat.com/x/kzmPAg""" + + # instantiate the list object + list_obj = CmdList() + + # get documents + if is_document and query: + docs = list_obj.list_documents_by_query(query) + list_obj.print_documents(docs), + + # get workitems + elif workitem: + # workitems is from the document: 'space/document' + if document: + wis = list_obj.list_workitems_in_doc(document) + list_obj.print_workitems(wis) + # get testcases is from run/template + elif run: + list_obj.print_testcases_from_run(run) + + # get links + elif links: + if testcase: + list_obj.print_links_for_testcase(testcase) + elif requirement: + list_obj.print_links_for_requirement(requirement) # get templates by query - elif (not is_document) and (query and template): + elif query and template: list_obj.print_templates_by_query(query) + # get runs by query + elif query: + list_obj.print_runs_by_query(query) + # get steps for testcase elif steps and testcase: list_obj.print_steps_for_testcase(testcase) - # get testcases from run/template - elif run and workitem: - list_obj.print_testcases_from_run(run) - # get plan ids elif plan_ids: list_obj.print_plan_ids(plan_ids) @@ -148,8 +109,10 @@ def list(ctx, help="assignee of run") @click.option("-c", "--comment", help="verdict comment of testcase in run") +@click.option("-d", "--description", + help="description of run") @click.option("-e", "--query", - help="query items") + help="query items e.g. --query=author.id:xhe") @click.option('-D', '--debug', default=True, is_flag=True, @@ -166,17 +129,16 @@ def list(ctx, 'blocked']), help="test result in run") @click.option("-r", "--run", - help="test run") + help="test run id") @click.option("-s", "--status", type=click.Choice(['notrun', 'inprogress', 'finished', 'invalid']), help="run status") -@click.pass_context -def update(ctx, - assignee, +def update(assignee, comment, + description, query, debug, testcase, @@ -185,53 +147,37 @@ def update(ctx, result, run, status): + ''' create run(s), update results and custom fileds for run(s). For more + info and examples: https://docs.engineering.redhat.com/x/kzmPAg''' - ''' create run(s), update results and custom fileds for run(s)''' - ctx.obj = Repo(assignee, - comment, - None, # document - query, - debug, - None, # is_document - testcase, - None, # links - template, - plannedin, - result, - None, # plan_ids - None, # requirement - run, - None, # steps - None, # workitem - status) - - # read config - LOCAL_CONFIG = os.path.expanduser("~") + "/.pylarion" - condict = Config().getconf(LOCAL_CONFIG) - - # instance update object + # instantiate the update object update_obj = CmdUpdate() - # update single run - if run and (not result) and (not status): - update_obj.update_runs(run, template, plannedin, assignee) - - # update one case result for run - elif run and result and testcase: - update_obj.update_1_result_for_runs(run, testcase, result, - assignee, comment) - - # update all cases result for run(s) - elif run and result and (not testcase): - update_obj.update_all_results_for_runs(run, result, - assignee, comment) - - # update status for run(s) - elif run and status: - update_obj.update_status_for_runs(run, status) - + if run: + if result: + if testcase: + # update one case result for runs + update_obj.update_1_case_result_for_run(run, + testcase, + result, + assignee, + comment) + else: + # update all case results for runs + update_obj.update_all_case_results_for_runs(run, + result, + assignee, + comment) + else: + # update/create runs + update_obj.update_runs(run, + template, + plannedin, + assignee, + status, + description) else: - click.echo('Please get usage: pylarion-cmd list --help') + click.echo('Please get usage: pylarion-cmd update --help') if __name__ == '__main__': cli() diff --git a/src/pylarion/cli/cmd.py b/src/pylarion/cli/cmd.py index 96633dd..bd43911 100644 --- a/src/pylarion/cli/cmd.py +++ b/src/pylarion/cli/cmd.py @@ -1,6 +1,5 @@ # -*- coding: utf8 -*- import datetime -import ConfigParser from pylarion.document import Document from pylarion.work_item import TestCase from pylarion.work_item import Requirement @@ -8,113 +7,22 @@ from pylarion.plan import Plan -class Repo(object): - '''Attributes includes the all options of command line''' - def __init__(self, - assignee=None, - comment=None, - document=None, - query=None, - debug=None, - is_document=None, - testcase=None, - links=None, - template=None, - plannedin=None, - result=None, - plan_ids=None, - requirement=None, - run=None, - steps=None, - workitem=None, - status=None): - self.assignee = assignee - self.comment = comment - self.document = document - self.query = query - self.debug = debug - self.is_document = is_document - self.testcase = testcase - self.links = links - self.template = template - self.plannedin = plannedin - self.result = result - self.plan_ids = plan_ids - self.requirement = requirement - self.run = run - self.steps = steps - self.workitem = workitem - self.status = status - - -class Config(object): - '''Attributes includes the usesful parameters in config''' - def __init__(self, - space=None, - plannedin=None, - assignee=None): - self.conf_space = space - self.conf_plannedin = plannedin - - def getconf(self, confile): - condict = {} - cfile = ConfigParser.SafeConfigParser() - - cfile.read(confile) - condict['con_space'] = cfile.get('cmd', 'space') - condict['con_plannedin'] = cfile.get('cmd', 'plannedin') - condict['assignee'] = cfile.get('cmd', 'assignee') - condict['output'] = cfile.get('cmd', 'output') - return condict - - class CmdList(object): - ''' An object to manage the command of update - - Attributes: - space (string) - ''' - - def __init__(self, space=None): - ''' constructor for the Module object. Provide the methods of - command update based on parameters passed in. - - Args: - space: specific space of the repository - - Returns: - None - ''' - - self.space = space - - def list_all_documents_under_space(self, fields=None): - fields = ['document_id', - 'document_name', - 'author', - 'created', - 'updated', - 'updated_by'] - doc_list = Document.get_documents(Document.default_project, - self.space, - fields) - return doc_list + ''' An object to manage the command of list''' def list_documents_by_query(self, - query, - is_sql=False, - fields=None): + query): fields = ['document_id', 'document_name', 'author', 'created', 'updated', 'updated_by'] - doc_list = Document.query(query, is_sql, fields) + doc_list = Document.query(query, False, fields) return doc_list - def print_documents(self, docs, fields): + def print_documents(self, docs): print 'Created%7sAuthor%7sDocument' % ('', '') print '-------%7s------%7s--------' % ('', '') @@ -124,6 +32,10 @@ def print_documents(self, docs, fields): doc.document_id) def list_workitems_in_doc(self, doc_name_with_space): + if doc_name_with_space.find('/') < 0: + print "Document format should be: 'space/document'" + exit(1) + doc = Document(Document.default_project, doc_name_with_space) fields = ['work_item_id', 'author', @@ -253,27 +165,13 @@ def print_plan_ids(self, query): class CmdUpdate(object): - ''' An object to manage the command of update - - Attributes: - None - ''' + ''' An object to manage the command of update''' - def __init__(self): - ''' constructor for the Module object. Provide the methods of - command update based on parameters passed in. + def update_all_case_results_for_run(self, run, result, user, comment): - Args: - None - - Returns: - None - ''' - - def update_all_results_for_run(self, run, result, user, comment): - - tr = TestRun(run.strip(), None, TestRun.default_project) - print 'Update %s:' % run.strip() + run = run.strip() + tr = TestRun(run, None, TestRun.default_project) + print '\nUpdate %s:' % run if not comment: comment = '' @@ -299,19 +197,20 @@ def update_all_results_for_run(self, run, result, user, comment): rec) print 'Done!' - def update_all_results_for_runs(self, runs, result, user, comment): + def update_all_case_results_for_runs(self, runs, result, user, comment): if runs.find(','): for run in runs.split(','): - self.update_all_results_for_run(run, result, user, comment) + self.update_all_case_results_for_run(run, result, + user, comment) else: - print 'Please use comma \',\' to seperate your runs!' + print "Please use comma ',' to seperate your runs!" - def update_1_result_for_run(self, - run, - testcase, - result, - user, - comment): + def update_1_case_result_for_run(self, + run, + testcase, + result, + user, + comment): if not comment: comment = '' @@ -322,42 +221,31 @@ def update_1_result_for_run(self, if user == 'None': user = TestRun.logged_in_user_id + is_found = False for rec in tr.records: - rec.executed = datetime.datetime.now() - rec.executed_by = user - rec.result = result - rec.comment = comment - if rec.test_case_id == testcase: - tr.update_test_record_by_object(testcase, rec) - print '%4sSet %s to %s (verdict %s)' % ('', - testcase, - result, - comment) - print 'Done!' + is_found = True + rec.executed = datetime.datetime.now() + rec.executed_by = user + rec.result = result + rec.comment = comment - def update_1_result_for_runs(self, - runs, - testcase, - result, - user, - comment): + tr.update_test_record_by_object(testcase, rec) + print "%4sSet %s to %s (verdict comment: '%s')" % ('', + testcase, + result, + comment) + return 0 - if runs.find(','): - for run in runs.split(','): - self.update_1_result_for_run(run, - testcase, - result, - user, - comment) - else: - print 'Please use comma \',\' to seperate your runs!' + if not is_found: + print 'Test case %s is not found in run.' % testcase def update_status_for_run(self, run, status): - tr = TestRun(run.strip(), None, TestRun.default_project) + run = run.strip() + tr = TestRun(run, None, TestRun.default_project) tr.status = status tr.update() print 'Updated %s status -> %s' % (run, status) @@ -370,18 +258,20 @@ def update_status_for_runs(self, for run in runs.split(','): self.update_status_for_run(run, status) else: - print 'Please use comma \',\' to seperate your runs!' + print "Please use comma ',' to seperate your runs!" def update_run(self, run, template=None, plannedin=None, assignee=None, + status=None, + description=None, is_template=False): - qrun = run.replace('-', '\-') + run = run.strip() query_ful = 'project.id:%s AND id:%s' % (TestRun.default_project, - qrun.strip()) + run) fields = ['query', 'created', @@ -400,40 +290,60 @@ def update_run(self, # Update run if exists, otherwise create it. if st: print 'Update the existing run: %s' % run - tr = TestRun(run.strip(), + tr = TestRun(run, None, TestRun.default_project) - else: - tr = TestRun.create(TestRun.default_project, - run.strip(), - template) - print '\nCreated %s:' % run - # set customer filed of plannedin - if plannedin: - tr.plannedin = plannedin - print '%4sSet Plannedin to %s' % ('', plannedin) + # set fields + if assignee != 'None': + tr.assignee = assignee + print '%4sSet Assignee to %s' % ('', assignee) + if plannedin is not None: + tr.plannedin = plannedin + print '%4sSet Plannedin to %s' % ('', plannedin) + if status is not None: + tr.status = status + print '%4sSet Status to %s' % ('', status) + if description is not None: + tr.description = description + print '%4sSet Description to %s' % ('', description) + tr.update() - if assignee == 'None': - tr.assignee = TestRun.logged_in_user_id else: - tr.assignee = assignee - - print '%4sSet Assignee to %s' % ('', tr.assignee) - tr.update() + tr = TestRun.create(TestRun.default_project, + run, + template, + assignee=assignee, + plannedin=plannedin, + status=status, + description=description) + # display fields + if assignee != 'None': + print '%4sSet Assignee to %s' % ('', assignee) + if plannedin is not None: + print '%4sSet Plannedin to %s' % ('', plannedin) + if status is not None: + print '%4sSet Status to %s' % ('', status) + if description is not None: + print '%4sSet Description to %s' % ('', description) + print 'Created %s:' % run def update_runs(self, runs, template=None, plannedin=None, - assignee=None): + assignee=None, + status=None, + description=None): if runs.find(','): for run in runs.split(','): self.update_run(run, template, plannedin, - assignee) + assignee, + status, + description) print 'Done!' else: - print 'Please use comma \',\' to seperate your runs!' + print "Please use comma ',' to seperate your runs!"