Files
gtav-src/tools_ng/techart/dcc/motionbuilder2014/python/RS/Utils/Bugstar.py
T
2025-09-29 00:52:08 +02:00

509 lines
16 KiB
Python
Executable File

"""
RS.Utils.Bugstar
Module for interfacing with Bugstar.
"""
import webbrowser
import clr
import re
from functools import wraps
import RS.Config
import System
#import System.Collections.Generic as Generic
clr.AddReference("RSG.Base")
from RSG.Base.Configuration import ConfigFactory
from RSG.Base import Configuration
clr.AddReference("RSG.Interop.Bugstar")
from RSG.Interop import Bugstar as IBugstar
from RSG.Interop.Bugstar.Organisation import Project
from RSG.Interop.Bugstar import BugCategory
from RSG.Interop.Bugstar import BugBuilder
from RSG.Interop.Bugstar import BugPriority
# Decorator
def cache(func):
"""
caches the value of the decorated function as a variable of the same name but that has a leading underscore.
This is done to avoid calling bugstar multiple times to retrieve the same data. Calls to bugstar are slow, so
we want to minimize the number of times that we try to access it as much as possible.
:param func: method object
the method which you are decorating, automatically gets passed when using the decorator expression
:return: func
"""
@wraps(func)
def wrapper(self, *args, **kwargs):
#Create the variable name from the method name
func_name = func.func_name
cached_attribute_name = "_{}".format(func_name)
#Get the value of the method from the object passed in
attribute_value = getattr(self, cached_attribute_name, None)
#Set the value of the variable by running the method
#If it hasn't been cached
if not attribute_value:
setattr(self, cached_attribute_name, func(self,*args, **kwargs))
#print cached_attribute_name, getattr(self, cached_attribute_name)
return getattr(self, cached_attribute_name, None)
return wrapper
#Class
class Bugstar(object):
category = { "A": BugCategory.A,
"B": BugCategory.B,
"C": BugCategory.C,
"D": BugCategory.D,
"Task": BugCategory.Task,
"Todo": BugCategory.Todo,
"Track": BugCategory.Track}
priority = { "High": BugPriority.High,
"Low" : BugPriority.Low,
1: BugPriority.High,
2: BugPriority.P2,
3: BugPriority.P3,
4: BugPriority.P4,
5: BugPriority.Low}
def __init__(self, username="gameasserts", password="gamea$$ert5", domain=""):
"""
logins into the server based on the credentials passed in. If no credentials are
passed in then the generic login info from North will be used.
The domain for rockstar is rockstar.t2.corp
:param username: string
your login name ei. dvega
:param password: string
your password
:param domain: string
the domain that you are trying to access ei. rockstar.t2.corp
:param connection: Bugstar.BugstarConnection instance()
the connection instance to bugstar
:return: True
"""
self.loggedin = False
self.login(username, password, domain)
def _AssertProject(self, project):
"""
check that the project is a RS.Interop.Bugstar.Project
:param project:
:return:
"""
assert isinstance(project, Project)
def login(self, username="gameasserts", password="gamea$$ert5", domain=""):
"""
logins into the server based on the credentials passed in. If no credentials are
passed in then the generic login info from North will be used.
The domain for rockstar is rockstar.t2.corp
:param username: string
your login name ei. dvega
:param password: string
your password
:param domain: string
the domain that you are trying to access ei. rockstar.t2.corp
:return: True
"""
#Thanks for the login North !
#Rockstar Domain : rockstar.t2.corp
try:
self.connection.Login(username, password, domain)
self.clear_cache()
self.loggedin = True
except:
self.loggedin = False
def connected(self):
return self.loggedin
@property
@cache
def connection(self):
"""
gets the bugstar connection instance
Return:
BugstarConnection instance
"""
#if "RDR3" in RS.Config.Project.Name:
# print "rdr"
# return self.rdr_connection
return IBugstar.BugstarConnection(self.config.RESTService, self.config.AttachmentService)
@property
def rdr_connection(self):
"""
At the time of writing, RDR has yet to update their tools to use the new Bugstar C# files.
This is a temporary work around to connect to bugstar in the meantime. To be removed at a later time
:return: BugstarConnection instance
"""
print (ConfigFactory.CreateConfig(), self.config)
print Configuration.IConfig(ConfigFactory.CreateConfig()), Configuration.Bugstar.IBugstarConfig(self.config)
return IBugstar.BugstarConnection(ConfigFactory.CreateConfig(), self.config)
@property
@cache
def config(self):
"""
Generates a Bugstar Config instance to use
Return:
BugstarConfig instance
"""
return ConfigFactory.CreateBugstarConfig()
@property
@cache
def project(self):
"""
Query the assigned Bugstar project for the current project.
Returns:
RSG.Model.Bugstar.Organisation.Project object.
"""
self._project_id = self.config.ProjectId
return Project.GetProjectById(self.connection, self.config.ProjectId)
@property
@cache
def projects(self):
"""
Collect all of the users projects as a dictionary.
Returns:
Dictionary of RSG.Model.Bugstar.Organisation.Project objects. The key
is the name of the project.
"""
projects = Project.GetProjects(self.connection)
return {project.Name: project for project in projects}
def get_project_by_name(self, project_name ):
"""
Get a Bugstar project.
Arguments:
projectName: The name of the project to get.
Returns:
RSG.Model.Bugstar.Organisation.Project object.
"""
return self.projects.get(project_name, None)
@property
@cache
def user(self):
"""
Returns the name of the current user
Return: string;
The name of the current user
"""
return self.project.CurrentUser
@property
@cache
def users(self):
"""
Gets a list of all the users on the project
:param project:
:return: dictionary
"""
#This regular expression is so we get names without the studio they work at
#ei. David Vega (R*NYC) to david vega
#Compiled the regular expression and assigned method to local variable to increase speed
#In python , when you call a method via it's class , ei. obj.method, it has to find it first which takes time.
#By assigning it to a variable we skip having to search for it and local scope variables are easier for python
#to access than global variables
user_name = re.compile("[a-z\- ]+", re.I)
user_name_match = user_name.match
lower = str.lower
users = {lower(user_name_match(user.Name.encode('utf-8')).group()[:-1]): user for user in self.project.Users}
return users
def get_user_by_name( self, name):
"""
Get a Bugstar user.
Arguments:
name: The friendly name of the user to look up. For example:
'Jason Hayes'
Returns:
If the user exists in the project, will return a RSG.Model.Bugstar.Organisation.User object. None if the user doesn't exist in the project.
"""
self._AssertProject(self.project)
return self.users.get(name.lower(), None)
def get_user_by_email(self, email):
"""
Get a Bugstar user via their email address
:param email: string
the email address for the user that you want. ei. david.vega@rockstargames.com
:param project: RSG.Interop.Bugstar.Organisation.Project()
The project instance generated from RSG.Interop.Bugstar.Organisation.Project()
:return: RSG.Interop.Bugstar.Organisation.User or None if not match
"""
lower = unicode.lower
email_dictionary = {lower(user.Email): user for user in self.project.Users if user.Email}
return email_dictionary.get(email.lower(), None)
def get_user_id(self, user=None):
"""
retrieves the user id of the provided user
:param user: string or RSG.Interop.Bugstar.Organisation.User
the name, email or User instance of the person who's user Id you want to get
:param project: RSG.Interop.Bugstar.Organisation.Project
the current project
:return: int
their id
"""
# Owner
if not user:
return self.user.Id
if isinstance(user, basestring):
if "@" in user:
user = self.get_user_by_email(user)
else:
user = self.get_user_by_name(user)
elif isinstance(user, int):
return user
return user.Id
@property
@cache
def teams(self):
lower = str.lower
return {lower(user.Name.encode('utf-8')): user for user in self.project.GetTeamsList()}
def get_team_by_name(self, name):
return self.team.get(name, None)
@property
@cache
def members(self):
members = dict(self.users)
members.update(self.teams)
return members
def get_member_by_name(self, name):
return self.members.get(name.lower(), None)
def get_member_id(self, member):
if not member:
return self.user.Id
if isinstance(member, basestring):
if "@" in member:
member = self.get_user_by_email(member)
else:
member = self.get_member_by_name(member)
elif isinstance(member, int):
return member
if member:
return member.Id
def open_bug(self, bugId ):
"""
Opens the supplied bug.
Arguments:
bugId: The bug id to open.
"""
webbrowser.open( 'url:bugstar:{0}'.format( bugId ) )
def create_bug(self,
summary,
description,
owner = None,
qaOwner = None,
reviewer = None,
ccList = [],
category = "Task",
priority = 3,
tags = []
):
"""
Creates a bug.
Arguments:
project: The project to add the bug. Requires a RSG.Interop.Bugstar.Organisation.Project object.
summary: The summary for the bug.
description: The description for the bug.
Keyword Arguments:
owner: The owner of the bug. Provide the friendly name. If not provided, the current user will be used. For example:
'Jason Hayes'
qaOwner: The QA owner of the bug. Provide the friendly name. If not provided, the current user will be used.
reviewer: The reviewer of the bug. Provide the friendly name. If not provided, the current user will be used.
category: The category type of the bug. Use RSG.Interop.Bugstar.BugCategory enums. For quick reference:
BugCategory.A
BugCategory.B
BugCategory.C
BugCategory.D
BugCategory.Task
BugCategory.Todo
BugCategory.Track
priority: The bug priority. Use RSG.Interop.Bugstar.BugPriority enums. For quick reference:
BugPriority.High
BugPriority.P2
BugPriority.P3
BugPriority.P4
BugPriority.Low
tags: List of tags to add to the bug.
Returns:
The created bug, which is a RSG.Interop.Bugstar.Bug object.
"""
self._AssertProject( self.project )
bugBuilder = BugBuilder( self.project )
bugBuilder.Summary = summary
bugBuilder.Description = description
bugBuilder.Category = self.category.get(category, BugCategory.Task)
bugBuilder.Priority = self.priority.get(priority, BugPriority.P3)
if owner:
# Owner
bugBuilder.DeveloperId = self.get_member_id(owner)
if qaOwner:
# QA Owner
bugBuilder.TesterId = self.get_member_id(qaOwner)
#Reviewer shouldn't be set- the reviewer list for RDR2 is limited, if set and reviewer not on the list
#It will throw a 505 Internal Error
#if reviewer:
# Reviewer
# bugBuilder.ReviewerId = self.get_member_id(reviewer)
# CC List
cc_list = [self.get_member_id(each) for each in ccList]
bugBuilder.CCList = System.Array[System.UInt32](cc_list)
# Tags
for tag in tags:
bugBuilder.Tags.Add( tag )
# Create the bug.
return bugBuilder.ToBug(self.connection)
def get_bug_by_id( self, bugId ):
"""
Get a bug by the supplied id.
Arguments:
bugId: The bug id to query.
Returns:
RSG.Model.Bugstar.Bug object, None if the bug could not be found.
"""
#Storing project variable to avoid calling bugstar multiple times
bug = IBugstar.Bug( self.project )
found = bug.GetBugById( self.project, bugId )
if found:
return found
else:
current_projects = dict(self.projects)
current_projects.pop(self.project.Name)
for project_name, project in current_projects.iteritems():
bug = IBugstar.Bug( project )
found = bug.GetBugById( project, bugId )
if found:
return found
return None
def clear_cache(self):
"""
Sets the value of the cached attributes to None so the cached attributes can be set again
:return: None
"""
[setattr(self, each, None) for each in dir(self)
if re.match("_(?=[a-z]+)", each) and each not in ("_config", "_connection", "_AssertProject")]
def CreateBugNull( pControl, pEvent ):
"""
TODO (Hayes 7/17/2013): Need to evaluate if this is still needed. For now, migrating the function
from the old bugstar module into this one.
"""
import pyfbsdk
#from pyfbsdk_additions import *
import RS.Core.Reference.Manager
lBugNull = pyfbsdk.FBFindModelByLabelName( "REFERENCE: BugNull" )
lSceneNull = RS.Core.Reference.Manager.GetReferenceSceneNull()
if not lBugNull:
lBugNull = pyfbsdk.FBCreateObject( "Browsing/Templates/Elements", "Null", "REFERENCE: BugNull")
lBugNull.PropertyCreate( 'Bug Numbers', pyfbsdk.FBPropertyType.kFBPT_charptr, 'String', False, True, None )
if lSceneNull:
lBugNull.Parent = lSceneNull
lBugNumber = pyfbsdk.FBMessageBoxGetUserValue( "Enter Bug Number", "BugNumber: ", '', pyfbsdk.FBPopupInputType.kFBPopupString, "Ok", "Cancel" )
lProp = lBugNull.PropertyList.Find( 'Bug Numbers' )
if lBugNumber != "":
lProp.Data = lProp.Data + ", " + str(lBugNumber)
del( lBugNull, lSceneNull, lBugNumber, lProp )