Loading tbc_check/checker.py +39 −0 Original line number Diff line number Diff line Loading @@ -467,6 +467,41 @@ def _check_job(job_name: str, tpl_body, job_prefix) -> int: return err_count def _check_inheritance(tpl_body: dict[str, Any]) -> int: job_bodies = { name: body for name, body in tpl_body.items() if name not in ["stages", "workflow", "variables", "rules"] and isinstance(body, dict) } # count non-hidden jobs is_single_job_tpl = sum(1 for name in job_bodies if not name.startswith(".")) == 1 # # Each template # - should define only one job # Or # - all jobs should inherit from a hidden base job # for name, body in iter(job_bodies.items()): base_job = body.get("extends", None) if is_single_job_tpl and base_job is not None: print( f" {AnsiColors.RED}✕ single job template: job '{name}' inherits another job{AnsiColors.RESET}" ) if not is_single_job_tpl and not name.startswith(".") and base_job is None: print( f" {AnsiColors.RED}✕ multiple job template: job '{name}' should inherit a base job{AnsiColors.RESET}" ) if base_job is not None and not base_job.startswith("."): print( f" {AnsiColors.RED}✕ multiple job template: job '{name}' inherits from non-hidden job '{base_job}'{AnsiColors.RESET}" ) if base_job is not None and base_job not in job_bodies: print( f" {AnsiColors.YELLOW}⚠ multiple job template: job '{name}' inherits from '{base_job}' which is not defined in current template{AnsiColors.RESET}" ) def _check_tpl( kicker: dict[str, any], root_kicker: Optional[dict[str, any]], Loading @@ -492,6 +527,10 @@ def _check_tpl( inputs: dict[str, dict[str, any]] = dict(tpl_spec["spec"]["inputs"]) err_count = 0 # check inheritance # ----------------- _check_inheritance(tpl_body=tpl_body) # check jobs # ---------- for name, body in tpl_body.items(): Loading tests/test_check_inheritance.py 0 → 100644 +104 −0 Original line number Diff line number Diff line import pytest from tbc_check import checker def test_check_inheritance_multiple_job_inheritance_from_undefined(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".base-job": {}, "prefix-job1": { "extends": ".base-job" }, "prefix-job2": { "extends": ".other-base-job" }, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( " \x1b[0;33m⚠ multiple job template: job 'prefix-job2' inherits from '.other-base-job' which is not defined in current template\x1b[0m\n" ) def test_check_inheritance_multiple_job_inheritance_bad(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".base-job": {}, "prefix-job1": { "extends": ".base-job" }, "prefix-job2": {}, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( " \x1b[0;31m✕ multiple job template: job 'prefix-job2' should inherit a base job\x1b[0m\n" ) def test_check_inheritance_multiple_job_inheritance_good(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".hidden": None, ".base-job": {}, "prefix-job1": { "extends": ".base-job" }, "prefix-job2": { "extends": ".base-job" }, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( "" ) def test_check_inheritance_multiple_job_inheritance_from_non_hidden(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".hidden": None, ".base-job": {}, "prefix-job1": { "extends": ".base-job" }, "prefix-job2": { "extends": "prefix-job1" }, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( " \x1b[0;31m✕ multiple job template: job 'prefix-job2' inherits from non-hidden job 'prefix-job1'\x1b[0m\n" ) def test_check_inheritance_single_job_with_inheritance(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".hidden": None, ".prefix-base": {}, "prefix-job1": { "extends": ".prefix-base" }, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( " \x1b[0;31m✕ single job template: job 'prefix-job1' inherits another job\x1b[0m\n" ) Loading
tbc_check/checker.py +39 −0 Original line number Diff line number Diff line Loading @@ -467,6 +467,41 @@ def _check_job(job_name: str, tpl_body, job_prefix) -> int: return err_count def _check_inheritance(tpl_body: dict[str, Any]) -> int: job_bodies = { name: body for name, body in tpl_body.items() if name not in ["stages", "workflow", "variables", "rules"] and isinstance(body, dict) } # count non-hidden jobs is_single_job_tpl = sum(1 for name in job_bodies if not name.startswith(".")) == 1 # # Each template # - should define only one job # Or # - all jobs should inherit from a hidden base job # for name, body in iter(job_bodies.items()): base_job = body.get("extends", None) if is_single_job_tpl and base_job is not None: print( f" {AnsiColors.RED}✕ single job template: job '{name}' inherits another job{AnsiColors.RESET}" ) if not is_single_job_tpl and not name.startswith(".") and base_job is None: print( f" {AnsiColors.RED}✕ multiple job template: job '{name}' should inherit a base job{AnsiColors.RESET}" ) if base_job is not None and not base_job.startswith("."): print( f" {AnsiColors.RED}✕ multiple job template: job '{name}' inherits from non-hidden job '{base_job}'{AnsiColors.RESET}" ) if base_job is not None and base_job not in job_bodies: print( f" {AnsiColors.YELLOW}⚠ multiple job template: job '{name}' inherits from '{base_job}' which is not defined in current template{AnsiColors.RESET}" ) def _check_tpl( kicker: dict[str, any], root_kicker: Optional[dict[str, any]], Loading @@ -492,6 +527,10 @@ def _check_tpl( inputs: dict[str, dict[str, any]] = dict(tpl_spec["spec"]["inputs"]) err_count = 0 # check inheritance # ----------------- _check_inheritance(tpl_body=tpl_body) # check jobs # ---------- for name, body in tpl_body.items(): Loading
tests/test_check_inheritance.py 0 → 100644 +104 −0 Original line number Diff line number Diff line import pytest from tbc_check import checker def test_check_inheritance_multiple_job_inheritance_from_undefined(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".base-job": {}, "prefix-job1": { "extends": ".base-job" }, "prefix-job2": { "extends": ".other-base-job" }, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( " \x1b[0;33m⚠ multiple job template: job 'prefix-job2' inherits from '.other-base-job' which is not defined in current template\x1b[0m\n" ) def test_check_inheritance_multiple_job_inheritance_bad(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".base-job": {}, "prefix-job1": { "extends": ".base-job" }, "prefix-job2": {}, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( " \x1b[0;31m✕ multiple job template: job 'prefix-job2' should inherit a base job\x1b[0m\n" ) def test_check_inheritance_multiple_job_inheritance_good(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".hidden": None, ".base-job": {}, "prefix-job1": { "extends": ".base-job" }, "prefix-job2": { "extends": ".base-job" }, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( "" ) def test_check_inheritance_multiple_job_inheritance_from_non_hidden(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".hidden": None, ".base-job": {}, "prefix-job1": { "extends": ".base-job" }, "prefix-job2": { "extends": "prefix-job1" }, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( " \x1b[0;31m✕ multiple job template: job 'prefix-job2' inherits from non-hidden job 'prefix-job1'\x1b[0m\n" ) def test_check_inheritance_single_job_with_inheritance(capfd: pytest.CaptureFixture[str]): tpl_body = { "workflow": None, "variables": None, "stages": None, ".hidden": None, ".prefix-base": {}, "prefix-job1": { "extends": ".prefix-base" }, } res = checker._check_inheritance(tpl_body=tpl_body) out, err = capfd.readouterr() assert out == ( " \x1b[0;31m✕ single job template: job 'prefix-job1' inherits another job\x1b[0m\n" )