Beispiel #1
0
 def eval(self):
     mappers = {
         "issue_types": (self.jira.get_issue_types, ),
         'subtask_types': (self.jira.get_subtask_issue_types, ),
         'projects': (self.jira.get_projects, ),
         'priorities': (self.jira.get_priorities, ),
         'statuses': (self.jira.get_statuses, ),
         'resolutions': (self.jira.get_resolutions, ),
         'components': (self.jira.get_components, 'project'),
         'versions': (self.jira.list_versions, 'project'),
         'transitions': (self.jira.get_available_transitions, 'issue'),
         'filters': (self.jira.get_filters, ),
         'aliases': (lambda: [{
             "name": k,
             "description": v
         } for k, v in list(Config(section='alias').items()).items()], )
     }
     func, arguments = mappers[self.args.type][0], mappers[
         self.args.type][1:]
     _ = []
     _k = {}
     for earg in arguments:
         if isinstance(earg, tuple):
             if getattr(self.args, earg[0]):
                 _k.update({earg[0]: getattr(self.args, earg[0])})
             else:
                 _k[earg[0]] = earg[1]
         else:
             if not getattr(self.args, earg):
                 raise UsageError("'--%s' is required for listing '%s'" %
                                  (earg, self.args.type))
             _.append(getattr(self.args, earg))
     found = False
     data = func(*_, **_k)
     data_dict = OrderedDict()
     if type(data) == type([]):
         for item in data:
             data_dict[item['name']] = item
     else:
         data_dict = data
     for item in list(data_dict.values()):
         found = True
         val = item
         if type(item) == type({}):
             val = colorfunc(item['name'], 'white')
             if 'key' in item and item['key']:
                 val += " [" + colorfunc(item['key'], 'magenta') + "]"
             if 'description' in item and item['description']:
                 val += " [" + colorfunc(item['description'], 'green') + "]"
         print_output(colorfunc(val, 'white'))
     if not found:
         raise UsageWarning("No %s found." % self.args.type)
Beispiel #2
0
    def adjust_story_timetracking(self, story, issue, dry=True, verbose=True):
        timetracking = story["timetracking"]
        estimate = self.spent_time_or_estimate(issue)
        estimate_human_readable = self.secs_to_human_readable(estimate)
        issue = self.jira.get_issue(issue["key"], raw=True)
        message = str(u"{}: {}: reduced by {}".format(
            issue.fields.assignee.displayName, issue.key,
            estimate_human_readable))

        new_original_raw = timetracking.originalEstimateSeconds - estimate
        new_remaining_raw = timetracking.remainingEstimateSeconds - estimate

        if new_original_raw < 0 or new_remaining_raw < 0:
            print_error(
                u"Story {} full. Estimate would become negative, skipping\n".
                format(story["key"]),
                severity=WARNING)
            return

        new_original = self.secs_to_human_readable(new_original_raw)
        new_remaining = self.secs_to_human_readable(new_remaining_raw)

        if verbose:
            msg = u"Adjusting estimate of story [{}]: {}".format(
                story["key"], story["summary"])
            msg += u"\nby issue [{}]: {}".format(issue.key,
                                                 issue.fields.summary)
            print_output(colorfunc(msg, "blue"))
            print_output(u"{}: {} - {} = {}".format(
                colorfunc("Original Estimate",
                          "white"), timetracking.originalEstimate,
                estimate_human_readable, new_original))
            print_output(u"{}: {} - {} = {}".format(
                colorfunc("Remaning Estimate",
                          "white"), timetracking.remainingEstimate,
                estimate_human_readable, new_remaining))
            print_output("comment: {}".format(colorfunc(message, "white")))
            print("")

        if not dry:
            # fields = {
            #    "timetracking": {"originalEstimate": "3w 2d 1h", "remainingEstimate": "3w 2d 1h"}}
            story = self.jira.get_issue(story["key"], raw=True)
            story.update(
                fields={
                    "timetracking": {
                        "originalEstimate": new_original,
                        "remainingEstimate": new_remaining
                    }
                })
            self.jira.add_comment(story, message)
Beispiel #3
0
def cli(args=sys.argv[1:]):
    import optparse
    alias_config = Config(section='alias')
    if set(list(alias_config.items().keys())).intersection(args):
        for alias, target in list(alias_config.items()).items():
            if args[0] == alias:
                args = shlex.split(target) + args[1:]
                break
    parser = build_parser()
    try:
        config = Config()
        pre_opts, pre_args = None, None
        try:
            optparser = optparse.OptionParser()

            def void(*args):
                raise SystemExit()

            optparser.print_usage = void
            optparser.add_option("", "--version", action='store_true', default=False)
            pre_opts, pre_args = optparser.parse_args(args)
        except SystemExit:
            pass
        if pre_opts and pre_opts.version:
            print(__version__)
            return
        if not (pre_opts and ("configure" in pre_args or "clear_cache" in pre_args)):
            post_args = parser.parse_args(args)
            jira = initialize(
                config, post_args.jira_url, post_args.username, post_args.password,
                persist=not (post_args.username or post_args.jira_url),
                protocol='rest'
            )
            return post_args.cmd(jira, post_args).execute()
        else:
            if "configure" in pre_args:
                config.reset()
                initialize(
                    config, "", "", "", True,
                    protocol='rest'
                )
            elif "clear_cache" in pre_args:
                clear_cache()
                print_output(colorfunc("jira-cli cache cleared", "green"))
            return

    except KeyboardInterrupt:
        print_error("aborted", severity=WARNING)
    except UsageWarning as e:
        print_error(str(e), severity=WARNING)
    except (JiraCliError, UsageError) as e:
        print_error(str(e))
    except (WebFault) as e:
        print_error(JiraCliError(e))
    except (JIRAError) as e:
        print_error(JiraCliError(e))
    except NotImplementedError as e:
        print_error(e)
Beispiel #4
0
def cli(args=sys.argv[1:]):
    parser = build_parser()
    try:
        config = Config()
        pre_opts, pre_args = None, None
        try:
            pre_opts, pre_args = fake_parse(args)
        except StopIteration:
            pre_opts, pre_args = None, None
            if "--v1" in args or config.v1:
                if '--v1' in sys.argv:
                    print_error(
                        "Use of the v1 interface is no longer supported. Please refer to jiracli.readthedocs.io",
                        WARNING
                    )
                    sys.argv.remove("--v1")
                return old_main()
        except SystemExit:
            pass
        if pre_opts and pre_opts.version:
            print(__version__)
            return
        if (
            not (pre_opts or pre_args) or (pre_opts and not (pre_opts.v1 or config.v1))
            and not (pre_opts and ("configure" in pre_args or "clear_cache" in pre_args))
        ):
            post_args = parser.parse_args(args)
            jira = initialize(
                config, post_args.jira_url, post_args.username, post_args.password,
                persist=not (post_args.username or post_args.jira_url),
                protocol=post_args.protocol or config.protocol or 'rest'
            )
            return post_args.cmd(jira, post_args).execute()
        else:
            if "configure" in pre_args:
                config.reset()
                initialize(
                    config, "", "", "", True,
                    protocol=pre_opts.protocol or config.protocol or 'soap'
                )
            elif "clear_cache" in pre_args:
                clear_cache()
                print_output(colorfunc("jira-cli cache cleared", "green"))
            return

    except KeyboardInterrupt:
        print_error("aborted", severity=WARNING)
    except UsageWarning as e:
        print_error(str(e), severity=WARNING)
    except (JiraCliError, UsageError) as e:
        print_error(str(e))
    except (WebFault) as e:
        print_error(JiraCliError(e))
    except (JIRAError) as e:
        print_error(JiraCliError(e))
    except NotImplementedError as e:
        print_error(e)
Beispiel #5
0
def initialize(config, base_url=None, username=None, password=None,
               persist=True, error=False, protocol='soap'):
    url = base_url or config.base_url
    bridge = get_bridge(protocol)(url, config, persist) if (url and not error) else None
    if error or not (url and bridge and bridge.ping()):
        url = url or prompt("Base url for the jira instance: ")
        username = (
            username
            or (not error and config.username)
            or prompt("username: "******"password: "******"would you like to persist the credentials to ~/.jira-cli/config.cfg?\n{0} [y/n]:"
        persist_warning = persist_warning.format(colorfunc('[WARNING: this will '
                                                  'store credentials in plaintext', 'red'))
        first_run = (
            not(
                config.base_url
                or config.username
                or config.password
            )
        )
        if persist or first_run:
            config.base_url = url
            config.save()
        try:
            jira.login(username, password)
            if (
                (persist or first_run)
                 and (
                    not (
                        config.username == username
                        or config.password == password
                    )
                )
                and "y" == prompt(persist_warning)
            ):
                config.username = username
                config.password = password
                config.save()
            config.save()
            return jira
        except JiraAuthenticationError:
            print_error("invalid username/password", severity=WARNING)
            return initialize(config, base_url=url, error=True, protocol=protocol, persist=persist)
        except JiraInitializationError:
            print_error("invalid jira location", severity=WARNING)
            config.base_url = ""
            return initialize(config, error=True, protocol=protocol, persist=persist)
    else:
        return bridge
Beispiel #6
0
def cli(args=sys.argv[1:]):
    parser = build_parser()
    try:
        config = Config()
        pre_opts, pre_args = None, None
        try:
            pre_opts, pre_args = fake_parse(args)
        except StopIteration:
            pre_opts, pre_args = None, None
            if not ("--v2" in args or config.v2):
                return old_main()
        except SystemExit:
            pass
        if pre_opts and pre_opts.version:
            print(__version__)
            return
        if (not (pre_opts or pre_args)
                or (pre_opts and (pre_opts.v2 or config.v2)) and
                not (pre_opts and
                     ("configure" in pre_args or "clear_cache" in pre_args))):
            post_args = parser.parse_args(args)
            jira = initialize(
                config,
                post_args.jira_url,
                post_args.username,
                post_args.password,
                persist=not (post_args.username or post_args.jira_url),
                protocol=post_args.protocol or config.protocol or 'soap')
            return post_args.cmd(jira, post_args).execute()
        else:
            if "configure" in pre_args:
                config.reset()
                initialize(config,
                           "",
                           "",
                           "",
                           True,
                           protocol=pre_opts.protocol or config.protocol
                           or 'soap')
            elif "clear_cache" in pre_args:
                clear_cache()
                print_output(colorfunc("jira-cli cache cleared", "green"))
            return

    except KeyboardInterrupt:
        print_error("aborted", severity=WARNING)
    except UsageWarning as e:
        print_error(str(e), severity=WARNING)
    except (JiraCliError, UsageError) as e:
        print_error(str(e))
    except (WebFault) as e:
        print_error(JiraCliError(e))
    except (JIRAError) as e:
        print_error(JiraCliError(e))
    except NotImplementedError as e:
        print_error(e)
Beispiel #7
0
def initialize(config,
               base_url=None,
               username=None,
               password=None,
               persist=True,
               error=False,
               protocol='soap'):
    url = base_url or config.base_url
    bridge = get_bridge(protocol)(url, config,
                                  persist) if (url and not error) else None
    if error or not (url and bridge and bridge.ping()):
        url = url or prompt("Base url for the jira instance: ")
        username = (username or (not error and config.username)
                    or prompt("username: "******"password: "******"would you like to persist the credentials to ~/.jira-cli/config.cfg?\n{0} [y/n]:"
        persist_warning = persist_warning.format(
            colorfunc('[WARNING: this will '
                      'store credentials in plaintext', 'red'))
        first_run = (not (config.base_url or config.username
                          or config.password))
        if persist or first_run:
            config.base_url = url
            config.save()
        try:
            jira.login(username, password)
            if ((persist or first_run)
                    and (not (config.username == username
                              or config.password == password))
                    and "y" == prompt(persist_warning)):
                config.username = username
                config.password = password
                config.save()
            config.save()
            return jira
        except JiraAuthenticationError:
            print_error("invalid username/password", severity=WARNING)
            return initialize(config,
                              base_url=url,
                              error=True,
                              protocol=protocol,
                              persist=persist)
        except JiraInitializationError:
            print_error("invalid jira location", severity=WARNING)
            config.base_url = ""
            return initialize(config,
                              error=True,
                              protocol=protocol,
                              persist=persist)
    else:
        return bridge
Beispiel #8
0
    def show_work_log(self):
        issue = self.jira.get_issue(self.args.jira_id)
        if not issue:
            return

        if "timetracking" in issue and hasattr(issue["timetracking"],
                                               "originalEstimate"):
            print_output("{}: {}".format(
                colorfunc("Estimated", "white"),
                colorfunc(issue["timetracking"].originalEstimate, "blue")))

            print_output("{}: {}".format(
                colorfunc("Remaining", "white"),
                colorfunc(issue["timetracking"].remainingEstimate, "blue")))

            time_spent_seconds = getattr(issue["timetracking"],
                                         "timeSpentSeconds", 0)

            if time_spent_seconds <= issue[
                    "timetracking"].originalEstimateSeconds:
                color = "green"
            else:
                color = "red"

            print_output("{}: {}".format(
                colorfunc("Logged   ", "white"),
                colorfunc(
                    getattr(issue["timetracking"], "timeSpent",
                            str(time_spent_seconds) + "m"), color)))
        print_output("")

        worklogs = issue["worklog"].worklogs
        for worklog in worklogs:
            print_output(self.format_worklog(worklog))
Beispiel #9
0
def cli(args=sys.argv[1:]):
    parser = build_parser()

    try:
        config = Config()
        pre_opts, pre_args = None, None
        try:
            pre_opts, pre_args = fake_parse(args)
        except StopIteration:
            pre_opts, pre_args = None, None
            if not ("--v2" in args or config.v2):
                return old_main()
        except SystemExit:
            pass
        if (
            not (pre_opts or pre_args) or (pre_opts and pre_opts.v2)
            and not (pre_opts and ("configure" in pre_args or "clear_cache" in pre_args))
        ):
            post_args = parser.parse_args(args)
            jira = initialize(
                config, post_args.jira_url, post_args.username, post_args.password,
                persist=not (post_args.username or post_args.jira_url),
                protocol=post_args.protocol or config.protocol
            )
            return post_args.cmd(jira, post_args).execute()
        else:
            if "configure" in pre_args:
                config.reset()
                initialize(config, "", "", "", True)
            elif "clear_cache" in pre_args:
                clear_cache()
                print_output(colorfunc("jira-cli cache cleared", "green"))
            return

    except KeyboardInterrupt:
        print_error("aborted", severity=WARNING)
    except UsageWarning as e:
        print_error(str(e), severity=WARNING)
    except (JiraCliError, UsageError) as e:
        print_error(str(e))
    except (WebFault) as e:
        print_error(JiraCliError(e))
    except (JIRAError) as e:
        print_error(JiraCliError(e))
    except NotImplementedError as e:
        print_error(e)
Beispiel #10
0
 def eval(self):
     if self.args.extra_fields:
         extras = self.extract_extras()
         self.jira.update_issue(self.args.issue, **extras)
     if self.args.issue_comment:
         self.jira.add_comment(
             self.args.issue, self.args.issue_comment if isinstance(
                 self.args.issue_comment, basestring) else
             get_text_from_editor())
         print_output(
             self.jira.format_issue(self.jira.get_issue(self.args.issue),
                                    comments_only=True))
     elif self.args.issue_priority:
         self.jira.update_issue(self.args.issue,
                                priority=self.jira.get_priorities()[
                                    self.args.issue_priority]["id"])
     elif self.args.issue_components:
         components = dict((k["name"], k["id"])
                           for k in self.jira.get_components(
                               self.args.issue.split("-")[0]))
         current_components = set(
             k["name"]
             for k in self.jira.get_issue(self.args.issue)["components"])
         if not set(
                 self.args.issue_components).issubset(current_components):
             new_components = current_components.union(
                 self.args.issue_components)
             self.jira.update_issue(
                 self.args.issue,
                 components=[components[k] for k in new_components])
             print_output(
                 colorfunc(
                     'component(s): %s added to %s' % (",".join(
                         self.args.issue_components), self.args.issue),
                     'green'))
         else:
             raise UsageWarning(
                 "component(s):[%s] already exist in %s" %
                 (",".join(self.args.issue_components), self.args.issue))
     elif self.args.issue_transition:
         self.jira.transition_issue(self.args.issue,
                                    self.args.issue_transition.lower(),
                                    self.args.resolution)
         print_output(
             colorfunc(
                 '%s transitioned to "%s"' %
                 (self.args.issue, self.args.issue_transition), 'green'))
     elif self.args.issue_assignee:
         self.jira.assign_issue(self.args.issue, self.args.issue_assignee)
         print_output(
             colorfunc(
                 '%s assigned to %s' %
                 (self.args.issue, self.args.issue_assignee), 'green'))
     elif self.args.labels:
         self.jira.add_labels(self.args.issue, self.args.labels, True)
         print_output(
             colorfunc(
                 '%s labelled with %s' %
                 (self.args.issue, ",".join(self.args.labels)), 'green'))
     if self.args.affects_version:
         self.jira.add_versions(self.args.issue, self.args.affects_version,
                                'affects')
         print_output(
             colorfunc(
                 'Added affected version(s) %s to %s' %
                 (",".join(self.args.affects_version), self.args.issue),
                 'green'))
     if self.args.remove_affects_version:
         self.jira.remove_versions(self.args.issue,
                                   self.args.remove_affects_version,
                                   'affects')
         print_output(
             colorfunc(
                 'Removed affected version(s) %s from %s' % (",".join(
                     self.args.remove_affects_version), self.args.issue),
                 'blue'))
     if self.args.fix_version:
         self.jira.add_versions(self.args.issue, self.args.fix_version,
                                'fix')
         print_output(
             colorfunc(
                 'Added fixed version(s) %s to %s' %
                 (",".join(self.args.fix_version), self.args.issue),
                 'green'))
     if self.args.remove_fix_version:
         self.jira.remove_versions(self.args.issue,
                                   self.args.remove_fix_version, 'fix')
         print_output(
             colorfunc(
                 'Removed fixed version(s) %s from %s' %
                 (",".join(self.args.remove_fix_version), self.args.issue),
                 'blue'))
Beispiel #11
0
 def format_worklog(self, worklog):
     return "%s %s : %s %s" % (
         colorfunc(worklog.created, "blue"),
         colorfunc(worklog.author, "white"), worklog.comment,
         colorfunc("[" + worklog.timeSpent + "]", "green"))
Beispiel #12
0
    def format_issue(self, issue, mode=0, formatter=None, comments_only=False):
        fields = {}
        status_color = "blue"
        status_string = JiraBridge.object_from_key(
            issue.setdefault('status', '1'), self.get_statuses)["name"]

        if status_string.lower() in ["resolved", "closed", "done"]:
            status_color = "green"
        elif status_string.lower() in [
                "open", "unassigned", "reopened", "to do"
        ]:
            status_color = "red"

        list_fields = set(['versions', 'fixversions'])

        special_fields = {
            "status":
            self.get_statuses,
            "priority":
            self.get_priorities,
            "type":
            lambda: dict(
                list(self.get_issue_types().items()) + list(
                    self.get_subtask_issue_types().items()))
        }

        if formatter:
            groups = re.compile("(%([\w]+))").findall(formatter)
            ret_str = formatter.encode('utf-8')
            for k, v in groups:
                if v.lower() in list(special_fields.keys()):
                    key = issue[v.lower()]
                    data = "" or JiraBridge.object_from_key(
                        key, special_fields[v.lower()])["name"]
                    ret_str = ret_str.replace(k, data)
                elif v.lower() in list_fields:
                    fix_versions = ", ".join(
                        v.name for v in issue.get('fixVersions', []))
                    ret_str = ret_str.replace(k, fix_versions.encode('utf-8'))
                else:
                    ret_str = ret_str.replace(k, issue.setdefault(
                        v.lower(), "")).encode('utf-8')
            return ret_str
        if mode >= 0:
            # minimal
            fields["issue"] = issue["key"]
            fields["status"] = colorfunc(
                JiraBridge.object_from_key(issue["status"],
                                           self.get_statuses)["name"],
                status_color)
            fields["reporter"] = issue.setdefault("reporter", "")
            fields["assignee"] = issue.setdefault("assignee", "")
            fields["summary"] = issue.setdefault("summary", "")
            fields["link"] = colorfunc("%s/browse/%s" %
                                       (self.base_url, issue["key"]),
                                       "white",
                                       attrs=["underline"])
        if mode == 1 or comments_only:
            fields["description"] = issue.setdefault("description", "") or ""
            if not issue.get("priority", ""):
                fields["priority"] = ""
            else:
                fields["priority"] = JiraBridge.object_from_key(
                    issue["priority"], self.get_priorities)["name"]
            fields["type"] = JiraBridge.object_from_key(
                issue["type"], self.get_issue_types if 'parent' not in issue
                else self.get_subtask_issue_types)["name"]
            fields["comments"] = "\n"
            comments = self.get_issue_comments(issue["key"])
            for comment in comments:
                comment_str = comment["body"].strip()
                fields["comments"] += "%s %s : %s\n" % (
                    colorfunc(comment["created"], "blue"),
                    colorfunc(comment["author"], "green"), comment_str)
        children_string = ""
        if mode > 1:
            description = (issue.setdefault("description", "")
                           or "").split("\n")
            fields["description"] = "\n".join(
                [description[0]] + [" " * 23 + k for k in description[1:]])

            for child in self.search_issues_jql("parent=%s" % issue["key"]):
                child_type = JiraBridge.object_from_key(
                    child["type"],
                    self.get_subtask_issue_types)["name"].lower()
                key = ("%s" % child_type).ljust(20)
                value = "%s (%s) %s" % (child["key"], child["summary"],
                                        colorfunc(
                                            "%s/browse/%s" %
                                            (self.base_url, child["key"]),
                                            "white",
                                            attrs=['underline']))
                children_string += "%s : %s\n" % (key, value)
        if comments_only:
            return fields["comments"].strip()
        elif mode < 0:
            url_str = colorfunc(parse.urljoin(self.base_url,
                                              "/browse/%s" % (issue["key"])),
                                "white",
                                attrs=["underline"])
            ret_str = colorfunc(issue["key"],
                                status_color) + " " + issue.setdefault(
                                    "summary", "") + " " + url_str
            if not COLOR:
                ret_str += " [%s] " % status_string
            return ret_str
        for k, v in list(fields.items()):
            if not v:
                fields[k] = ""
        formatted = "\n".join(" : ".join((k.ljust(20), v))
                              for k, v in list(fields.items())
                              if not k == 'comments') + "\n"
        formatted += children_string
        if "comments" in fields:
            formatted += fields["comments"]
        return formatted
Beispiel #13
0
def cli(args=sys.argv[1:]):
    alias_config = Config(section='alias')
    if set(alias_config.items().keys()).intersection(args):
        for alias, target in alias_config.items().items():
            if args[0] == alias:
                args = shlex.split(target) + args[1:]
                break
    parser = build_parser()
    try:
        config = Config()
        pre_opts, pre_args = None, None
        try:
            pre_opts, pre_args = fake_parse(args)
        except StopIteration:
            pre_opts, pre_args = None, None
            if "--v1" in args or config.v1:
                if '--v1' in sys.argv:
                    print_error(
                        "Use of the v1 interface is no longer supported. Please refer to jiracli.readthedocs.io",
                        WARNING)
                    sys.argv.remove("--v1")
                return old_main()
        except SystemExit:
            pass
        if pre_opts and pre_opts.version:
            print(__version__)
            return
        if (not (pre_opts or pre_args)
                or (pre_opts and not (pre_opts.v1 or config.v1)) and
                not (pre_opts and
                     ("configure" in pre_args or "clear_cache" in pre_args))):
            post_args = parser.parse_args(args)
            jira = initialize(
                config,
                post_args.jira_url,
                post_args.username,
                post_args.password,
                persist=not (post_args.username or post_args.jira_url),
                protocol=post_args.protocol or config.protocol or 'rest')
            return post_args.cmd(jira, post_args).execute()
        else:
            if "configure" in pre_args:
                config.reset()
                initialize(config,
                           "",
                           "",
                           "",
                           True,
                           protocol=pre_opts.protocol or config.protocol
                           or 'soap')
            elif "clear_cache" in pre_args:
                clear_cache()
                print_output(colorfunc("jira-cli cache cleared", "green"))
            return

    except KeyboardInterrupt:
        print_error("aborted", severity=WARNING)
    except UsageWarning as e:
        print_error(str(e), severity=WARNING)
    except (JiraCliError, UsageError) as e:
        print_error(str(e))
    except (WebFault) as e:
        print_error(JiraCliError(e))
    except (JIRAError) as e:
        print_error(JiraCliError(e))
    except NotImplementedError as e:
        print_error(e)