예제 #1
0
파일: fb.py 프로젝트: lbolla/fbcli
 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
예제 #2
0
    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()
예제 #3
0
    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']
예제 #4
0
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())
예제 #5
0
    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()
예제 #6
0
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")
예제 #7
0
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))
    })
예제 #8
0
    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)
예제 #9
0
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),
    )
예제 #10
0
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
예제 #11
0
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))
예제 #12
0
    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