Repository: conan-io/conan
Pull request #16013 (2024-04-03 20:44:31)

new test_package_folder attribute
Changelog: Feature: Add new ``test_package_folder`` attribute to ``conanfile.py`` to define a different custom location and name rather than ``test_package`` default.
Docs: https://github.com/conan-io/docs/pull/XXXX

Close https://github.com/conan-io/conan/issues/16008


Patch:
diff --git a/conan/cli/commands/create.py b/conan/cli/commands/create.py
index 36b967882..d5b2e186e 100644
--- a/conan/cli/commands/create.py
+++ b/conan/cli/commands/create.py
@@ -40,7 +40,6 @@ def create(conan_api, parser, *args):
 
     cwd = os.getcwd()
     path = conan_api.local.get_conanfile_path(args.path, cwd, py=True)
-    test_conanfile_path = _get_test_conanfile_path(args.test_folder, path)
     overrides = eval(args.lockfile_overrides) if args.lockfile_overrides else None
     lockfile = conan_api.lockfile.get_lockfile(lockfile=args.lockfile,
                                                conanfile_path=path,
@@ -98,6 +97,9 @@ def create(conan_api, parser, *args):
         lockfile = conan_api.lockfile.update_lockfile(lockfile, deps_graph, args.lockfile_packages,
                                                       clean=args.lockfile_clean)
 
+    test_package_folder = getattr(conanfile, "test_package_folder", None) \
+        if args.test_folder is None else args.test_folder
+    test_conanfile_path = _get_test_conanfile_path(test_package_folder, path)
     # If the user provide --test-missing and the binary was not built from source, skip test_package
     if args.test_missing and deps_graph.root.dependencies\
             and deps_graph.root.dependencies[0].dst.binary != BINARY_BUILD:


Test patch:
diff --git a/conans/test/integration/conanfile/test_deploy_method.py b/conans/test/integration/conanfile/test_deploy_method.py
index 7579ec5c0..1c8a3f1ba 100644
--- a/conans/test/integration/conanfile/test_deploy_method.py
+++ b/conans/test/integration/conanfile/test_deploy_method.py
@@ -76,3 +76,53 @@ def test_deploy_local():
     # I can exclude the current consumer, it won't fail
     c.run("install . --deployer-package=!& --deployer-package=*")
     assert "Install finished successfully" in c.out
+
+
+def test_deploy_method_tool_requires():
+    # Test to validate https://github.com/conan-io/docs/issues/3649
+    c = TestClient()
+    tool = textwrap.dedent(r"""
+        import os
+        from conan import ConanFile
+        from conan.tools.files import save, chdir
+        class Pkg(ConanFile):
+            name = "tool"
+            version = "0.1"
+            type = "application"
+
+            def package(self):
+               with chdir(self, self.package_folder):
+                   echo = "@echo off\necho MYTOOL RUNNING!!"
+                   save(self, "mytool.bat", echo)
+                   save(self, "mytool.sh", echo)
+                   os.chmod("mytool.sh", 0o777)
+
+            def package_info(self):
+               self.buildenv_info.prepend_path("PATH", self.package_folder)
+        """)
+    conanfile = textwrap.dedent("""
+        import os
+        from conan import ConanFile
+        from conan.tools.env import VirtualBuildEnv
+        class Pkg(ConanFile):
+            name = "pkg"
+            version = "0.1"
+            tool_requires = "tool/0.1"
+            settings = "os"
+
+            def deploy(self):
+                self.output.info(f"DEPLOY {os.getcwd()}")
+                venv = VirtualBuildEnv(self)
+                with venv.vars().apply():
+                    ext = "bat" if self.settings.os == "Windows" else "sh"
+                    self.run(f"mytool.{ext}")
+        """)
+    c.save({"tool/conanfile.py": tool,
+            "pkg/conanfile.py": conanfile})
+
+    c.run("create tool")
+    c.run("create pkg")
+
+    # install can deploy all
+    c.run("install --requires=pkg/0.1 -c:b tools.graph:skip_binaries=False --deployer-package=*")
+    assert "MYTOOL RUNNING!!" in c.out
diff --git a/conans/test/integration/layout/test_layout_generate.py b/conans/test/integration/layout/test_layout_generate.py
index 7548f0788..0fdbbe8ef 100644
--- a/conans/test/integration/layout/test_layout_generate.py
+++ b/conans/test/integration/layout/test_layout_generate.py
@@ -125,3 +125,33 @@ def test_generate_build_folder_test_package():
             "test_package/conanfile.py": conanfile})
     c.run("create .")
     assert f"build_folder in test_package: True" in c.out
+
+
+class TestCustomTestPackage:
+    def test_custom_test_package(self):
+        c = TestClient(light=True)
+        conanfile = GenConanfile("pkg", "0.1").with_class_attribute('test_package_folder="mytest"')
+        c.save({"conanfile.py": conanfile,
+                "mytest/conanfile.py": GenConanfile().with_test("self.output.info('MYTEST!')"),
+                "mytest2/conanfile.py": GenConanfile().with_test("self.output.info('MYTEST2!')")})
+        c.run("create .")
+        assert "MYTEST!" in c.out
+        c.run("create . -tf=mytest2")
+        assert "MYTEST2!" in c.out
+
+    def test_custom_test_package_subfolder(self):
+        c = TestClient(light=True)
+        conanfile = GenConanfile("pkg", "0.1").with_class_attribute('test_package_folder="my/test"')
+        c.save({"pkg/conanfile.py": conanfile,
+                "pkg/my/test/conanfile.py": GenConanfile().with_test("self.output.info('MYTEST!')")})
+        c.run("create pkg")
+        assert "MYTEST!" in c.out
+
+    def test_custom_test_package_sibling(self):
+        c = TestClient(light=True)
+        conanfile = GenConanfile("pkg", "0.1").with_class_attribute(
+            'test_package_folder="../my/test"')
+        c.save({"pkg/conan/conanfile.py": conanfile,
+                "pkg/my/test/conanfile.py": GenConanfile().with_test("self.output.info('MYTEST!')")})
+        c.run("create pkg/conan")
+        assert "MYTEST!" in c.out