aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzaverden <zaverden@yandex-team.com>2024-03-18 13:20:51 +0300
committerzaverden <zaverden@yandex-team.com>2024-03-18 15:09:21 +0300
commitebc6526bccdf9d2304b9eef3a0a9eaba8e7e38f7 (patch)
tree9a6a87cdab117790774a6e04ece2e058fc16a85b
parent29127cb44e4ff8ecde3924e1af7bb4213fda2a9f (diff)
downloadydb-ebc6526bccdf9d2304b9eef3a0a9eaba8e7e38f7.tar.gz
feat(TS_TYPECHECK): implementation
881bda4539ae182b7975c149191642ded49990e3
-rw-r--r--build/conf/ts/ts.conf2
-rw-r--r--build/conf/ts/ts_test.conf18
-rw-r--r--build/plugins/lib/test_const/__init__.py1
-rw-r--r--build/plugins/nots.py61
-rw-r--r--build/plugins/ytest.py12
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):