From 52792b6843304d47bd9c7a367957bf704a282131 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 28 Nov 2024 09:21:41 -0700 Subject: [PATCH 1/3] feat: github formatted output --- djlint/github_output.py | 237 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 djlint/github_output.py diff --git a/djlint/github_output.py b/djlint/github_output.py new file mode 100644 index 00000000..6749f2ca --- /dev/null +++ b/djlint/github_output.py @@ -0,0 +1,237 @@ +"""Build djLint console output.""" + +from __future__ import annotations + +import math +import shutil +import sys +from collections import Counter +from pathlib import Path +from typing import TYPE_CHECKING + +import regex as re +from click import echo +from colorama import Fore, Style + +if TYPE_CHECKING: + from collections.abc import Collection, Iterable, Mapping, Sequence + + from djlint.settings import Config + from djlint.types import LintError, ProcessResult + + +try: + sys.stdout.reconfigure(encoding="utf-8") # type: ignore[union-attr] +except Exception: + pass + + +def _count_digits(num: int, /) -> int: + """Faster alternative to len(str(num))""" + if num == 0: + return 1 + return math.floor(math.log10(abs(num))) + 1 + + +def print_output( + config: Config, file_errors: Iterable[ProcessResult], file_count: int +) -> int: + """Print results to console.""" + file_quantity = build_quantity(file_count) + # format errors + reformat_success_message = "" + lint_success_message = "" + lint_error_count = 0 + format_error_count = 0 + print_blanks = not config.stdin and not config.quiet + + if print_blanks: + echo() + + for error in sorted( + file_errors, + key=lambda x: next(iter(next(iter(x.values())))), # type: ignore[call-overload] + ): + if error.get("format_message") and not config.stdin: + # reformat message + format_error_count += build_check_output(error["format_message"], config) + + if error.get("lint_message"): + # lint message + lint_error_count += build_output(error["lint_message"], config) + + if config.statistics and config.lint: + build_stats_output(tuple(x.get("lint_message") for x in file_errors), config) + + tense_message = ( + build_quantity(format_error_count) + " would be" + if config.check + else build_quantity_tense(format_error_count) + ) + reformat_success_message = f"{tense_message} updated." + + error_case = "error" if lint_error_count == 1 else "errors" + lint_success_message += ( + f"Linted {file_quantity}, found {lint_error_count} {error_case}." + ) + + if print_blanks: + echo() + + if not config.quiet and not config.stdin and (config.reformat or config.check): + reformat_success_color = ( + Fore.RED + Style.BRIGHT if (format_error_count) > 0 else Fore.BLUE + ) + echo(f"{reformat_success_color}{reformat_success_message}{Style.RESET_ALL}") + + if config.lint and not config.quiet: + lint_success_color = ( + Fore.RED + Style.BRIGHT if (lint_error_count) > 0 else Fore.BLUE + ) + echo(f"{lint_success_color}{lint_success_message}{Style.RESET_ALL}") + + if print_blanks: + echo() + + return lint_error_count + format_error_count + + +def build_relative_path(url: str, project_root: Path) -> str: + """Get path relative to project.""" + url_path = Path(url) + if project_root != url_path and project_root in url_path.parents: + return str(url_path.relative_to(project_root)) + + return url + + +def build_output(error: Mapping[str, Iterable[LintError]], config: Config) -> int: + """Build output for file errors.""" + errors = sorted( + next(iter(error.values())), + key=lambda x: tuple(int(i) for i in x["line"].split(":")), + ) + + width, _ = shutil.get_terminal_size() + + if not errors: + return 0 + + filename = build_relative_path(next(iter(error)), config.project_root) + + if ( + "{filename}" not in config.linter_output_format and not config.stdin + ): # noqa: RUF027 + echo( + f"{Fore.GREEN}{Style.BRIGHT}\n{filename}\n{Style.DIM}" + + "".join("─" for _ in range(1, width)) + + Style.RESET_ALL + ) + + for message_dict in errors: + line = Fore.BLUE + message_dict["line"] + Style.RESET_ALL + code = ( + (Fore.RED if message_dict["code"][:1] == "E" else Fore.YELLOW) + + message_dict["code"] + + Style.RESET_ALL + ) + message = message_dict["message"] + match = ( + Fore.BLUE + + re.sub(r"\s{2,}|\n", " ", message_dict["match"]) + + Style.RESET_ALL + ) + + echo( + config.linter_output_format.format( + filename=filename, + line=line, + code=code, + message=message, + match=match, + ), + err=False, + ) + + return len(errors) + + +def build_check_output(errors: Mapping[str, Sequence[str]], config: Config) -> int: + """Build output for reformat check.""" + if not errors: + return 0 + + color = {"-": Fore.YELLOW, "+": Fore.GREEN, "@": Style.BRIGHT + Fore.BLUE} + width, _ = shutil.get_terminal_size() + + if not config.quiet and bool(next(iter(errors.values()))): + echo( + Fore.GREEN + + Style.BRIGHT + + "\n" + + build_relative_path(next(iter(errors)), config.project_root) + + "\n" + + Style.DIM + + "".join("─" for _ in range(1, width)) + + Style.RESET_ALL + ) + + for diff in next(iter(errors.values()))[2:]: + echo( + f"{color.get(diff[:1], Style.RESET_ALL)}{diff}{Style.RESET_ALL}", + err=False, + ) + + return sum(1 for v in errors.values() if v) + + +def build_quantity(size: int) -> str: + """Count files in a list.""" + return str(size) + " file" + ("s" if size > 1 or size == 0 else "") + + +def build_quantity_tense(size: int) -> str: + """Count files in a list.""" + return ( + str(size) + + " file" + + ("s" if size > 1 or size == 0 else "") + + " " + + ("were" if size > 1 or size == 0 else "was") + ) + + +def build_stats_output( + errors: Collection[Mapping[str, Iterable[LintError]] | None], config: Config +) -> int: + """Build output for linter statistics.""" + if not errors: + return 0 + + codes = tuple( + code["code"] for error in errors if error for code in next(iter(error.values())) + ) + + messages = { + rule["rule"]["name"]: rule["rule"]["message"] for rule in config.linter_rules + } + + echo() + width, _ = shutil.get_terminal_size() + echo( + f"{Fore.GREEN}{Style.BRIGHT}Statistics{Style.RESET_ALL}\n{Style.DIM}{'─' * width}{Style.RESET_ALL}" + ) + + if messages and codes: + longest_code = len(max(messages, key=len)) + longest_count = len(str(max(Counter(codes).values(), key=_count_digits))) + + for code in sorted(Counter(codes).items()): + code_space = (longest_code - len(code[0])) * " " + count_space = (longest_count - _count_digits(code[1])) * " " + + echo( + f"{Fore.YELLOW}{code[0]}{Fore.BLUE} {code_space}{code[1]}{Style.RESET_ALL} {count_space}{messages[code[0]]}" + ) + + return sum(Counter(codes).values()) From 44ce6692b4cf72a80eac4bb8dc88dd1d25a1dec4 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Thu, 28 Nov 2024 09:46:17 -0700 Subject: [PATCH 2/3] feat: github output support automatically enabled when GITHUB_ACTIONS exists --- djlint/__init__.py | 43 ++++---- djlint/github_output.py | 212 +++++----------------------------------- djlint/settings.py | 115 +++++++--------------- 3 files changed, 85 insertions(+), 285 deletions(-) diff --git a/djlint/__init__.py b/djlint/__init__.py index 0597b3f7..6272b9ea 100644 --- a/djlint/__init__.py +++ b/djlint/__init__.py @@ -23,6 +23,7 @@ from djlint.reformat import reformat_file from djlint.settings import Config from djlint.src import get_src +from djlint.github_output import print_github_output if TYPE_CHECKING: from djlint.types import ProcessResult @@ -70,9 +71,7 @@ help="Indent spacing. [default: 4]", show_default=False, ) -@click.option( - "--quiet", is_flag=True, help="Do not print diff when reformatting." -) +@click.option("--quiet", is_flag=True, help="Do not print diff when reformatting.") @click.option( "--profile", type=str, @@ -83,9 +82,7 @@ is_flag=True, help="Only format or lint files that starts with a comment with the text 'djlint:on'", ) -@click.option( - "--lint", is_flag=True, help="Lint for common issues. [default option]" -) +@click.option("--lint", is_flag=True, help="Lint for common issues. [default option]") @click.option( "--use-gitignore", is_flag=True, @@ -133,9 +130,7 @@ help='Codes to include. ex: "H014,H017"', show_default=False, ) -@click.option( - "--ignore-case", is_flag=True, help="Do not fix case on known html tags." -) +@click.option("--ignore-case", is_flag=True, help="Do not fix case on known html tags.") @click.option( "--ignore-blocks", type=str, @@ -215,9 +210,7 @@ @click.option( "--indent-css", type=int, help="Set CSS indent level.", show_default=False ) -@click.option( - "--indent-js", type=int, help="Set JS indent level.", show_default=False -) +@click.option("--indent-js", type=int, help="Set JS indent level.", show_default=False) @click.option( "--close-void-tags", is_flag=True, @@ -244,6 +237,11 @@ help="Consolidate blank lines down to x lines. [default: 0]", show_default=False, ) +@click.option( + "--github-output", + is_flag=True, + help="Output GitHub-compatible formatting.", +) @colorama_text(autoreset=True) def main( *, @@ -287,8 +285,10 @@ def main( no_function_formatting: bool, no_set_formatting: bool, max_blank_lines: int | None, + github_output: bool = False, ) -> None: """djLint · HTML template linter and formatter.""" + config = Config( src[0], extension=extension, @@ -383,7 +383,7 @@ def main( Fore.GREEN + Style.BRIGHT, Style.RESET_ALL + " ", ) - if not config.stdin and not config.quiet: + if not config.stdin and not config.quiet and not github_output: echo() progress_char = " »" if sys.platform == "win32" else "┈━" @@ -409,13 +409,12 @@ def main( colour="BLUE", ascii=progress_char, leave=False, + disable=github_output, ) as pbar: for future in as_completed(futures): file_errors.append(future.result()) pbar.update() - elapsed = pbar.format_interval( - pbar.format_dict["elapsed"] - ) + elapsed = pbar.format_interval(pbar.format_dict["elapsed"]) finished_bar_message = f"{Fore.BLUE + Style.BRIGHT}{message}{Style.RESET_ALL} {Fore.GREEN + Style.BRIGHT}{{n_fmt}}/{{total_fmt}}{Style.RESET_ALL} {Fore.BLUE + Style.BRIGHT}files{Style.RESET_ALL} {{bar}} {Fore.GREEN + Style.BRIGHT}{elapsed}{Style.RESET_ALL} " @@ -426,12 +425,11 @@ def main( colour="GREEN", ascii=progress_char, leave=True, + disable=github_output, ): pass else: - file_errors = [ - future.result() for future in as_completed(futures) - ] + file_errors = [future.result() for future in as_completed(futures)] if temp_file and (config.reformat or config.check): # if using stdin, only give back formatted code. @@ -448,6 +446,13 @@ def main( finally: Path(temp_file.name).unlink(missing_ok=True) + if ( + github_output + and print_github_output(config, file_errors, len(file_list)) + and not config.warn + ): + sys.exit(1) + if print_output(config, file_errors, len(file_list)) and not config.warn: sys.exit(1) diff --git a/djlint/github_output.py b/djlint/github_output.py index 6749f2ca..2a1c5d85 100644 --- a/djlint/github_output.py +++ b/djlint/github_output.py @@ -1,237 +1,71 @@ -"""Build djLint console output.""" +"""Build djLint GitHub workflow command output.""" from __future__ import annotations - -import math -import shutil -import sys -from collections import Counter from pathlib import Path from typing import TYPE_CHECKING - -import regex as re from click import echo -from colorama import Fore, Style if TYPE_CHECKING: - from collections.abc import Collection, Iterable, Mapping, Sequence - + from collections.abc import Iterable, Mapping, Sequence from djlint.settings import Config from djlint.types import LintError, ProcessResult -try: - sys.stdout.reconfigure(encoding="utf-8") # type: ignore[union-attr] -except Exception: - pass - - -def _count_digits(num: int, /) -> int: - """Faster alternative to len(str(num))""" - if num == 0: - return 1 - return math.floor(math.log10(abs(num))) + 1 - - -def print_output( +def print_github_output( config: Config, file_errors: Iterable[ProcessResult], file_count: int ) -> int: - """Print results to console.""" - file_quantity = build_quantity(file_count) - # format errors - reformat_success_message = "" - lint_success_message = "" + """Print results as GitHub workflow commands.""" lint_error_count = 0 format_error_count = 0 - print_blanks = not config.stdin and not config.quiet - - if print_blanks: - echo() for error in sorted( file_errors, - key=lambda x: next(iter(next(iter(x.values())))), # type: ignore[call-overload] + key=lambda x: next(iter(next(iter(x.values())))), ): if error.get("format_message") and not config.stdin: - # reformat message - format_error_count += build_check_output(error["format_message"], config) - + format_error_count += print_format_errors(error["format_message"], config) if error.get("lint_message"): - # lint message - lint_error_count += build_output(error["lint_message"], config) - - if config.statistics and config.lint: - build_stats_output(tuple(x.get("lint_message") for x in file_errors), config) - - tense_message = ( - build_quantity(format_error_count) + " would be" - if config.check - else build_quantity_tense(format_error_count) - ) - reformat_success_message = f"{tense_message} updated." - - error_case = "error" if lint_error_count == 1 else "errors" - lint_success_message += ( - f"Linted {file_quantity}, found {lint_error_count} {error_case}." - ) - - if print_blanks: - echo() - - if not config.quiet and not config.stdin and (config.reformat or config.check): - reformat_success_color = ( - Fore.RED + Style.BRIGHT if (format_error_count) > 0 else Fore.BLUE - ) - echo(f"{reformat_success_color}{reformat_success_message}{Style.RESET_ALL}") - - if config.lint and not config.quiet: - lint_success_color = ( - Fore.RED + Style.BRIGHT if (lint_error_count) > 0 else Fore.BLUE - ) - echo(f"{lint_success_color}{lint_success_message}{Style.RESET_ALL}") - - if print_blanks: - echo() + lint_error_count += print_lint_errors(error["lint_message"], config) return lint_error_count + format_error_count -def build_relative_path(url: str, project_root: Path) -> str: - """Get path relative to project.""" - url_path = Path(url) - if project_root != url_path and project_root in url_path.parents: - return str(url_path.relative_to(project_root)) - - return url - - -def build_output(error: Mapping[str, Iterable[LintError]], config: Config) -> int: - """Build output for file errors.""" +def print_lint_errors(error: Mapping[str, Iterable[LintError]], config: Config) -> int: + """Print lint errors in GitHub format.""" errors = sorted( next(iter(error.values())), key=lambda x: tuple(int(i) for i in x["line"].split(":")), ) - - width, _ = shutil.get_terminal_size() - if not errors: return 0 filename = build_relative_path(next(iter(error)), config.project_root) - if ( - "{filename}" not in config.linter_output_format and not config.stdin - ): # noqa: RUF027 - echo( - f"{Fore.GREEN}{Style.BRIGHT}\n{filename}\n{Style.DIM}" - + "".join("─" for _ in range(1, width)) - + Style.RESET_ALL - ) - for message_dict in errors: - line = Fore.BLUE + message_dict["line"] + Style.RESET_ALL - code = ( - (Fore.RED if message_dict["code"][:1] == "E" else Fore.YELLOW) - + message_dict["code"] - + Style.RESET_ALL - ) - message = message_dict["message"] - match = ( - Fore.BLUE - + re.sub(r"\s{2,}|\n", " ", message_dict["match"]) - + Style.RESET_ALL - ) - + line = message_dict["line"].split(":")[0] + level = "error" if message_dict["code"].startswith("E") else "warning" echo( - config.linter_output_format.format( - filename=filename, - line=line, - code=code, - message=message, - match=match, - ), - err=False, + f"::{level} file={filename},line={line}::{message_dict['code']} {message_dict['message']}" ) return len(errors) -def build_check_output(errors: Mapping[str, Sequence[str]], config: Config) -> int: - """Build output for reformat check.""" +def print_format_errors(errors: Mapping[str, Sequence[str]], config: Config) -> int: + """Print format errors in GitHub format.""" if not errors: return 0 - color = {"-": Fore.YELLOW, "+": Fore.GREEN, "@": Style.BRIGHT + Fore.BLUE} - width, _ = shutil.get_terminal_size() - - if not config.quiet and bool(next(iter(errors.values()))): - echo( - Fore.GREEN - + Style.BRIGHT - + "\n" - + build_relative_path(next(iter(errors)), config.project_root) - + "\n" - + Style.DIM - + "".join("─" for _ in range(1, width)) - + Style.RESET_ALL - ) - - for diff in next(iter(errors.values()))[2:]: - echo( - f"{color.get(diff[:1], Style.RESET_ALL)}{diff}{Style.RESET_ALL}", - err=False, - ) + filename = build_relative_path(next(iter(errors)), config.project_root) + if bool(next(iter(errors.values()))): + echo(f"::error file={filename}::Formatting changes required") return sum(1 for v in errors.values() if v) -def build_quantity(size: int) -> str: - """Count files in a list.""" - return str(size) + " file" + ("s" if size > 1 or size == 0 else "") - - -def build_quantity_tense(size: int) -> str: - """Count files in a list.""" - return ( - str(size) - + " file" - + ("s" if size > 1 or size == 0 else "") - + " " - + ("were" if size > 1 or size == 0 else "was") - ) - - -def build_stats_output( - errors: Collection[Mapping[str, Iterable[LintError]] | None], config: Config -) -> int: - """Build output for linter statistics.""" - if not errors: - return 0 - - codes = tuple( - code["code"] for error in errors if error for code in next(iter(error.values())) - ) - - messages = { - rule["rule"]["name"]: rule["rule"]["message"] for rule in config.linter_rules - } - - echo() - width, _ = shutil.get_terminal_size() - echo( - f"{Fore.GREEN}{Style.BRIGHT}Statistics{Style.RESET_ALL}\n{Style.DIM}{'─' * width}{Style.RESET_ALL}" - ) - - if messages and codes: - longest_code = len(max(messages, key=len)) - longest_count = len(str(max(Counter(codes).values(), key=_count_digits))) - - for code in sorted(Counter(codes).items()): - code_space = (longest_code - len(code[0])) * " " - count_space = (longest_count - _count_digits(code[1])) * " " - - echo( - f"{Fore.YELLOW}{code[0]}{Fore.BLUE} {code_space}{code[1]}{Style.RESET_ALL} {count_space}{messages[code[0]]}" - ) - - return sum(Counter(codes).values()) +def build_relative_path(url: str, project_root: Path) -> str: + """Get path relative to project.""" + url_path = Path(url) + if project_root != url_path and project_root in url_path.parents: + return str(url_path.relative_to(project_root)) + return url diff --git a/djlint/settings.py b/djlint/settings.py index 9a1391f7..8c0f5385 100644 --- a/djlint/settings.py +++ b/djlint/settings.py @@ -145,17 +145,13 @@ def load_project_settings(src: Path, config: Path | None) -> dict[str, Any]: else: djlint_content.update(load_djlintrc_config(config)) except Exception as error: - logger.error( - "%sFailed to load config file %s. %s", Fore.RED, config, error - ) + logger.error("%sFailed to load config file %s. %s", Fore.RED, config, error) if pyproject_file := find_pyproject(src): try: content = load_pyproject_config(pyproject_file) except Exception as error: - logger.error( - "%sFailed to load pyproject.toml file. %s", Fore.RED, error - ) + logger.error("%sFailed to load pyproject.toml file. %s", Fore.RED, error) else: if content: djlint_content.update(content) @@ -165,9 +161,7 @@ def load_project_settings(src: Path, config: Path | None) -> dict[str, Any]: try: djlint_content.update(load_djlint_toml_config(djlint_toml_file)) except Exception as error: - logger.error( - "%sFailed to load djlint.toml file. %s", Fore.RED, error - ) + logger.error("%sFailed to load djlint.toml file. %s", Fore.RED, error) elif djlintrc_file := find_djlintrc(src): try: @@ -188,10 +182,7 @@ def validate_rules( if "name" not in rule["rule"]: warning = True echo(Fore.RED + "Warning: A rule is missing a name! 😢") - if ( - "patterns" not in rule["rule"] - and "python_module" not in rule["rule"] - ): + if "patterns" not in rule["rule"] and "python_module" not in rule["rule"]: warning = True echo( Fore.RED @@ -289,6 +280,7 @@ def __init__( no_function_formatting: bool = False, no_set_formatting: bool = False, max_blank_lines: int | None = None, + github_output: bool = False, ) -> None: self.reformat = reformat self.check = check @@ -300,9 +292,7 @@ def __init__( else: self.project_root = find_project_root(Path(src).resolve()) - djlint_settings = load_project_settings( - self.project_root, configuration - ) + djlint_settings = load_project_settings(self.project_root, configuration) self.gitignore = load_gitignore(self.project_root) # custom configuration options @@ -310,26 +300,20 @@ def __init__( self.use_gitignore: bool = use_gitignore or djlint_settings.get( "use_gitignore", False ) - self.extension: str = str( - extension or djlint_settings.get("extension", "html") - ) + self.extension: str = str(extension or djlint_settings.get("extension", "html")) self.quiet: bool = quiet or djlint_settings.get("quiet", False) self.require_pragma: bool = ( require_pragma - or str(djlint_settings.get("require_pragma", "false")).lower() - == "true" + or str(djlint_settings.get("require_pragma", "false")).lower() == "true" ) self.custom_blocks: str = str( - build_custom_blocks( - custom_blocks or djlint_settings.get("custom_blocks") - ) + build_custom_blocks(custom_blocks or djlint_settings.get("custom_blocks")) or "" ) self.custom_html: str = str( - build_custom_html(custom_html or djlint_settings.get("custom_html")) - or "" + build_custom_html(custom_html or djlint_settings.get("custom_html")) or "" ) self.format_attribute_template_tags: bool = ( @@ -345,30 +329,21 @@ def __init__( ignore_blocks or djlint_settings.get("ignore_blocks", "") ) - self.preserve_blank_lines: bool = ( - preserve_blank_lines - or djlint_settings.get("preserve_blank_lines", False) + self.preserve_blank_lines: bool = preserve_blank_lines or djlint_settings.get( + "preserve_blank_lines", False ) - self.format_js: bool = format_js or djlint_settings.get( - "format_js", False - ) + self.format_js: bool = format_js or djlint_settings.get("format_js", False) self.js_config = ( - {"indent_size": indent_js} - if indent_js - else djlint_settings.get("js") + {"indent_size": indent_js} if indent_js else djlint_settings.get("js") ) or {} self.css_config = ( - {"indent_size": indent_css} - if indent_css - else djlint_settings.get("css") + {"indent_size": indent_css} if indent_css else djlint_settings.get("css") ) or {} - self.format_css: bool = format_css or djlint_settings.get( - "format_css", False - ) + self.format_css: bool = format_css or djlint_settings.get("format_css", False) self.ignore_case: bool = ignore_case or djlint_settings.get( "ignore_case", False @@ -377,9 +352,8 @@ def __init__( self.close_void_tags: bool = close_void_tags or djlint_settings.get( "close_void_tags", False ) - self.no_line_after_yaml: bool = ( - no_line_after_yaml - or djlint_settings.get("no_line_after_yaml", False) + self.no_line_after_yaml: bool = no_line_after_yaml or djlint_settings.get( + "no_line_after_yaml", False ) self.no_set_formatting: bool = no_set_formatting or djlint_settings.get( "no_set_formatting", False @@ -414,20 +388,15 @@ def __init__( profile or djlint_settings.get("profile", "all") ).lower() - self.linter_output_format: str = ( - linter_output_format - or djlint_settings.get( - "linter_output_format", "{code} {line} {message} {match}" - ) + self.linter_output_format: str = linter_output_format or djlint_settings.get( + "linter_output_format", "{code} {line} {message} {match}" ) # load linter rules rule_set = validate_rules( chain( yaml.safe_load( - (Path(__file__).parent / "rules.yaml").read_text( - encoding="utf-8" - ) + (Path(__file__).parent / "rules.yaml").read_text(encoding="utf-8") ), load_custom_rules(self.project_root), ) @@ -502,13 +471,9 @@ def __init__( | venv """ - self.exclude: str = exclude or djlint_settings.get( - "exclude", default_exclude - ) + self.exclude: str = exclude or djlint_settings.get("exclude", default_exclude) - extend_exclude = extend_exclude or djlint_settings.get( - "extend_exclude", "" - ) + extend_exclude = extend_exclude or djlint_settings.get("extend_exclude", "") if extend_exclude: self.exclude += r" | " + r" | ".join( @@ -523,14 +488,12 @@ def __init__( # add blank line after load tags self.blank_line_after_tag: str | None = ( - blank_line_after_tag - or djlint_settings.get("blank_line_after_tag", None) + blank_line_after_tag or djlint_settings.get("blank_line_after_tag", None) ) # add blank line before load tags self.blank_line_before_tag: str | None = ( - blank_line_before_tag - or djlint_settings.get("blank_line_before_tag", None) + blank_line_before_tag or djlint_settings.get("blank_line_before_tag", None) ) # add line break after multi-line tags @@ -673,9 +636,7 @@ def __init__( try: self.max_attribute_length = max_attribute_length or int( - djlint_settings.get( - "max_attribute_length", self.max_attribute_length - ) + djlint_settings.get("max_attribute_length", self.max_attribute_length) ) except ValueError: echo( @@ -764,20 +725,20 @@ def __init__( (\s*?/?>) """ - self.attribute_style_pattern: str = ( - r"^(.*?)(style=)([\"|'])(([^\"']+?;)+?)\3" + self.attribute_style_pattern: str = r"^(.*?)(style=)([\"|'])(([^\"']+?;)+?)\3" + + self.ignored_attributes = frozenset( + { + "href", + "action", + "data-url", + "src", + "url", + "srcset", + "data-src", + } ) - self.ignored_attributes = frozenset({ - "href", - "action", - "data-url", - "src", - "url", - "srcset", - "data-src", - }) - self.start_template_tags: str = ( (rf"(?!{self.ignore_blocks})" if self.ignore_blocks else "") + r""" From defa6905c7ebc36ef8519547806082deeeb8f064 Mon Sep 17 00:00:00 2001 From: Michael Bianco Date: Sat, 30 Nov 2024 11:11:55 -0700 Subject: [PATCH 3/3] fix: GITHUB_ACTIONS sourcing --- djlint/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/djlint/__init__.py b/djlint/__init__.py index 6272b9ea..adb1dd3d 100644 --- a/djlint/__init__.py +++ b/djlint/__init__.py @@ -240,7 +240,9 @@ @click.option( "--github-output", is_flag=True, + default=bool(os.getenv("GITHUB_ACTIONS")), help="Output GitHub-compatible formatting.", + show_default=True, ) @colorama_text(autoreset=True) def main(