Esempio n. 1
0
 def should_skip(self):
     """ If 'task' is not installed, we can't run these tests. """
     return not TaskWarriorExperimental.can_use()
Esempio n. 2
0
 def should_skip(self):
     """ If 'task' is not installed, we can't run these tests. """
     return not TaskWarriorExperimental.can_use()
Esempio n. 3
0
def synchronize(issues, conf):

    def _bool_option(section, option, default):
        try:
            return section in conf.sections() and \
                asbool(conf.get(section, option, default))
        except NoOptionError:
            return default

    notify = _bool_option('notifications', 'notifications', 'False')
    experimental = _bool_option('general', 'experimental', 'False')

    if experimental is True:
        # @TODO don't hardcode path to config filename.
        tw = TaskWarriorExperimental(config_filename='~/.bugwarrior_taskrc')
    else:
        tw = TaskWarrior()

    # Load info about the task database
    tasks = tw.load_tasks()

    is_bugwarrior_task = lambda task: \
        task.get('description', '').startswith(MARKUP)

    # Prune down to only tasks managed by bugwarrior
    for key in tasks.keys():
        tasks[key] = filter(is_bugwarrior_task, tasks[key])

    # Build a list of only the descriptions of those local bugwarrior tasks
    local_descs = [t['description'] for t in sum(tasks.values(), [])
                   if t['status'] not in ('deleted')]

    # Now for the remote data.
    # Build a list of only the descriptions of those remote issues
    remote_descs = [i['description'] for i in issues]

    # Build the list of tasks that need to be added
    is_new = lambda issue: issue['description'] not in local_descs
    new_issues = filter(is_new, issues)
    old_issues = filter(lambda i: not is_new(i), issues)

    # Build the list of local tasks that need to be completed
    is_done = lambda task: task['description'] not in remote_descs
    done_tasks = filter(is_done, tasks['pending'])

    log.name('db').struct(new=len(new_issues), completed=len(done_tasks))

    # Add new issues
    for issue in new_issues:
        log.name('db').info(
            "Adding task {0}",
            issue['description'].encode("utf-8")
        )
        if notify:
            send_notification(issue, 'Created', conf)
        tw.task_add(**issue)

    # Update any issues that may have had new properties added.  These are
    # usually annotations that come from comments in the issue thread.
    pending_descriptions = [t['description'] for t in tasks['pending']]
    for upstream_issue in old_issues:
        if upstream_issue['description'] not in pending_descriptions:
            continue

        id, task = tw.get_task(description=upstream_issue['description'])
        for key in upstream_issue:
            if key not in task:
                if experimental is True and "annotation_" in key:
                    # TaskWarrior doesn't currently (2.2.0) allow for setting
                    # the annotation entry key. This means that each annotation
                    # key will always be updated to the current date and time,
                    # which in turn means BW will always think a task has been
                    # updated. Until this is resolved in 2.3.0, ignore
                    # annotation updates in experimental mode.
                    continue
                log.name('db').info(
                    "Updating {0} on {1}",
                    key,
                    upstream_issue['description'].encode("utf-8"),
                )
                if notify:
                    send_notification(upstream_issue, 'Updated', conf)
                task[key] = upstream_issue[key]
                id, task = tw.task_update(task)

    # Delete old issues
    for task in done_tasks:
        log.name('db').info(
            "Completing task {0}",
            task['description'].encode("utf-8"),
        )
        if notify:
            send_notification(task, 'Completed', conf)

        tw.task_done(uuid=task['uuid'])
        if experimental is True:
            # `task merge` only updates/adds tasks, it won't delete them, so
            # call task_done() on the primary TW task database.
            tw_done = TaskWarriorExperimental()
            tw_done.task_done(uuid=task['uuid'])

    # Merge tasks with users local DB
    if experimental is True:
        # Call task merge from users local database
        config = tw.load_config(config_filename='~/.bugwarrior_taskrc')
        bwtask_data = "%s/" % config['data']['location']
        subprocess.call([
            'task', 'rc.verbose=nothing', 'rc.merge.autopush=no',
            'merge', bwtask_data])
        # Delete completed tasks from Bugwarrior tasks DB. This allows for
        # assigning/unassigning tasks in a remote service, and tracking status
        # changes in Bugwarrior.
        subprocess.call([
            'task', 'rc:~/.bugwarrior_taskrc', 'rc.verbose=nothing',
            'rc.confirmation=no', 'rc.bulk=100', 'status:completed',
            'delete'])

    # Send notifications
    if notify:
        send_notification(
            dict(description="New: %d, Completed: %d" % (
                len(new_issues), len(done_tasks)
            )),
            'bw_finished',
            conf,
        )