Repository: conda-forge/conda-smithy

Issue:
Fix test_regenerate
This recipe has git reset --hard at the end. Will be a nasty surprise if somebody ran the tests without commiting their changes


Discussion:
Guessing this refers to [this line]( https://github.com/conda-forge/conda-smithy/blob/ac5114ca6fce044d8e6fa56d5f2a1b725eed0882/tests/test_cli.py#L104 )? We could create a temporary directory to run this test in instead of running it in `conda-smithy`.

Resolving patch:
diff --git a/conda_smithy/configure_feedstock.py b/conda_smithy/configure_feedstock.py
--- a/conda_smithy/configure_feedstock.py
+++ b/conda_smithy/configure_feedstock.py
@@ -160,9 +160,12 @@ def _collapse_subpackage_variants(list_of_metas):
     top_level_loop_vars = set()
 
     all_used_vars = set()
+    all_variants = set()
 
     for meta in list_of_metas:
         all_used_vars.update(meta.get_used_vars())
+        all_variants.update(conda_build.utils.HashableDict(v) for v in meta.config.variants)
+        all_variants.add(conda_build.utils.HashableDict(meta.config.variant))
 
     top_level_loop_vars = list_of_metas[0].get_used_loop_vars(force_top_level=True)
     top_level_vars = list_of_metas[0].get_used_vars(force_top_level=True)
@@ -174,30 +177,42 @@ def _collapse_subpackage_variants(list_of_metas):
     #     configuration per item, and we want a single dict, with each key representing many values
     squished_input_variants = conda_build.variants.list_of_dicts_to_dict_of_lists(
         list_of_metas[0].config.input_variants)
+    squished_used_variants = conda_build.variants.list_of_dicts_to_dict_of_lists(list(all_variants))
+
+    # these are variables that only occur in the top level, and thus won't show up as loops in the
+    #     above collection of all variants.  We need to transfer them from the input_variants.
+    preserve_top_level_loops = set(top_level_loop_vars) - set(all_used_vars)
 
     # Add in some variables that should always be preserved
     all_used_vars.update(set(('zip_keys', 'pin_run_as_build', 'MACOSX_DEPLOYMENT_TARGET')))
     all_used_vars.update(top_level_vars)
 
-    all_used_vars = {key: squished_input_variants[key]
-                     for key in all_used_vars if key in squished_input_variants}
+    used_key_values = {key: squished_input_variants[key]
+                       for key in all_used_vars if key in squished_input_variants}
+
+    for k, v in squished_used_variants.items():
+        if k in all_used_vars:
+            used_key_values[k] = v
+
+    for k in preserve_top_level_loops:
+        used_key_values[k] = squished_input_variants[k]
 
-    _trim_unused_zip_keys(all_used_vars)
-    _trim_unused_pin_run_as_build(all_used_vars)
+    _trim_unused_zip_keys(used_key_values)
+    _trim_unused_pin_run_as_build(used_key_values)
 
     # to deduplicate potentially zipped keys, we blow out the collection of variables, then
     #     do a set operation, then collapse it again
 
-    all_used_vars = conda_build.variants.dict_of_lists_to_list_of_dicts(
-        all_used_vars, extend_keys={'zip_keys', 'pin_run_as_build',
-                                    'ignore_version', 'ignore_build_only_deps'})
-    all_used_vars = set(conda_build.utils.HashableDict(variant) for variant in all_used_vars)
-    all_used_vars = conda_build.variants.list_of_dicts_to_dict_of_lists(list(all_used_vars))
+    used_key_values = conda_build.variants.dict_of_lists_to_list_of_dicts(
+        used_key_values, extend_keys={'zip_keys', 'pin_run_as_build',
+                                      'ignore_version', 'ignore_build_only_deps'})
+    used_key_values = set(conda_build.utils.HashableDict(variant) for variant in used_key_values)
+    used_key_values = conda_build.variants.list_of_dicts_to_dict_of_lists(list(used_key_values))
 
-    _trim_unused_zip_keys(all_used_vars)
-    _trim_unused_pin_run_as_build(all_used_vars)
+    _trim_unused_zip_keys(used_key_values)
+    _trim_unused_pin_run_as_build(used_key_values)
 
-    return break_up_top_level_values(top_level_loop_vars, all_used_vars), top_level_loop_vars
+    return break_up_top_level_values(top_level_loop_vars, used_key_values), top_level_loop_vars
 
 
 def dump_subspace_config_files(metas, root_path, output_name):
@@ -511,7 +526,7 @@ def render_README(jinja_env, forge_config, forge_dir):
     meta = conda_build.api.render(os.path.join(forge_dir, 'recipe'),
                                   variant_config_files=forge_config['variant_config_files'],
                                   permit_undefined_jinja=True, finalize=False,
-                                  bypass_env_check=True)[0][0]
+                                  bypass_env_check=True, trim_skip=False)[0][0]
     template = jinja_env.get_template('README.md.tmpl')
     target_fname = os.path.join(forge_dir, 'README.md')
     forge_config['noarch_python'] = meta.noarch


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -62,6 +62,11 @@ def config_yaml(testing_workdir):
             'python': ['2.7'],
         }
         yaml.dump(config, f, default_flow_style=False)
+    with open(os.path.join(testing_workdir, 'long_config.yaml'), 'w') as f:
+        config = {
+            'python': ['2.7', '3.5', '3.6'],
+        }
+        yaml.dump(config, f, default_flow_style=False)
     return testing_workdir
 
 
@@ -131,6 +136,53 @@ def py_recipe(config_yaml, request):
                                                                                   'config.yaml')]))
 
 
+@pytest.fixture(scope='function')
+def skipped_recipe(config_yaml, request):
+    os.makedirs(os.path.join(config_yaml, 'recipe'))
+    with open(os.path.join(config_yaml, 'recipe', 'meta.yaml'), 'w') as fh:
+        fh.write("""
+package:
+    name: skip-test
+    version: 1.0.0
+build:
+    skip: True
+requirements:
+    build:
+        - python
+    run:
+        - python
+about:
+    home: home
+    """)
+    return RecipeConfigPair(str(config_yaml),
+                            _load_forge_config(config_yaml,
+                                               variant_config_files=[os.path.join(config_yaml,
+                                                                                  'config.yaml')]))
+
+@pytest.fixture(scope='function')
+def python_skipped_recipe(config_yaml, request):
+    os.makedirs(os.path.join(config_yaml, 'recipe'))
+    with open(os.path.join(config_yaml, 'recipe', 'meta.yaml'), 'w') as fh:
+        fh.write("""
+package:
+    name: py-test
+    version: 1.0.0
+build:
+    skip: True   # [py36]
+requirements:
+    build:
+        - python
+    run:
+        - python
+about:
+    home: home
+    """)
+    return RecipeConfigPair(str(config_yaml),
+                            _load_forge_config(config_yaml,
+                                               variant_config_files=[os.path.join(config_yaml,
+                                                                                  'config.yaml')]))
+
+
 @pytest.fixture(scope='function')
 def jinja_env(request):
     tmplt_dir = os.path.join(conda_forge_content, 'templates')
diff --git a/tests/test_cli.py b/tests/test_cli.py
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -3,6 +3,7 @@
 import os
 import subprocess
 import yaml
+import shutil
 
 from conda_smithy import cli
 
@@ -36,9 +37,6 @@ def test_init(py_recipe):
     assert os.path.isdir(destination)
 
 
-#TODO: remove the 2 lines below. https://github.com/conda-forge/conda-smithy/issues/650
-import pytest
-@pytest.mark.xfail
 def test_init_multiple_output_matrix(testing_workdir):
     parser = argparse.ArgumentParser()
     subparser = parser.add_subparsers()
@@ -71,35 +69,34 @@ def test_init_multiple_output_matrix(testing_workdir):
     assert 'zlib' not in config
 
 
-def test_regenerate(py_recipe):
+def test_regenerate(py_recipe, testing_workdir):
     parser = argparse.ArgumentParser()
     subparser = parser.add_subparsers()
     regen_obj = cli.Regenerate(subparser)
     recipe = py_recipe.recipe
     feedstock_dir = os.path.join(_thisdir, 'recipes', 'click-test-feedstock')
-    args = RegenerateArgs(feedstock_directory=feedstock_dir,
+    dest_dir = os.path.join(testing_workdir, 'click-test-feedstock')
+    shutil.copytree(feedstock_dir, dest_dir)
+    subprocess.call('git init'.split(), cwd=dest_dir)
+    subprocess.call('git add *'.split(), cwd=dest_dir)
+    subprocess.call('git commit -m "init"'.split(), cwd=dest_dir)
+    matrix_folder = os.path.join(dest_dir, '.ci_support')
+
+    # original rendering was with py27, 36, no target_platform
+    assert len(os.listdir(matrix_folder)) == 7
+
+    args = RegenerateArgs(feedstock_directory=dest_dir,
                           commit=False,
                           variant_config_files=os.path.join(recipe, 'config.yaml'))
-    matrix_folder = os.path.join(feedstock_dir, '.ci_support')
+    regen_obj(args)
 
-    initial_commit = subprocess.check_output(['git', 'rev-parse', 'HEAD'],
-                                             cwd=feedstock_dir).strip()
-    try:
-        # original rendering was with py27, 36, no target_platform
-        assert len(os.listdir(matrix_folder)) == 7
-        regen_obj(args)
-        # should add 2, as the config.yaml adds in target_platform
-        assert len(os.listdir(matrix_folder)) == 9
+    # should add 2, as the config.yaml adds in target_platform
+    assert len(os.listdir(matrix_folder)) == 9
 
-        # reduce the python matrix and make sure the matrix files reflect the change
-        args = RegenerateArgs(feedstock_directory=feedstock_dir,
-                              commit=False,
-                              variant_config_files=os.path.join(recipe, 'short_config.yaml'))
-        matrix_folder = os.path.join(feedstock_dir, '.ci_support')
-        # one py ver, no target_platform  (tests that older configs don't stick around)
-        regen_obj(args)
-        assert len(os.listdir(matrix_folder)) == 4
-    finally:
-        # reset the test dir for next time
-        subprocess.call(['git', 'reset', '--hard', initial_commit],
-                        cwd=feedstock_dir)
+    # reduce the python matrix and make sure the matrix files reflect the change
+    args = RegenerateArgs(feedstock_directory=dest_dir,
+                          commit=False,
+                          variant_config_files=os.path.join(recipe, 'short_config.yaml'))
+    # one py ver, no target_platform  (tests that older configs don't stick around)
+    regen_obj(args)
+    assert len(os.listdir(matrix_folder)) == 4
diff --git a/tests/test_configure_feedstock.py b/tests/test_configure_feedstock.py
--- a/tests/test_configure_feedstock.py
+++ b/tests/test_configure_feedstock.py
@@ -97,11 +97,9 @@ def test_py_matrix_travis(py_recipe, jinja_env):
                               forge_dir=py_recipe.recipe)
     # this configuration should be run
     assert py_recipe.config['travis']['enabled']
-    # no appveyor.yaml should have been written.  Nothing else, either, since we only ran
-    #     appveyor render.  No matrix dir should exist.
     matrix_dir = os.path.join(py_recipe.recipe, '.ci_support')
     assert os.path.isdir(matrix_dir)
-    # single matrix entry - readme is generated later in main function
+    # two matrix enties - one per py ver
     assert len(os.listdir(matrix_dir)) == 2
 
 
@@ -134,3 +132,23 @@ def test_circle_with_empty_yum_reqs_raises(py_recipe, jinja_env):
         cnfgr_fdstk.render_circle(jinja_env=jinja_env,
                                   forge_config=py_recipe.config,
                                   forge_dir=py_recipe.recipe)
+
+
+def test_render_with_all_skipped_generates_readme(skipped_recipe, jinja_env):
+    cnfgr_fdstk.render_README(jinja_env=jinja_env,
+                              forge_config=skipped_recipe.config,
+                              forge_dir=skipped_recipe.recipe)
+
+
+def test_render_windows_with_skipped_python(python_skipped_recipe, jinja_env):
+    config = python_skipped_recipe.config
+    config['variant_config_files'] = [os.path.join(python_skipped_recipe.recipe, 'long_config.yaml')]
+    cnfgr_fdstk.render_appveyor(jinja_env=jinja_env,
+                                forge_config=config,
+                                forge_dir=python_skipped_recipe.recipe)
+    # this configuration should be skipped
+    assert python_skipped_recipe.config['appveyor']['enabled']
+
+    matrix_dir = os.path.join(python_skipped_recipe.recipe, '.ci_support')
+    # matrix has 2.7, 3.5, 3.6, but 3.6 is skipped.  Should be 2 entries.
+    assert len(os.listdir(matrix_dir)) == 2