def returnTicket(ticket_num, option, config): fb = FogBugz(config['FOGBUGZ_URL'], config['FOGBUGZ_TOKEN']) if option == "short": retrieve_ticket = fb.search(q=ticket_num, cols='ixBug,sTitle,sProject') if retrieve_ticket.cases['count'] == str(1): ticket_title = retrieve_ticket.cases.case.stitle.string ticket_project = retrieve_ticket.cases.case.sproject.string ticket_URL = "https://tenthwave.fogbugz.com/f/cases/"+ticket_num ticket = "Ticket: " + ticket_num + " | " + ticket_title + "\n\n" + ticket_URL return ticket else: return "Something went wrong! Either Fogbugz is down, you're a magician calling a number that does not exist yet, or it somehow returned more than one ticket." else: retrieve_ticket = fb.search(q=ticket_num, cols="ixBug,sTitle,sLatestTextSummary,sArea,sProject") if retrieve_ticket.cases['count'] == str(1): ticket_title = retrieve_ticket.cases.case.stitle.string ticket_area = retrieve_ticket.cases.case.sarea.string ticket_project = retrieve_ticket.cases.case.sproject.string ticket_URL = "https://tenthwave.fogbugz.com/f/cases/"+ticket_num ticket_last_update = retrieve_ticket.cases.case.slatesttextsummary.string ticket = ticket_URL + "\n\nTicket: " + ticket_num + "\n" + ticket_project + " : " + ticket_area + "\n*" + ticket_title + "*\n\n" + ticket_last_update return ticket else: return "Something went wrong! Either Fogbugz is down, you're a magician calling a number that does not exist yet, or it somehow returned more than one ticket."
def cgi(): fb = FogBugz(fbsettings.URL, fbsettings.TOKEN) resp = fb.search(q='project:inbox area:* status:active due:today orderby:due', cols="dtDue,sTitle") cases = [] for case in resp.cases: date = datetime.strptime(case.dtdue.string, '%Y-%m-%dT%H:%M:%SZ').strftime('%m/%d/%Y') time = case.dtdue.string[11:16] departure = case.stitle.string.encode('UTF-8').replace('\"', '') track = random.randrange(0, 100) if (datetime.strptime(case.dtdue.string, '%Y-%m-%dT%H:%M:%SZ') - datetime.now()).days < 0: status = 3 else: status = 2 cases.append({'sDate': date, 'sTime': time, 'sDeparture': departure, 'nStatus': status, 'nTrack': track, 'bLight': False}) #turn on the top light try: cases[0]['bLight'] = True except: pass print("Content-Type: application/json", end='\n\n') json.dump(cases, sys.stdout)
def cgi_callback(): ## Begin sample data loading ## ## Customize with your own logic ## fb = FogBugz(fbsettings.URL, fbsettings.TOKEN) resp = fb.search( q='project:inbox area:* status:active due:today orderby:due', cols="dtDue,sTitle") cases = [] for case in resp.cases: date = datetime.strptime(case.dtdue.string, '%Y-%m-%dT%H:%M:%SZ').strftime('%m/%d/%Y') time = case.dtdue.string[11:16] departure = case.stitle.string.encode('UTF-8').replace('\"', '') track = random.randrange(0, 100) if (datetime.strptime(case.dtdue.string, '%Y-%m-%dT%H:%M:%SZ') - datetime.now()).days < 0: status = 3 else: status = 2 cases.append({ 'sDate': date, 'sTime': time, 'sDeparture': departure, 'nStatus': status, 'nTrack': track, 'bLight': False })
def main(): if len(sys.argv) != 3: sys.exit("Incorrect number of arguments") c = readcFile(sys.argv[1]) c['test.build'] = sys.argv[2] rawCrashes = getCrashesFromDirectory(c['test.separator'], c['test.dir']) crashes = parseCrashes(rawCrashes, c) if (len(crashes) != 0): fb = FogBugz(c['fogbugz.url']) fogbugzQuery = 'project:\"' + c['fogbugz.project'] + '"' fb.logon(c['fogbugz.user'], c['fogbugz.pass']) fogBugzResp = fb.search(q=fogbugzQuery, cols='ixBug,sTitle,fOpen,events') crashes = flagExcludeList(c, crashes) crashes = flagFBDuplicates(fogBugzResp, crashes, c) logCrashesToFogbugz(fb, c, crashes) emailReport(c, crashes) print 'Done'
def get_requirements_cases(project_name): """ Looks for all cases of category:"Requirement" in Fogbugz Returns a list of case dictionary objects with the following of a case: [ { "id" : FogBugz ID of case, "title" : Title of case, "status" : FogBugz status (i.e. 'proposed', 'approved', etc), "event" : Description of requirement, "area" : FogBugz area of case (Front End, Support, etc), "url" : URL to actual case in FogBugz, "children": Subcases attached to current case } ] """ fb = FogBugz(FB_URL, FB_TOKEN) print "Requesting Data" resp = fb.search(q='category:"Requirement" orderby:"ixBug" project:"' + project_name + '"', cols="sTitle,sArea,ixBug,sLatestTextSummary,sFixFor,sStatus,ixBugChildren") return get_cases_from_XML(resp)
def cgi_callback(): ## Begin sample data loading ## ## Customize with your own logic ## fb = FogBugz(fbsettings.URL, fbsettings.TOKEN) resp = fb.search(q='project:inbox area:* status:active due:today orderby:due', cols="dtDue,sTitle") cases = [] for case in resp.cases: date = datetime.strptime(case.dtdue.string, '%Y-%m-%dT%H:%M:%SZ').strftime('%m/%d/%Y') time = case.dtdue.string[11:16] departure = case.stitle.string.encode('UTF-8').replace('\"', '') track = random.randrange(0, 100) if (datetime.strptime(case.dtdue.string, '%Y-%m-%dT%H:%M:%SZ') - datetime.now()).days < 0: status = 3 else: status = 2 cases.append({'sDate': date, 'sTime': time, 'sDeparture': departure, 'nStatus': status, 'nTrack': track, 'bLight': False}) # turn on the top light try: cases[0]['bLight'] = True except: pass ## End sample data loading ## # save json data to be read by liveFogbugz.py f = open('fogbugz.json','w') f.write(json.dumps(cases, sys.stdout)) f.close() # this page doesn't return the json, but might as well return some stats stats = {'error': False, 'cases': len(cases)} # support a callback param, or default to "void" params = cgi.parse_qs(os.environ['QUERY_STRING']) callback = 'void' if params.has_key('callback'): callback = params['callback'][0] print('Content-Type: application/javascript\n') print('%s(%s);' % (callback,json.dumps(stats, sys.stdout)))
def update_tickets(args): cols = [ "ixBug", "sStatus", "sTitle", 'sTags', "ixPersonOpenedBy", "dtOpened", "sProject", 'plugin_customfields', "latestEvent" ] fb = FogBugz('https://daily.manuscript.com/') fb.logon(args.email, args.password) query = {"status": "Active", "AssignedTo": "Unassigned"} querystring = " ".join(["{}:{}".format(k, v) for k, v in query.items()]) resp = fb.search(q=querystring, cols=",".join(cols)) for casexml in resp.cases.childGenerator(): #logger.info("case:##{}".format(casexml)) logger.debug(casexml['ixBug']) id = casexml['ixBug'] question = casexml.sTitle.getText() latest_event = casexml.events event_id = latest_event.ixBugEvent.getText() message_body = latest_event.s.getText() answers_string = "" pdb.set_trace() if message_body == "": answers = googler(question) for ele in answers: answers_string += "\n".join( [ele['title'], ele['url'], ele['abstract']]) answers_string += '\n\n' fb.edit(ixBug=id, sEvent=answers_string, ixPersonAssignedTo=casexml.ixPersonOpenedBy.getText()) else: for line in [i for i in message_body.split('\n') if i != '']: answers_string = "" if line.startswith("##"): answers_string += '**' + line[3:].encode('utf-8') answers_string += '\n' answers = googler(line[3:]) for ele in answers: answers_string += "\n".join( [ele['title'], ele['url'], ele['abstract']]) answers_string += '\n\n' fb.edit( ixBug=id, ixPersonAssignedTo=casexml.ixPersonOpenedBy.getText(), sEvent=answers_string) #fb.edit(ixBug=id,ixBugEvent=event_id,sEvent=answers_string,ixPersonAssignedT=casexml.ixPersonOpenedBy.getText()) else: break
def doPrivmsg(self, irc, msg): if(self.registryValue('enable', msg.args[0])): match = re.search('.*Bug[sz]id *: *(\d{1,5})', msg.args[1], re.IGNORECASE) if match: fb = FogBugz(fbSettings.fb_url) fb.logon(fbSettings.fb_user, fbSettings.fb_pass) query_cols='sTitle,sStatus,sPriority' resp = fb.search(q=match.group(1), cols = query_cols) if len(resp.findAll('case')) > 0 : for cur_case in resp.cases.childGenerator(): # Dump Title title_message = '[BugzID ' + match.group(1) + '] ' + ircutils.bold(str(cur_case.stitle.string).replace('<![CDATA[','').replace(']]>','')) + ' (' + cur_case.sstatus.string + ', ' + cur_case.spriority.string +')' irc.queueMsg(ircmsgs.privmsg(msg.args[0], title_message)) # Dump URL to ticket url_message = fbSettings.fb_url + '/default.asp?' + match.group(1) irc.queueMsg(ircmsgs.privmsg(msg.args[0], url_message)) else : irc.queueMsg(ircmsgs.privmsg(msg.args[0], 'Sorry, ' + ircutils.bold(match.group(1)) + ' is not a known BugID.'))
def main(): if len(sys.argv) != 3: sys.exit("Incorrect number of arguments") c = readcFile(sys.argv[1]) c['test.build']=sys.argv[2] rawCrashes = getCrashesFromDirectory(c['test.separator'], c['test.dir']) crashes = parseCrashes(rawCrashes, c) if (len(crashes) != 0): fb = FogBugz(c['fogbugz.url']) fogbugzQuery='project:\"' + c['fogbugz.project'] + '"' fb.logon(c['fogbugz.user'], c['fogbugz.pass']) fogBugzResp = fb.search(q=fogbugzQuery,cols='ixBug,sTitle,fOpen,events') crashes = flagExcludeList(c, crashes) crashes = flagFBDuplicates(fogBugzResp, crashes, c) logCrashesToFogbugz(fb, c, crashes) emailReport(c, crashes) print 'Done'
from fogbugz import FogBugz import csv import sys # Fill in the following values as appropriate to your installation S_FOGBUGZ_URL = 'https://fogbugz.unity3d.com' TOKEN = "" S_EMAIL = '' S_PASSWORD = '' fb = FogBugz(S_FOGBUGZ_URL, TOKEN) #fb.logon(S_EMAIL, S_PASSWORD) #Get all cases in milestone 2018.2 resp = fb.search(q='version:"'+ sys.argv[1] +'*"',cols="ixBug,ixBugParent,fOpen,sTitle,sProject,ixArea,sArea,sStatus,ixPriority,sFixFor,sVersion,sComputer,dtOpened,dtClosed,plugin_customfields_at_fogcreek_com_userxpainr32d") #print resp print "Started on version" + sys.argv[1] filename = "fogbugzData.csv" csv = open(filename, "w") columnTitleRow = "Bug ID,Bug Parent ID,is Open,Title,Project,Area ID,Area,Status,Priority,Fix For,Version,Computer,User Pain, Date Opened, Date Closed" csv.write(columnTitleRow) csv.write("\n") for case in resp.cases.childGenerator(): #assign the cols to variables if case.ixBug.string != None: bugID = case.ixBug.string
from fogbugz import FogBugz from datetime import datetime, timedelta import csv S_FOGBUGZ_URL = 'https://fogbugz.com/' S_EMAIL = '' S_PASSWORD = '' fb = FogBugz(S_FOGBUGZ_URL) fb.logon(S_EMAIL, S_PASSWORD) resp = fb.search( q='sFixFor="2018.2"', cols= 'ixBug, ixBugParent, fOpen, sTitle, ixProject, ixArea, sArea, ixStatus, ixPriority,sFixFor, dtFixFor, sVersion, sComputer, c, ixCategory, dtOpened, dtClosed' ) filename = "fogbugzData.csv" csv = open(filename, "w") columnTitleRow = "ixBug,ixBugParent,fOpen,sTitle,dtDue" csv.write(columnTitleRow) for case in resp.cases: bugID = case.ixBug.string title = case.sTitle.string open = case.fOpen.string version = case.ixProject.string priority = case.ixPriority.string status = case.ixStatus.string
print 'password to: ok' else: PASSWORD_TO = raw_input('set password to: ') print '-----------------------------------------------------------' print 'Trying to login ........' fbz_to = FogBugz(URL_TO) fbz_to.logon(EMAIL_TO, PASSWORD_TO) print 'ok' except BaseException or Exception: print '*** Cannot login to [{0}] ***'.format(URL_TO) print 'copy terminated' sys.exit() # when q='' it takes the user's (from) current selected filter in fogbugz.com (and copies only those cases) resp_from = fbz_from.search(q='', cols='ixBug,ixBugParent,ixStatus,sTitle,sProject,sFixFor,' 'sCategory,sPersonAssignedTo,sPriority,dtDue,events') for case in resp_from.cases.childGenerator(): title = case.stitle.string.encode('UTF-8') # to eliminate the garbage from <![CDATA[title here]]> resp_to = fbz_to.search(q='title:"{0}"'.format(title), cols='ixBug') if resp_to.cases.case: print case.ixbug.string, 'ALREADY EXISTS as', resp_to.cases.case.ixbug.string else: resp_new_case = fbz_to.new(ixBug=case.ixbug.string, ixBugParent=case.ixbugparent.string, sTitle=case.stitle.string, sProject=case.sproject.string, sFixFor=case.sfixfor.string, sCategory=case.scategory.string, sPersonAssignedTo=case.spersonassignedto.string, spriority=case.spriority.string, dtdue=case.dtdue.string, cols='ixBug') new_id = int(resp_new_case.ixbug.string)
help='List the available milestones') args = parser.parse_args() pp = pprint.PrettyPrinter(indent=4) milestone_map = {} milestones = fogbugz.listFixFors() for item in milestones.findAll('fixfor'): number = item.ixfixfor.string.encode('UTF-8') name = item.sfixfor.string.encode('UTF-8') milestone_map.update({name:number}) if args.list: pp.pprint(milestone_map) ms = "test1" tickets_per_milestone = {} #print args.milestone if args.milestone: for milestone_name in args.milestone: try: current_milestone = milestone_map[milestone_name] query = ('milestone:' + current_milestone) response = (fogbugz.search(q=query)) ticket_quantity = response.cases['count'] tickets_per_milestone.update({current_milestone:ticket_quantity}) except KeyError: raise KeyError("I donno this milestone") if len(tickets_per_milestone.keys())>0: pp.pprint(tickets_per_milestone)
print(filt) ''' # -------------------------------------------------------------- # SECTION: Get all recently updated cases and their information. # -------------------------------------------------------------- query='edited:"' + str(fbSettings.LASTRECORDED) + '..now"' #query="106265" #query="105112" query="106243" query='edited:today' # SEARCH for all cases that were recently edited. These are the cases that needs their data updated. resp=fb.search(q=query, cols='ixBug,sTitle,sProject,sArea,sCategory,ixPersonAssignedTo,sPersonAssignedTo,sPriority,sStatus,dtOpened,dtClosed,ixPersonOpenedBy,ixBugParent,sFixFor,ixPersonResolvedBy,ixPersonClosedBy,dtResolved,dtDue,dtLastUpdated,ixKanban,ixPersonLastEditedBy,hrsElapsed,hrsCurrEst,hrsOrigEst,hrsElapsedExtra,plugin_kanbanboard_at_ergonlabs_com_ixkanbancolumn,plugin_kanbanboard_at_ergonlabs_com_ncolor')#include Kanban to see other Kanban fields (though not useful) # cols='dtResolved,dtDue,dtLastUpdated,ixPersonLastEditedBy,hrsElapsed,hrsCurrEst,hrsOrigEst,hrsElapsedExtra,Kanban,plugin_kanbanboard_at_ergonlabs_com_ixkanbancolumn,plugin_kanbanboard_at_ergonlabs_com_ncolor' #resp=fb.search(q="kanban:1",cols='ixBug,sTitle,dtResolved,dtDue,dtLastUpdated,ixKanban,ixPersonLastEditedBy,hrsElapsed,hrsCurrEst,hrsOrigEst,hrsElapsedExtra', max=2) #print resp.prettify() minID=0 maxID=2000 step=100 PersonsList = {} insertValues = [] # values to insert into dbo.Case insertDates = set() # values to insert into dbo.TimeTable caseXML=[] # class for cases, to improve readability class Case:
class Bugz(object): def __init__(self): self.config = yaml.load(file('bugzbot.conf', 'r')) self.fb = FogBugz(self.config['FOGBUGZ_URL'], self.config['FOGBUGZ_TOKEN']) def returnUser(self, _semail): self.user = self.fb.viewPerson(semail=_semail) try: self.fb_user = self.user.people.person.sfullname.string return self.fb_user except AttributeError: return "User not found" def assignTicket(self, ticket_num, user, orig_user): self.touser = self.returnUser(user) print user print self.touser if self.touser != "User not found": self.event = "This ticket was assigned to you by slack user " + \ orig_user[1] + " courtesy of bugzbot!" self.fb.edit(ixBug=ticket_num, sPersonAssignedTo=self.touser, sEvent=self.event) self.checker = self.fb.search(q=ticket_num, cols="ixPersonAssignedTo") print self.checker if self.checker.cases.case.ixpersonassignedto.string != "93": return "success" else: return "One of us screwed up. I got stuck with the ticket somehow." \ "Please follow up and manually assign the ticket so it does not get lost in the shuffle!" else: return "Fogbugz user was not found. Please try again." def returnTicket(self, option, ticket_num): if option: self.retrieve_ticket = self.fb.search(q=ticket_num, cols='ixBug,sTitle,sProject') if self.retrieve_ticket.cases['count'] == str(1): self.ticket_title = self.retrieve_ticket.cases.case.stitle.string self.ticket_project = self.retrieve_ticket.cases.case.sproject.string self.ticket_URL = "https://tenthwave.fogbugz.com/f/cases/" + ticket_num self.ticket = "Ticket: " + ticket_num + " | " + self.ticket_title + \ "\n\n" + self.ticket_URL print self.ticket return self.ticket else: msg = "Something went wrong! Either Fogbugz is down, you're a magician calling a number " \ "that does not exist yet, or it somehow returned more than one ticket." print msg return msg else: self.retrieve_ticket = self.fb.search( q=ticket_num, cols="ixBug,sTitle,sLatestTextSummary,sArea,sProject") if self.retrieve_ticket.cases['count'] == str(1): self.ticket_title = self.retrieve_ticket.cases.case.stitle.string self.ticket_area = self.retrieve_ticket.cases.case.sarea.string self.ticket_project = self.retrieve_ticket.cases.case.sproject.string self.ticket_URL = "https://tenthwave.fogbugz.com/f/cases/" + ticket_num self.ticket_last_update = self.retrieve_ticket.cases.case.slatesttextsummary.string self.ticket = self.ticket_URL + "\n\nTicket: " + ticket_num + "\n" + self.ticket_project + \ " : " + self.ticket_area + "\n*" + self.ticket_title + "*\n\n" + self.ticket_last_update print self.ticket return self.ticket else: msg = "Something went wrong! Either Fogbugz is down, you're a magician calling a number " \ "that does not exist yet, or it somehow returned more than one ticket." print msg return msg
def main(): fb = FogBugz(S_FOGBUGZ_URL) fb.logon(S_EMAIL, S_PASSWORD) # how ugly is this, do we export one bug or all? if EXPORT_BUG != 0: resp = fb.search(q=str(EXPORT_BUG), cols='ixBug', max=MAX_BUGS) else: resp = fb.search(q='type:"Cases"', cols='ixBug', max=MAX_BUGS) cases = resp.cases.findAll('case') num_cases = len(cases) counter = 0 batch = 1 issues = [] components = [] BACKUP_DIR = os.getcwd() + '/' + 'attachments' for case in cases: counter += 1 print("Processing case: " + str(counter) + " of " + str(num_cases)) ixBug = int(case['ixBug']) print(ixBug) respBug = fb.search( q='%s' % ixBug, cols= 'sTitle,sPersonAssignedTo,sProject,sArea,sCategory,sPriority,fOpen,events' ) xmlBug = respBug.cases.findAll('case')[0] issue = {} issue['externalId'] = int(xmlBug['ixBug']) issue['created'] = get_date_created(xmlBug) issue['summary'] = get_attribute(xmlBug, 'sTitle') issue['assignee'] = S_USER issue['reporter'] = S_USER component = get_attribute(xmlBug, 'sProject') issue['components'] = [component] # gathering all the components (Fogbugz projects) as we ecounter them if component not in components: components.append(component) issue['issueType'] = "Support" issue['priority'] = get_attribute(xmlBug, 'sPriority') issue['resolution'] = get_attribute(xmlBug, 'fOpen') issue['attachments'] = [] issue['comments'] = get_events(xmlBug, issue, BACKUP_DIR) print(issue) print("Long body running count = " + str(len(LONG_BODY_COMMENTS))) print("Long body issues = " + str([c for c in LONG_BODY_COMMENTS])) issues.append(issue) if counter % BATCH_SIZE == 0: dump_json(batch, counter, components, issues) issues = [] batch += 1 # one last dump dump_json(batch, counter, components, issues)
# set the current filter to a saved one # and then retrieve all the cases associated with that filter # # the filter is set by number, which has to be looked up by a separate XML query (see get_filter_list.py) from fogbugz import FogBugz import fbSettings # login fb = FogBugz(fbSettings.URL, fbSettings.TOKEN) # Set filter resp = fb.setCurrentFilter(sFilter='65',) # filter id 65 the arbitary filter picked in this example # Get results resp = fb.search(cols='ixBug,sTitle,sFixFor,sArea') print "Raw response:" print resp print "\nPrettified response:" print resp.prettify() print "\nParsed response via Beautiful Soup:" for case in resp.cases.childGenerator(): print case.ixbug.string, case.stitle.string.encode('UTF-8'), case.sfixfor.string, case.sarea.string
else: PASSWORD_TO = raw_input('set password to: ') print '-----------------------------------------------------------' print 'Trying to login ........' fbz_to = FogBugz(URL_TO) fbz_to.logon(EMAIL_TO, PASSWORD_TO) print 'ok' except BaseException or Exception: print '*** Cannot login to [{0}] ***'.format(URL_TO) print 'copy terminated' sys.exit() # when q='' it takes the user's (from) current selected filter in fogbugz.com (and copies only those cases) resp_from = fbz_from.search( q='', cols='ixBug,ixBugParent,ixStatus,sTitle,sProject,sFixFor,' 'sCategory,sPersonAssignedTo,sPriority,dtDue,events') for case in resp_from.cases.childGenerator(): title = case.stitle.string.encode( 'UTF-8') # to eliminate the garbage from <![CDATA[title here]]> resp_to = fbz_to.search(q='title:"{0}"'.format(title), cols='ixBug') if resp_to.cases.case: print case.ixbug.string, 'ALREADY EXISTS as', resp_to.cases.case.ixbug.string else: resp_new_case = fbz_to.new( ixBug=case.ixbug.string, ixBugParent=case.ixbugparent.string, sTitle=case.stitle.string, sProject=case.sproject.string,
''' ''' filters=fb.listFilters() for filt in filters: print(filt) ''' # -------------------------------------------------------------- # SECTION: Get all recently updated cases and their information. # -------------------------------------------------------------- query='edited:"' + str(fbSettings.LASTRECORDED) + '..today"' # SEARCH for all cases that were recently edited. These are the cases that needs their data updated. resp=fb.search(q=query, cols='ixBug,sTitle,sProject,sArea,sCategory,sPersonAssignedTo,sPriority,sStatus,dtOpened,dtClosed,ixPersonOpenedBy,ixBugParent,sFixFor,ixPersonResolvedBy,ixPersonClosedBy,dtLastUpdated') PersonsList = {} # A dictionary of people recorded in Fogbugz. Needed because SEARCH only gives ixPerson (an ID) not the name. Then VIEWPERSON is used to get the name. This helps avoid having to search the same person multiple times. insertValues = [] # A list of tuples, where tuples are the case's information, to be inserted or updated into dbo.Case. insertDates = set() # A set of dates to insert into dbo.TimeTable maxDate = datetime.strptime(fbSettings.LASTRECORDED,'%Y-%m-%d %H:%M:%SZ') print "previous update time = " print maxDate # Go through each case and get its information. Clean up the data along the way. for case in resp.cases.childGenerator(): # get Opened By user IDOpenedBy = case.ixpersonopenedby.string StrOpenedBy = '' if IDOpenedBy in PersonsList: StrOpenedBy = PersonsList[IDOpenedBy]
# standard custom compare-two-value routine for use by built-in sort function return cmp(int(a), int(b)) # compare as integers # user input sProject = raw_input('Project to get: ') sMilestone = raw_input('Milestone to get: ') sFilename = "releasenotes_" + sProject + "_" + sMilestone + ".txt" # FogBugz search string sSearch = "project:\"" + sProject + "\" milestone:\"" + sMilestone + "\"" # open session with FogBugz using our API token fb = FogBugz(fbSettings.URL, fbSettings.TOKEN) # run the search resp = fb.search(q=sSearch,cols='ixBug,sArea,sTitle,sReleaseNotes') # list that we will read cases into L = list() # iterate over the returned list of cases and add those with release notes to the list for case in resp.cases.childGenerator(): myReleaseNote = case.sreleasenotes.string # just capture cases with release notes attached ('None' is the null result) if myReleaseNote != None: # add the case to the list L.append((case.sarea.string, case.ixbug.string, case.stitle.string.encode('UTF-8'), case.sreleasenotes.string.encode('UTF-8'))) #tuple L.sort()
import settings from optparse import OptionParser parser = OptionParser() parser.add_option('-s', '--search', dest='search', help="Search for the given keywords", metavar="KEYWORDS") (options, args) = parser.parse_args() print options print args from fogbugz import FogBugz fb = FogBugz(settings.url) fb.logon(settings.user_email, settings.user_pass) if options.search: resp = fb.search(q=settings.default_search_prefix + options.search, cols="sTitle,ixPriority,hrsOrigEst,hrsCurrEst,hrsElapsed,ixBugParent" ) for case in resp.cases.childGenerator(): print case['ixbug'], case.stitle.string print case
# Explicit testing / error would be nice here. trello = TrelloApi(os.environ['TRELLO_API_KEY']) if not os.environ['TRELLO_USER_TOKEN']=='' : trello.set_token(os.environ['TRELLO_USER_TOKEN']) fb = FogBugz(os.environ['FOGBUGZ_URL']) fb.logon(os.environ['FOGBUGZ_USER'],os.environ['FOGBUGZ_PASSWORD']) # Find cards in board with specified label. for cur_card in trello.boards.get_card(os.environ['TRELLO_BOARD_TO_PARSE']): for cur_card_label in cur_card['labels']: if cur_card_label['name'] == os.environ['TRELLO_LABEL_TO_PARSE'] : # Create case in Fogbugz if not exist fogbugz_response=fb.search(q='tag:"' + cur_card['id'] + '"',cols='ixBug') if len(fogbugz_response.cases) == 0 : fb.new(sTitle=cur_card['name'], sTags=cur_card['id'], ixProject=os.environ['FOGBUGZ_DEFAULT_PROJECT']) # Get ixBug value fogbugz_response=fb.search(q='tag:"' + cur_card['id'] + '"',cols='ixBug') fogbugz_id=fogbugz_response.ixbug.string # Load fogbugz updates into dictionary. fogbugz_updates=[] messages_response=fb.search(q=fogbugz_id,cols='sTitle,events') for case in messages_response.cases.childGenerator() : for event in case.events.childGenerator(): current_string=str(event.shtml.string) # Fogbugz stores all shtml data in CDATA container, we need to strip this out. There must be a way to parse this # with BeautifulSoup...
from time import strftime IX_PERSON_UP_FOR_GRABS = 53 # the ixPerson value of the Up For Grabs user IX_AREA_SUPPORT = 36 # the ixArea value of the cases in your support queue REPS = { 25 : ['Danny Test',1], # a list of team members, using this format: 52 : ['Eric Test', 1]} # { ixPerson : [name, weight]... #Log onto FogBugz print "Logging in..." fogbugz = FogBugz(fbSettings.URL) fogbugz.logon(fbSettings.Login, fbSettings.pw) assignment = {} #Add users and current assignment count to dictionary. for rep in REPS: searchString = 'assignedto: "=%s" status:"Reviewed"' % (rep) num = str(fogbugz.search(q=searchString)).split('"') assignment[rep] = num[1] for user in assignment: print user, "has", assignment[user], "assignment(s)!" #Code for assignment is only scaleable up to this point. Per convo w/ Danny, we will review this and make necessary edits once we hire more automation engineers. sum = int(assignment.values()[0])-int(assignment.values()[1]) #Obtain all tickets assigned to our main QA user. searchString = 'assignedto: "=%s"' % (IX_PERSON_UP_FOR_GRABS) grabs = fogbugz.search(q=searchString) tickets = [] for case in grabs.cases.childGenerator(): tickets.append(case['ixbug']) #Assign as necessary print len(tickets), "total tickets..." c = 0 try:
fb = FogBugz("https://sailthru.fogbugz.com/") # To run this needs a d.txt file that contains the json of: {"login":"******","pass":"******"} with open('../d.txt') as json_data: data = json.load(json_data) login = data["login"] passw = data["pass"] fb.logon(login,passw) milestones = fb.listFixFors() #this is not being used now ... it gets the most current milestone... i could probably trash it.. milestone_dates, sep, tail = milestones.sfixfor.renderContents().partition('T') miled = milestones.findAll('dt',limit=2)[1] work = miled.renderContents().partition('T') milestone = work[0] milestone = milestone.replace("-","/") print milestone search = 'milestone'+':'+args.o_variable+' '+'status:open -status:Merged -milestone:Undecided Project:Sailthru' print search response = fb.search(q=search) for case in response.cases.childGenerator(): print case['ixbug'] fb.edit(ixBug=case['ixbug'],sFixFor=args.n_variable)
# 11.59pm 19th endDateLocal = userTimezone.localize(datetime(2012, 05, 19, 23, 59)) # API expects UTC dates so convert utc = pytz.utc startDateUTC = utc.normalize(startDateLocal.astimezone(utc)) endDateUTC = utc.normalize(endDateLocal.astimezone(utc)) # Expected format by API formatString = "%Y-%m-%dT%H:%M:%SZ" # Logged-in user's timesheet response = fb.listIntervals(dtStart=startDateUTC.strftime(formatString), dtEnd=endDateUTC.strftime(formatString)) # Reference of cases and their project allCases = fb.search(q="orderby:'lastupdated'", cols="ixBug,sProject") caseProjects = {} for case in allCases.findAll("case"): caseProjects[case.ixbug.string] = case.sproject f = open("report.csv", "wt") try: writer = csv.writer(f, quoting=csv.QUOTE_NONNUMERIC) writer.writerow(("ID", "Start Date", "End Date", "Duration", "Duration (seconds)", "Description", "Project")) outputFormatString = "%d %b %Y, %H:%M" totalDeltaSeconds = 0 for interval in response.findAll("interval"): # Convert dates from API (UTC) to user's timezone startDateConvertedUTC = utc.localize(datetime.strptime(interval.dtstart.string, formatString)) startDateConvertedLocal = startDateConvertedUTC.astimezone(userTimezone) startDateString = startDateConvertedLocal.strftime(outputFormatString)
def Connect(self): # Create FogBugz object. fb = FogBugz(fbLogon.URL, fbLogon.TOKEN) return fb.search(q=self.q, cols=self.cols) fb.logoff