diff --git a/conda_smithy/configure_feedstock.py b/conda_smithy/configure_feedstock.py index aba123d42..ef8c9f9c6 100644 --- a/conda_smithy/configure_feedstock.py +++ b/conda_smithy/configure_feedstock.py @@ -693,12 +693,63 @@ def _collapse_subpackage_variants( logger.debug("final used_key_values %s", pprint.pformat(used_key_values)) + configs = break_up_top_level_values(top_level_loop_vars, used_key_values) + + # return (configs, top_level_loop_vars) + return ( - break_up_top_level_values(top_level_loop_vars, used_key_values), + [ + config + for config in configs + if not _is_config_skipped(config, top_level_loop_vars, list_of_metas) + ], top_level_loop_vars, ) +def _is_config_skipped(config, top_level_loop_vars, list_of_metas): + trimmed_config = {loop_var: config[loop_var] for loop_var in top_level_loop_vars} + logger.debug("checking config: %s", trimmed_config) + for i, meta in enumerate(list_of_metas): + trimmed_meta = { + loop_var: meta.config.variant.get(loop_var) + for loop_var in top_level_loop_vars + } + logger.debug(" checking in meta: %s", trimmed_meta) + for loop_var in top_level_loop_vars: + variant = meta.config.variant + if loop_var not in variant: + logger.debug( + " skipping meta because %s is not in meta variant", loop_var + ) + break + if isinstance(variant[loop_var], (list, set)) and set( + config[loop_var] + ) - set(variant[loop_var]): + logger.debug( + " skipping meta because %s in meta variant is %s, but in config is %s", + loop_var, + variant[loop_var], + config[loop_var], + ) + break + if isinstance(variant[loop_var], (int, float, str)) and set( + config[loop_var] + ) - set([variant[loop_var]]): + logger.debug( + " skipping meta because %s in meta variant is %s and in config is %s", + loop_var, + [variant[loop_var]], + config[loop_var], + ) + break + else: + logger.debug(" FOUND! meta variant matches config") + return False + logger.debug(" SKIPPED!") + return True + + def _yaml_represent_ordereddict(yaml_representer, data): # represent_dict processes dict-likes with a .sort() method or plain iterables of key-value # pairs. Only for the latter it never sorts and retains the order of the OrderedDict. diff --git a/news/2434-skipped-matrix.rst b/news/2434-skipped-matrix.rst new file mode 100644 index 000000000..f62da7153 --- /dev/null +++ b/news/2434-skipped-matrix.rst @@ -0,0 +1,23 @@ +**Added:** + +* + +**Changed:** + +* + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* Fix configuration generation by respecting additive ``skip`` statements properly. (#1617 via #2434) + +**Security:** + +* diff --git a/tests/recipes/skip_rerenders_ok/conda_build_config.yaml b/tests/recipes/skip_rerenders_ok/conda_build_config.yaml new file mode 100644 index 000000000..35d40156a --- /dev/null +++ b/tests/recipes/skip_rerenders_ok/conda_build_config.yaml @@ -0,0 +1,7 @@ +# https://github.com/conda-forge/conda-smithy/issues/1617 +mpi: + - openmpi + - nompi +double: + - "no" + - "yes" diff --git a/tests/recipes/skip_rerenders_ok/meta.yaml b/tests/recipes/skip_rerenders_ok/meta.yaml new file mode 100644 index 000000000..5ccafcfcf --- /dev/null +++ b/tests/recipes/skip_rerenders_ok/meta.yaml @@ -0,0 +1,11 @@ +package: + name: skip-rerenders-ok + version: 1.0 + +build: + # Only build for linux so we get up-to 4 configs (as per the conda-build-config-file) + skip: true # [not linux64] + # With this one skip, we remove one entry from the 2x2 matrix + skip: true # [mpi == "nompi" and double == "yes"] + +about: {} diff --git a/tests/test_cli.py b/tests/test_cli.py index e4a8aa4a5..4b724b919 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,6 +3,7 @@ import os import shutil import subprocess +from pathlib import Path from textwrap import dedent import pytest @@ -349,6 +350,39 @@ def test_render_variant_mismatches(testing_workdir): assert data["a"] == data["b"] +def test_render_skipped_variants(testing_workdir): + """ + Regression test for https://github.com/conda-forge/conda-smithy/issues/1617 + """ + parser = argparse.ArgumentParser() + subparser = parser.add_subparsers() + init_obj = cli.Init(subparser) + regen_obj = cli.Regenerate(subparser) + _thisdir = os.path.abspath(os.path.dirname(__file__)) + recipe = os.path.join(_thisdir, "recipes", "skip_rerenders_ok") + feedstock_dir = os.path.join(testing_workdir, "test-skipped-variants-feedstock") + args = InitArgs( + recipe_directory=recipe, + feedstock_directory=feedstock_dir, + temporary_directory=os.path.join(recipe, "temp"), + ) + init_obj(args) + args = RegenerateArgs( + feedstock_directory=feedstock_dir, + feedstock_config=None, + commit=False, + no_check_uptodate=True, + exclusive_config_file="recipe/conda_build_config.yaml", + check=False, + temporary_directory=os.path.join(recipe, "temp"), + ) + regen_obj(args) + + # We skip one config out of the 2x2 matrix, so we expect three configs + configs = list(Path(feedstock_dir, ".ci_support").glob("*.yaml")) + assert len(configs) == 3 + + def test_render_readme_with_v1_recipe_name(testing_workdir): parser = argparse.ArgumentParser() subparser = parser.add_subparsers()