@@ -32,10 +32,10 @@ def __init__(self, msg):
3232class RequestResponseError (Exception ):
3333
3434 def __init__ (self , msg , status_code ):
35- super (Exception , self ).__init__ ("Request Error: code %s: %s" %
35+ super (Exception , self ).__init__ ("Request Error: code %s: %s" %
3636 (status_code , msg ) )
3737 self .status_code = status_code
38-
38+
3939
4040""" Format unix timestamp to human readable. Automatically detects timestamps with seconds or milliseconds.
4141"""
@@ -324,7 +324,7 @@ def print_available_free_android_devices(self, limit=0):
324324 if device ['creditsPrice' ] == 0 and device ['locked' ] == False and device ['osType' ] == "ANDROID" :
325325 print (device ['displayName' ])
326326 print ("" )
327-
327+
328328 """ Print available frameworks
329329 """
330330 def print_available_frameworks (self , os_type = None , limit = 0 ):
@@ -387,7 +387,7 @@ def get_project(self, project_id):
387387 def print_projects (self , limit = 0 ):
388388 me = self .get_me ()
389389 print ("Projects for %s <%s>:" % (me ['name' ], me ['email' ]))
390-
390+
391391 for project in self .get_projects (limit )['data' ]:
392392 print ("%s %s \" %s\" " % (str (project ['id' ]).ljust (10 ), project ['type' ].ljust (15 ), project ['name' ]))
393393
@@ -468,9 +468,9 @@ def set_project_framework(self, project_id, frameworkId):
468468
469469
470470 """ Start a test run using test run config
471- e.g '{"frameworkId":12252,
472- "osType": "ANDROID",
473- "projectId":1234,
471+ e.g '{"frameworkId":12252,
472+ "osType": "ANDROID",
473+ "projectId":1234,
474474 "files":[{"id":9876}, {"id":5432}]
475475 "testRunParameters":[{"key":"xyz", "value":"abc"}],
476476 "deviceGroupId":6854
@@ -629,7 +629,7 @@ def get_device_run_files(self, project_id, test_run_id, device_session_id, tags=
629629 else :
630630 return self .get ("me/projects/%s/runs/%s/device-sessions/%s/output-file-set/files?tag[]=%s" % (project_id , test_run_id , device_session_id , tags ))
631631
632- """ Get list of input files
632+ """ Get list of input files
633633 """
634634 def get_input_files (self , limit = 0 ):
635635 return self .get ("me/files?limit={}&filter=s_direction_eq_INPUT" .format (limit ))
@@ -650,8 +650,8 @@ def print_builds(self, job_id, limit=0):
650650 for build in self .get_builds (job_id , limit )['data' ]:
651651 print ("%s %s %s %s %s" % (str (build ['id' ]).ljust (12 ), str (build ['buildNumber' ]).ljust (5 ), build ['state' ].ljust (10 ), build ['status' ].ljust (10 ), build ['duration' ]))
652652
653-
654-
653+
654+
655655 """ Get builds from the job
656656 """
657657 def get_builds (self , job_id , limit = 0 ):
@@ -692,14 +692,14 @@ def create_job(self, job_name, content, job_type="BUILD"):
692692 isDirectory
693693 fileUrlEnvVariable
694694
695- usage: client.create_build(job_id, json.dumps({"fileId":123213...))
695+ usage: client.create_build(job_id, json.dumps({"fileId":123213...))
696696 """
697697 def create_build (self , job_id , build_config = {}):
698698 build = self .post (path = "me/jobs/{}/builds" .format (job_id ), payload = build_config , headers = {'Content-type' : 'application/json' , 'Accept' : 'application/json' })
699699 logger .info ("build %s: %s (%s) " % (build ['id' ], build ['buildNumber' ], build ['state' ] ))
700700 return build
701701
702- """ Update job
702+ """ Upload job
703703 """
704704 def upload_job (self , job_id ,job_name , content ):
705705 job = self .post (path = "me/jobs/{}" .format (job_id ), payload = {"name" : job_name , "content" : content })
@@ -756,7 +756,7 @@ def wait_build(self, job_id, build_id):
756756 while True :
757757 time .sleep (self .polling_interval_mins * 6 )
758758 if not self .api_key :
759- self .access_token = None
759+ self .access_token = None
760760 self .get_token ()
761761 buildStatus = self .get_build (job_id , build_id )
762762 if buildStatus and 'state' in buildStatus :
@@ -857,6 +857,91 @@ def download_test_screenshots(self, project_id, test_run_id):
857857 else :
858858 logger .info ("Device %s has errored or has not finished - skipping" % device_run ['device' ]['displayName' ])
859859
860+ """ Get access groups
861+ """
862+ def get_access_groups (self ):
863+ return self .get ("me/access-groups" )
864+
865+ """ Get access group by id
866+ """
867+ def get_access_group (self , access_group_id ):
868+ return self .get ("me/access-groups/{}" .format (access_group_id ))
869+
870+ """ Create access group
871+ """
872+ def create_access_group (self , access_group_name , access_group_scope = "USER" ):
873+ group = self .post (path = "me/access-groups" , payload = {"name" : access_group_name , "scope" : access_group_scope })
874+ return group
875+
876+ """ Update access group
877+ """
878+ def update_access_group (self , access_group_id , access_group_name , access_group_scope ):
879+ # TODO: what if group_name or group_scope aren't provided??
880+ group = self .post (path = "me/access-groups/{}" .format (access_group_id ), payload = {"name" : access_group_name , "scope" : access_group_scope })
881+ return group
882+
883+ """ Delete access group
884+ """
885+ def delete_access_group (self , access_group_id ):
886+ # TODO: what if group_name or group_scope aren't provided??
887+ return self .delete (path = "me/access-groups/{}" .format (access_group_id ))
888+
889+ """ Get access group resources by id
890+ """
891+ def get_access_group_resources (self , access_group_id ):
892+ return self .get ("me/access-groups/{}/resources" .format (access_group_id ))
893+
894+ """ Get resource from access group
895+ """
896+ def get_access_group_resource (self , access_group_id , resource_id ):
897+ return self .get ("ame/ccess-groups/{}/resources/{}" .format (access_group_id , resource_id ))
898+
899+ """ Delete resource from access group
900+ """
901+ def delete_access_group_resource (self , access_group_id , resource_id ):
902+ return self .delete ("me/access-groups/{}/resources/{}" .format (access_group_id , resource_id ))
903+
904+ """ Get access group users
905+ """
906+ def get_access_group_users (self , access_group_id ):
907+ return self .get ("me/access-groups/{}/users" .format (access_group_id ))
908+
909+ """ Add user to access group
910+ """
911+ def add_access_group_user (self , access_group_id , email ):
912+ return self .post ("me/access-groups/{}/users" .format (access_group_id ), payload = {"email" : email })
913+
914+ """ Get user from access group
915+ """
916+ def get_access_group_user (self , access_group_id , user_id ):
917+ return self .get ("me/access-groups/{}/users/{}" .format (access_group_id , user_id ))
918+
919+ """ Delete user from access group
920+ """
921+ def delete_access_group_user (self , access_group_id , user_id ):
922+ return self .delete ("me/access-groups/{}/users/{}" .format (access_group_id , user_id ))
923+
924+ """ Share device group with access group
925+ """
926+ def share_device_group (self , device_group_id , access_group_id ):
927+ return self .post ("me/device-groups/{}/share" .format (device_group_id ), payload = {"accessGroupId" : access_group_id })
928+
929+ """ Share file set with access group
930+ """
931+ def share_file_set (self , file_set_id , access_group_id ):
932+ return self .post ("me/file-sets/{}/share" .format (file_set_id ), payload = {"accessGroupId" : access_group_id })
933+
934+ """ Share file with access group
935+ """
936+ def share_file (self , file_id , access_group_id ):
937+ return self .post ("me/files/{}/share" .format (file_id ), payload = {"accessGroupId" : access_group_id })
938+
939+ """ Share project with access group
940+ """
941+ def share_project (self , project_id , access_group_id ):
942+ return self .post ("me/projects/{}/share" .format (project_id ), payload = {"accessGroupId" : access_group_id })
943+
944+
860945 def get_parser (self ):
861946 class MyParser (OptionParser ):
862947 def format_epilog (self , formatter ):
@@ -905,11 +990,11 @@ def format_epilog(self, formatter):
905990 Download test run screenshots. Screenshots will be downloaded to
906991 current directory in a structure:
907992 [test-run-id]/[device-run-id]-[device-name]/screenshots/...
908- jobs Get list of your jobs
909- builds <job-id> Get list of your builds
993+ jobs Get list of your jobs
994+ builds <job-id> Get list of your builds
910995 create-job <job-name> <job-configuration> Create a new job. Job configuration in Jenkins pipeline format
911996 See the sample of Jenkisfile in http://docs.bitbar.com/build-service/guide.html
912- update-job <job-id> <job-name> <job-configuration>
997+ update-job <job-id> <job-name> <job-configuration>
913998 Update existing job
914999 create-build <job-id> <build-configuration> Create a new build job. See https://cloud.testdroid.com/cloud/swagger-ui.html
9151000 for details of build configuration
@@ -918,6 +1003,32 @@ def format_epilog(self, formatter):
9181003 download-builds-files <job-id> <build-id> Download all the results of the specific build
9191004 wait-build <job-id> <build-id> Await completion (polling) of the build
9201005
1006+ access-groups Get access groups
1007+ access-group <access-group-id> Get an access group by id
1008+ access-group-create <name> <scope> Create a new access group
1009+ access-group-update <access-group-id> <name> <scope>
1010+ Update an access group
1011+ access-group-delete <access-group-id> Delete an access group
1012+ access-group-resources <access-group-id> Get resources in an access group
1013+ access-group-resource <access-group-id> <resource-id>
1014+ Get a resource in an access group by id
1015+ access-group-resource-remove <access-group-id> <resource-id>
1016+ Remove a resource from an access group
1017+ access-group-users <access-group-id> Get users in an access group
1018+ access-group-users-get <access-group-id> <user-id>
1019+ Get a user in an access group
1020+ access-group-users-add <access-group-id> <user-email>
1021+ Add a user to an access group
1022+ access-group-users-remove <access-group-id> <user-email>
1023+ Remove a user from an access group
1024+
1025+ share-device-group <device-group-id> <access-group-id>
1026+ Share a device group with an access group
1027+ share-file-set <file-set-id> <access-group-id>
1028+ Share a file set with an access group
1029+ share-file <file-id> <access-group-id> Share a file with an access group
1030+ share-project <project-id> <access-group-id>
1031+ Share a project with an access group
9211032"""
9221033 parser = MyParser (usage = usage , description = description , epilog = epilog , version = "%s %s" % ("%prog" , __version__ ))
9231034 parser .add_option ("-k" , "--apikey" , dest = "apikey" ,
@@ -937,7 +1048,7 @@ def format_epilog(self, formatter):
9371048 return parser
9381049
9391050 def get_commands (self ):
940- commands = {
1051+ return {
9411052 "me" : self .get_me ,
9421053 "device-groups" : self .print_device_groups ,
9431054 "available-free-devices" : self .print_available_free_devices ,
@@ -968,10 +1079,24 @@ def get_commands(self):
9681079 "delete-job" : self .delete_job ,
9691080 "delete-build" : self .delete_build ,
9701081 "download-builds-files" : self .download_build_output_files ,
971- "wait-build" : self .wait_build
972-
1082+ "wait-build" : self .wait_build ,
1083+ "access-groups" : self .get_access_groups ,
1084+ "access-group" : self .get_access_group ,
1085+ "access-group-create" : self .create_access_group ,
1086+ "access-group-update" : self .update_access_group ,
1087+ "access-group-delete" : self .delete_access_group ,
1088+ "access-group-resources" : self .get_access_group_resources ,
1089+ "access-group-resource" : self .get_access_group_resource ,
1090+ "access-group-resource-remove" : self .delete_access_group_resource ,
1091+ "access-group-users" : self .get_access_group_users ,
1092+ "access-group-users-add" : self .add_access_group_user ,
1093+ "access-group-users-get" : self .get_access_group_user ,
1094+ "access-group-users-remove" : self .delete_access_group_user ,
1095+ "share-device-group" : self .share_device_group ,
1096+ "share-file-set" : self .share_file_set ,
1097+ "share-file" : self .share_file ,
1098+ "share-project" : self .share_project ,
9731099 }
974- return commands
9751100
9761101 def cli (self , parser , commands ):
9771102 (options , args ) = parser .parse_args ()
@@ -985,7 +1110,7 @@ def cli(self, parser, commands):
9851110 if sys .version_info [0 ] > 2 :
9861111 http .client .HTTPConnection .debuglevel = 1
9871112 else :
988- httplib .HTTPConnection .debuglevel = 1
1113+ httplib .HTTPConnection .debuglevel = 1
9891114 logging .getLogger ().setLevel (logging .DEBUG )
9901115 requests_log = logging .getLogger ("requests.packages.urllib3" )
9911116 requests_log .setLevel (logging .DEBUG )
0 commit comments