def _fb(self): # Get connection lazily, to simplify testing if self.__fb is None: if self.uses_token: self.__fb = fogbugz.FogBugz(self._fburl, self._fbtoken) else: self.__fb = fogbugz.FogBugz(self._fburl) return self.__fb
def update_to_fogbugz(self, case_id): """Update the case via the Fogbugz API. :param id: Fogbugz case id """ case = self.get(id=case_id) fb = fogbugz.FogBugz(settings.AUTH_FOGBUGZ_SERVER, settings.FOGBUGZ_TOKEN) case_info = self.get_case_info(case_id, fb=fb) try: edits = case.edits.select_for_update() except DatabaseError: # concurrent update is running return handlers = { CaseEdit.TYPE_MIGRATION_URL: self.update_to_fogbugz_migration_url, CaseEdit.TYPE_MIGRATION_REVIEWED: self.update_to_fogbugz_migration_reviewed, CaseEdit.TYPE_MIGRATION_UNREVIEWED: self.update_to_fogbugz_migration_unreviewed, CaseEdit.TYPE_MIGRATION_REPORT: self.update_to_fogbugz_migration_report, CaseEdit.TYPE_DEPLOYMENT_REPORT: self.update_to_fogbugz_deployment_report, } for edit in edits: response = None handler = handlers.get(edit.type) if handler: response = handler(case, fb, case_info, edit.params) if response and not response.case: raise RuntimeError(response) edit.delete()
def __init__(self, config=None): self.fb = None self.categories = None if config: self.fb = fogbugz.FogBugz(config['source']['url'], config['source']['token']) self.categories = config['categories']
def get_fogbugz_tags(request, case_number=None): """Get a list of all available or just case's tags.""" fogbugz_instance = fogbugz.FogBugz(settings.FOGBUGZ_URL, token=request.user.fogbugzprofile.token) if case_number: resp = fogbugz_instance.search(q=case_number, cols='tags') resp = (tg.text.strip() for tg in resp.find('tags').findAll('tag')) else: resp = fogbugz_instance.listTags() resp = (getattr(tg.find('stag'), 'text', '').strip() for tg in resp.findAll('tag')) return sorted( tag for tag in resp if request.REQUEST.get('term', '').lower() in tag.lower())
def __init__(self): cmd.Cmd.__init__(self) self.prompt = 'FB > ' run_config = False try: config = {} f = open(CONFIG_FILE, 'r') for sLine in f.readlines(): opt, val = map(lambda s: s.strip(), sLine.split('=')) config[opt] = val f.close() self._fb = fogbugz.FogBugz(config['url']) self._fb._token = config['token'] except IOError: run_config = True except KeyError: run_config = True if run_config: f = open(CONFIG_FILE, 'w') sys.stdout.write('FogBugz URL: ') url = sys.stdin.readline().strip() f.write('url = %s\n' % url) sys.stdout.write('Email: ') email = sys.stdin.readline().strip() sys.stdout.write('Password: '******'\n' or ch == '\r': break print ch password += ch self._fb = fogbugz.FogBugz(url) self._fb.logon(email, password) f.write('token = %s\n' % self._fb._token) f.close()
def fetch_cases(): """Fetch missing and update existing cases from fogbugz for all known releases.""" logger.info("Start fetching cases") fb = fogbugz.FogBugz(settings.AUTH_FOGBUGZ_SERVER, settings.FOGBUGZ_TOKEN) release_query = ' OR '.join('milestone:"{0}"'.format(release.number) for release in Release.objects.all()) resp = fb.search( q='({0}) AND ({ciproject}:"*")'.format( release_query, ciproject=settings.FOGBUGZ_CI_PROJECT_FIELD_ID), cols= 'sTitle,sOriginalTitle,sFixFor,dtFixFor,sProject,sArea,dtLastUpdated,tags,' + settings.FOGBUGZ_CI_PROJECT_FIELD_ID) cases = resp.findAll('case') logger.info('Found %s cases to fetch from fogbugz', len(cases)) for case_xml in cases: update_case_from_fogbugz.apply_async(kwargs=dict( case_id=int(case_xml.attrs['ixbug']))) logger.info("Task finished")
def mark_issue_approved(request, issue, case_id, target_branch): """Mark issue's latest revision as approved. :param issue: `Issue` object to mark it's latest revision as approved :param case_id: `str` id of the Fogbugz case to assign the case to Mergekeepers user :param target_branch: `str` target branch to merge approved revision into. """ fogbugz_instance = fogbugz.FogBugz(settings.FOGBUGZ_URL, token=request.user.fogbugzprofile.token) # get information from the fogbugz case _, _, _, _, ci_project, _ = get_fogbugz_case_info(request, case_id) if not ci_project or ci_project == '--': raise RuntimeError( 'You need to set CI Project field in the Fogbugz case ' '<a href="{settings.FOGBUGZ_URL}default.asp?{case_id}" target="_blank">{case_id}</a>. ' 'Please do so and try again.'.format( case_id=case_id, settings=settings)) latest_patchset = issue.latest_patchset if not latest_patchset or issue.latest_reviewed_rev == issue.latest_patch_rev: raise RuntimeError('No patchset found to approve.') issue.latest_reviewed_rev = issue.latest_patch_rev issue.save() latest_patchset.revision = issue.latest_patch_rev latest_patchset.save() tags = set(get_fogbugz_tags(request, case_id)) tags.add(settings.FOGBUGZ_APPROVED_TAG) fogbugz_instance.edit(**{ "ixBug": str(case_id), "ixPersonAssignedTo": str(settings.FOGBUGZ_MERGEKEEPER_USER_ID), settings.FOGBUGZ_APPROVED_REVISION_FIELD_ID: issue.latest_reviewed_rev, settings.FOGBUGZ_TARGET_BRANCH_FIELD_ID: target_branch, 'sTags': ','.join(sorted(tags)) })
def get_case_info(self, case_id, fb=None): """Get case info from the Fogbugz API. :param case_id: Fogbugz case id :type case_id: int :param fb: optional fogbugz client instance """ if fb is None: fb = fogbugz.FogBugz(settings.AUTH_FOGBUGZ_SERVER, settings.FOGBUGZ_TOKEN) resp = fb.search( q=case_id, cols= 'sTitle,sOriginalTitle,sFixFor,dtFixFor,sProject,sArea,dtLastUpdated,tags,{0},{1}' .format( settings.FOGBUGZ_CI_PROJECT_FIELD_ID, settings.FOGBUGZ_REVISION_FIELD_ID, ), max=1) case = resp.cases.find('case') if case is None: raise ValidationError('Case with such id cannot be found', case_id) return self.parse_case_info(case)
def get_fogbugz_case_info(request, case_number): """Get Fogbugz case information. :param: case_number: `int` Fogbugz case number. :return: `tuple` in form ('case_number', 'case_title', 'original_branch', 'feature_branch', 'ci_project', 'target_branch') """ try: token = request.user.fogbugzprofile.token except Exception: return (None, None, None, None, None, None) fogbugz_instance = fogbugz.FogBugz(settings.FOGBUGZ_URL, token=token) resp = fogbugz_instance.search( q='ixBug:"{0}"'.format(case_number), cols=','.join([ 'sTitle', settings.FOGBUGZ_ORIGINAL_BRANCH_FIELD_ID, settings.FOGBUGZ_FEATURE_BRANCH_FIELD_ID, settings.FOGBUGZ_CI_PROJECT_FIELD_ID, settings.FOGBUGZ_TARGET_BRANCH_FIELD_ID])) def get_field(field): value = getattr(resp, field) if value is not None: return value.text or value.string else: return '' return ( case_number, get_field('stitle'), get_field(settings.FOGBUGZ_ORIGINAL_BRANCH_FIELD_ID), get_field(settings.FOGBUGZ_FEATURE_BRANCH_FIELD_ID), get_field(settings.FOGBUGZ_CI_PROJECT_FIELD_ID), get_field(settings.FOGBUGZ_TARGET_BRANCH_FIELD_ID), )
def get_fogbugz_assignees(request, case_number): """Get a list of people that a given case has been assigned to.""" fogbugz_instance = fogbugz.FogBugz(settings.FOGBUGZ_URL, token=request.user.fogbugzprofile.token) resp = fogbugz_instance.search(q=case_number, cols='events') possible_assignees = [] fetched_person_ids = set() events = resp.findAll('event') events.reverse() for event in events: try: person_id = int(event.find('ixpersonassignedto').text) if person_id == 0: # Special id signifying invalid user. raise ValueError except ValueError: continue if person_id in fetched_person_ids: # Already added this person. continue person_name = fogbugz_instance.viewPerson(ixPerson=person_id).find('sfullname').text fetched_person_ids.add(person_id) if request.REQUEST.get('term', '').lower() in person_name.lower(): possible_assignees.append((person_id, person_name)) if len(possible_assignees) >= 2: return ( # Person who assigned review [possible_assignees[1]] + # Reviewer [possible_assignees[0]] + # Everybody else possible_assignees[2:] ) else: return possible_assignees
def fogbugz_assign_case(request, case_number, target, message, tags): """Assign a fogbugz case.""" fogbugz_instance = fogbugz.FogBugz(settings.FOGBUGZ_URL, token=request.user.fogbugzprofile.token) fogbugz_instance.assign(ixBug=case_number, ixPersonAssignedTo=target, sEvent=message, sTags=','.join(tags))
def authenticate(self, username=None, password=None): if not username or not password: return None ## FogBugz does case insensitive matching. We lower-case the input ## and then do an insensitive match on the e-mail field. ## This will allow for hand created accounts, and for when ## LDAP is enabled. username = username.lower() fbcfg = FogBugzSettings() ## first check to see if there is already a user account for this ## user. user = None email = '' ixPerson = 0 email_login = False UserModel = get_user_model() ## the problem here is that it could be the email address ## or an LDAP user login. try: if email_re.search(username): ## it's an e-mail address... email_login = True user = UserModel.objects.get(email__iexact=username) elif '\\' in username: ## LDAP username with domain specified, strip the '\\' username = username.split('\\')[-1] user = UserModel.objects.get_by_natural_key(username) else: user = UserModel.objects.get_by_natural_key(username) except UserModel.DoesNotExist: logger.debug("No pre-existing user model for user (%s).", username) if not user and not fbcfg.AUTO_CREATE_USERS: ## no existing user, and not allowed to create new ones logger.debug( "Login Failed: No auto creation of users, " "login failed for user (%s).", username) return None if not email_login and not fbcfg.SERVER_USES_LDAP: ## Reguardless if it is an existing user, if we do not have ## SERVER_USES_LDAP set then we must require an e-mail login. ## If this is a non-FogBugz login, then a later backend ## will do the authentication for it. logger.debug( "Login Failed: User (%s) logged in with non-e-mail " "username and AUTH_FOGBUGZ_SERVER_USES_LDAP " "is not set. ", username) return None if not user and email_login and fbcfg.SERVER_USES_LDAP: ## no existing user, and logging in with e-mail, but ## fogbugz has LDAP integration allowing for logging in ## with both e-mail and ldap name. Because of this, we only ## allow creating the user account when logging in with the ## LDAP username, not the e-mail. Once a person logs in with ## the LDAP username, they can authenticate with the e-mail ## address. logger.debug( "Login Failed: User logged in for the first time " "with an e-mail address (%s), but the FogBugz server " "(%s) is configured for LDAP authentication. User " "must login with their LDAP username the " "first time. ", username, fbcfg.SERVER) return None try: fb = fogbugz.FogBugz(fbcfg.SERVER) except fogbugz.FogBugzConnectionError, e: ## Log the error logger.error( "Login Failed: " "FogBugz Server (%s) Connection Error: %s", fbcfg.SERVER, e.message) return None