From ba89a5de6f11b2a0fe354bc01b953d36c52acad1 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 30 Apr 2025 11:38:07 +0200 Subject: [PATCH] Codegen: make missing `codeql` error clearer --- misc/codegen/generators/qlgen.py | 10 ++++++++++ misc/codegen/test/test_qlgen.py | 24 +++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/misc/codegen/generators/qlgen.py b/misc/codegen/generators/qlgen.py index eefcad3e943..05c945f3462 100755 --- a/misc/codegen/generators/qlgen.py +++ b/misc/codegen/generators/qlgen.py @@ -24,6 +24,7 @@ Moreover in the test directory for each in it will generate bene import logging import pathlib import re +import shutil import subprocess import typing import itertools @@ -257,6 +258,15 @@ def format(codeql, files): if not ql_files: return format_cmd = [codeql, "query", "format", "--in-place", "--"] + ql_files + if "/" in codeql: + if not pathlib.Path(codeql).exists(): + raise FormatError(f"Provided CodeQL binary `{codeql}` does not exist") + else: + codeql_path = shutil.which(codeql) + if not codeql_path: + raise FormatError( + f"`{codeql}` not found in PATH. Either install it, or pass `-- --codeql-binary` with a full path") + codeql = codeql_path res = subprocess.run(format_cmd, stderr=subprocess.PIPE, text=True) if res.returncode: for line in res.stderr.splitlines(): diff --git a/misc/codegen/test/test_qlgen.py b/misc/codegen/test/test_qlgen.py index 01dee251999..75e587fbd5e 100644 --- a/misc/codegen/test/test_qlgen.py +++ b/misc/codegen/test/test_qlgen.py @@ -52,6 +52,8 @@ def qlgen_opts(opts): opts.ql_format = True opts.root_dir = paths.root_dir opts.force = False + opts.codeql_binary = "./my_fake_codeql" + pathlib.Path(opts.codeql_binary).touch() return opts @@ -499,7 +501,6 @@ def test_class_dir_imports(generate_import_list): def test_format(opts, generate, render_manager, run_mock): - opts.codeql_binary = "my_fake_codeql" run_mock.return_value.stderr = "some\nlines\n" render_manager.written = [ pathlib.Path("x", "foo.ql"), @@ -508,13 +509,12 @@ def test_format(opts, generate, render_manager, run_mock): ] generate([schema.Class('A')]) assert run_mock.mock_calls == [ - mock.call(["my_fake_codeql", "query", "format", "--in-place", "--", "x/foo.ql", "bar.qll"], + mock.call([opts.codeql_binary, "query", "format", "--in-place", "--", "x/foo.ql", "bar.qll"], stderr=subprocess.PIPE, text=True), ] def test_format_error(opts, generate, render_manager, run_mock): - opts.codeql_binary = "my_fake_codeql" run_mock.return_value.stderr = "some\nlines\n" run_mock.return_value.returncode = 1 render_manager.written = [ @@ -526,6 +526,24 @@ def test_format_error(opts, generate, render_manager, run_mock): generate([schema.Class('A')]) +def test_format_no_codeql(opts, generate, render_manager, run_mock): + pathlib.Path(opts.codeql_binary).unlink() + render_manager.written = [ + pathlib.Path("bar.qll"), + ] + with pytest.raises(qlgen.FormatError): + generate([schema.Class('A')]) + + +def test_format_no_codeql_in_path(opts, generate, render_manager, run_mock): + opts.codeql_binary = "my_fake_codeql" + render_manager.written = [ + pathlib.Path("bar.qll"), + ] + with pytest.raises(qlgen.FormatError): + generate([schema.Class('A')]) + + @pytest.mark.parametrize("force", [False, True]) def test_manage_parameters(opts, generate, renderer, force): opts.force = force