Compare commits
2 Commits
50e0eb839e
...
6c50bd267e
Author | SHA1 | Date |
---|---|---|
Roland Thomas Jr | 6c50bd267e | |
Roland Thomas Jr | 7b872484e9 |
|
@ -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")
|
|
@ -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}')
|
|
|
@ -1,17 +1,19 @@
|
||||||
import json
|
import json
|
||||||
from typing import Dict, List
|
from datetime import datetime
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
from jira import JIRA
|
from jira import JIRA
|
||||||
from jira.exceptions import JIRAError
|
from jira.exceptions import JIRAError
|
||||||
|
from jira.resources import Issue
|
||||||
from prompt_toolkit import PromptSession
|
from prompt_toolkit import PromptSession
|
||||||
from prompt_toolkit.completion import Completer, Completion
|
from prompt_toolkit.completion import Completer, Completion
|
||||||
from prompt_toolkit.lexers import PygmentsLexer
|
from prompt_toolkit.lexers import PygmentsLexer
|
||||||
|
from prompt_toolkit.shortcuts import confirm
|
||||||
from prompt_toolkit.styles import Style
|
from prompt_toolkit.styles import Style
|
||||||
from prompt_toolkit.validation import ValidationError, Validator
|
from prompt_toolkit.validation import ValidationError, Validator
|
||||||
from prompt_toolkit.shortcuts import confirm
|
|
||||||
from pygments.lexer import RegexLexer
|
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.console import Console
|
||||||
from rich.text import Text as RichText
|
from rich.text import Text as RichText
|
||||||
|
|
||||||
|
@ -38,10 +40,10 @@ class JQLLexer(RegexLexer):
|
||||||
Keyword,
|
Keyword,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
r"(?i)\b(?:Assignee|affectedVersion|Attachments|Category|Comment|Component|Created|createdDate|"
|
r"(?i)\b(?:assignee|affectedVersion|attachments|category|comment|component|created|createdDate|"
|
||||||
r"Creator|Description|Due|duedate|Filter|fixVersion|issuekey|issuetype|issueLinkType|Labels|"
|
r"creator|cescription|due|duedate|filter|fixVersion|issuekey|issuetype|issueLinkType|labels|"
|
||||||
r"lastViewed|Priority|Project|Reporter|Resolved|Sprint|Status|statusCategory|Summary|Text|"
|
r"lastViewed|priority|project|reporter|resolved|Sprint|status|statusCategory|summary|text|"
|
||||||
r"timespent|Voter|Watcher)\b",
|
r"timespent|updated|updatedDate|voter|watcher|watchers)\b",
|
||||||
Name.Attribute,
|
Name.Attribute,
|
||||||
),
|
),
|
||||||
(r"(?i)(=|!=|<|>|<=|>=|~|!~|IN|NOT IN|IS|IS NOT|WAS|WAS IN|WAS NOT IN|WAS NOT)", Operator),
|
(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",
|
"summary",
|
||||||
"text",
|
"text",
|
||||||
"timespent",
|
"timespent",
|
||||||
|
"updated",
|
||||||
"voter",
|
"voter",
|
||||||
"watcher",
|
"watcher",
|
||||||
],
|
],
|
||||||
|
@ -281,21 +284,26 @@ def load_config():
|
||||||
|
|
||||||
|
|
||||||
class JQLPrompt:
|
class JQLPrompt:
|
||||||
def __init__(self, jira, console):
|
def __init__(self, jira):
|
||||||
self.jira = jira
|
self.jira: JIRA = jira
|
||||||
self.console = console
|
self.console: Console = Console(color_system="truecolor", record=True)
|
||||||
self.session = self.create_jql_prompt_session()
|
self.session: PromptSession = self.create_jql_prompt_session()
|
||||||
self.jql = JQLPrinter(console)
|
self.jql: JQLPrinter = JQLPrinter(self.console)
|
||||||
self.query_count = 0
|
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):
|
def get_query_count(self):
|
||||||
space = self.console.width // 4
|
space = self.console.width // 3
|
||||||
query_count_str = f"Query count: {self.query_count}"
|
query_count_str = f"Query Count: {self.query_count}" if self.query_count else ""
|
||||||
plain_text = f"{query_count_str:^{space}}{query_count_str:^{space}}{query_count_str:^{space}}{query_count_str:^{space}}"
|
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)]
|
return [("bg:#2E3440 #D8DEE9", plain_text)]
|
||||||
|
|
||||||
def create_jql_prompt_session(self):
|
def create_jql_prompt_session(self):
|
||||||
completer = JQLCompleter(completions)
|
completer: JQLCompleter = JQLCompleter(completions)
|
||||||
return PromptSession(
|
return PromptSession(
|
||||||
message=[("#B48EAD", "JQL \u276f ")],
|
message=[("#B48EAD", "JQL \u276f ")],
|
||||||
lexer=PygmentsLexer(JQLLexer),
|
lexer=PygmentsLexer(JQLLexer),
|
||||||
|
@ -310,8 +318,9 @@ class JQLPrompt:
|
||||||
validate_while_typing=False,
|
validate_while_typing=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_input(self):
|
def prompt(self) -> Optional[List[Issue]]:
|
||||||
user_input = self.session.prompt()
|
user_input: str = self.session.prompt()
|
||||||
|
self.issue_count = 0
|
||||||
if not user_input:
|
if not user_input:
|
||||||
do_empty_query = confirm(
|
do_empty_query = confirm(
|
||||||
[("#EBCB8B bold", "[?] "), ("#D8DEE9 bold", "Do you want to perform an empty query?")],
|
[("#EBCB8B bold", "[?] "), ("#D8DEE9 bold", "Do you want to perform an empty query?")],
|
||||||
|
@ -328,21 +337,39 @@ class JQLPrompt:
|
||||||
self.query_count += 1
|
self.query_count += 1
|
||||||
self.console.print(
|
self.console.print(
|
||||||
RichText.assemble(
|
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),
|
self.jql.pygments_to_rich(user_input),
|
||||||
),
|
),
|
||||||
end="",
|
end="",
|
||||||
)
|
)
|
||||||
for issue in issues:
|
return issues
|
||||||
self.console.print(f"{issue.key}: {issue.fields.summary}")
|
self.console.print("[!] No issues found.", style="#BF616A bold")
|
||||||
|
|
||||||
def run(self):
|
def multi_prompt(self) -> Optional[List[Issue]]:
|
||||||
|
self.issues = []
|
||||||
while True:
|
while True:
|
||||||
try:
|
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):
|
except (EOFError, KeyboardInterrupt):
|
||||||
break
|
break
|
||||||
self.console.print("Goodbye!", style="#BF616A bold")
|
if self.issues:
|
||||||
|
self.console.print(f"[+] Issues added: {self.total_issue_count}", 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():
|
def main():
|
||||||
config = load_config()
|
config = load_config()
|
||||||
console = Console(color_system="truecolor")
|
|
||||||
jira = JIRA(server=config["server"], basic_auth=(config["username"], config["token"]))
|
jira = JIRA(server=config["server"], basic_auth=(config["username"], config["token"]))
|
||||||
prompt = JQLPrompt(jira, console)
|
prompt = JQLPrompt(jira)
|
||||||
prompt.run()
|
prompt.multi_prompt()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
Loading…
Reference in New Issue