def te_st_live(self):
        yt = Connection('https://tickets.i.gini.net', username, password)
        print 'connected to [%s]' % yt.baseUrl
        all_backend_issues = yt.getIssues('Backend', 'state:complete', 0, 1)
        print 'found %d issues' % len(all_backend_issues)
        changes = yt.get_changes_for_issue(all_backend_issues[0].id)

        state_changes = filter(has_state_changes, changes)
        self.assertEqual(4, len(state_changes))

        open_state_changes = filter(partial(has_new_value, 'In Progress'),
                                    state_changes)
        self.assertEqual(1, len(open_state_changes))

        open_state_time = open_state_changes[0].updated

        open_state_datetime = datetime.datetime.fromtimestamp(open_state_time /
                                                              1000.0)
        self.assertEqual(2016, open_state_datetime.year)
        self.assertEqual(7, open_state_datetime.month)
        self.assertEqual(6, open_state_datetime.day)

        resolved_state_changes = filter(has_resolved_value, state_changes)
        self.assertEqual(1, len(resolved_state_changes))

        complete_state_time = resolved_state_changes[0].updated
        complete_state_datetime = datetime.datetime.fromtimestamp(
            complete_state_time / 1000.0)
        self.assertEqual(2016, complete_state_datetime.year)
        self.assertEqual(7, complete_state_datetime.month)
        self.assertEqual(13, complete_state_datetime.day)

        self.assertEqual(datetime.timedelta(7, 3875, 903000),
                         complete_state_datetime - open_state_datetime)
Esempio n. 2
0
def proyecto_elegido(bot, update, user_data):
    bot.sendChatAction(chat_id=update.callback_query.from_user.id,
                       action=ChatAction.TYPING)

    # Es la primera vez que entra o cambia tipo de tareas?
    user_data['tipo_tarea'] = '#Unresolved'
    if not user_data.get('proyecto'):
        user_data['proyecto'] = update.callback_query.data
        logger.info('Elegir Proyecto Opción {}'.format(user_data['proyecto']))
    else:
        user_data['tipo_tarea'] = update.callback_query.data
        logger.info('Elegir Proyecto Opción {} {}'.format(
            user_data['proyecto'], user_data['tipo_tarea']))

    connection = Connection(user_data['host']['host'],
                            user_data['host']['username'],
                            user_data['host']['pass'])
    username, email = splitEmail(user_data['host']['username'])

    query = 'Type: Task and {} and ( Assignee: {} or #Unassigned )'.format(
        user_data['tipo_tarea'], username)
    issues = connection.getIssues(user_data['proyecto'], query, 0, 20)

    keyboard = []
    texto = '*Tareas:* \n '
    for issue in issues:
        texto += '\n *[{}]* _{}, {}_\n *Prioridad:* _{}_\n *Resumen:* {} \n'.format(
            issue['id'], issue['Type'], issue['State'], issue['Priority'],
            escapeMarkdown(utf8(issue['summary'])))
        keyboard.append(
            InlineKeyboardButton(issue['id'], callback_data=issue['id']))
    # Agrego posibilidad de ver otras tareas
    if user_data['tipo_tarea'] == '#Unresolved':
        keyboard.append(
            InlineKeyboardButton('Ver solucionadas',
                                 callback_data='#Resolved'))
    else:
        keyboard.append(
            InlineKeyboardButton('Ver no solucionadas',
                                 callback_data='#Unresolved'))
    # 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)

    texto += '\n *Elegí la tarea:*'

    if len(keyboard) > 0:
        update.callback_query.edit_message_text(text=texto,
                                                reply_markup=reply_markup,
                                                parse_mode='Markdown')
        return ISSUE
    else:
        update.callback_query.edit_message_text(
            text="No hay tareas asignadas a vos! Chau")
        return ConversationHandler.END
class ConnectionTest(unittest.TestCase):
    def setUp(self):
        #self.con = Connection('http://teamsys.intellij.net', 'resttest', 'resttest')
        self.con = Connection("http://localhost:8081", "root", "root")

    def test_getProject(self):
        p = self.con.getProject('SB')
        self.assertEqual(p.id, 'SB')
        self.assertEqual(p.name, 'Sandbox')

    def test_getSubsystems(self):
        subsystems = self.con.getSubsystems('SB')
        default = [s for s in subsystems if s.isDefault][0]
        self.assertTrue(default is not None)

    def test_getIssue(self):
        i = self.con.getIssue('SB-1')
        self.assertEqual(i.id, 'SB-1')
        self.assertEqual(i.numberInProject, '1')
        self.assertEqual(i.projectShortName, 'SB')

    def test_createIssue(self):
        i = self.con.createIssue('SB', 'resttest', 'Test issue',
                                 'Test description', '2', 'Bug', 'First',
                                 'Open', '', '', '')
        self.assertEqual(i.projectShortName, 'SB')
        self.assertEqual(i.priority, '2')
        self.assertEqual(i.type, 'Bug')
        self.assertEqual(i.subsystem, 'First')

    def test_createIssueAttachment(self):
        i = self.con.createIssue('SB', 'resttest', 'For attachmkents test',
                                 'Test description', '2', 'Bug', 'First',
                                 'Open', '', '', '')
        fname = 'connection_test.py'
        content = open(fname)
        self.con.createAttachment(i.id, fname, content)
        self.assertEqual(fname, self.con.getAttachments(i.id)[0].name)

    def test_createAndDeleteSubsystem(self):
        name = 'Test Subsystem [' + str(random.random()) + "]"
        self.con.createSubsystemDetailed('SB', name, False, 'resttest')
        s = self.con.getSubsystem('SB', name)
        self.assertEqual(s.name, name)
        self.assertEqual(s.isDefault, 'false')
        #todo: uncomment when fix deployed to teamsys
        #self.assertEqual(s.defaultAssignee, 'resttest')
        self.con.deleteSubsystem('SB', name)

    def test_importIssues(self):
        issues = self.con.getIssues("A", "", 0, 10)
        for issue in issues:
            if hasattr(issue, "Assignee"):
                issue["assigneeName"] = issue["Assignee"]
                del issue.Assignee
        self.con.importIssues("B", "assignees", issues)
    def __init__(self, host, user, password, api_key):
        connection = Connection(url=host, api_key=api_key)

        # get one issue
        issue = connection.getIssue('PI-1000')

        # get first 10 issues in project JT for query 'for: me #unresolved'
        issues = connection.getIssues(
            'pi', '#Resolved Fixed in build: {Next Build}', 0, 10)
        for issue in issues:
            print(issue)
class ConnectionTest(unittest.TestCase):

    def setUp(self):
        #self.con = Connection('http://teamsys.intellij.net', 'resttest', 'resttest')
        self.con = Connection("http://localhost:8081", "root", "root")
    def test_getProject(self):
        p = self.con.getProject('SB')
        self.assertEqual(p.id, 'SB')
        self.assertEqual(p.name, 'Sandbox')

    def test_getSubsystems(self):
        subsystems = self.con.getSubsystems('SB')
        default = [s for s in subsystems if s.isDefault][0]
        self.assertTrue(default is not None)        

    def test_getIssue(self):
        i = self.con.getIssue('SB-1')
        self.assertEqual(i.id, 'SB-1')
        self.assertEqual(i.numberInProject, '1')
        self.assertEqual(i.projectShortName, 'SB')

    def test_createIssue(self):
        i = self.con.createIssue('SB', 'resttest', 'Test issue', 'Test description', '2', 'Bug', 'First', 'Open', '', '', '')
        self.assertEqual(i.projectShortName, 'SB')
        self.assertEqual(i.priority, '2')
        self.assertEqual(i.type, 'Bug')
        self.assertEqual(i.subsystem, 'First')

    def test_createIssueAttachment(self):
        i = self.con.createIssue('SB', 'resttest', 'For attachmkents test', 'Test description', '2', 'Bug', 'First', 'Open', '', '', '')
        fname = 'connection_test.py'
        content = open(fname)
        self.con.createAttachment(i.id, fname, content)
        self.assertEqual(fname, self.con.getAttachments(i.id)[0].name)

    def test_createAndDeleteSubsystem(self):
        name = 'Test Subsystem [' + str(random.random()) + "]"
        self.con.createSubsystemDetailed('SB', name, False, 'resttest')
        s = self.con.getSubsystem('SB', name)
        self.assertEqual(s.name, name)
        self.assertEqual(s.isDefault, 'false')
        #todo: uncomment when fix deployed to teamsys
        #self.assertEqual(s.defaultAssignee, 'resttest')
        self.con.deleteSubsystem('SB', name)

    def test_importIssues(self):
        issues = self.con.getIssues("A", "", 0, 10)
        for issue in issues:
            if hasattr(issue, "Assignee"):
                issue["assigneeName"] = issue["Assignee"]
                del issue.Assignee
        self.con.importIssues("B", "assignees", issues)
Esempio n. 6
0
def issues_list_yt(request):
    yt = YouTrack('https://taptaxi.myjetbrains.com/youtrack/', token=ytt)
    issues = yt.getIssues(
        'SUP', 'Тип: Обращение_клиента сортировать: создана по убыв.', '',
        '50')

    #for issue in issues:
    #issue.created = datetime.strptime(issue.created, '%Y-%m-%dT%H:%M:%S.%f%z')

    deps = Department.objects.filter().order_by('dep_name')
    return render(request, 'contacts/issues_yt.html', {
        'issues': issues,
        'deps': deps
    })
def import_attachments_only(source_url, source_login, source_password,
                            target_url, target_login, target_password,
                            project_ids):
    if not project_ids:
        print 'No projects to import. Exit...'
        return
    start = 0
    max = 20
    source = Connection(source_url, source_login, source_password)
    target = Connection(target_url, target_login, target_password)
    user_importer = UserImporter(source, target, caching_users=True)
    for projectId in project_ids:
        while True:
            try:
                print 'Get issues from %d to %d' % (start, start + max)
                issues = source.getIssues(projectId, '', start, max)
                if len(issues) <= 0:
                    break
                for issue in issues:
                    print 'Process attachments for issue %s' % issue.id
                    attachments = issue.getAttachments()
                    users = set([])
                    for a in attachments:
                        author = a.getAuthor()
                        if author is not None:
                            users.add(author)
                    user_importer.importUsersRecursively(users)
                    for a in attachments:
                        print 'Transfer attachment of %s: %s' % (issue.id, a.name.encode('utf-8'))
                        try:
                            target.createAttachmentFromAttachment(issue.id, a)
                        except BaseException, e:
                            print 'Cannot import attachment [ %s ]' % a.name.encode('utf-8')
                            print repr(e)
            except Exception, e:
                print 'Cannot process issues from %d to %d' % (start, start + max)
                traceback.print_exc()
                raise e
            start += max
Esempio n. 8
0
            else:
                create_project_custom_field(target, field, projectId)

        # copy issues
        start = 0
        max = 20

        sync_workitems = True

        print "Import issues"

        while True:
            try:
                print "Get issues from " + str(start) + " to " + str(start +
                                                                     max)
                issues = source.getIssues(projectId, query, start, max)

                if len(issues) <= 0:
                    break

                if convert_period_values and period_cf_names:
                    for issue in issues:
                        for pname in period_cf_names:
                            for fname in issue.__dict__:
                                if fname.lower() != pname:
                                    continue
                                issue[fname] = period_to_minutes(issue[fname])

                users = set([])

                for issue in issues:
def import_attachments_only(source_url, source_login, source_password,
                            target_url, target_login, target_password,
                            project_ids, params=None):
    if not project_ids:
        print 'No projects to import. Exit...'
        return
    if params is None:
        params = {}
    start = 0
    max = 20
    source = Connection(source_url, source_login, source_password)
    target = Connection(target_url, target_login, target_password)
    user_importer = UserImporter(source, target, caching_users=params.get('enable_user_caching', True))
    for projectId in project_ids:
        while True:
            try:
                print 'Get issues from %d to %d' % (start, start + max)
                issues = source.getIssues(projectId, '', start, max)
                if len(issues) <= 0:
                    break
                for issue in issues:
                    print 'Process attachments for issue %s' % issue.id
                    existing_attachments = dict()
                    try:
                        for a in target.getAttachments(issue.id):
                            existing_attachments[a.name + '\n' + a.created] = a
                    except youtrack.YouTrackException, e:
                        if e.response.status == 404:
                            print "Skip importing attachments because issue %s doesn't exist" % issue.id
                            continue
                        raise e

                    attachments = []

                    users = set([])
                    for a in issue.getAttachments():
                        if a.name + '\n' + a.created in existing_attachments and not params.get('replace_attachments'):
                            print "Skip attachment '%s' (created: %s) because it's already exists" \
                                  % (a.name.encode('utf-8'), a.created)
                            continue
                        attachments.append(a)
                        author = a.getAuthor()
                        if author is not None:
                            users.add(author)
                    user_importer.importUsersRecursively(users)

                    for a in attachments:
                        print 'Transfer attachment of %s: %s' % (issue.id, a.name.encode('utf-8'))
                        try:
                            target.createAttachmentFromAttachment(issue.id, a)
                        except BaseException, e:
                            print 'Cannot import attachment [ %s ]' % a.name.encode('utf-8')
                            print repr(e)
                            continue
                        if params.get('replace_attachments'):
                            try:
                                old_attachment = existing_attachments.get(a.name + '\n' + a.created)
                                if old_attachment:
                                    print 'Deleting old attachment'
                                    target.deleteAttachment(issue.id, old_attachment.id)
                            except BaseException, e:
                                print "Cannot delete attachment '%s' from issue %s" % (a.name.encode('utf-8'), issue.id)
                                print e
                create_project_custom_field(target, field, projectId)

        # copy issues
        start = 0
        max = 20

        sync_workitems = enable_time_tracking(source, target, projectId)
        tt_settings = target.getProjectTimeTrackingSettings(projectId)

        print "Import issues"
        last_created_issue_number = 0

        while True:
            try:
                print "Get issues from " + str(start) + " to " + str(start + max)
                issues = source.getIssues(projectId, query, start, max)

                if len(issues) <= 0:
                    break

                if convert_period_values and period_cf_names:
                    for issue in issues:
                        for pname in period_cf_names:
                            for fname in issue.__dict__:
                                if fname.lower() != pname:
                                    continue
                                issue[fname] = period_to_minutes(issue[fname])

                users = set([])

                for issue in issues:
def Main(sendTo, subject, yamlMessage):
    """
    Workflow Zabbix-YouTrack
    :param sendTo: URL to Youtrack (ex. https://youtrack.example.com)
    :param subject: subject from Zabbix Action
    :param yamlMessage: message from Zabbix Action
    :return:
    """

    # ----- Use below example yamlMessage to debug -----
#     yamlMessage = """Name: 'Test Zabbix-YT workflow, ignore it'
# Text: 'Agent ping (server:agent.ping()): DOWN (1) '
# Hostname: 'server.exmpale.ru'
# Status: "OK"
# Severity: "High"
# EventID: "96976"
# TriggerID: "123456789012" """

    messages = yaml.load(yamlMessage)

    # ----- START Issue parameters -----
    # Correspondence between the YouTrackPriority and ZabbixSeverity
    # Critical >= High
    # Normal < High

    ytPriority = 'Normal'
    if messages['Severity'] == 'Disaster' or messages['Severity'] == 'High':
        ytPriority = 'Critical'

    ytName = "{} ZabbixTriggerID::{}".format(messages['Name'], messages['TriggerID'])
    # ----- END Issue parameters -----

    # ----- START Youtrack Issue description -----
    # Search link to other issue
    searchString = "Hostname: '{}'".format(messages['Hostname'])
    linkToHostIssue = "{youtrack}/issues/{projectname}?q={query}".format(
        youtrack=sendTo,
        projectname=YT_PROJECT_NAME,
        query=urllib.parse.quote(searchString, safe='')
    )

    issueDescription = """
{ytName}
-----
{yamlMessage}
-----
- [https://zabbix.example.com/zabbix.php?action=dashboard.view Zabbix Dashboard]
- Show [{linkToHostIssue} all issue for *this host*]
""".format(
        ytName=ytName,
        yamlMessage=yamlMessage,
        linkToHostIssue=linkToHostIssue, )

    # ----- END Youtrack Issue description -----

    # ----- START Youtrack current week -----

    # Create connect to Youtrack API
    connection = Connection(sendTo, YT_USER, YT_PASSWORD)

    # Get current week in YT format (Sprint planned)
    version = connection.getAllBundles('version')

    for fixVersion in version[0].values:
        if fixVersion['archived'] == False and fixVersion['released'] == False:
            fixVersionWeek = fixVersion['name']
            break
    # ----- END Youtrack current week -----

    # ----- START Youtrack get or create issue -----
    # Get issue if exist
    # Search for TriggerID
    createNewIssue = False

    logger.debug("Get issue with text '{}'".format(messages['TriggerID']))
    issue = connection.getIssues(YT_PROJECT_NAME,
                                 "ZabbixTriggerID::{}".format(messages['TriggerID']),
                                 0,
                                 1)


    if len(issue) == 0:
        createNewIssue = True

    else:
        # if issue contains TriggerID in summary, then it's good issue
        # else create new issue, this is bad issue, not from Zabbix
        if "ZabbixTriggerID::{}".format(messages['TriggerID']) in issue[0]['summary']:
            issueId = issue[0]['id']
            issue = connection.getIssue(issueId)
        else:
            createNewIssue = True

    # Create new issue
    if createNewIssue:
        logger.debug("Create new issue because it is not exist")
        issue = connection.createIssue(YT_PROJECT_NAME,
                                       'Unassigned',
                                       ytName,
                                       issueDescription,
                                       priority=ytPriority,
                                       subsystem=YT_SUBSYSTEM,
                                       type=YT_TYPE,
                                       )
        time.sleep(3)

        # Parse ID for new issue
        result = re.search(r'(CM-\d*)', issue[0]['location'])
        issueId = result.group(0)
        issue = connection.getIssue(issueId)

    logger.debug("Issue have id={}".format(issueId))

    # Set issue service
    ExecAndLog(connection, issueId, "Service {}".format(YT_SERVICE))

    # Update priority
    ExecAndLog(connection, issueId, "Priority {}".format(ytPriority))

    # ----- END Youtrack get or create issue -----

    # ----- START PROBLEM block ------
    if messages['Status'] == "PROBLEM":

        # Issue exist and NOT Hold on, Unnassigned and Estimated time set
        if issue['State'] != 'Hold on':

            # Estimated time
            ExecAndLog(connection, issueId, "Estimated time {}".format(YT_TIME))

            # Update fix version
            ExecAndLog(connection=connection, issueId=issueId, command="Sprint planned {}".format(fixVersionWeek))

        # Reopen if Fixed or Verified or Canceled
        if issue['State'] == 'Fixed' or issue['State'] == 'Verified' or issue['State'] == 'Canceled':
            # Reopen Issue
            ExecAndLog(connection, issueId, "State reopen")

            # Assignee issue
            ExecAndLog(connection, issueId, command="Assignee Unassigned")

        # Update summary and description for issue
        logger.debug("Run command in {issueId}: {command}".format(issueId=issueId,
                                                                  command="""Update summary and description with connection.updateIssue method"""
                                                                  ))
        connection.updateIssue(issueId=issueId, summary=ytName, description=issueDescription)

        # Add comment
        logger.debug("Run command in {issueId}: {command}".format(issueId=issueId,
                                                                  command="""Now is PROBLEM {}""".format(
                                                                      messages['Text'])
                                                                  ))
        connection.executeCommand(issueId=issueId,
                                  command="",
                                  comment=YT_COMMENT.format(
                                      status=messages['Status'],
                                      text=messages['Text'])
                                  )

        # Send ID to Zabbix:
        logger.debug("ZABBIX-API: Send Youtrack ID to {}".format(messages['EventID']))
        Zbx.event.acknowledge(eventids=messages['EventID'], message="Create Youtrack task")
        Zbx.event.acknowledge(eventids=messages['EventID'],
                              message="https://youtrack.example.com/issue/{}".format(issueId))
    # ----- End PROBLEM block ------


    # ----- Start OK block -----
    if messages['Status'] == "OK":

        if issue['State'] == 'Hold on' or issue['State'] == 'Registered':
            # Cancel if not in work
            ExecAndLog(connection, issueId, command="State Cancel")

            # Assignee issue
            ExecAndLog(connection, issueId, command="Assignee {}".format(YT_ASSIGNEE))

        if issue['State'] == 'Fixed':
            # Verify if Fixed
            ExecAndLog(connection, issueId, command="State verify")

        logger.debug("Run command in {issueId}: {command}".format(issueId=issueId,
                                                                  command="""Now is OK {}""".format(messages['Text'])
                                                                  ))
        connection.executeCommand(issueId=issueId,
                                  command="",
                                  comment=YT_COMMENT.format(
                                      status=messages['Status'],
                                      text=messages['Text'])
                                  )
    REDMINE_URL = config.get('REDMINE', 'url')
    REDMINE_API_KEY = config.get('REDMINE', 'api key')
    REDMINE_PROJECT = config.get('REDMINE', 'project')
    YOUTRACK_PROJECT = config.get('YOUTRACK', 'project')
    SEARCH_QUERY = config.get('YOUTRACK', 'search query').replace('\n', '')

    try:
        youtrack = Connection(YOUTRACK_URL, LOGIN, PASSWRD)
    except YouTrackException as yt_exc:
        print yt_exc
        sys.exit(0)

    redmine = Redmine(REDMINE_URL, key=REDMINE_API_KEY, requests={'verify': False})

    print "Getting YouTrack issues..."
    issues_list = youtrack.getIssues('project: ' + YOUTRACK_PROJECT + ' ' + SEARCH_QUERY, 0, 5000)

    try:
        redmine_users = get_redmine_users()
        redmine_trackers = get_redmine_trackers()
        redmine_statuses = get_redmine_statuses()
        redmine_priorities = get_redmine_priorities()
        redmine_versions = get_redmine_project_versions()
        redmine_custom_fields = get_redmine_custom_fields()
    except Exception as e:
        print e
        sys.exit(0)

    issues_dict = {}

    print "==========Copying from YouTrack to Redmine=========="
Esempio n. 13
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')
Esempio n. 14
0
def proyecto_elegido(bot, update, user_data):
    bot.sendChatAction(chat_id=update.callback_query.from_user.id,
                       action=ChatAction.TYPING)

    # Es la primera vez que entra o cambia tipo de tareas?
    if not user_data.get('proyecto'):
        user_data['proyecto'] = update.callback_query.data
        user_data['pagging'] = [0, max_issues_per_page]
        user_data['tipo_tarea'] = '#{Sin resolver}'
        logger.info('Elegir Proyecto Opción {}'.format(user_data['proyecto']))
    elif update.callback_query.data == '>':
        user_data['pagging'] = [
            user_data['pagging'][0] + max_issues_per_page,
            user_data['pagging'][1] + max_issues_per_page
        ]
    elif update.callback_query.data == '<':
        user_data['pagging'] = [
            user_data['pagging'][0] - max_issues_per_page,
            user_data['pagging'][1] - max_issues_per_page
        ]
    else:
        user_data['tipo_tarea'] = update.callback_query.data
        user_data['pagging'] = [0, max_issues_per_page]
        logger.info('Elegir Proyecto Opción {} {}'.format(
            user_data['proyecto'], user_data['tipo_tarea']))

    logger.info('paginas {}/{}'.format(user_data['pagging'][0],
                                       user_data['pagging'][1]))

    connection = Connection(user_data['host']['host'],
                            user_data['host']['username'],
                            user_data['host']['pass'])
    username, email = splitEmail(user_data['host']['username'])

    #of #me #{Sin asignar} -Resolved
    query = '(asignado a: ' + username + ' o #{Sin asignar}) y ' + user_data[
        'tipo_tarea']
    logger.info(query)
    issues = connection.getIssues(user_data['proyecto'], query,
                                  user_data['pagging'][0], max_issues_per_page)

    #Necesito guardar el numero de issues segun query para el paginado pq es lento
    if user_data['tipo_tarea'] == '#resuelta':
        if not user_data.get('issue_count_resueltas'):
            user_data['issue_count_resueltas'] = connection.getNumberOfIssues(
                query + ' y #' + user_data['proyecto'])
        issue_count = user_data['issue_count_resueltas']
    else:
        if not user_data.get('issue_count_no_resueltas'):
            user_data[
                'issue_count_no_resueltas'] = connection.getNumberOfIssues(
                    query + ' y #' + user_data['proyecto'])
        issue_count = user_data['issue_count_no_resueltas']

    keyboard = []
    texto = '*Tareas:* \n '
    for issue in issues:
        texto += '\n *[{}]* _{}, {}_\n *Prioridad:* _{}_\n *Resumen:* {} \n'.format(
            issue['id'], issue['Type'], issue['State'], issue['Priority'],
            escapeMarkdown(utf8(issue['summary'])))
        keyboard.append(
            InlineKeyboardButton(issue['id'], callback_data=issue['id']))
    # Agrego posibilidad de ver otras tareas
    if user_data['tipo_tarea'] == '#{Sin resolver}':
        keyboard.append(
            InlineKeyboardButton('Ver solucionadas',
                                 callback_data='#resuelta'))
    else:
        keyboard.append(
            InlineKeyboardButton('Ver no solucionadas',
                                 callback_data='#{Sin resolver}'))

    #Paginado
    if user_data['pagging'][0] > 0:
        keyboard.append(InlineKeyboardButton('<', callback_data='<'))
    if len(issues) >= 5:
        keyboard.append(InlineKeyboardButton('>', callback_data='>'))

    # 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)

    texto += '\n *Elegí la tarea:*'

    if len(keyboard) > 0:
        update.callback_query.edit_message_text(text=texto,
                                                reply_markup=reply_markup,
                                                parse_mode='Markdown')
        return ISSUE
    else:
        update.callback_query.edit_message_text(
            text="No hay tareas asignadas a vos! Chau")
        return ConversationHandler.END
Esempio n. 15
0
def Main(sendTo, subject, yamlMessage):
    """
    Workflow Zabbix-YouTrack
    :param sendTo: URL to Youtrack (ex. https://youtrack.example.com)
    :param subject: subject from Zabbix Action
    :param yamlMessage: message from Zabbix Action
    :return:
    """

    # ----- Use below example yamlMessage to debug -----
    #     yamlMessage = """Name: 'Test Zabbix-YT workflow, ignore it'
    # Text: 'Agent ping (server:agent.ping()): DOWN (1) '
    # Hostname: 'server.exmpale.ru'
    # Status: "OK"
    # Severity: "High"
    # EventID: "96976"
    # TriggerID: "123456789012" """

    messages = yaml.load(yamlMessage)

    # ----- START Issue parameters -----
    # Correspondence between the YouTrackPriority and ZabbixSeverity
    # Critical >= High
    # Normal < High

    ytPriority = 'Normal'
    if messages['Severity'] == 'Disaster' or messages['Severity'] == 'High':
        ytPriority = 'Critical'

    ytName = "{} ZabbixTriggerID::{}".format(messages['Name'],
                                             messages['TriggerID'])
    # ----- END Issue parameters -----

    # ----- START Youtrack Issue description -----
    # Search link to other issue
    searchString = "Hostname: '{}'".format(messages['Hostname'])
    linkToHostIssue = "{youtrack}/issues/{projectname}?q={query}".format(
        youtrack=sendTo,
        projectname=YT_PROJECT_NAME,
        query=urllib.parse.quote(searchString, safe=''))

    issueDescription = """
{ytName}
-----
{yamlMessage}
-----
- [https://zabbix.example.com/zabbix.php?action=dashboard.view Zabbix Dashboard]
- Show [{linkToHostIssue} all issue for *this host*]
""".format(
        ytName=ytName,
        yamlMessage=yamlMessage,
        linkToHostIssue=linkToHostIssue,
    )

    # ----- END Youtrack Issue description -----

    # ----- START Youtrack current week -----

    # Create connect to Youtrack API
    connection = Connection(sendTo, YT_USER, YT_PASSWORD)

    # Get current week in YT format (Sprint planned)
    version = connection.getAllBundles('version')

    for fixVersion in version[0].values:
        if fixVersion['archived'] == False and fixVersion['released'] == False:
            fixVersionWeek = fixVersion['name']
            break
    # ----- END Youtrack current week -----

    # ----- START Youtrack get or create issue -----
    # Get issue if exist
    # Search for TriggerID
    createNewIssue = False

    logger.debug("Get issue with text '{}'".format(messages['TriggerID']))
    issue = connection.getIssues(
        YT_PROJECT_NAME, "ZabbixTriggerID::{}".format(messages['TriggerID']),
        0, 1)

    if len(issue) == 0:
        createNewIssue = True

    else:
        # if issue contains TriggerID in summary, then it's good issue
        # else create new issue, this is bad issue, not from Zabbix
        if "ZabbixTriggerID::{}".format(
                messages['TriggerID']) in issue[0]['summary']:
            issueId = issue[0]['id']
            issue = connection.getIssue(issueId)
        else:
            createNewIssue = True

    # Create new issue
    if createNewIssue:
        logger.debug("Create new issue because it is not exist")
        issue = connection.createIssue(
            YT_PROJECT_NAME,
            'Unassigned',
            ytName,
            issueDescription,
            priority=ytPriority,
            subsystem=YT_SUBSYSTEM,
            type=YT_TYPE,
        )
        time.sleep(3)

        # Parse ID for new issue
        result = re.search(r'(CM-\d*)', issue[0]['location'])
        issueId = result.group(0)
        issue = connection.getIssue(issueId)

    logger.debug("Issue have id={}".format(issueId))

    # Set issue service
    ExecAndLog(connection, issueId, "Service {}".format(YT_SERVICE))

    # Update priority
    ExecAndLog(connection, issueId, "Priority {}".format(ytPriority))

    # ----- END Youtrack get or create issue -----

    # ----- START PROBLEM block ------
    if messages['Status'] == "PROBLEM":

        # Issue exist and NOT Hold on, Unnassigned and Estimated time set
        if issue['State'] != 'Hold on':

            # Estimated time
            ExecAndLog(connection, issueId,
                       "Estimated time {}".format(YT_TIME))

            # Update fix version
            ExecAndLog(connection=connection,
                       issueId=issueId,
                       command="Sprint planned {}".format(fixVersionWeek))

        # Reopen if Fixed or Verified or Canceled
        if issue['State'] == 'Fixed' or issue['State'] == 'Verified' or issue[
                'State'] == 'Canceled':
            # Reopen Issue
            ExecAndLog(connection, issueId, "State reopen")

            # Assignee issue
            ExecAndLog(connection, issueId, command="Assignee Unassigned")

        # Update summary and description for issue
        logger.debug("Run command in {issueId}: {command}".format(
            issueId=issueId,
            command=
            """Update summary and description with connection.updateIssue method"""
        ))
        connection.updateIssue(issueId=issueId,
                               summary=ytName,
                               description=issueDescription)

        # Add comment
        logger.debug("Run command in {issueId}: {command}".format(
            issueId=issueId,
            command="""Now is PROBLEM {}""".format(messages['Text'])))
        connection.executeCommand(issueId=issueId,
                                  command="",
                                  comment=YT_COMMENT.format(
                                      status=messages['Status'],
                                      text=messages['Text']))

        # Send ID to Zabbix:
        logger.debug("ZABBIX-API: Send Youtrack ID to {}".format(
            messages['EventID']))
        Zbx.event.acknowledge(eventids=messages['EventID'],
                              message="Create Youtrack task")
        Zbx.event.acknowledge(
            eventids=messages['EventID'],
            message="https://youtrack.example.com/issue/{}".format(issueId))
    # ----- End PROBLEM block ------

    # ----- Start OK block -----
    if messages['Status'] == "OK":

        if issue['State'] == 'Hold on' or issue['State'] == 'Registered':
            # Cancel if not in work
            ExecAndLog(connection, issueId, command="State Cancel")

            # Assignee issue
            ExecAndLog(connection,
                       issueId,
                       command="Assignee {}".format(YT_ASSIGNEE))

        if issue['State'] == 'Fixed':
            # Verify if Fixed
            ExecAndLog(connection, issueId, command="State verify")

        logger.debug("Run command in {issueId}: {command}".format(
            issueId=issueId,
            command="""Now is OK {}""".format(messages['Text'])))
        connection.executeCommand(issueId=issueId,
                                  command="",
                                  comment=YT_COMMENT.format(
                                      status=messages['Status'],
                                      text=messages['Text']))
Esempio n. 16
0
try:
    passwd_encoded = Config.get('USER', 'PASSWORD')
    passwd = base64.b64decode(passwd_encoded)
except ConfigParser.NoOptionError:
    passwd = getpass.getpass('Password is not set! Type password: '******'USER', 'PASSWORD', passwd_encoded)
    with open('config', 'w') as cfg_file:
        Config.write(cfg_file)
try:
    connection = Connection(server, domain + '\\' + user, passwd)

    # Get array of issues
    issues_list = connection.getIssues(
        project, 'Category: {' + category +
        '} State: -Obsolete sort by: {issue id} asc', 0, 2000)

    doc = minidom.Document()
    root = doc.createElement('sections')

    def get_super_parents(issues):
        parent_dict = dict()
        for issue in issues:
            parent_dict[issue.id] = (connection.getIssues(
                project, 'Category: {' + category +
                '} State: -Obsolete Parent for: ' + issue.id, 0, 2000))
        parents = []
        for s in range(len(parent_dict.items())):
            if not parent_dict.items()[s][1]:
                parents.append(parent_dict.items()[s][0])
    REDMINE_PROJECT = config.get('REDMINE', 'project')
    YOUTRACK_PROJECT = config.get('YOUTRACK', 'project')
    SEARCH_QUERY = config.get('YOUTRACK', 'search query').replace('\n', '')

    try:
        youtrack = Connection(YOUTRACK_URL, LOGIN, PASSWRD)
    except YouTrackException as yt_exc:
        print yt_exc
        sys.exit(0)

    redmine = Redmine(REDMINE_URL,
                      key=REDMINE_API_KEY,
                      requests={'verify': False})

    print "Getting YouTrack issues..."
    issues_list = youtrack.getIssues(
        'project: ' + YOUTRACK_PROJECT + ' ' + SEARCH_QUERY, 0, 5000)

    try:
        redmine_users = get_redmine_users()
        redmine_trackers = get_redmine_trackers()
        redmine_statuses = get_redmine_statuses()
        redmine_priorities = get_redmine_priorities()
        redmine_versions = get_redmine_project_versions()
        redmine_custom_fields = get_redmine_custom_fields()
    except Exception as e:
        print e
        sys.exit(0)

    issues_dict = {}

    print "==========Copying from YouTrack to Redmine=========="
Esempio n. 18
0
parentdir = os.path.dirname(os.path.abspath(__file__))
libdir = parentdir + '/youtrack/'
sys.path.append(libdir)
from youtrack.connection import Connection

passwd = open('password.txt', 'r').read().strip()
user = config.USERNAME
server = 'https://106.125.46.213/youtrack/'
connection = Connection(server, user, passwd)

category = config.CATEGORY

print category + ' mindmap creation...'

# Get array of issues
issues_list = connection.getIssues('TRAR', 'Category: ' + category + ' State: -Obsolete sort by: {issue id} asc', 0, 2000)

issue_map = xmind.load(category + ".xmind")
sheet = issue_map.getPrimarySheet()
sheet.setTitle(category)
root_primary = sheet.getRootTopic()
root_primary.setTitle(category)


def getSuperParents(issues):
    parent_dict = dict()
    for issue in issues:
        parent_dict[issue.id] = (connection.getIssues('TRAR', 'Category: ' + category + ' State: -Obsolete Parent for: ' + issue.id, 0, 2000))
    parents = []
    for s in range(len(parent_dict.items())):
        if not parent_dict.items()[s][1]:
user = Config.get('USER', 'Username')

try:
    passwd_encoded = Config.get('USER', 'PASSWORD')
    passwd = base64.b64decode(passwd_encoded)
except ConfigParser.NoOptionError:
    passwd = getpass.getpass('Password is not set! Type password: '******'USER', 'PASSWORD', passwd_encoded)
    with open('config', 'w') as cfg_file:
        Config.write(cfg_file)
try:
    connection = Connection(server, domain + '\\' + user, passwd)

    # Get array of issues
    issues_list = connection.getIssues(project, 'Category: {' + category + '} State: -Obsolete sort by: {issue id} asc', 0, 2000)

    doc = minidom.Document()
    root = doc.createElement('sections')

    def get_super_parents(issues):
        parent_dict = dict()
        for issue in issues:
            parent_dict[issue.id] = (connection.getIssues(project, 'Category: {' + category + '} State: -Obsolete Parent for: ' + issue.id, 0, 2000))
        parents = []
        for s in range(len(parent_dict.items())):
            if not parent_dict.items()[s][1]:
                parents.append(parent_dict.items()[s][0])
        return parents

    def get_subtasks(issue_id):
def youtrack2youtrack(source_url, source_login, source_password, target_url, target_login, target_password,
                      project_ids, query='', source_token=None, target_token=None, params=None):
    if not len(project_ids):
        print("You should sign at least one project to import")
        return
    if params is None:
        params = {}

    source = Connection(source_url, source_login, source_password) if (source_token is None) else Connection(source_url,
                                                                                                             token=source_token)
    target = Connection(target_url, target_login, target_password) if (target_token is None) else Connection(target_url,
                                                                                                             token=target_token)
    # , proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP, 'localhost', 8888)

    print("Import issue link types")
    for ilt in source.getIssueLinkTypes():
        try:
            print(target.createIssueLinkType(ilt))
        except youtrack.YouTrackException as e:
            print(e.message)

    user_importer = UserImporter(source, target, caching_users=params.get('enable_user_caching', True))
    link_importer = LinkImporter(target)

    # create all projects with minimum info and project lead set
    created_projects = []
    for project_id in project_ids:
        created = create_project_stub(source, target, project_id, user_importer)
        created_projects.append(created)

    # save created project ids to create correct group roles afterwards
    user_importer.addCreatedProjects([project.id for project in created_projects])
    # import project leads with group they are included and roles assigned to these groups
    user_importer.importUsersRecursively([target.getUser(project.lead) for project in created_projects])
    # afterwards in a script any user import imply recursive import

    cf_names_to_import = set([])  # names of cf prototypes that should be imported
    for project_id in project_ids:
        cf_names_to_import.update([pcf.name.capitalize() for pcf in source.getProjectCustomFields(project_id)])

    target_cf_names = [pcf.name.capitalize() for pcf in target.getCustomFields()]

    period_cf_names = []

    for cf_name in cf_names_to_import:
        source_cf = source.getCustomField(cf_name)
        if source_cf.type.lower() == 'period':
            period_cf_names.append(source_cf.name.lower())

        print("Processing custom field '%s'" % utf8encode(cf_name))
        if cf_name in target_cf_names:
            target_cf = target.getCustomField(cf_name)
            if not (target_cf.type == source_cf.type):
                print("In your target and source YT instances you have field with name [ %s ]" % utf8encode(cf_name))
                print("They have different types. Source field type [ %s ]. Target field type [ %s ]" %
                      (source_cf.type, target_cf.type))
                print("exiting...")
                exit()
        else:
            if hasattr(source_cf, "defaultBundle"):
                create_bundle_from_bundle(source, target, source_cf.defaultBundle, source_cf.type, user_importer)
            target.createCustomField(source_cf)

    failed_commands = []

    for projectId in project_ids:
        source = Connection(source_url, source_login, source_password) if (source_token is None) else Connection(
            source_url, token=source_token)
        target = Connection(target_url, target_login, target_password) if (target_token is None) else Connection(
            target_url, token=target_token)
        # , proxy_info = httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP, 'localhost', 8888)
        # reset connections to avoid disconnections
        user_importer.resetConnections(source, target)
        link_importer.resetConnections(target)

        # copy project, subsystems, versions
        project = source.getProject(projectId)

        link_importer.addAvailableIssuesFrom(projectId)
        project_custom_fields = source.getProjectCustomFields(projectId)
        # create bundles and additional values
        for pcf_ref in project_custom_fields:
            pcf = source.getProjectCustomField(projectId, pcf_ref.name)
            if hasattr(pcf, "bundle"):
                try:
                    create_bundle_from_bundle(source, target, pcf.bundle, source.getCustomField(pcf.name).type,
                                              user_importer)
                except youtrack.YouTrackException as e:
                    if e.response.status != 409:
                        raise e
                    else:
                        print(e)

        target_project_fields = [pcf.name.lower() for pcf in target.getProjectCustomFields(projectId)]
        for field in project_custom_fields:
            if field.name.lower() in target_project_fields:
                if hasattr(field, 'bundle'):
                    if field.bundle != target.getProjectCustomField(projectId, field.name).bundle:
                        target.deleteProjectCustomField(projectId, field.name)
                        create_project_custom_field(target, field, projectId)
            else:
                try:
                    create_project_custom_field(target, field, projectId)
                except youtrack.YouTrackException as e:
                    if e.response.status != 409:
                        raise e
                    else:
                        print(e)

        # copy issues
        start = 0
        max = 20

        sync_workitems = enable_time_tracking(source, target, projectId)
        tt_settings = target.getProjectTimeTrackingSettings(projectId)

        print("Import issues")
        last_created_issue_number = 0

        while True:
            try:
                print("Get issues from " + str(start) + " to " + str(start + max))
                issues = source.getIssues(projectId, query, start, max)

                if len(issues) <= 0:
                    break

                if convert_period_values and period_cf_names:
                    for issue in issues:
                        for pname in period_cf_names:
                            for fname in issue.__dict__:
                                if fname.lower() != pname:
                                    continue
                                issue[fname] = period_to_minutes(issue[fname])

                users = set([])

                for issue in issues:
                    print("Collect users for issue [%s]" % issue.id)

                    users.add(issue.getReporter())
                    if issue.hasAssignee():
                        if isinstance(issue.Assignee, (list, tuple)):
                            users.update(issue.getAssignee())
                        else:
                            users.add(issue.getAssignee())
                    # TODO: http://youtrack.jetbrains.net/issue/JT-6100
                    users.add(issue.getUpdater())
                    if issue.hasVoters():
                        users.update(issue.getVoters())
                    for comment in issue.getComments():
                        users.add(comment.getAuthor())

                    print("Collect links for issue [%s]" % issue.id)
                    link_importer.collectLinks(issue.getLinks(True))
                    # links.extend(issue.getLinks(True))

                    # fix problem with comment.text
                    for comment in issue.getComments():
                        if not hasattr(comment, "text") or (len(comment.text.strip()) == 0):
                            setattr(comment, 'text', 'no text')

                user_importer.importUsersRecursively(users)

                print("Create issues [" + str(len(issues)) + "]")
                if params.get('create_new_issues'):
                    create_issues(target, issues, last_created_issue_number)
                else:
                    print(target.importIssues(projectId, project.name + ' Assignees', issues))
                link_importer.addAvailableIssues(issues)

                for issue in issues:
                    try:
                        target_issue = target.getIssue(issue.id)
                    except youtrack.YouTrackException as e:
                        print("Cannot get target issue")
                        print(e)
                        continue

                    if params.get('sync_tags') and issue.tags:
                        try:
                            for tag in issue.tags:
                                tag = re.sub(r'[,&<>]', '_', tag)
                                try:
                                    target.executeCommand(issue.id, 'tag ' + tag, disable_notifications=True)
                                except youtrack.YouTrackException:
                                    tag = re.sub(r'[\s-]', '_', tag)
                                    target.executeCommand(issue.id, 'tag ' + tag, disable_notifications=True)
                        except youtrack.YouTrackException as e:
                            print("Cannot sync tags for issue " + issue.id)
                            print(e)

                    if params.get('add_new_comments'):
                        target_comments = dict()
                        max_id = 0
                        for c in target_issue.getComments():
                            target_comments[c.created] = c
                            if max_id < c.created:
                                max_id = c.created
                        for c in issue.getComments():
                            if c.created > max_id or c.created not in target_comments:
                                group = None
                                if hasattr(c, 'permittedGroup'):
                                    group = c.permittedGroup
                                try:
                                    target.executeCommand(issue.id, 'comment', c.text, group, c.author,
                                                          disable_notifications=True)
                                except youtrack.YouTrackException as e:
                                    print('Cannot add comment to issue')
                                    print(e)

                    if params.get('sync_custom_fields'):
                        skip_fields = []
                        if tt_settings and tt_settings.Enabled and tt_settings.TimeSpentField:
                            skip_fields.append(tt_settings.TimeSpentField)
                        skip_fields = [name.lower() for name in skip_fields]
                        for pcf in [pcf for pcf in project_custom_fields if pcf.name.lower() not in skip_fields]:
                            target_cf_value = None
                            if pcf.name in target_issue:
                                target_cf_value = target_issue[pcf.name]
                                if isinstance(target_cf_value, (list, tuple)):
                                    target_cf_value = set(target_cf_value)
                                elif target_cf_value == target.getProjectCustomField(projectId, pcf.name).emptyText:
                                    target_cf_value = None
                            source_cf_value = None
                            if pcf.name in issue:
                                source_cf_value = issue[pcf.name]
                                if isinstance(source_cf_value, (list, tuple)):
                                    source_cf_value = set(source_cf_value)
                                elif source_cf_value == source.getProjectCustomField(projectId, pcf.name).emptyText:
                                    source_cf_value = None
                            if source_cf_value == target_cf_value:
                                continue
                            if isinstance(source_cf_value, set) or isinstance(target_cf_value, set):
                                if source_cf_value is None:
                                    source_cf_value = set([])
                                elif not isinstance(source_cf_value, set):
                                    source_cf_value = set([source_cf_value])
                                if target_cf_value is None:
                                    target_cf_value = set([])
                                elif not isinstance(target_cf_value, set):
                                    target_cf_value = set([target_cf_value])
                                for v in target_cf_value:
                                    if v not in source_cf_value:
                                        target.executeCommand(issue.id, 'remove %s %s' % (pcf.name, v),
                                                              disable_notifications=True)
                                for v in source_cf_value:
                                    if v not in target_cf_value:
                                        target.executeCommand(issue.id, 'add %s %s' % (pcf.name, v),
                                                              disable_notifications=True)
                            else:
                                if source_cf_value is None:
                                    source_cf_value = target.getProjectCustomField(projectId, pcf.name).emptyText
                                if pcf.type.lower() == 'date':
                                    m = re.match(r'(\d{10})(?:\d{3})?', str(source_cf_value))
                                    if m:
                                        source_cf_value = datetime.datetime.fromtimestamp(
                                            int(m.group(1))).strftime('%Y-%m-%d')
                                elif pcf.type.lower() == 'period':
                                    source_cf_value = '%sm' % source_cf_value
                                command = '%s %s' % (pcf.name, source_cf_value)
                                try:
                                    target.executeCommand(issue.id, command, disable_notifications=True)
                                except youtrack.YouTrackException as e:
                                    if e.response.status == 412 and e.response.reason.find('Precondition Failed') > -1:
                                        print('WARN: Some workflow blocks following command: %s' % command)
                                        failed_commands.append((issue.id, command))

                    if sync_workitems:
                        workitems = source.getWorkItems(issue.id)
                        if workitems:
                            existing_workitems = dict()
                            target_workitems = target.getWorkItems(issue.id)
                            if target_workitems:
                                for w in target_workitems:
                                    _id = '%s\n%s\n%s' % (w.date, w.authorLogin, w.duration)
                                    if hasattr(w, 'description'):
                                        _id += '\n%s' % w.description
                                    existing_workitems[_id] = w
                            new_workitems = []
                            for w in workitems:
                                _id = '%s\n%s\n%s' % (w.date, w.authorLogin, w.duration)
                                if hasattr(w, 'description'):
                                    _id += '\n%s' % w.description
                                if _id not in existing_workitems:
                                    new_workitems.append(w)
                            if new_workitems:
                                print("Process workitems for issue [ " + issue.id + "]")
                                try:
                                    user_importer.importUsersRecursively(
                                        [source.getUser(w.authorLogin)
                                         for w in new_workitems])
                                    target.importWorkItems(issue.id, new_workitems)
                                except youtrack.YouTrackException as e:
                                    if e.response.status == 404:
                                        print("WARN: Target YouTrack doesn't support workitems importing.")
                                        print("WARN: Workitems won't be imported.")
                                        sync_workitems = False
                                    else:
                                        print("ERROR: Skipping workitems because of error:" + str(e))

                    print("Process attachments for issue [%s]" % issue.id)
                    existing_attachments = dict()
                    try:
                        for a in target.getAttachments(issue.id):
                            existing_attachments[a.name + '\n' + a.created] = a
                    except youtrack.YouTrackException as e:
                        if e.response.status == 404:
                            print("Skip importing attachments because issue %s doesn't exist" % issue.id)
                            continue
                        raise e

                    attachments = []

                    users = set([])
                    for a in issue.getAttachments():
                        if a.name + '\n' + a.created in existing_attachments and not params.get('replace_attachments'):
                            a.name = utf8encode(a.name)
                            try:
                                print("Skip attachment '%s' (created: %s) because it's already exists"
                                      % (utf8encode(a.name), utf8encode(a.created)))
                            except Exception:
                                pass
                            continue
                        attachments.append(a)
                        author = a.getAuthor()
                        if author is not None:
                            users.add(author)
                    user_importer.importUsersRecursively(users)

                    for a in attachments:
                        print("Transfer attachment of " + utf8encode(issue.id) + ": " + utf8encode(a.name))
                        # TODO: add authorLogin to workaround http://youtrack.jetbrains.net/issue/JT-6082
                        # a.authorLogin = target_login
                        try:
                            target.createAttachmentFromAttachment(issue.id, a)
                        except BaseException as e:
                            print("Cant import attachment [ %s ]" % utf8encode(a.name))
                            print(repr(e))
                            continue
                        if params.get('replace_attachments'):
                            try:
                                old_attachment = existing_attachments.get(a.name + '\n' + a.created)
                                if old_attachment:
                                    print('Deleting old attachment')
                                    target.deleteAttachment(issue.id, old_attachment.id)
                            except BaseException as e:
                                print("Cannot delete attachment '%s' from issue %s" % (
                                utf8encode(a.name), utf8encode(issue.id)))
                                print(e)

            except Exception as e:
                print('Cant process issues from ' + str(start) + ' to ' + str(start + max))
                traceback.print_exc()
                raise e

            start += max

    print("Import issue links")
    link_importer.importCollectedLinks()

    print("Trying to execute failed commands once again")
    for issue_id, command in failed_commands:
        try:
            print('Executing command on issue %s: %s' % (issue_id, command))
            target.executeCommand(issue_id, command, disable_notifications=True)
        except youtrack.YouTrackException as e:
            print('Failed to execute command for issue #%s: %s' % (issue_id, command))
            print(e)
def import_attachments_only(source_url, source_login, source_password,
                            target_url, target_login, target_password,
                            project_ids, source_token=None, target_token=None, params=None):
    if not project_ids:
        print('No projects to import. Exit...')
        return
    if params is None:
        params = {}
    start = 0
    max = 20
    source = Connection(source_url, source_login, source_password) if (source_token is None) else Connection(source_url,
                                                                                                             token=source_token)
    target = Connection(target_url, target_login, target_password) if (target_token is None) else Connection(target_url,
                                                                                                             token=target_token)

    user_importer = UserImporter(source, target, caching_users=params.get('enable_user_caching', True))
    for projectId in project_ids:
        while True:
            try:
                print('Get issues from %d to %d' % (start, start + max))
                issues = source.getIssues(projectId, '', start, max)
                if len(issues) <= 0:
                    break
                for issue in issues:
                    print('Process attachments for issue %s' % issue.id)
                    existing_attachments = dict()
                    try:
                        for a in target.getAttachments(issue.id):
                            existing_attachments[a.name + '\n' + a.created] = a
                    except youtrack.YouTrackException as e:
                        if e.response.status == 404:
                            print("Skip importing attachments because issue %s doesn't exist" % issue.id)
                            continue
                        raise e

                    attachments = []

                    users = set([])
                    for a in issue.getAttachments():
                        if a.name + '\n' + a.created in existing_attachments and not params.get('replace_attachments'):
                            print("Skip attachment '%s' (created: %s) because it's already exists" %
                                  (utf8encode(a.name), utf8encode(a.created)))
                            continue
                        attachments.append(a)
                        author = a.getAuthor()
                        if author is not None:
                            users.add(author)
                    user_importer.importUsersRecursively(users)

                    for a in attachments:
                        print('Transfer attachment of %s: %s' % (utf8encode(issue.id), utf8encode(a.name)))
                        try:
                            target.createAttachmentFromAttachment(issue.id, a)
                        except BaseException as e:
                            print('Cannot import attachment [ %s ]' % utf8encode(a.name))
                            print(repr(e))
                            continue
                        if params.get('replace_attachments'):
                            try:
                                old_attachment = existing_attachments.get(a.name + '\n' + a.created)
                                if old_attachment:
                                    print('Deleting old attachment')
                                    target.deleteAttachment(issue.id, old_attachment.id)
                            except BaseException as e:
                                print("Cannot delete attachment '%s' from issue %s" % (
                                utf8encode(a.name), utf8encode(issue.id)))
                                print(e)
            except Exception as e:
                print('Cannot process issues from %d to %d' % (start, start + max))
                traceback.print_exc()
                raise e
            start += max
Esempio n. 22
0
libdir = parentdir + '/youtrack/'
sys.path.append(libdir)
from youtrack.connection import Connection

passwd = open('password.txt', 'r').read().strip()
user = config.USERNAME
server = 'https://106.125.46.213/youtrack/'
connection = Connection(server, user, passwd)

category = config.CATEGORY

print category + ' mindmap creation...'

# Get array of issues
issues_list = connection.getIssues(
    'TRAR',
    'Category: ' + category + ' State: -Obsolete sort by: {issue id} asc', 0,
    2000)

issue_map = xmind.load(category + ".xmind")
sheet = issue_map.getPrimarySheet()
sheet.setTitle(category)
root_primary = sheet.getRootTopic()
root_primary.setTitle(category)


def getSuperParents(issues):
    parent_dict = dict()
    for issue in issues:
        parent_dict[issue.id] = (connection.getIssues(
            'TRAR', 'Category: ' + category +
            ' State: -Obsolete Parent for: ' + issue.id, 0, 2000))