diff options
author | zaverden <zaverden@yandex-team.com> | 2024-03-18 13:20:51 +0300 |
---|---|---|
committer | zaverden <zaverden@yandex-team.com> | 2024-03-18 15:09:21 +0300 |
commit | ebc6526bccdf9d2304b9eef3a0a9eaba8e7e38f7 (patch) | |
tree | 9a6a87cdab117790774a6e04ece2e058fc16a85b | |
parent | 29127cb44e4ff8ecde3924e1af7bb4213fda2a9f (diff) | |
download | ydb-ebc6526bccdf9d2304b9eef3a0a9eaba8e7e38f7.tar.gz |
feat(TS_TYPECHECK): implementation
881bda4539ae182b7975c149191642ded49990e3
-rw-r--r-- | build/conf/ts/ts.conf | 2 | ||||
-rw-r--r-- | build/conf/ts/ts_test.conf | 18 | ||||
-rw-r--r-- | build/plugins/lib/test_const/__init__.py | 1 | ||||
-rw-r--r-- | build/plugins/nots.py | 61 | ||||
-rw-r--r-- | build/plugins/ytest.py | 12 |
5 files changed, 83 insertions, 11 deletions
diff --git a/build/conf/ts/ts.conf b/build/conf/ts/ts.conf index 14a3f9b507..6c5953491e 100644 --- a/build/conf/ts/ts.conf +++ b/build/conf/ts/ts.conf @@ -75,8 +75,6 @@ macro _TS_CONFIG_EPILOGUE() { _GLOB(TS_GLOB_FILES $TS_GLOB_INCLUDE EXCLUDE $TS_GLOB_EXCLUDE) _GLOB(_TS_LINT_SRCS_VALUE **/*.(ts|tsx|js|jsx) EXCLUDE $TS_EXCLUDE_DIR_GLOB $TS_COMMON_OUTDIR_GLOB $TS_GLOB_EXCLUDE_ADDITIONAL) - - _SETUP_EXTRACT_NODE_MODULES_RECIPE(${MODDIR}) } # Used as inputs in TS_COMPILE through `$_AS_HIDDEN_INPUTS(IN $TS_INPUT_FILES)` diff --git a/build/conf/ts/ts_test.conf b/build/conf/ts/ts_test.conf index 273a8a5687..cd5dc172f1 100644 --- a/build/conf/ts/ts_test.conf +++ b/build/conf/ts/ts_test.conf @@ -105,15 +105,17 @@ macro _TS_TEST_FOR_ARGS(FOR_MOD, RELATIVE?"${CURDIR}":"${ARCADIA_ROOT}") { } macro _SETUP_EXTRACT_NODE_MODULES_RECIPE(FOR_PATH) { - DEPENDS(devtools/frontend_build_platform/nots/recipes/extract_node_modules) USE_RECIPE(devtools/frontend_build_platform/nots/recipes/extract_node_modules/recipe $FOR_PATH workspace_node_modules.tar) } macro _SETUP_EXTRACT_OUTPUT_TARS_RECIPE(FOR_PATH) { - DEPENDS(devtools/frontend_build_platform/nots/recipes/extract_output_tars) USE_RECIPE(devtools/frontend_build_platform/nots/recipes/extract_output_tars/recipe $FOR_PATH) } +macro _SETUP_INSTALL_NODE_MODULES_RECIPE() { + USE_RECIPE(devtools/frontend_build_platform/nots/recipes/install_node_modules/recipe $NOTS_TOOL_BASE_ARGS) +} + ### @usage: TS_TEST_CONFIG(Path) ### @@ -167,3 +169,15 @@ macro TS_TEST_DATA(RENAME="", GLOBS...) { macro TS_TEST_DEPENDS_ON_BUILD() { ENABLE(_TS_TEST_DEPENDS_ON_BUILD) } + +_TS_TYPECHECK_VALUE=none +_TS_TYPECHECK_TSCONFIG= + +macro NO_TS_TYPECHECK() { + SET(_TS_TYPECHECK_VALUE none) +} + +macro TS_TYPECHECK(TS_CONFG="") { + ENABLE(_TS_TYPECHECK_VALUE) + SET(_TS_TYPECHECK_TSCONFIG $TS_CONFG) +} diff --git a/build/plugins/lib/test_const/__init__.py b/build/plugins/lib/test_const/__init__.py index 79783a0218..819a8b7012 100644 --- a/build/plugins/lib/test_const/__init__.py +++ b/build/plugins/lib/test_const/__init__.py @@ -74,6 +74,7 @@ STYLE_TEST_TYPES = [ "flake8", "black", "ruff", + "tsc_typecheck", ] REGULAR_TEST_TYPES = [ diff --git a/build/plugins/nots.py b/build/plugins/nots.py index d9c951f54e..4aa30eae51 100644 --- a/build/plugins/nots.py +++ b/build/plugins/nots.py @@ -2,7 +2,7 @@ import os import ymake import ytest -from _common import get_norm_unit_path, rootrel_arc_src, to_yesno +from _common import resolve_common_const, get_norm_unit_path, rootrel_arc_src, to_yesno # 1 is 60 files per chunk for TIMEOUT(60) - default timeout for SIZE(SMALL) @@ -32,7 +32,7 @@ class PluginLogger(object): parts.append(m if isinstance(m, str) else repr(m)) # cyan color (code 36) for messages - return "\033[0;32m{}\033[0;49m \033[0;36m{}\033[0;49m".format(self.prefix, " ".join(parts)) + return "\033[0;32m{}\033[0;49m\n\033[0;36m{}\033[0;49m".format(self.prefix, " ".join(parts)) def info(self, *messages): if self.unit: @@ -251,6 +251,7 @@ def on_ts_configure(unit, *tsconfig_paths): _filter_inputs_by_rules_from_tsconfig(unit, tsconfig) _setup_eslint(unit) + _setup_tsc_typecheck(unit, tsconfig_paths) def __set_append(unit, var_name, value): @@ -362,6 +363,8 @@ def _setup_eslint(unit): return unit.on_peerdir_ts_resource("eslint") + user_recipes = unit.get("TEST_RECIPES_VALUE") + unit.on_setup_extract_node_modules_recipe(unit.get("MODDIR")) mod_dir = unit.get("MODDIR") lint_files = _resolve_module_files(unit, mod_dir, lint_files) @@ -372,15 +375,54 @@ def _setup_eslint(unit): } _add_test(unit, "eslint", lint_files, deps, test_record, mod_dir) + unit.set(["TEST_RECIPES_VALUE", user_recipes]) + + +def _setup_tsc_typecheck(unit, tsconfig_paths: list[str]): + if not _is_tests_enabled(unit): + return + + if unit.get("_TS_TYPECHECK_VALUE") == "none": + return + + typecheck_files = ytest.get_values_list(unit, "TS_INPUT_FILES") + if not typecheck_files: + return + + tsconfig_path = tsconfig_paths[0] + + if len(tsconfig_paths) > 1: + tsconfig_path = unit.get("_TS_TYPECHECK_TSCONFIG") + if not tsconfig_path: + macros = " or ".join([f"TS_TYPECHECK({p})" for p in tsconfig_paths]) + raise Exception(f"Module uses several tsconfig files, specify which one to use for typecheck: {macros}") + abs_tsconfig_path = unit.resolve(unit.resolve_arc_path(tsconfig_path)) + if not abs_tsconfig_path: + raise Exception(f"tsconfig for typecheck not found: {tsconfig_path}") + + unit.on_peerdir_ts_resource("typescript") + user_recipes = unit.get("TEST_RECIPES_VALUE") + unit.on_setup_install_node_modules_recipe() + unit.on_setup_extract_output_tars_recipe([unit.get("MODDIR")]) + + _add_test( + unit, + test_type="tsc_typecheck", + test_files=[resolve_common_const(f) for f in typecheck_files], + deps=_create_pm(unit).get_peers_from_package_json(), + test_record={"TS_CONFIG_PATH": tsconfig_path}, + test_cwd=unit.get("MODDIR"), + ) + unit.set(["TEST_RECIPES_VALUE", user_recipes]) def _resolve_module_files(unit, mod_dir, file_paths): + mod_dir_with_sep_len = len(mod_dir) + 1 resolved_files = [] for path in file_paths: resolved = rootrel_arc_src(path, unit) if resolved.startswith(mod_dir): - mod_dir_with_sep_len = len(mod_dir) + 1 resolved = resolved[mod_dir_with_sep_len:] resolved_files.append(resolved) @@ -393,17 +435,26 @@ def _add_test(unit, test_type, test_files, deps=None, test_record=None, test_cwd def sort_uniq(text): return sorted(set(text)) + recipes_lines = ytest.format_recipes(unit.get("TEST_RECIPES_VALUE")).strip().splitlines() + if recipes_lines: + deps = deps or [] + deps.extend([os.path.dirname(r.strip().split(" ")[0]) for r in recipes_lines]) + if deps: - unit.ondepends(sort_uniq(deps)) + joined_deps = "\n".join(deps) + logger.info(f"{test_type} deps: \n{joined_deps}") + unit.ondepends(deps) test_dir = get_norm_unit_path(unit) full_test_record = { + # Key to discover suite (see devtools/ya/test/explore/__init__.py#gen_suite) + "SCRIPT-REL-PATH": test_type, + # Test name as shown in PR check, should be unique inside one module "TEST-NAME": test_type.lower(), "TEST-TIMEOUT": unit.get("TEST_TIMEOUT") or "", "TEST-ENV": ytest.prepare_env(unit.get("TEST_ENV_VALUE")), "TESTED-PROJECT-NAME": os.path.splitext(unit.filename())[0], "TEST-RECIPES": ytest.prepare_recipes(unit.get("TEST_RECIPES_VALUE")), - "SCRIPT-REL-PATH": test_type, "SOURCE-FOLDER-PATH": test_dir, "BUILD-FOLDER-PATH": test_dir, "BINARY-PATH": os.path.join(test_dir, unit.filename()), diff --git a/build/plugins/ytest.py b/build/plugins/ytest.py index 23b63cc69f..a290b831f3 100644 --- a/build/plugins/ytest.py +++ b/build/plugins/ytest.py @@ -43,10 +43,18 @@ def ontest_data(unit, *args): ymake.report_configure_error("TEST_DATA is removed in favour of DATA") -def prepare_recipes(data): +def format_recipes(data: str | None) -> str: + if not data: + return "" + data = data.replace('"USE_RECIPE_DELIM"', "\n") data = data.replace("$TEST_RECIPES_VALUE", "") - return base64.b64encode(six.ensure_binary(data or "")) + return data + + +def prepare_recipes(data: str | None) -> str: + formatted = format_recipes(data) + return base64.b64encode(six.ensure_binary(formatted)) def prepare_env(data): |