Repository: conda/conda-build

Issue:
Recipes defining `outputs` without `package/version` fail in 3.28.0
### What happened?

https://github.com/conda/conda-build/pull/5055 corrected how the metadata's version was validated and resulted in multi outputs failing to build unless they also define the top level `package/version`.

Xref https://github.com/conda-forge/admin-requests/pull/890

### Conda Details

<details>
<summary><code>conda info</code></summary>

```
     active environment : None
            shell level : 0
       user config file : /Users/kodegard/.condarc
 populated config files : /Users/kodegard/.condarc
          conda version : 23.11.0
    conda-build version : 3.28.0
         python version : 3.10.13.final.0
                 solver : libmamba (default)
       virtual packages : __archspec=1=m1
                          __conda=23.11.0=0
                          __osx=13.6=0
                          __unix=0=0
       base environment : /Users/kodegard/.conda/arm64/23.10.0/3.11  (writable)
      conda av data dir : /Users/kodegard/.conda/arm64/23.10.0/3.11/etc/conda
  conda av metadata url : None
           channel URLs : https://repo.anaconda.com/pkgs/main/osx-arm64
                          https://repo.anaconda.com/pkgs/main/noarch
                          https://repo.anaconda.com/pkgs/r/osx-arm64
                          https://repo.anaconda.com/pkgs/r/noarch
          package cache : /Users/kodegard/.conda/arm64/23.10.0/3.11/pkgs
                          /Users/kodegard/.conda/pkgs
       envs directories : /Users/kodegard/.conda/arm64/23.10.0/3.11/envs
                          /Users/kodegard/.conda/envs
               platform : osx-arm64
             user-agent : conda/23.11.0 requests/2.31.0 CPython/3.10.13 Darwin/22.6.0 OSX/13.6 solver/libmamba conda-libmamba-solver/23.11.1 libmambapy/1.5.3
                UID:GID : 501:20
             netrc file : None
           offline mode : False
```

</details>


Discussion:

Resolving patch:
diff --git a/conda_build/metadata.py b/conda_build/metadata.py
--- a/conda_build/metadata.py
+++ b/conda_build/metadata.py
@@ -1442,7 +1442,7 @@ def name(self) -> str:
 
     def version(self) -> str:
         version = self.get_value("package/version", "")
-        if not version and self.final:
+        if not version and not self.get_section("outputs") and self.final:
             sys.exit("Error: package/version missing in: %r" % self.meta_path)
         version = str(version)
         check_bad_chrs(version, "package/version")


Test patch:
diff --git a/tests/test-recipes/split-packages/_empty_outputs_requires_package_version/meta.yaml b/tests/test-recipes/split-packages/_empty_outputs_requires_package_version/meta.yaml
new file mode 100644
--- /dev/null
+++ b/tests/test-recipes/split-packages/_empty_outputs_requires_package_version/meta.yaml
@@ -0,0 +1,6 @@
+package:
+  name: _empty_outputs_requires_package_version
+  # when there are not outputs, package/version is required
+  # version: 0
+
+outputs:
diff --git a/tests/test-recipes/split-packages/_multi_outputs_without_package_version/meta.yaml b/tests/test-recipes/split-packages/_multi_outputs_without_package_version/meta.yaml
new file mode 100644
--- /dev/null
+++ b/tests/test-recipes/split-packages/_multi_outputs_without_package_version/meta.yaml
@@ -0,0 +1,12 @@
+package:
+  name: _multi_outputs_without_package_version
+  # when there are outputs, package/version is not required
+  # version: 0
+
+outputs:
+  - name: a
+    version: 1
+  - name: b
+    version: 2
+  - name: c
+    version: 3
diff --git a/tests/test-recipes/split-packages/_order/meta.yaml b/tests/test-recipes/split-packages/_order/meta.yaml
--- a/tests/test-recipes/split-packages/_order/meta.yaml
+++ b/tests/test-recipes/split-packages/_order/meta.yaml
@@ -1,6 +1,6 @@
 package:
   name: toplevel-ab
-  version: 0.0.1
+  version: 1
 
 outputs:
   - name: a
diff --git a/tests/test_api_build.py b/tests/test_api_build.py
--- a/tests/test_api_build.py
+++ b/tests/test_api_build.py
@@ -412,6 +412,9 @@ def dummy_executable(folder, exename):
     return exename
 
 
+@pytest.mark.skip(
+    reason="GitHub discontinued SVN, see https://github.com/conda/conda-build/issues/5098"
+)
 def test_checkout_tool_as_dependency(testing_workdir, testing_config, monkeypatch):
     # "hide" svn by putting a known bad one on PATH
     exename = dummy_executable(testing_workdir, "svn")
diff --git a/tests/test_subpackages.py b/tests/test_subpackages.py
--- a/tests/test_subpackages.py
+++ b/tests/test_subpackages.py
@@ -442,3 +442,20 @@ def test_build_string_does_not_incorrectly_add_hash(testing_config):
     assert len(output_files) == 4
     assert any("clang_variant-1.0-cling.tar.bz2" in f for f in output_files)
     assert any("clang_variant-1.0-default.tar.bz2" in f for f in output_files)
+
+
+def test_multi_outputs_without_package_version(testing_config):
+    # outputs without package/version is allowed
+    recipe = os.path.join(subpackage_dir, "_multi_outputs_without_package_version")
+    outputs = api.build(recipe, config=testing_config)
+    assert len(outputs) == 3
+    assert outputs[0].endswith("a-1-0.tar.bz2")
+    assert outputs[1].endswith("b-2-0.tar.bz2")
+    assert outputs[2].endswith("c-3-0.tar.bz2")
+
+
+def test_empty_outputs_requires_package_version(testing_config):
+    # no outputs means package/version is required
+    recipe = os.path.join(subpackage_dir, "_empty_outputs_requires_package_version")
+    with pytest.raises(SystemExit, match="package/version missing"):
+        api.build(recipe, config=testing_config)