diff --git a/gatorgrade/generate/generate.py b/gatorgrade/generate/generate.py index 8dd91164..4dafe19e 100644 --- a/gatorgrade/generate/generate.py +++ b/gatorgrade/generate/generate.py @@ -119,6 +119,7 @@ def write_yaml_of_paths_list( "description": f"Complete all TODOs in {file_path_fixed}", "check": "MatchFileFragment", "options": {"fragment": "TODO", "count": 0, "exact": True}, + "motivation": "You're doint Great" } ] } diff --git a/gatorgrade/input/in_file_path.py b/gatorgrade/input/in_file_path.py index a9cd048d..f6743acc 100644 --- a/gatorgrade/input/in_file_path.py +++ b/gatorgrade/input/in_file_path.py @@ -1,5 +1,6 @@ """Generates a list of commands to be run through gatorgrader.""" +import random from collections import namedtuple from pathlib import Path from typing import Any @@ -35,7 +36,6 @@ def parse_yaml_file(file_path: Path) -> List[Any]: # return a blank list that calling function handles return [] - def reformat_yaml_data(data): """Reformat the raw data from a YAML file into a list of tuples.""" reformatted_data = [] @@ -65,3 +65,47 @@ def add_checks_to_list(path, data_list, reformatted_data): else: # Adds the current check to the reformatted data list reformatted_data.append(CheckData(file_context=path, check=ddict)) break + + +def add_quotes_to_yaml(file_path: Path, new_quotes: List[str]): + """Add motivational quotes to the YAML file under the key 'motivational_quotes'.""" + if not file_path.exists(): + print(f"Error: File not found at {file_path}") + return + + try: + with open(file_path, encoding=DEFAULT_ENCODING) as file: + data = yaml.safe_load(file) or {} # Load existing data or start fresh + + # Ensure 'motivational_quotes' exists in the YAML structure + if "motivational_quotes" not in data: + data["motivational_quotes"] = [] + + # Append new quotes, avoiding duplicates + existing_quotes = set(data["motivational_quotes"]) + for quote in new_quotes: + if quote not in existing_quotes: + data["motivational_quotes"].append(quote) + + # Write the updated data back to the file + with open(file_path, 'w', encoding=DEFAULT_ENCODING) as file: + yaml.safe_dump(data, file) + + print("Motivational quotes added successfully!") + + except yaml.YAMLError as e: + print(f"Error processing YAML file: {e}") + + +def get_random_quote(file_path: Path) -> str: + """Retrieve a random motivational quote from the YAML file.""" + if not file_path.exists(): + return "No motivational quotes available. Add some to the YAML file!" + + try: + with open(file_path, encoding=DEFAULT_ENCODING) as file: + data = yaml.safe_load(file) + quotes = data.get("motivational", []) + return random.choice(quotes) if quotes else "No motivational quotes available." + except Exception as e: + return f"Error retrieving quotes: {e}" \ No newline at end of file diff --git a/gatorgrade/main.py b/gatorgrade/main.py index 42bbbd81..d1f60df8 100644 --- a/gatorgrade/main.py +++ b/gatorgrade/main.py @@ -45,6 +45,7 @@ def gatorgrade( 3. the name of the file or environment variable\ 4. use 'env md GITHUB_STEP_SUMMARY' to create GitHub job summary in GitHub Action", ), + run_motivation: bool = typer.Option( False, "--motivation", help="Enable a motivational message" ), ): """Run the GatorGrader checks in the specified gatorgrade.yml file.""" # if ctx.subcommand is None then this means @@ -55,7 +56,7 @@ def gatorgrade( # there are valid checks and thus the # tool should run them with run_checks if len(checks) > 0: - checks_status = run_checks(checks, report) + checks_status = run_checks(checks, report, run_motivation)#run_status_bar, #no_status_bar, ) # no checks were created and this means # that, most likely, the file was not # valid and thus the tool cannot run checks diff --git a/gatorgrade/output/check_result.py b/gatorgrade/output/check_result.py index f6e88c29..9ad573c8 100644 --- a/gatorgrade/output/check_result.py +++ b/gatorgrade/output/check_result.py @@ -14,6 +14,7 @@ def __init__( json_info, path: Union[str, None] = None, diagnostic: str = "No diagnostic message available", + motivation: str = "" ): """Construct a CheckResult. @@ -30,6 +31,7 @@ def __init__( self.diagnostic = diagnostic self.path = path self.run_command = "" + self.motivation = "" def display_result(self, show_diagnostic: bool = False) -> str: """Print check's passed or failed status, description, and, optionally, diagnostic message. @@ -48,7 +50,7 @@ def display_result(self, show_diagnostic: bool = False) -> str: return message def __repr__(self): - return f"CheckResult(passed={self.passed}, description='{self.description}', json_info={self.json_info}, path='{self.path}', diagnostic='{self.diagnostic}', run_command='{self.run_command}')" + return f"CheckResult(passed={self.passed}, description='{self.description}', json_info={self.json_info}, path='{self.path}', diagnostic='{self.diagnostic}', run_command='{self.run_command}', motivation={self.motivation}')" def __str__(self, show_diagnostic: bool = False) -> str: """Print check's passed or failed status, description, and, optionally, diagnostic message. diff --git a/gatorgrade/output/output.py b/gatorgrade/output/output.py index 8fc94c5b..724dc0ff 100644 --- a/gatorgrade/output/output.py +++ b/gatorgrade/output/output.py @@ -8,6 +8,8 @@ from typing import List from typing import Tuple from typing import Union +from rich.console import Console +from rich.panel import Panel import gator import rich @@ -76,6 +78,10 @@ def _run_gg_check(check: GatorGraderCheck) -> CheckResult: file_name = check.gg_args[i + 3] file_path = dir_name + "/" + file_name break + motivation = "" + if "--motivation" in check.gg_args: + index_of_motivation = check.gg_args.index("--hint") + motivation = check.gg_args[index_of_motivation + 1] # If arguments are formatted incorrectly, catch the exception and # return it as the diagnostic message # Disable pylint to catch any type of exception thrown by GatorGrader @@ -90,6 +96,7 @@ def _run_gg_check(check: GatorGraderCheck) -> CheckResult: json_info=check.json_info, diagnostic=diagnostic, path=file_path, + motivation=motivation ) @@ -189,6 +196,9 @@ def create_markdown_report_file(json: dict) -> str: if "file" == i: val = check["options"]["file"] markdown_contents += f"\n\t- **file:** {val}" + if "motivation" == i: + val = check["options"]["motivation"] + markdown_contents += f"\n\t- **file:** {val}" elif "command" in check: val = check["command"] markdown_contents += f"\n\t- **command:** {val}" @@ -283,9 +293,28 @@ def write_json_or_md_file(file_name, content_type, content): "\n[red]Can't open or write the target file, check if you provide a valid path" ) from e +console = Console() + +class Motivation: + def __init__(self, quotes: dict): # type: ignore + """Construct a Motivation. + + Args: + quotes: A dictionary of motivational quotes with keys like "low_motivation", "high_motivation". + context: Additional context or description about the quote. Optional. + """ + self.quotes = quotes + + + def get_motivation(self, motivation_level: str): + """Retrieve a motivational quote based on the motivation level.""" + quote = self.quotes.get(motivation_level, "Keep going, you're doing great!") + return f"{quote}" + def run_checks( - checks: List[Union[ShellCheck, GatorGraderCheck]], report: Tuple[str, str, str] + checks: List[Union[ShellCheck, GatorGraderCheck]], report: Tuple[str, str, str], + run_motivation=False ) -> bool: """Run shell and GatorGrader checks and display whether each has passed or failed. @@ -300,6 +329,7 @@ def run_checks( for check in checks: result = None command_ran = None + motivation = "" # run a shell check; this means # that it is going to run a command # in the shell as a part of a check; @@ -311,6 +341,7 @@ def run_checks( result = _run_shell_check(check) command_ran = check.command result.run_command = command_ran + result.motivation = motivation # run a check that GatorGrader implements elif isinstance(check, GatorGraderCheck): result = _run_gg_check(check) @@ -327,6 +358,8 @@ def run_checks( index_of_command = check.gg_args.index("--command") index_of_new_command = int(index_of_command) + 1 result.run_command = check.gg_args[index_of_new_command] + if "motivation" in check.gg_args: + result.motivation = check["motivation"] # there were results from running checks # and thus they must be displayed if result is not None: @@ -338,6 +371,7 @@ def run_checks( # and print what ShellCheck command that Gatorgrade ran if len(failed_results) > 0: print("\n-~- FAILURES -~-\n") + print("Rebekah Test") for result in failed_results: # main.console.print("This is a result") # main.console.print(result) @@ -353,6 +387,11 @@ def run_checks( rich.print( f"[blue] → Run this command: [green]{result.run_command}\n" ) + """if result.motivation != "": + rich.print( + f"[bright cyan] {result.motivation}\n" + )""" + # determine how many of the checks passed and then # compute the total percentage of checks passed passed_count = len(results) - len(failed_results) @@ -372,6 +411,25 @@ def run_checks( # determine whether or not the run was a success or not: # if all of the tests pass then the function returns True; # otherwise the function must return False + motivation_quotes = {"low_motivation": "You're just getting warmed up!", "high_motivation": "Finish Line Insight"} + motivation = Motivation(motivation_quotes) + if run_motivation: + if 0.25 <= percent < 0.75: + console.print( + Panel( + motivation.get_motivation("low_motivation"), + expand=False, title="Motivation", + border_style="bright_cyan" + ) + ) + elif percent >= 0.75: + console.print( + Panel( + motivation.get_motivation("high_motivation"), + expand=False, title="Motivation", + border_style="bright_cyan" + ) + ) summary_status = True if passed_count == len(results) else False return summary_status