Beispiel #1
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 the local keyring? [y/n]:"

        first_run = (
            not(
                config.base_url
                or config.username
                or keyring.get_password('jira-cli',username)
            )
        )
        if persist or first_run:
            config.base_url = url
            config.save()
            keyring.set_password('jira-cli',username,password)
        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
                keyring.set_password('jira-cli',username,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 #2
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 the local keyring? [y/n]:"

        first_run = (not (config.base_url or config.username
                          or keyring.get_password('jira-cli', username)))
        if persist or first_run:
            config.base_url = url
            config.save()
            keyring.set_password('jira-cli', username, password)
        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
                keyring.set_password('jira-cli', username, 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 #3
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 #4
0
    def eval(self):
        if self.args.search_freetext:
            issues = self.jira.search_issues(self.args.search_freetext,
                                             project=self.args.project)
        elif self.args.search_jql:
            issues = self.jira.search_issues_jql(self.args.search_jql)
        elif self.args.filter:
            issues = self.jira.get_issues_by_filter(*self.args.filter)
        else:
            issues = [
                issue for issue in
                [self.jira.get_issue(jira) for jira in self.args.jira_ids]
                if issue is not None
            ]

        for issue in issues:
            # get the time estimate values

            if "student" in issue["labels"]:
                print_output(u"{} is a student task, skipping...\n".format(
                    issue["key"]))
                continue

            estimate = self.spent_time_or_estimate(issue, quiet=True)
            if estimate is None:
                print_error(u"{} has no time estimate\n".format(issue["key"]),
                            severity=WARNING)
                continue

            # get the epic of this issue (warning if none)
            bookkeeping_story = self.get_parent_story(issue)
            if bookkeeping_story is None:
                print_error(u"{} has no parent story. Assignee: {}\n".format(
                    issue["key"], issue["assignee"]),
                            severity=WARNING)
                continue

            # check if the issue in question was already mentioned in the comments
            if self.issue_already_substracted(issue, bookkeeping_story):
                print_output(
                    u"{} already mentioned in the comments of {}\n".format(
                        issue["key"], bookkeeping_story["key"]))
            else:
                self.adjust_story_timetracking(
                    bookkeeping_story,
                    issue,
                    dry=self.args.dry,
                    verbose=(self.args.verbosity > 0))
Beispiel #5
0
    def spent_time_or_estimate(self, issue, quiet=False):
        """This function will return the time spent on an issue, when the time is less or equal
        to the original estimate, otherwise the original estimate is returned.

        We now want to run this function after the sprint has ended, thus an issue without a
        timelog will issue a warning.

        returns  [orininal, remaning]"""
        if "aggregatetimespent" not in issue or issue[
                "aggregatetimespent"] == 0:
            if not quiet:
                print_error(u"No time was logged on {}\n".format(issue["key"]))
            return None

        if "timeoriginalestimate" not in issue or issue[
                "timeoriginalestimate"] == 0:
            if not quiet:
                print_error(u"Missing time estimate for {}\n".format(
                    issue["key"]))
            return None

        estimate = issue["timeoriginalestimate"]
        logged = issue["aggregatetimespent"]

        if not quiet and logged > estimate:
            print_error(u"Attention: {} was overbooked by {}\n".format(
                issue["key"], self.secs_to_human_readable(logged - estimate)),
                        severity=WARNING)

        return min(estimate, logged)
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)
            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 #7
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
            )
            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 #8
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)
Beispiel #9
0
def initialize(config,
               base_url=None,
               username=None,
               password=None,
               persist=True,
               error=False,
               protocol='soap',
               reset=False):
    url = base_url or config.base_url
    auth_method = config.auth_method
    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: ")
        if not auth_method:
            auth_method = prompt(
                "Auth method for jira(auth, basic_auth, oauth). More details: https://jira.readthedocs.io/en/master/examples.html#authentication: "
            )
            config.auth_method = auth_method
            config.save()

        if auth_method in ("auth", "basic_auth"):
            username = (username or (not error and config.username)
                        or prompt("username: "******"password: "******"oauth":
            access_token = ((not error and config.oauth_access_token)
                            or prompt("OAuth access token: "))
            access_token_secret = ((
                not error and
                (not reset and keyring.get_password('jira-cli', access_token)))
                                   or prompt("OAuth access token secret: ",
                                             True))
            consumer_key = ((not error and config.oauth_consumer_key)
                            or prompt("OAuth consumer key: "))
            key_cert_file = ((not error and config.oauth_key_cert_file)
                             or prompt("OAuth key/cert filename: "))
            with open(key_cert_file, 'r') as f:
                key_cert_data = f.read()
            auth_kwargs = {
                auth_method: {
                    'access_token': access_token,
                    'access_token_secret': access_token_secret,
                    'consumer_key': consumer_key,
                    'key_cert': key_cert_data,
                }
            }
        else:
            raise NotImplementedError("Unknown auth method: %s" % auth_method)
        jira = not error and bridge or get_bridge(protocol)(url, config,
                                                            persist)
        persist_warning = "would you like to persist the credentials to the local keyring? [y/n]:"

        if auth_method in ("auth", "basic_auth"):
            first_run = (not (config.base_url or config.username
                              or keyring.get_password('jira-cli', username)))
            if persist or first_run:
                config.base_url = url
                config.save()
                keyring.set_password('jira-cli', username, password)
        elif auth_method == "oauth":
            first_run = (not (config.base_url or config.access_token or
                              keyring.get_password('jira-cli', access_token)))
            if persist or first_run:
                config.base_url = url
                config.save()
                keyring.set_password('jira-cli', access_token,
                                     access_token_secret)
        else:
            raise NotImplementedError("Unknown auth method: %s" % auth_method)
        try:
            jira.login(**auth_kwargs)
        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)
        if (auth_method in ("auth", "basic_auth") and (persist or first_run)
                and
            (not (config.username == username or config.password == password))
                and "y" == prompt(persist_warning)):
            config.username = username
            keyring.set_password('jira-cli', username, password)
            config.save()
        elif (auth_method == "oauth" and (persist or first_run)
              and (not config.oauth_access_token == access_token)
              and "y" == prompt(persist_warning)):
            config.oauth_access_token = access_token
            config.oauth_consumer_key = consumer_key
            config.oauth_key_cert_file = key_cert_file
            keyring.set_password('jira-cli', access_token, access_token_secret)
            config.save()
        config.save()
        return jira
    else:
        return bridge
Beispiel #10
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)
Beispiel #11
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)