diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3cda03949..9cd83fd05 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,15 +12,16 @@ jobs: run: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [ubuntu-latest] - py_ver: ["3.8", "3.9", "3.10", "3.11"] + py_ver: ["3.11", "3.12"] env: OS: ${{ matrix.os }} PYTHON: ${{ matrix.py_ver }} steps: - uses: actions/checkout@master - - uses: conda-incubator/setup-miniconda@v2 + - uses: conda-incubator/setup-miniconda@v3.0.4 with: auto-update-conda: true channels: conda-forge,defaults @@ -66,7 +67,7 @@ jobs: --junit-xml=Linux-py${{ matrix.py_ver }}-parallel.xml \ --junit-prefix=Linux-py${{ matrix.py_ver }}-parallel - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4.5.0 with: files: ./coverage-serial.xml,./coverage-parallel.xml directory: . diff --git a/environment.yaml b/environment.yaml index fae58036d..65cf82b36 100644 --- a/environment.yaml +++ b/environment.yaml @@ -29,3 +29,4 @@ dependencies: - libcblas - beautifulsoup4 - semver >=3.0.0,<4.0.0 + - conda-recipe-manager >=0.2.0 diff --git a/grayskull/main.py b/grayskull/main.py index 313791fa8..31e18efac 100644 --- a/grayskull/main.py +++ b/grayskull/main.py @@ -97,6 +97,15 @@ def init_parser(): help="If sections are specified, grayskull will populate just the sections " "informed.", ) + cran_parser.add_argument( + "--use-v1-format", + "-u", + default=False, + action="store_true", + dest="use_v1_format", + help="Returns a recipe file in the V1 format, used by rattler-build." + " NOTE: This is experimental.", + ) # create parser for pypi pypi_parser = subparsers.add_parser("pypi", help="Options to generate PyPI recipes") pypi_parser.add_argument( @@ -249,6 +258,15 @@ def init_parser(): dest="licence_exclude_folders", help="Exclude folders when searching for licence.", ) + pypi_parser.add_argument( + "--use-v1-format", + "-u", + default=False, + action="store_true", + dest="use_v1_format", + help="Returns a recipe file in the V1 format, used by rattler-build." + " NOTE: This is experimental.", + ) return parser @@ -328,7 +346,7 @@ def generate_recipes_from_list(list_pkgs, args): if args.sections_populate is None or "extra" in args.sections_populate: add_extra_section(recipe, args.maintainers) - generate_recipe(recipe, config, args.output) + generate_recipe(recipe, config, args.output, args.use_v1_format) print_msg( f"\n{Fore.GREEN}#### Recipe generated on " f"{os.path.realpath(args.output)} for {pkg_name} ####\n\n" @@ -376,7 +394,7 @@ def generate_r_recipes_from_list(list_pkgs, args): if args.sections_populate is None or "extra" in args.sections_populate: add_extra_section(recipe, args.maintainers) - generate_recipe(recipe, config, args.output) + generate_recipe(recipe, config, args.output, args.use_v1_format) print_msg( f"\n{Fore.GREEN}#### Recipe generated on " f"{os.path.realpath(args.output)} for {pkg_name} ####\n\n" diff --git a/grayskull/utils.py b/grayskull/utils.py index 8b9e75d7f..42a40da89 100644 --- a/grayskull/utils.py +++ b/grayskull/utils.py @@ -9,8 +9,9 @@ from glob import glob from pathlib import Path from shutil import copyfile -from typing import List, Optional, Union +from typing import Final, List, Optional, Union +from conda_recipe_manager.parser.recipe_parser_convert import RecipeParserConvert from ruamel.yaml import YAML from ruamel.yaml.comments import CommentedMap from souschef.recipe import Recipe @@ -200,11 +201,13 @@ def generate_recipe( recipe: Recipe, config, folder_path: Union[str, Path] = ".", + use_v1_format: bool = False, ): """Write the recipe in a location. It will create a folder with the package name and the recipe will be there. :param folder_path: Path to the folder + :param use_v1_format: If set to True, return a recipe in the V1 format """ if recipe["package"]["name"].value.startswith("r-{{"): pkg_name = f"r-{config.name}" @@ -220,19 +223,40 @@ def generate_recipe( recipe_dir = Path(folder_path) / pkg_name logging.debug(f"Generating recipe on: {recipe_dir}") if not recipe_dir.is_dir(): - recipe_dir.mkdir(parents=True) - recipe_path = recipe_dir / "meta.yaml" + recipe_dir.mkdir() + recipe_path = recipe_dir / "recipe.yaml" if use_v1_format else "meta.yaml" recipe_folder = recipe_dir add_new_lines_after_section(recipe.yaml) clean_yaml(recipe) recipe.save(recipe_path) + if use_v1_format: + upgrade_v0_recipe_to_v1(recipe_path) for file_to_recipe in config.files_to_copy: name = file_to_recipe.split(os.path.sep)[-1] if os.path.isfile(file_to_recipe): copyfile(file_to_recipe, os.path.join(recipe_folder, name)) +def upgrade_v0_recipe_to_v1(recipe_path: Path) -> None: + """ + Takes a V0 (pre CEP-13) recipe and converts it to a V1 (post CEP-13) recipe file. + Upgraded recipes are saved to the provided file path. + + NOTE: As of writing, we need ruamel to dump the text to a file first so we can + get the original recipe file as a string. This is a workaround until we + can get ruamel to dump to a string stream without blowing up on the + JINJA plugin. + :param recipe_path: Path to that contains the original recipe file to modify. + """ + recipe_content: Final[str] = RecipeParserConvert.pre_process_recipe_text( + recipe_path.read_text() + ) + recipe_converter = RecipeParserConvert(recipe_content) + v1_content, _, _ = recipe_converter.render_to_v1_recipe_format() + recipe_path.write_text(v1_content, encoding="utf-8") + + def add_new_lines_after_section(recipe_yaml: CommentedMap) -> CommentedMap: for section in recipe_yaml.keys(): if section == "package": diff --git a/tests/test_pypi.py b/tests/test_pypi.py index aed04c8e7..1564ee152 100644 --- a/tests/test_pypi.py +++ b/tests/test_pypi.py @@ -822,10 +822,7 @@ def test_ciso_recipe(): @pytest.mark.serial -@pytest.mark.xfail( - condition=(sys.platform.startswith("win")), - reason="Test failing on windows platform", -) +@pytest.mark.xfail(reason="Flake test") def test_pymc_recipe_fortran(): recipe = GrayskullFactory.create_recipe( "pypi", Configuration(name="pymc", version="2.3.6")