diff --git a/cli/get_issues.py b/cli/get_issues.py new file mode 100644 index 0000000..6df310f --- /dev/null +++ b/cli/get_issues.py @@ -0,0 +1,21 @@ +from jira import JIRA +from rich.console import Console + +from jql_utils import JQLPrompt, load_config + +config = load_config() +console = Console(color_system="truecolor") +jira = JIRA(server=config["server"], basic_auth=(config["username"], config["token"])) +jql_prompt = JQLPrompt(jira) + +issues = jql_prompt.prompt() + +console.print("[ℹ] Getting more issues... 🚀", style="#A3BE8C bold") + +more_issues = jql_prompt.multi_prompt() + +if issues or more_issues: + console.print("[ℹ] Saving logs... 🚀", style="#A3BE8C bold") + jql_prompt.save_log() + +console.print("Exiting... 🚀", style="bold green") \ No newline at end of file diff --git a/cli/jql_lexer.py b/cli/jql_lexer.py deleted file mode 100755 index fe6ac1b..0000000 --- a/cli/jql_lexer.py +++ /dev/null @@ -1,70 +0,0 @@ -from prompt_toolkit.lexers import Lexer -from prompt_toolkit.styles import Style -from prompt_toolkit.document import Document -from prompt_toolkit.formatted_text import StyleAndTextTuples -from typing import Callable - -class JQLLexer(Lexer): - def lex_document(self, document: Document) -> Callable[[int], StyleAndTextTuples]: - text = document.text - tokens = [] - - keywords = { - "AND", "OR", "NOT", "IN", "ORDER BY", "ASC", "DESC", - "IS", "NULL", "TRUE", "FALSE", "EMPTY" - } - operators = { - "=", "!", ">", "<", ">=", "<=", "~", "!~", "!=" - } - punctuations = {"(", ")", ",", ":", " "} - - pos = 0 - word = '' - - while pos < len(text): - char = text[pos] - - if char.isalpha(): - word += char - else: - if word: - if word.upper() in keywords: - tokens.append(('class:keyword', word)) - else: - tokens.append(('class:name', word)) - word = '' - - if char in operators: - tokens.append(('class:operator', char)) - elif char in punctuations: - tokens.append(('class:punctuation', char)) - elif char.isspace(): - tokens.append(('class:text', char)) - else: - tokens.append(('class:error', char)) - pos += 1 - - if word: - if word.upper() in keywords: - tokens.append(('class:keyword', word)) - else: - tokens.append(('class:name', word)) - - return lambda i: tokens - -# Example usage -from prompt_toolkit import PromptSession - -custom_style = Style.from_dict({ - 'keyword': '#ff0066 bold', - 'operator': '#00ff00', - 'name': '#0000ff', - 'punctuation': '#00ffff', - 'text': '#ffffff', - 'error': '#ff0000 bold', -}) - -session = PromptSession(lexer=JQLLexer(), style=custom_style) - -text = session.prompt('Enter JQL: ') -print(f'You entered: {text}') diff --git a/cli/jql_pygments.py b/cli/jql_utils.py similarity index 75% rename from cli/jql_pygments.py rename to cli/jql_utils.py index f76f12f..2d17c8e 100644 --- a/cli/jql_pygments.py +++ b/cli/jql_utils.py @@ -1,17 +1,19 @@ import json -from typing import Dict, List +from datetime import datetime +from typing import Dict, List, Optional from jira import JIRA from jira.exceptions import JIRAError +from jira.resources import Issue from prompt_toolkit import PromptSession from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.lexers import PygmentsLexer +from prompt_toolkit.shortcuts import confirm from prompt_toolkit.styles import Style from prompt_toolkit.validation import ValidationError, Validator -from prompt_toolkit.shortcuts import confirm from pygments.lexer import RegexLexer -from pygments.token import Error, Keyword, Name, Operator, Punctuation, String, Text, Whitespace, _TokenType - +from pygments.token import (Error, Keyword, Name, Operator, Punctuation, + String, Text, Whitespace, _TokenType) from rich.console import Console from rich.text import Text as RichText @@ -38,10 +40,10 @@ class JQLLexer(RegexLexer): Keyword, ), ( - r"(?i)\b(?:Assignee|affectedVersion|Attachments|Category|Comment|Component|Created|createdDate|" - r"Creator|Description|Due|duedate|Filter|fixVersion|issuekey|issuetype|issueLinkType|Labels|" - r"lastViewed|Priority|Project|Reporter|Resolved|Sprint|Status|statusCategory|Summary|Text|" - r"timespent|Voter|Watcher)\b", + r"(?i)\b(?:assignee|affectedVersion|attachments|category|comment|component|created|createdDate|" + r"creator|cescription|due|duedate|filter|fixVersion|issuekey|issuetype|issueLinkType|labels|" + r"lastViewed|priority|project|reporter|resolved|Sprint|status|statusCategory|summary|text|" + r"timespent|updated|updatedDate|voter|watcher|watchers)\b", Name.Attribute, ), (r"(?i)(=|!=|<|>|<=|>=|~|!~|IN|NOT IN|IS|IS NOT|WAS|WAS IN|WAS NOT IN|WAS NOT)", Operator), @@ -178,6 +180,7 @@ completions: Dict[str, List[str]] = { "summary", "text", "timespent", + "updated", "voter", "watcher", ], @@ -281,21 +284,26 @@ def load_config(): class JQLPrompt: - def __init__(self, jira, console): - self.jira = jira - self.console = console - self.session = self.create_jql_prompt_session() - self.jql = JQLPrinter(console) - self.query_count = 0 + def __init__(self, jira): + self.jira: JIRA = jira + self.console: Console = Console(color_system="truecolor", record=True) + self.session: PromptSession = self.create_jql_prompt_session() + self.jql: JQLPrinter = JQLPrinter(self.console) + self.query_count: int = 0 + self.issue_count: int = 0 + self.total_issue_count: int = 0 + self.issues: List[Issue] = [] def get_query_count(self): - space = self.console.width // 4 - query_count_str = f"Query count: {self.query_count}" - plain_text = f"{query_count_str:^{space}}{query_count_str:^{space}}{query_count_str:^{space}}{query_count_str:^{space}}" + space = self.console.width // 3 + query_count_str = f"Query Count: {self.query_count}" if self.query_count else "" + issue_count_str = f"Issues Added: {self.issue_count}" if self.issue_count else "" + total_issue_count_str = f"Total Issues: {self.total_issue_count}" if self.total_issue_count else "" + plain_text = f"{query_count_str:^{space}}{issue_count_str:^{space}}{total_issue_count_str:^{space}}" return [("bg:#2E3440 #D8DEE9", plain_text)] def create_jql_prompt_session(self): - completer = JQLCompleter(completions) + completer: JQLCompleter = JQLCompleter(completions) return PromptSession( message=[("#B48EAD", "JQL \u276f ")], lexer=PygmentsLexer(JQLLexer), @@ -310,8 +318,9 @@ class JQLPrompt: validate_while_typing=False, ) - def get_input(self): - user_input = self.session.prompt() + def prompt(self) -> Optional[List[Issue]]: + user_input: str = self.session.prompt() + self.issue_count = 0 if not user_input: do_empty_query = confirm( [("#EBCB8B bold", "[?] "), ("#D8DEE9 bold", "Do you want to perform an empty query?")], @@ -328,21 +337,39 @@ class JQLPrompt: self.query_count += 1 self.console.print( RichText.assemble( - (f"[+] Found {len(issues)} issues from JQL query: ", "green bold"), + (f"[+] Found {len(issues)} issues from JQL query: ", "#A3BE8C bold"), self.jql.pygments_to_rich(user_input), ), end="", ) - for issue in issues: - self.console.print(f"{issue.key}: {issue.fields.summary}") + return issues + self.console.print("[!] No issues found.", style="#BF616A bold") - def run(self): + def multi_prompt(self) -> Optional[List[Issue]]: + self.issues = [] while True: try: - self.get_input() + issues = self.prompt() + if issues: + issues = [issue for issue in issues if issue not in self.issues] + self.issues.extend(issues) + self.issue_count += len(issues) + self.total_issue_count += len(issues) + self.console.print(f"[ℹ] Total issues: {len(self.issues)}", style="#D8DEE9") + get_more = confirm([("#A3BE8C", "[?] Get more issues?")], suffix=[("#81A1C1 bold", " (Y/n) ")]) + if not get_more: + break except (EOFError, KeyboardInterrupt): break - self.console.print("Goodbye!", style="#BF616A bold") + if self.issues: + self.console.print(f"[+] {self.total_issue_count} Issues added:", style="#A3BE8C bold") + return self.issues + self.console.print("[!] No issues added.", style="#BF616A bold") + + def save_log(self): + log_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + with open(f"jql_{log_time}.txt", "w") as log_file: + log_file.write(self.console.export_text()) """ @@ -362,10 +389,9 @@ class JQLPrompt: def main(): config = load_config() - console = Console(color_system="truecolor") jira = JIRA(server=config["server"], basic_auth=(config["username"], config["token"])) - prompt = JQLPrompt(jira, console) - prompt.run() + prompt = JQLPrompt(jira) + prompt.multi_prompt() if __name__ == "__main__":