def process_commits(secret=None):
     if context_secret and secret != context_secret:
         abort(403)
     yt = Connection(yt_url, yt_login, yt_password)
     try:
         cmd_pattern = re.compile(
             r'#((?:%s)-\d+)(?:\s+(.+))?' %
             '|'.join(yt.getProjects().keys()),
             re.IGNORECASE | re.MULTILINE)
     except YouTrackException:
         app.logger.warning('Cannot get projects from YT')
         cmd_pattern = re.compile(r'#([A-z]+-\d+)(?:\s+(.+))?',
                                  re.MULTILINE)
     payload = json.loads(request.form.get('payload'))
     commits_url_template = get_commits_url_template(payload)
     for commit in payload['commits']:
         message = commit['message'].encode('utf-8')
         issue_refs = cmd_pattern.findall(message)
         if not issue_refs:
             continue
         commit_node = commit['node']
         commit_url = commits_url_template % commit['raw_node']
         timestamp = commit['utctimestamp']
         author = commit['author'].encode('utf-8')
         match = re.search(r'<(.+?)>', commit['raw_author'])
         if not match:
             app.logger.error("Cannot get author's email address.")
             abort(400)
         users = yt.getUsers(params={'q': match.group(1)})
         if not users:
             app.logger.error('Cannot find user with email ' +
                              match.group(1))
             abort(400)
         if len(users) != 1:
             app.logger.error('Not unique email address ' + match.group(1))
             abort(400)
         comment = "Commit [%s %s] made by '''%s''' on ''%s''\n{quote}%s{quote}" \
                   % (commit_url, commit_node, author, timestamp, message)
         cmd_exec_result = True
         for issue_id, command in issue_refs:
             if command is None:
                 command = ''
             try:
                 app.logger.info(
                     "Adding commit %s to issue %s (command: %s)" %
                     (commit_node, issue_id, command))
                 yt.executeCommand(issue_id,
                                   command,
                                   comment,
                                   run_as=users[0].login)
             except YouTrackException as e:
                 cmd_exec_result = False
                 app.logger.error(
                     'Failed to add commit %s to issue %s: %s' %
                     (commit_node, issue_id, e.message))
         if not cmd_exec_result:
             abort(500)
     return 'success'
 def process_commits(secret=None):
     if context_secret and secret != context_secret:
         abort(403)
     yt = Connection(yt_url, yt_login, yt_password)
     try:
         cmd_pattern = re.compile(
             r'#((?:%s)-\d+)(?:\s+(.+))?' % '|'.join(yt.getProjects().keys()),
             re.IGNORECASE | re.MULTILINE)
     except YouTrackException:
         app.logger.warning('Cannot get projects from YT')
         cmd_pattern = re.compile(r'#([A-z]+-\d+)(?:\s+(.+))?', re.MULTILINE)
     payload = json.loads(request.form.get('payload'))
     commits_url_template = get_commits_url_template(payload)
     for commit in payload['commits']:
         message = commit['message'].encode('utf-8')
         issue_refs = cmd_pattern.findall(message)
         if not issue_refs:
             continue
         commit_node = commit['node']
         commit_url = commits_url_template % commit['raw_node']
         timestamp = commit['utctimestamp']
         author = commit['author'].encode('utf-8')
         match = re.search(r'<(.+?)>', commit['raw_author'])
         if not match:
             app.logger.error("Cannot get author's email address.")
             abort(400)
         users = yt.getUsers(params={'q': match.group(1)})
         if not users:
             app.logger.error('Cannot find user with email ' + match.group(1))
             abort(400)
         if len(users) != 1:
             app.logger.error('Not unique email address ' + match.group(1))
             abort(400)
         comment = "Commit [%s %s] made by '''%s''' on ''%s''\n{quote}%s{quote}" \
                   % (commit_url, commit_node, author, timestamp, message)
         cmd_exec_result = True
         for issue_id, command in issue_refs:
             if command is None:
                 command = ''
             try:
                 app.logger.info("Adding commit %s to issue %s (command: %s)" %
                                 (commit_node, issue_id, command))
                 yt.executeCommand(issue_id, command, comment, run_as=users[0].login)
             except YouTrackException as e:
                 cmd_exec_result = False
                 app.logger.error('Failed to add commit %s to issue %s: %s' %
                                  (commit_node, issue_id, e.message))
         if not cmd_exec_result:
             abort(500)
     return 'success'
Exemple #3
0
def host_elegido(bot, update, user_data):
    bot.sendChatAction(chat_id=update.callback_query.from_user.id,
                       action=ChatAction.TYPING)

    usuario = usuarios.getCollection().find_one(
        {'chat_id': update.callback_query.from_user.id})
    logger.info('Elegir host Opción {}'.format(update.callback_query.data))

    host = next(x for x in usuario['hosts']
                if x['host'] == update.callback_query.data)
    user_data['host'] = host

    try:
        connection = Connection(user_data['host']['host'],
                                user_data['host']['username'],
                                user_data['host']['pass'])
        connections[usuario['chat_id']] = connection
        proyectos = connection.getProjects()

    except YouTrackException as e:
        logger.error(e)
        del user_data['host']['pass']
        usuarios.getCollection().update(
            {'chat_id': update.callback_query.from_user.id},
            {'$pull': {
                'hosts': user_data['host']
            }})

        return CONFIRMAR

    keyboard = []
    for proyecto in proyectos.keys():
        keyboard.append(
            InlineKeyboardButton(proyectos[proyecto], callback_data=proyecto))

    # Acomodo el teclado
    keyboard = [keyboard[i:i + 3] for i in range(0, len(keyboard), 3)]
    reply_markup = InlineKeyboardMarkup(keyboard,
                                        resize_keyboard=True,
                                        one_time_keyboard=True)
    update.callback_query.edit_message_text(text="Bien! Elegí un proyecto",
                                            reply_markup=reply_markup)
    return PROYECTO
def main(a_pat, yt_url, yt_login, yt_pass):
    """ Creates connections to Asana and your YouTrack site, then migrates tasks """
    a_conn = asana.Client.access_token(a_pat)
    yt_conn = Connection(yt_url, yt_login, yt_pass)
    print 'Logged in with Asana User {} and YouTrack User {}'.format(
        a_conn.users.me()['name'],
        yt_conn.getUser(yt_login).login)

    # Get list of Asana Workspaces to migrate - all except Personal Projects
    a_workspaces = [
        w for w in a_conn.workspaces.find_all()
        if w['name'] != "Personal Projects"
    ]
    print "Found Asana Workspaces (excluding Personal Projects): {}".format(
        [a['name'] for a in a_workspaces])
    yt_projects = [yt_conn.getProject(p) for p in yt_conn.getProjects()]
    print "Found existing YouTrack Projects: {}".format(
        [y.name for y in yt_projects])

    for a_work in a_workspaces:
        if a_work['name'] not in [p.name for p in yt_projects]:
            print "Creating YouTrack Project from {} Workspace".format(
                a_work['name'])
        yt_proj = None
        for p in yt_projects:
            if p.name == a_work['name']:
                yt_proj = p
                break
        if yt_proj is None:
            yt_proj = yt.Project()
            yt_proj.name = a_work['name']
            yt_proj.id = a_work['name'].replace(' ', '').upper()
            yt_proj.lead = yt_login
            print yt_conn.createProject(yt_proj)

        field_name = 'AsanaID'
        cf = yt.CustomField()
        cf.name = field_name
        cf.type = 'string'
        cf.isPrivate = False
        cf.visibleByDefault = False

        # print "Existing Project Fields: {}".format(yt_conn.getProjectCustomFields(yt_proj.id))
        try:
            asana_id_exists = yt_conn.getCustomField(field_name)
        except:
            asana_id_exists = False
        if not asana_id_exists:
            print 'Creating YouTrack Custom Field to save our Asana ID in'
            yt_conn.createCustomField(cf)

        try:
            asana_id_exists = yt_conn.getProjectCustomField(
                yt_proj.id, 'Due Date')
        except:
            asana_id_exists = None
        if not asana_id_exists:
            print 'Adding YouTrack Due Date Field to {} Project'.format(
                yt_proj.id)
            yt_conn.createProjectCustomFieldDetailed(yt_proj.id, 'Due Date',
                                                     '')

        try:
            asana_id_exists = yt_conn.getProjectCustomField(
                yt_proj.id, field_name)
        except:
            asana_id_exists = False
        if not asana_id_exists:
            print 'Adding YouTrack Custom Field {} to {} Project'.format(
                field_name, yt_proj.id)
            yt_conn.createProjectCustomFieldDetailed(yt_proj.id, field_name,
                                                     '')

        # Migrate users and save our list for later so we can assign people
        migrate_workspace_users(a_conn, yt_conn, a_work)
        migrate_projects_to_subsystems(a_conn, yt_conn, a_work, yt_proj)
        migrate_tasks_to_issues(a_conn, yt_conn, a_work, yt_proj, yt_login)
Exemple #5
0
def identificar(bot, update, user_data):
    info = update.message.text
    bot.sendChatAction(chat_id=update.message.chat_id,
                       action=ChatAction.TYPING)
    if not user_data.get('host', None) or not user_data['host'].get(
            'host', None):
        logger.info("Host received {}".format(info))
        try:
            info = checkAndFixUrl(info)
            user_data['host'] = {}
            user_data['host']['host'] = info
            keyboard = [[
                InlineKeyboardButton(text="Correcto", callback_data='host_ok'),
                InlineKeyboardButton(text="Corregir", callback_data='host_ko')
            ]]
            reply_markup = InlineKeyboardMarkup(keyboard,
                                                resize_keyboard=False,
                                                one_time_keyboard=True)
            update.message.reply_text("Es correcto el host? {}:".format(
                user_data['host']['host']),
                                      reply_markup=reply_markup)
            return CONFIRMAR
        except Exception as e:
            logger.error(e)
            update.message.reply_text(
                "{} no parece ser un host correcto, intentá de nuevo".format(
                    info))
            return IDENTIFICAR
    elif not user_data['host'].get('username', None):
        logger.info("Username received {}".format(info))
        user_data['host']['username'] = info
        keyboard = [[
            InlineKeyboardButton(text="Correcto", callback_data='username_ok'),
            InlineKeyboardButton(text="Corregir", callback_data='username_ko')
        ]]
        reply_markup = InlineKeyboardMarkup(keyboard,
                                            resize_keyboard=False,
                                            one_time_keyboard=True)
        update.message.reply_text("Es correcto el usuario? {}:".format(
            user_data['host']['username']),
                                  reply_markup=reply_markup)
        return CONFIRMAR
    else:
        logger.info("Password received")
        # Try to login
        user_data['host']['pass'] = info
        try:
            connection = Connection(user_data['host']['host'],
                                    user_data['host']['username'],
                                    user_data['host']['pass'])
            logger.info("good login")
            usuario = usuarios.getCollection().find_one(
                {'chat_id': update.message.chat_id})
            if not usuario:
                usuarios.getCollection().insert_one({
                    'chat_id':
                    update.message.chat_id,
                    'hosts': [user_data['host']]
                })
            else:
                usuarios.getCollection().update_one(
                    {'chat_id': update.message.chat_id},
                    {'$push': {
                        'hosts': user_data['host']
                    }})
            logger.info(user_data['host'])
            proyectos = connection.getProjects()
            keyboard = []
            for proyecto in proyectos.keys():
                keyboard.append([
                    InlineKeyboardButton(proyectos[proyecto],
                                         callback_data=proyecto)
                ])
            reply_markup = InlineKeyboardMarkup(keyboard,
                                                resize_keyboard=True,
                                                one_time_keyboard=True)
            update.message.reply_text("Bien! Elegí un proyecto",
                                      reply_markup=reply_markup)
            return PROYECTO

        except Exception as e:
            logger.error(e)
            update.message.reply_text("Clave incorrecta")
            return IDENTIFICAR

        return CONFIRMAR
Exemple #6
0
class YouTrackExporter(object):

    def __init__(self, yt, influx):
        self.yt = YouTrack(**yt)
        self.influx = InfluxDBClient(**influx)
        self.logger = logging.getLogger('worktime_reporter')
        self.project_blacklist = ['RRS', 'RR_INS']

    def get_all_issues(self, project):
        def _gen():
            skip = 0
            while True:
                issues = self.yt.getIssues(project.id,
                                           'Spent time: -?', skip, 50)
                if not issues:
                    break
                skip += len(issues)
                yield issues
        return itertools.chain.from_iterable(_gen())

    def issue_to_measurement(self, project, issue):
        self.logger.info(f'Looking into issue {issue.id}')
        lead_time = getattr(issue, 'Lead time', None)
        stream = getattr(issue, 'Stream', None)
        target = getattr(issue, 'Target', 'Core')
        _type = getattr(issue, 'Type', None)
        resolved = getattr(issue, 'resolved', None)
        estimation = getattr(issue, 'Estimation', None)
        tags = {
            'project': project.id,
            'issue': issue.id,
            'stream': stream,
            'target': target,
            'type': _type
        }
        counter = defaultdict(lambda: 0)
        for work_item in self.yt.getWorkItems(issue.id):
            _tags = dict(tags)
            _tags['author'] = getattr(work_item, 'authorLogin', None)
            created = getattr(work_item, 'created', None)
            work_type = getattr(work_item, 'worktype', None)
            date = getattr(work_item, 'date', created)
            duration = int(work_item.duration)
            if not created:
                continue
            created_dt = datetime.datetime.fromtimestamp(float(created)/1000)
            date_dt = datetime.datetime.fromtimestamp(float(date)/1000)
            time_dt = datetime.datetime.combine(date_dt.date(), created_dt.time(), date_dt.tzinfo)
            time_ts = int(datetime.datetime.timestamp(time_dt)*1000)
            counter[work_type] += duration
            yield {
                'measurement': 'work_item',
                'tags': _tags,
                'time': time_ts,
                'fields': {
                    work_type: duration
                }
            }

        cycle_time = counter['Analytics'] + counter['Development'] + counter['Testing']
        created = getattr(issue, 'created', None)
        if estimation:
            yield {
                'measurement': 'issue',
                'tags': tags,
                'time': int(created),
                'fields': {
                    'estimation': int(estimation)
                }
            }
        if lead_time and resolved:
            yield {
                'measurement': 'issue',
                'tags': tags,
                'time': int(resolved),
                'fields': {
                    'lead_time': float(lead_time),
                    'cycle_time': cycle_time,
                }
            }

    def process_project(self, project):
        if project.id in self.project_blacklist:
            self.logger.info(f'Skipping project {project.id}, blacklisted')
            return

        ts = self.yt.getProjectTimeTrackingSettings(project['id'])
        if not ts.Enabled:
            self.logger.info(
                f'Skipping project {project.id}, no time tracking')
            return

        self.logger.info(f'Looking into project {project.id}')
        issues = self.get_all_issues(project)
        measurements = (self.issue_to_measurement(project, issue) for issue in issues)
        return itertools.chain.from_iterable(measurements)

    def export(self):
        def _gen():
            projects = self.yt.getProjects()
            for project_id in projects:
                project = self.yt.getProject(project_id)
                measurements = self.process_project(project)
                if measurements:
                    yield measurements

        self.influx.drop_measurement('issue')
        self.influx.drop_measurement('work_item')

        measurements = itertools.chain.from_iterable(_gen())
        for chunk in grouper(measurements, 50):
            filtered = filter(lambda x: x is not None, chunk)
            self.influx.write_points(filtered, time_precision='ms')