Compare commits
No commits in common. "6c50bd267e780ff5164ac46baa6848962fcb2766" and "50e0eb839ed62dd8ec3a5fd19e97cbe6b158ab77" have entirely different histories.
6c50bd267e
...
50e0eb839e
|
@ -1,21 +0,0 @@
|
||||||
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")
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
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,19 +1,17 @@
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from typing import Dict, List
|
||||||
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,
|
from pygments.token import Error, Keyword, Name, Operator, Punctuation, String, Text, Whitespace, _TokenType
|
||||||
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
|
||||||
|
|
||||||
|
@ -40,10 +38,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|cescription|due|duedate|filter|fixVersion|issuekey|issuetype|issueLinkType|labels|"
|
r"Creator|Description|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|updated|updatedDate|voter|watcher|watchers)\b",
|
r"timespent|Voter|Watcher)\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),
|
||||||
|
@ -180,7 +178,6 @@ completions: Dict[str, List[str]] = {
|
||||||
"summary",
|
"summary",
|
||||||
"text",
|
"text",
|
||||||
"timespent",
|
"timespent",
|
||||||
"updated",
|
|
||||||
"voter",
|
"voter",
|
||||||
"watcher",
|
"watcher",
|
||||||
],
|
],
|
||||||
|
@ -284,26 +281,21 @@ def load_config():
|
||||||
|
|
||||||
|
|
||||||
class JQLPrompt:
|
class JQLPrompt:
|
||||||
def __init__(self, jira):
|
def __init__(self, jira, console):
|
||||||
self.jira: JIRA = jira
|
self.jira = jira
|
||||||
self.console: Console = Console(color_system="truecolor", record=True)
|
self.console = console
|
||||||
self.session: PromptSession = self.create_jql_prompt_session()
|
self.session = self.create_jql_prompt_session()
|
||||||
self.jql: JQLPrinter = JQLPrinter(self.console)
|
self.jql = JQLPrinter(console)
|
||||||
self.query_count: int = 0
|
self.query_count = 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 // 3
|
space = self.console.width // 4
|
||||||
query_count_str = f"Query Count: {self.query_count}" if self.query_count else ""
|
query_count_str = f"Query count: {self.query_count}"
|
||||||
issue_count_str = f"Issues Added: {self.issue_count}" if self.issue_count else ""
|
plain_text = f"{query_count_str:^{space}}{query_count_str:^{space}}{query_count_str:^{space}}{query_count_str:^{space}}"
|
||||||
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 = JQLCompleter(completions)
|
completer = JQLCompleter(completions)
|
||||||
return PromptSession(
|
return PromptSession(
|
||||||
message=[("#B48EAD", "JQL \u276f ")],
|
message=[("#B48EAD", "JQL \u276f ")],
|
||||||
lexer=PygmentsLexer(JQLLexer),
|
lexer=PygmentsLexer(JQLLexer),
|
||||||
|
@ -318,9 +310,8 @@ class JQLPrompt:
|
||||||
validate_while_typing=False,
|
validate_while_typing=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
def prompt(self) -> Optional[List[Issue]]:
|
def get_input(self):
|
||||||
user_input: str = self.session.prompt()
|
user_input = 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?")],
|
||||||
|
@ -337,39 +328,21 @@ 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: ", "#A3BE8C bold"),
|
(f"[+] Found {len(issues)} issues from JQL query: ", "green bold"),
|
||||||
self.jql.pygments_to_rich(user_input),
|
self.jql.pygments_to_rich(user_input),
|
||||||
),
|
),
|
||||||
end="",
|
end="",
|
||||||
)
|
)
|
||||||
return issues
|
for issue in issues:
|
||||||
self.console.print("[!] No issues found.", style="#BF616A bold")
|
self.console.print(f"{issue.key}: {issue.fields.summary}")
|
||||||
|
|
||||||
def multi_prompt(self) -> Optional[List[Issue]]:
|
def run(self):
|
||||||
self.issues = []
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
issues = self.prompt()
|
self.get_input()
|
||||||
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
|
||||||
if self.issues:
|
self.console.print("Goodbye!", style="#BF616A bold")
|
||||||
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())
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -389,9 +362,10 @@ 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)
|
prompt = JQLPrompt(jira, console)
|
||||||
prompt.multi_prompt()
|
prompt.run()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
Loading…
Reference in New Issue