From 8c4ac88be9ebbe61442116b9937fa09abb214954 Mon Sep 17 00:00:00 2001 From: Julian Hofer Date: Thu, 2 Apr 2026 15:02:54 +0200 Subject: [PATCH 1/4] Fix pixi.toml syntax --- pixi.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixi.toml b/pixi.toml index fba1167..f3dc4a9 100644 --- a/pixi.toml +++ b/pixi.toml @@ -1,4 +1,4 @@ -[project] +[workspace] name = "conda-recipe-v2-schema" authors = ["Bas Zalmstra "] channels = ["conda-forge"] From 6ca865d554ed000dd2e4d1f965f1f470cb2cb3e2 Mon Sep 17 00:00:00 2001 From: Julian Hofer Date: Thu, 2 Apr 2026 12:22:40 +0000 Subject: [PATCH 2/4] fix: add fields missing from schema that are present in implementation --- conda_recipe_v2_schema/model.py | 58 ++++ schema.json | 461 +++++++++++++++++++++++++++++++- 2 files changed, 515 insertions(+), 4 deletions(-) diff --git a/conda_recipe_v2_schema/model.py b/conda_recipe_v2_schema/model.py index 981c379..2577778 100644 --- a/conda_recipe_v2_schema/model.py +++ b/conda_recipe_v2_schema/model.py @@ -94,6 +94,17 @@ class BaseSource(StrictBaseModel): ) +class AttestationConfig(StrictBaseModel): + bundle_url: NonEmptyStr | None = Field( + default=None, + description="URL to download the attestation bundle from (e.g., .sigstore.json file). Auto-derived for PyPI sources if not specified.", + ) + publishers: list[NonEmptyStr] = Field( + default=[], + description="Publisher identities to verify (e.g., 'github:owner/repo'). All specified publishers must match.", + ) + + class UrlSource(BaseSource): url: NonEmptyStr | list[NonEmptyStr] = Field( ..., @@ -105,6 +116,10 @@ class UrlSource(BaseSource): None, description="A file name to rename the downloaded file to (does not apply to archives).", ) + attestation: AttestationConfig | None = Field( + default=None, + description="Optional attestation verification configuration.", + ) class BaseGitSource(BaseSource): @@ -113,6 +128,14 @@ class BaseGitSource(BaseSource): None, description="A value to use when shallow cloning the repository." ) lfs: bool = Field(default=False, description="Should we LFS files be checked out as well") + submodules: bool | None = Field( + default=None, + description="Whether to recursively initialize and update submodules.", + ) + expected_commit: NonEmptyStr | None = Field( + default=None, + description="An expected commit hash to verify after checkout.", + ) class GitRev(BaseGitSource): @@ -192,6 +215,14 @@ class ScriptEnv(StrictBaseModel): ) +class PostProcess(StrictBaseModel): + files: ConditionalList[NonEmptyStr] = Field( + ..., description="Files to apply post-processing to" + ) + regex: str | JinjaExpr = Field(..., description="Regular expression pattern to match") + replacement: str | JinjaExpr = Field(..., description="Replacement string") + + class Build(StrictBaseModel): number: UnsignedInt | JinjaExpr | None = Field( 0, @@ -251,6 +282,11 @@ class Build(StrictBaseModel): None, description="Glob patterns to include or exclude files from the package." ) + post_process: ConditionalList[PostProcess] = Field( + [], + description="Post-processing operations using regex replacements on files.", + ) + class BaseScript(StrictBaseModel): interpreter: NonEmptyStr | None = Field( @@ -265,6 +301,10 @@ class BaseScript(StrictBaseModel): default=[], description="Secrets that are set as environment variables but never shown in the logs or the environment.", ) + cwd: NonEmptyStr | None = Field( + default=None, + description="The working directory to use when executing the script.", + ) class FileScript(BaseScript): @@ -507,6 +547,16 @@ class RTestElement(StrictBaseModel): r: RTestElementInner = Field(..., description="R specific test configuration") +class RubyTestElementInner(StrictBaseModel): + requires: ConditionalList[NonEmptyStr] = Field( + ..., description="A list of Ruby modules to check after having installed the built package." + ) + + +class RubyTestElement(StrictBaseModel): + ruby: RubyTestElementInner = Field(..., description="Ruby specific test configuration") + + class DownstreamTestElement(StrictBaseModel): downstream: MatchSpec = Field( ..., @@ -567,6 +617,7 @@ class PackageContentTest(StrictBaseModel): | PythonTestElement | PerlTestElement | RTestElement + | RubyTestElement | DownstreamTestElement | PackageContentTest ) @@ -599,6 +650,9 @@ class About(StrictBaseModel): license_file: ConditionalList[PathNoBackslash] | None = Field( None, description="Paths to the license files of this package." ) + license_family: str | None = Field( + None, description="The license family (deprecated, but still used in some recipes)." + ) # Text summary: str | None = Field(None, description="A short description of the package.") @@ -760,6 +814,10 @@ class ComplexRecipe(BaseRecipe): ..., description="A list of outputs that are generated for this recipe." ) + tests: ConditionalList[TestElement] | None = Field( + None, description="Top-level tests that are inherited by outputs" + ) + class SimpleRecipe(BaseRecipe): package: SimplePackage = Field(..., description="The package name and version.") diff --git a/schema.json b/schema.json index c3ba529..a442418 100644 --- a/schema.json +++ b/schema.json @@ -92,6 +92,19 @@ "description": "Paths to the license files of this package.", "title": "License File" }, + "license_family": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The license family (deprecated, but still used in some recipes).", + "title": "License Family" + }, "summary": { "anyOf": [ { @@ -137,6 +150,37 @@ "title": "About", "type": "object" }, + "AttestationConfig": { + "additionalProperties": false, + "properties": { + "bundle_url": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "URL to download the attestation bundle from (e.g., .sigstore.json file). Auto-derived for PyPI sources if not specified.", + "title": "Bundle Url" + }, + "publishers": { + "default": [], + "description": "Publisher identities to verify (e.g., 'github:owner/repo'). All specified publishers must match.", + "items": { + "minLength": 1, + "type": "string" + }, + "title": "Publishers", + "type": "array" + } + }, + "title": "AttestationConfig", + "type": "object" + }, "BaseGitSource": { "additionalProperties": false, "properties": { @@ -212,6 +256,33 @@ "description": "Should we LFS files be checked out as well", "title": "Lfs", "type": "boolean" + }, + "submodules": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Whether to recursively initialize and update submodules.", + "title": "Submodules" + }, + "expected_commit": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "An expected commit hash to verify after checkout.", + "title": "Expected Commit" } }, "required": [ @@ -541,6 +612,32 @@ "default": null, "description": "Glob patterns to include or exclude files from the package.", "title": "Files" + }, + "post_process": { + "anyOf": [ + { + "$ref": "#/$defs/PostProcess" + }, + { + "$ref": "#/$defs/IfStatement" + }, + { + "items": { + "anyOf": [ + { + "$ref": "#/$defs/PostProcess" + }, + { + "$ref": "#/$defs/IfStatement" + } + ] + }, + "type": "array" + } + ], + "default": [], + "description": "Post-processing operations using regex replacements on files.", + "title": "Post Process" } }, "title": "Build", @@ -868,6 +965,71 @@ ], "description": "A list of outputs that are generated for this recipe.", "title": "Outputs" + }, + "tests": { + "anyOf": [ + { + "$ref": "#/$defs/ScriptTestElement" + }, + { + "$ref": "#/$defs/PythonTestElement" + }, + { + "$ref": "#/$defs/PerlTestElement" + }, + { + "$ref": "#/$defs/RTestElement" + }, + { + "$ref": "#/$defs/RubyTestElement" + }, + { + "$ref": "#/$defs/DownstreamTestElement" + }, + { + "$ref": "#/$defs/PackageContentTest" + }, + { + "$ref": "#/$defs/IfStatement" + }, + { + "items": { + "anyOf": [ + { + "$ref": "#/$defs/ScriptTestElement" + }, + { + "$ref": "#/$defs/PythonTestElement" + }, + { + "$ref": "#/$defs/PerlTestElement" + }, + { + "$ref": "#/$defs/RTestElement" + }, + { + "$ref": "#/$defs/RubyTestElement" + }, + { + "$ref": "#/$defs/DownstreamTestElement" + }, + { + "$ref": "#/$defs/PackageContentTest" + }, + { + "$ref": "#/$defs/IfStatement" + } + ] + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Top-level tests that are inherited by outputs", + "title": "Tests" } }, "required": [ @@ -930,6 +1092,20 @@ "description": "Secrets that are set as environment variables but never shown in the logs or the environment.", "title": "Secrets" }, + "cwd": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The working directory to use when executing the script.", + "title": "Cwd" + }, "content": { "anyOf": [ { @@ -1366,6 +1542,20 @@ "description": "Secrets that are set as environment variables but never shown in the logs or the environment.", "title": "Secrets" }, + "cwd": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "The working directory to use when executing the script.", + "title": "Cwd" + }, "file": { "anyOf": [ { @@ -1594,6 +1784,33 @@ "title": "Lfs", "type": "boolean" }, + "submodules": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Whether to recursively initialize and update submodules.", + "title": "Submodules" + }, + "expected_commit": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "An expected commit hash to verify after checkout.", + "title": "Expected Commit" + }, "branch": { "description": "Branch to check out", "minLength": 1, @@ -1684,6 +1901,33 @@ "title": "Lfs", "type": "boolean" }, + "submodules": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Whether to recursively initialize and update submodules.", + "title": "Submodules" + }, + "expected_commit": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "An expected commit hash to verify after checkout.", + "title": "Expected Commit" + }, "rev": { "description": "Revision to checkout to (hash or ref)", "minLength": 1, @@ -1774,6 +2018,33 @@ "title": "Lfs", "type": "boolean" }, + "submodules": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Whether to recursively initialize and update submodules.", + "title": "Submodules" + }, + "expected_commit": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "An expected commit hash to verify after checkout.", + "title": "Expected Commit" + }, "tag": { "description": "Tag to checkout", "minLength": 1, @@ -1941,7 +2212,7 @@ "title": "IfStatement[Annotated[str, StringConstraints]]", "type": "object" }, - "IfStatement_Union_ScriptTestElement__PythonTestElement__PerlTestElement__RTestElement__DownstreamTestElement__PackageContentTest__": { + "IfStatement_Union_ScriptTestElement__PythonTestElement__PerlTestElement__RTestElement__RubyTestElement__DownstreamTestElement__PackageContentTest__": { "additionalProperties": false, "properties": { "if": { @@ -1962,6 +2233,9 @@ { "$ref": "#/$defs/RTestElement" }, + { + "$ref": "#/$defs/RubyTestElement" + }, { "$ref": "#/$defs/DownstreamTestElement" }, @@ -1983,6 +2257,9 @@ { "$ref": "#/$defs/RTestElement" }, + { + "$ref": "#/$defs/RubyTestElement" + }, { "$ref": "#/$defs/DownstreamTestElement" }, @@ -2010,6 +2287,9 @@ { "$ref": "#/$defs/RTestElement" }, + { + "$ref": "#/$defs/RubyTestElement" + }, { "$ref": "#/$defs/DownstreamTestElement" }, @@ -2031,6 +2311,9 @@ { "$ref": "#/$defs/RTestElement" }, + { + "$ref": "#/$defs/RubyTestElement" + }, { "$ref": "#/$defs/DownstreamTestElement" }, @@ -2053,7 +2336,7 @@ "if", "then" ], - "title": "IfStatement[Union[ScriptTestElement, PythonTestElement, PerlTestElement, RTestElement, DownstreamTestElement, PackageContentTest]]", + "title": "IfStatement[Union[ScriptTestElement, PythonTestElement, PerlTestElement, RTestElement, RubyTestElement, DownstreamTestElement, PackageContentTest]]", "type": "object" }, "IfStatement_Union_UrlSource__GitRev__GitTag__GitBranch__BaseGitSource__LocalSource__": { @@ -2560,6 +2843,9 @@ { "$ref": "#/$defs/RTestElement" }, + { + "$ref": "#/$defs/RubyTestElement" + }, { "$ref": "#/$defs/DownstreamTestElement" }, @@ -2567,7 +2853,7 @@ "$ref": "#/$defs/PackageContentTest" }, { - "$ref": "#/$defs/IfStatement_Union_ScriptTestElement__PythonTestElement__PerlTestElement__RTestElement__DownstreamTestElement__PackageContentTest__" + "$ref": "#/$defs/IfStatement_Union_ScriptTestElement__PythonTestElement__PerlTestElement__RTestElement__RubyTestElement__DownstreamTestElement__PackageContentTest__" }, { "items": { @@ -2584,6 +2870,9 @@ { "$ref": "#/$defs/RTestElement" }, + { + "$ref": "#/$defs/RubyTestElement" + }, { "$ref": "#/$defs/DownstreamTestElement" }, @@ -2591,7 +2880,7 @@ "$ref": "#/$defs/PackageContentTest" }, { - "$ref": "#/$defs/IfStatement_Union_ScriptTestElement__PythonTestElement__PerlTestElement__RTestElement__DownstreamTestElement__PackageContentTest__" + "$ref": "#/$defs/IfStatement_Union_ScriptTestElement__PythonTestElement__PerlTestElement__RTestElement__RubyTestElement__DownstreamTestElement__PackageContentTest__" } ] }, @@ -2960,6 +3249,32 @@ "description": "Glob patterns to include or exclude files from the package.", "title": "Files" }, + "post_process": { + "anyOf": [ + { + "$ref": "#/$defs/PostProcess" + }, + { + "$ref": "#/$defs/IfStatement" + }, + { + "items": { + "anyOf": [ + { + "$ref": "#/$defs/PostProcess" + }, + { + "$ref": "#/$defs/IfStatement" + } + ] + }, + "type": "array" + } + ], + "default": [], + "description": "Post-processing operations using regex replacements on files.", + "title": "Post Process" + }, "cache_only": { "default": false, "deprecated": true, @@ -3256,6 +3571,71 @@ "title": "PerlTestElementInner", "type": "object" }, + "PostProcess": { + "additionalProperties": false, + "properties": { + "files": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "$ref": "#/$defs/IfStatement" + }, + { + "items": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "$ref": "#/$defs/IfStatement" + } + ] + }, + "type": "array" + } + ], + "description": "Files to apply post-processing to", + "title": "Files" + }, + "regex": { + "anyOf": [ + { + "type": "string" + }, + { + "pattern": "\\$\\{\\{.*\\}\\}", + "type": "string" + } + ], + "description": "Regular expression pattern to match", + "title": "Regex" + }, + "replacement": { + "anyOf": [ + { + "type": "string" + }, + { + "pattern": "\\$\\{\\{.*\\}\\}", + "type": "string" + } + ], + "description": "Replacement string", + "title": "Replacement" + } + }, + "required": [ + "files", + "regex", + "replacement" + ], + "title": "PostProcess", + "type": "object" + }, "PrefixDetection": { "additionalProperties": false, "properties": { @@ -3807,6 +4187,61 @@ "title": "Requirements", "type": "object" }, + "RubyTestElement": { + "additionalProperties": false, + "properties": { + "ruby": { + "allOf": [ + { + "$ref": "#/$defs/RubyTestElementInner" + } + ], + "description": "Ruby specific test configuration" + } + }, + "required": [ + "ruby" + ], + "title": "RubyTestElement", + "type": "object" + }, + "RubyTestElementInner": { + "additionalProperties": false, + "properties": { + "requires": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "$ref": "#/$defs/IfStatement" + }, + { + "items": { + "anyOf": [ + { + "minLength": 1, + "type": "string" + }, + { + "$ref": "#/$defs/IfStatement" + } + ] + }, + "type": "array" + } + ], + "description": "A list of Ruby modules to check after having installed the built package.", + "title": "Requires" + } + }, + "required": [ + "requires" + ], + "title": "RubyTestElementInner", + "type": "object" + }, "RunExports": { "additionalProperties": false, "properties": { @@ -4190,6 +4625,9 @@ { "$ref": "#/$defs/RTestElement" }, + { + "$ref": "#/$defs/RubyTestElement" + }, { "$ref": "#/$defs/DownstreamTestElement" }, @@ -4214,6 +4652,9 @@ { "$ref": "#/$defs/RTestElement" }, + { + "$ref": "#/$defs/RubyTestElement" + }, { "$ref": "#/$defs/DownstreamTestElement" }, @@ -4741,6 +5182,18 @@ "default": null, "description": "A file name to rename the downloaded file to (does not apply to archives).", "title": "File Name" + }, + "attestation": { + "anyOf": [ + { + "$ref": "#/$defs/AttestationConfig" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional attestation verification configuration." } }, "required": [ From 157bf3b164cfaa7097f6518751676207315b2f12 Mon Sep 17 00:00:00 2001 From: Julian Hofer Date: Thu, 2 Apr 2026 12:24:06 +0000 Subject: [PATCH 3/4] fix: remove schema fields not present in implementation --- conda_recipe_v2_schema/model.py | 66 +---- schema.json | 503 +------------------------------- 2 files changed, 7 insertions(+), 562 deletions(-) diff --git a/conda_recipe_v2_schema/model.py b/conda_recipe_v2_schema/model.py index 2577778..a84318d 100644 --- a/conda_recipe_v2_schema/model.py +++ b/conda_recipe_v2_schema/model.py @@ -201,20 +201,6 @@ class RunExports(StrictBaseModel): ) -class ScriptEnv(StrictBaseModel): - passthrough: ConditionalList[NonEmptyStr] = Field( - [], - description="Environments variables to leak into the build environment from the host system. During build time these variables are recorded and stored in the package output. Use `secrets` for environment variables that should not be recorded.", - ) - env: dict[str, str] = Field( - {}, description="Environment variables to set in the build environment." - ) - secrets: ConditionalList[NonEmptyStr] = Field( - [], - description="Environment variables to leak into the build environment from the host system that contain sensitve information. Use with care because this might make recipes no longer reproducible on other machines.", - ) - - class PostProcess(StrictBaseModel): files: ConditionalList[NonEmptyStr] = Field( ..., description="Files to apply post-processing to" @@ -268,11 +254,6 @@ class Build(StrictBaseModel): description="Configuration to post-process dynamically linked libraries and executables", ) - link_options: LinkOptions | None = Field( - None, - description="Options that influence how a package behaves when it is installed or uninstalled.", - ) - prefix_detection: PrefixDetection | None = Field( None, description="Options that influence how the prefix replacement is done.", @@ -354,8 +335,6 @@ class Python(StrictBaseModel): default=[], description="Skip compiling pyc for some files" ) - disable_pip: bool | JinjaExpr = Field(default=False) - site_packages_path: str | JinjaExpr | None = Field( default=None, description="The path to the site-packages folder. This is advertised by Python to install noarch packages in the correct location. Only valid for a Python package.", @@ -433,18 +412,6 @@ class StagingRequirements(StrictBaseModel): ) -class LinkOptions(StrictBaseModel): - post_link_script: NonEmptyStr | None = Field( - None, - description="Script to execute after the package has been linked into an environment", - ) - pre_unlink_script: NonEmptyStr | None = Field( - None, - description="Script to execute before uninstalling the package from an environment", - ) - pre_link_message: NonEmptyStr | None = Field(None, description="Message to show before linking") - - ######################### # Requirements Section # ######################### @@ -627,13 +594,6 @@ class PackageContentTest(StrictBaseModel): ######### -class DescriptionFile(StrictBaseModel): - file: PathNoBackslash = Field( - ..., - description="Path in the source directory that contains the packages description. E.g. README.md", - ) - - class About(StrictBaseModel): # URLs homepage: AnyHttpUrl | None = Field(None, description="Url of the homepage of the package.") @@ -656,9 +616,9 @@ class About(StrictBaseModel): # Text summary: str | None = Field(None, description="A short description of the package.") - description: str | DescriptionFile | None = Field( + description: str | None = Field( None, - description="Extended description of the package or a file (usually a README).", + description="Extended description of the package.", ) prelink_message: str | None = None @@ -669,19 +629,6 @@ class About(StrictBaseModel): ########### -class OutputBuild(Build): - cache_only: bool = Field( - default=False, - deprecated="Use staging outputs instead.", - description="Do not output a package but use this output as an input to others.", - ) - cache_from: ConditionalList[NonEmptyStr] | None = Field( - None, - deprecated="Use staging outputs instead.", - description="Take the output of the specified outputs and copy them in the working directory.", - ) - - class StagingBuild(StrictBaseModel): script: str | Script | ConditionalList[NonEmptyStr] | None = Field( None, @@ -733,7 +680,7 @@ class Output(StrictBaseModel): source: ConditionalList[Source] | None = Field( None, description="The source items to be downloaded and used for the build." ) - build: OutputBuild | None = Field( + build: Build | None = Field( None, description="Describes how the package should be build." ) @@ -749,11 +696,6 @@ class Output(StrictBaseModel): description="A human readable description of the package information. The values here are merged with the top level `about` field.", ) - extra: dict[str, Any] | None = Field( - None, - description="An set of arbitrary values that are included in the package manifest. The values here are merged with the top level `extras` field.", - ) - ##################### # The Recipe itself # @@ -796,7 +738,7 @@ class Cache(StrictBaseModel): None, description="The dependencies needed at cache-build time." ) - build: OutputBuild | None = Field( + build: Build | None = Field( None, description="Describes how the package should be build." ) diff --git a/schema.json b/schema.json index a442418..81aa9ab 100644 --- a/schema.json +++ b/schema.json @@ -123,15 +123,12 @@ { "type": "string" }, - { - "$ref": "#/$defs/DescriptionFile" - }, { "type": "null" } ], "default": null, - "description": "Extended description of the package or a file (usually a README).", + "description": "Extended description of the package.", "title": "Description" }, "prelink_message": { @@ -558,18 +555,6 @@ "default": null, "description": "Configuration to post-process dynamically linked libraries and executables" }, - "link_options": { - "anyOf": [ - { - "$ref": "#/$defs/LinkOptions" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Options that influence how a package behaves when it is installed or uninstalled." - }, "prefix_detection": { "anyOf": [ { @@ -720,7 +705,7 @@ "build": { "anyOf": [ { - "$ref": "#/$defs/OutputBuild" + "$ref": "#/$defs/Build" }, { "type": "null" @@ -1138,22 +1123,6 @@ "title": "ContentScript", "type": "object" }, - "DescriptionFile": { - "additionalProperties": false, - "properties": { - "file": { - "description": "Path in the source directory that contains the packages description. E.g. README.md", - "pattern": "^[^\\\\]+$", - "title": "File", - "type": "string" - } - }, - "required": [ - "file" - ], - "title": "DescriptionFile", - "type": "object" - }, "DownstreamTestElement": { "additionalProperties": false, "properties": { @@ -2517,55 +2486,6 @@ "title": "IgnoreRunExports", "type": "object" }, - "LinkOptions": { - "additionalProperties": false, - "properties": { - "post_link_script": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Script to execute after the package has been linked into an environment", - "title": "Post Link Script" - }, - "pre_unlink_script": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Script to execute before uninstalling the package from an environment", - "title": "Pre Unlink Script" - }, - "pre_link_message": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Message to show before linking", - "title": "Pre Link Message" - } - }, - "title": "LinkOptions", - "type": "object" - }, "LocalSource": { "additionalProperties": false, "properties": { @@ -2805,7 +2725,7 @@ "build": { "anyOf": [ { - "$ref": "#/$defs/OutputBuild" + "$ref": "#/$defs/Build" }, { "type": "null" @@ -2909,415 +2829,11 @@ ], "default": null, "description": "A human readable description of the package information. The values here are merged with the top level `about` field." - }, - "extra": { - "anyOf": [ - { - "type": "object" - }, - { - "type": "null" - } - ], - "default": null, - "description": "An set of arbitrary values that are included in the package manifest. The values here are merged with the top level `extras` field.", - "title": "Extra" } }, "title": "Output", "type": "object" }, - "OutputBuild": { - "additionalProperties": false, - "properties": { - "number": { - "anyOf": [ - { - "minimum": 0, - "type": "integer" - }, - { - "pattern": "\\$\\{\\{.*\\}\\}", - "type": "string" - }, - { - "type": "null" - } - ], - "default": 0, - "description": "Build number to version current build in addition to package version", - "title": "Number" - }, - "string": { - "anyOf": [ - { - "type": "string" - }, - { - "pattern": "\\$\\{\\{.*\\}\\}", - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "The build string to identify build variant. This is usually omitted (can use `${{ hash }}`) variable here)", - "title": "String" - }, - "skip": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - }, - { - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - } - ] - }, - "type": "array" - }, - { - "type": "null" - } - ], - "default": null, - "description": "List of conditions under which to skip the build of the package. If any of these condition returns true the build is skipped.", - "title": "Skip" - }, - "noarch": { - "anyOf": [ - { - "enum": [ - "generic", - "python" - ], - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Can be either 'generic' or 'python'. A noarch 'python' package compiles .pyc files upon installation.", - "title": "Noarch" - }, - "script": { - "anyOf": [ - { - "type": "string" - }, - { - "$ref": "#/$defs/FileScript" - }, - { - "$ref": "#/$defs/ContentScript" - }, - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - }, - { - "items": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - } - ] - }, - "type": "array" - }, - { - "type": "null" - } - ], - "default": null, - "description": "The script to execute to invoke the build. If the string is a single line and ends with `.sh` or `.bat`, then we interpret it as a file.", - "title": "Script" - }, - "merge_build_and_host_envs": { - "anyOf": [ - { - "type": "boolean" - }, - { - "pattern": "\\$\\{\\{.*\\}\\}", - "type": "string" - }, - { - "type": "null" - } - ], - "default": false, - "description": "Merge the build and host environments (used in many R packages on Windows)", - "title": "Merge Build And Host Envs" - }, - "always_include_files": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - }, - { - "items": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - } - ] - }, - "type": "array" - } - ], - "default": [], - "description": "Files to be included even if they are present in the PREFIX before building.", - "title": "Always Include Files" - }, - "always_copy_files": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - }, - { - "items": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - } - ] - }, - "type": "array" - }, - { - "$ref": "#/$defs/GlobDict" - }, - { - "items": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - }, - { - "items": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - } - ] - }, - "type": "array" - }, - { - "$ref": "#/$defs/GlobDict" - } - ] - }, - "type": "array" - } - ], - "default": [], - "description": "Do not soft- or hard-link these files but instead always copy them into the environment", - "title": "Always Copy Files" - }, - "variant": { - "anyOf": [ - { - "$ref": "#/$defs/Variant" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Options that influence how the different variants are computed." - }, - "python": { - "anyOf": [ - { - "$ref": "#/$defs/Python" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Python specific build configuration" - }, - "dynamic_linking": { - "anyOf": [ - { - "$ref": "#/$defs/DynamicLinking" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Configuration to post-process dynamically linked libraries and executables" - }, - "link_options": { - "anyOf": [ - { - "$ref": "#/$defs/LinkOptions" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Options that influence how a package behaves when it is installed or uninstalled." - }, - "prefix_detection": { - "anyOf": [ - { - "$ref": "#/$defs/PrefixDetection" - }, - { - "type": "null" - } - ], - "default": null, - "description": "Options that influence how the prefix replacement is done." - }, - "files": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - }, - { - "items": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - } - ] - }, - "type": "array" - }, - { - "$ref": "#/$defs/GlobDict" - } - ], - "default": null, - "description": "Glob patterns to include or exclude files from the package.", - "title": "Files" - }, - "post_process": { - "anyOf": [ - { - "$ref": "#/$defs/PostProcess" - }, - { - "$ref": "#/$defs/IfStatement" - }, - { - "items": { - "anyOf": [ - { - "$ref": "#/$defs/PostProcess" - }, - { - "$ref": "#/$defs/IfStatement" - } - ] - }, - "type": "array" - } - ], - "default": [], - "description": "Post-processing operations using regex replacements on files.", - "title": "Post Process" - }, - "cache_only": { - "default": false, - "deprecated": true, - "description": "Do not output a package but use this output as an input to others.", - "title": "Cache Only", - "type": "boolean" - }, - "cache_from": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - }, - { - "items": { - "anyOf": [ - { - "minLength": 1, - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - } - ] - }, - "type": "array" - }, - { - "type": "null" - } - ], - "default": null, - "deprecated": true, - "description": "Take the output of the specified outputs and copy them in the working directory.", - "title": "Cache From" - } - }, - "title": "OutputBuild", - "type": "object" - }, "PackageContentTest": { "additionalProperties": false, "properties": { @@ -3842,19 +3358,6 @@ "description": "Skip compiling pyc for some files", "title": "Skip Pyc Compilation" }, - "disable_pip": { - "anyOf": [ - { - "type": "boolean" - }, - { - "pattern": "\\$\\{\\{.*\\}\\}", - "type": "string" - } - ], - "default": false, - "title": "Disable Pip" - }, "site_packages_path": { "anyOf": [ { From a0c7e2b325a88185cca410be7e0df9f50e0ac231 Mon Sep 17 00:00:00 2001 From: Julian Hofer Date: Thu, 2 Apr 2026 12:25:22 +0000 Subject: [PATCH 4/4] fix: correct type mismatches between schema and implementation --- conda_recipe_v2_schema/model.py | 10 +++------- schema.json | 21 --------------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/conda_recipe_v2_schema/model.py b/conda_recipe_v2_schema/model.py index a84318d..1711d74 100644 --- a/conda_recipe_v2_schema/model.py +++ b/conda_recipe_v2_schema/model.py @@ -353,7 +353,7 @@ class PrefixDetection(StrictBaseModel): ignore: bool | JinjaExpr | ConditionalList[PathNoBackslash] = Field( default=False, description="Ignore all or specific files for prefix replacement" ) - ignore_binary_files: bool | JinjaExpr | ConditionalList[PathNoBackslash] = Field( + ignore_binary_files: bool | JinjaExpr = Field( default=False, description="Whether to detect binary files with prefix or not" ) @@ -680,9 +680,7 @@ class Output(StrictBaseModel): source: ConditionalList[Source] | None = Field( None, description="The source items to be downloaded and used for the build." ) - build: Build | None = Field( - None, description="Describes how the package should be build." - ) + build: Build | None = Field(None, description="Describes how the package should be build.") requirements: Requirements | None = Field(None, description="The package dependencies") @@ -738,9 +736,7 @@ class Cache(StrictBaseModel): None, description="The dependencies needed at cache-build time." ) - build: Build | None = Field( - None, description="Describes how the package should be build." - ) + build: Build | None = Field(None, description="Describes how the package should be build.") class ComplexRecipe(BaseRecipe): diff --git a/schema.json b/schema.json index 81aa9ab..2a6e16d 100644 --- a/schema.json +++ b/schema.json @@ -3210,27 +3210,6 @@ { "pattern": "\\$\\{\\{.*\\}\\}", "type": "string" - }, - { - "pattern": "^[^\\\\]+$", - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - }, - { - "items": { - "anyOf": [ - { - "pattern": "^[^\\\\]+$", - "type": "string" - }, - { - "$ref": "#/$defs/IfStatement" - } - ] - }, - "type": "array" } ], "default": false,