Loading README.md +1 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,6 @@ poetry run tbc-check path/to/tbc/template - for each variable in the `kicker.json` file (main template and variants): - mapped input is declared in the related template with same name, type, default, options and description (WARNING only) - the variable is declared in the related template with expected input mapping (`$[[ inputs.input-name ]]`) - the input/variable is documented in the README (WARNING only) - the input/variable is documented in the README with same default (WARNING only) If any non-WARNING rule fails, `tbc-check` fails with exit code 127. tbc/checker.py +20 −3 Original line number Diff line number Diff line Loading @@ -104,7 +104,20 @@ class DocVar(BaseModel): var_name: str input_name: Optional[str] = None description: str default: str default_cell: str def default(self, type: GlInputType) -> Optional[str]: code_expr_match = re.match(r"`([^`]*)`", self.default_cell) explicit_default = code_expr_match.group(1) if code_expr_match else None if type == GlInputType.boolean: # return bool(self.default) if self.default != None else False return explicit_default or "false" if type == GlInputType.number: # return int(self.default) if self.default != None else 0 return explicit_default or "0" return explicit_default or '' def _get_var(tpl_desc: dict[str, any], var_name: str) -> Optional[TbcVar]: Loading Loading @@ -136,11 +149,16 @@ def _get_var(tpl_desc: dict[str, any], var_name: str) -> Optional[TbcVar]: def _check_var(tbc_var: TbcVar, var_prefix: str, tpl_spec: dict[str, any], tpl_impl: dict[str, any], main_tpl_desc: Optional[dict[str, any]], doc_vars: list[DocVar]) -> int: has_no_input = tbc_var.secret or main_tpl_desc and _get_var(main_tpl_desc, tbc_var.name) or tbc_var.name.startswith("TBC_") expected_input_name = tbc_var.input_name(var_prefix) expected_gl_input = tbc_var.to_gl() # check variable is declared in doc doc_var = next(filter(lambda dv: dv.var_name == tbc_var.name, doc_vars), None) if doc_var == None: print(f" {bcolors.YELLOW}⚠ <{tbc_var.name}>: not documented in README{bcolors.RESET}") else: # check default if doc_var.default(expected_gl_input.type) != expected_gl_input.default: print(f" {bcolors.YELLOW}⚠ <{tbc_var.name}/{expected_input_name}>: README default ({doc_var.default(tbc_var.type)}) doesn't match Kicker's ({expected_gl_input.default}){bcolors.YELLOW}") if doc_var.lock and not tbc_var.secret: print(f" {bcolors.YELLOW}⚠ <{tbc_var.name}>: is not declared as a secret but has a lock in README{bcolors.RESET}") elif not doc_var.lock and tbc_var.secret: Loading Loading @@ -184,7 +202,6 @@ def _check_var(tbc_var: TbcVar, var_prefix: str, tpl_spec: dict[str, any], tpl_i err_count = 0 # check actual input is as expected actual_gl_input = GlInput.parse_obj(declared_input) expected_gl_input = tbc_var.to_gl() if actual_gl_input.type != expected_gl_input.type: print(f" {bcolors.RED}✕ <{tbc_var.name}/{expected_input_name}>: type ({actual_gl_input.type}) doesn't match Kicker's ({expected_gl_input.type}){bcolors.RESET}") Loading Loading @@ -287,7 +304,7 @@ def _load_vars_from_doc(project_dir: Path) -> list[DocVar]: # group 4: <description> # group 5: <default> var_doc_regex = re.compile(r"^\| *(:lock:)? *`([a-zA-Z0-9-_]+)`(?: *\/ *`([a-zA-Z0-9-_]+)`)? *\| *([^|]*) *\| *([^|]*)\ *\|$", flags=re.MULTILINE) return [DocVar(lock=bool(match.group(1)), var_name=match.group(3) or match.group(2), input_name=match.group(2) if match.group(3) else None, description=match.group(4), default=match.group(5)) for match in var_doc_regex.finditer(readme_content)] return [DocVar(lock=bool(match.group(1)), var_name=match.group(3) or match.group(2), input_name=match.group(2) if match.group(3) else None, description=match.group(4), default_cell=match.group(5)) for match in var_doc_regex.finditer(readme_content)] def run(): Loading Loading
README.md +1 −1 Original line number Diff line number Diff line Loading @@ -24,6 +24,6 @@ poetry run tbc-check path/to/tbc/template - for each variable in the `kicker.json` file (main template and variants): - mapped input is declared in the related template with same name, type, default, options and description (WARNING only) - the variable is declared in the related template with expected input mapping (`$[[ inputs.input-name ]]`) - the input/variable is documented in the README (WARNING only) - the input/variable is documented in the README with same default (WARNING only) If any non-WARNING rule fails, `tbc-check` fails with exit code 127.
tbc/checker.py +20 −3 Original line number Diff line number Diff line Loading @@ -104,7 +104,20 @@ class DocVar(BaseModel): var_name: str input_name: Optional[str] = None description: str default: str default_cell: str def default(self, type: GlInputType) -> Optional[str]: code_expr_match = re.match(r"`([^`]*)`", self.default_cell) explicit_default = code_expr_match.group(1) if code_expr_match else None if type == GlInputType.boolean: # return bool(self.default) if self.default != None else False return explicit_default or "false" if type == GlInputType.number: # return int(self.default) if self.default != None else 0 return explicit_default or "0" return explicit_default or '' def _get_var(tpl_desc: dict[str, any], var_name: str) -> Optional[TbcVar]: Loading Loading @@ -136,11 +149,16 @@ def _get_var(tpl_desc: dict[str, any], var_name: str) -> Optional[TbcVar]: def _check_var(tbc_var: TbcVar, var_prefix: str, tpl_spec: dict[str, any], tpl_impl: dict[str, any], main_tpl_desc: Optional[dict[str, any]], doc_vars: list[DocVar]) -> int: has_no_input = tbc_var.secret or main_tpl_desc and _get_var(main_tpl_desc, tbc_var.name) or tbc_var.name.startswith("TBC_") expected_input_name = tbc_var.input_name(var_prefix) expected_gl_input = tbc_var.to_gl() # check variable is declared in doc doc_var = next(filter(lambda dv: dv.var_name == tbc_var.name, doc_vars), None) if doc_var == None: print(f" {bcolors.YELLOW}⚠ <{tbc_var.name}>: not documented in README{bcolors.RESET}") else: # check default if doc_var.default(expected_gl_input.type) != expected_gl_input.default: print(f" {bcolors.YELLOW}⚠ <{tbc_var.name}/{expected_input_name}>: README default ({doc_var.default(tbc_var.type)}) doesn't match Kicker's ({expected_gl_input.default}){bcolors.YELLOW}") if doc_var.lock and not tbc_var.secret: print(f" {bcolors.YELLOW}⚠ <{tbc_var.name}>: is not declared as a secret but has a lock in README{bcolors.RESET}") elif not doc_var.lock and tbc_var.secret: Loading Loading @@ -184,7 +202,6 @@ def _check_var(tbc_var: TbcVar, var_prefix: str, tpl_spec: dict[str, any], tpl_i err_count = 0 # check actual input is as expected actual_gl_input = GlInput.parse_obj(declared_input) expected_gl_input = tbc_var.to_gl() if actual_gl_input.type != expected_gl_input.type: print(f" {bcolors.RED}✕ <{tbc_var.name}/{expected_input_name}>: type ({actual_gl_input.type}) doesn't match Kicker's ({expected_gl_input.type}){bcolors.RESET}") Loading Loading @@ -287,7 +304,7 @@ def _load_vars_from_doc(project_dir: Path) -> list[DocVar]: # group 4: <description> # group 5: <default> var_doc_regex = re.compile(r"^\| *(:lock:)? *`([a-zA-Z0-9-_]+)`(?: *\/ *`([a-zA-Z0-9-_]+)`)? *\| *([^|]*) *\| *([^|]*)\ *\|$", flags=re.MULTILINE) return [DocVar(lock=bool(match.group(1)), var_name=match.group(3) or match.group(2), input_name=match.group(2) if match.group(3) else None, description=match.group(4), default=match.group(5)) for match in var_doc_regex.finditer(readme_content)] return [DocVar(lock=bool(match.group(1)), var_name=match.group(3) or match.group(2), input_name=match.group(2) if match.group(3) else None, description=match.group(4), default_cell=match.group(5)) for match in var_doc_regex.finditer(readme_content)] def run(): Loading