diff --git a/conan_test.go b/conan_test.go index ba2cbeb49..a7334b185 100644 --- a/conan_test.go +++ b/conan_test.go @@ -454,6 +454,30 @@ func createConanProject(t *testing.T, outputFolder string) string { return projectPath } +func createConanProjectNoName(t *testing.T, outputFolder string) string { + projectSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "conan", "conanproject-noname") + tmpDir, cleanupCallback := coretests.CreateTempDirWithCallbackAndAssert(t) + + projectPath := filepath.Join(tmpDir, outputFolder) + require.NoError(t, biutils.CopyDir(projectSrc, projectPath, true, nil)) + + t.Cleanup(cleanupCallback) + + return projectPath +} + +func createConanProjectSubdir(t *testing.T, outputFolder string) string { + projectSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "conan", "conanproject-subdir") + tmpDir, cleanupCallback := coretests.CreateTempDirWithCallbackAndAssert(t) + + projectPath := filepath.Join(tmpDir, outputFolder) + require.NoError(t, biutils.CopyDir(projectSrc, projectPath, true, nil)) + + t.Cleanup(cleanupCallback) + + return projectPath +} + func configureConanRemote(t *testing.T) { // Remove existing remote if any _ = exec.Command("conan", "remote", "remove", tests.ConanVirtualRepo).Run() @@ -472,6 +496,209 @@ func cleanupConanRemote() { _ = exec.Command("conan", "remote", "remove", tests.ConanLocalRepo).Run() } +// TestConanInstallRequiresNoRecipe tests 'jf conan install --requires' without any conanfile. +func TestConanInstallRequiresNoRecipe(t *testing.T) { + initConanTest(t) + buildNumber := "1" + + // Create empty project dir (no conanfile) + tmpDir, cleanupCallback := coretests.CreateTempDirWithCallbackAndAssert(t) + t.Cleanup(cleanupCallback) + projectPath := filepath.Join(tmpDir, "no-recipe-test") + require.NoError(t, os.MkdirAll(projectPath, 0755)) + + wd, err := os.Getwd() + require.NoError(t, err) + chdirCallback := clientTestUtils.ChangeDirWithCallback(t, wd, projectPath) + defer chdirCallback() + + configureConanRemote(t) + defer cleanupConanRemote() + + jfrogCli := coretests.NewJfrogCli(execMain, "jfrog", "") + args := []string{ + "conan", "install", + "--requires", "zlib/1.3.1", + "--build", "missing", + "-r", tests.ConanVirtualRepo, + "--build-name=" + tests.ConanBuildName, + "--build-number=" + buildNumber, + } + require.NoError(t, jfrogCli.Exec(args...), "conan install --requires should succeed without a conanfile") + + require.NoError(t, artifactoryCli.Exec("bp", tests.ConanBuildName, buildNumber)) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.ConanBuildName, artHttpDetails) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, tests.ConanBuildName, buildNumber) + require.NoError(t, err) + require.True(t, found, "build info was expected to be found") + + buildInfoModules := publishedBuildInfo.BuildInfo.Modules + require.Len(t, buildInfoModules, 1, "Expected 1 module") + assert.Equal(t, buildinfo.Conan, buildInfoModules[0].Type, "Module type should be conan") + assert.GreaterOrEqual(t, len(buildInfoModules[0].Dependencies), 1, "Expected at least 1 dependency (zlib)") +} + +// TestConanInstallWithNameVersionOverrides tests conan install with --name and --version overrides +// applied to a local conanfile.py. Conan 2.x does not allow --name/--version with --requires, +// so a conanfile is required. +func TestConanInstallWithNameVersionOverrides(t *testing.T) { + initConanTest(t) + buildNumber := "1" + + projectPath := createConanProjectNoName(t, "conan-name-version-override-test") + wd, err := os.Getwd() + require.NoError(t, err) + chdirCallback := clientTestUtils.ChangeDirWithCallback(t, wd, projectPath) + defer chdirCallback() + + configureConanRemote(t) + defer cleanupConanRemote() + + jfrogCli := coretests.NewJfrogCli(execMain, "jfrog", "") + args := []string{ + "conan", "install", ".", + "--build", "missing", + "--name", "my-custom-project", + "--version", "2.5.0", + "-r", tests.ConanVirtualRepo, + "--build-name=" + tests.ConanBuildName, + "--build-number=" + buildNumber, + } + require.NoError(t, jfrogCli.Exec(args...)) + + require.NoError(t, artifactoryCli.Exec("bp", tests.ConanBuildName, buildNumber)) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.ConanBuildName, artHttpDetails) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, tests.ConanBuildName, buildNumber) + require.NoError(t, err) + require.True(t, found, "build info was expected to be found") + + buildInfoModules := publishedBuildInfo.BuildInfo.Modules + require.Len(t, buildInfoModules, 1) + assert.Equal(t, "my-custom-project:2.5.0", buildInfoModules[0].Id, + "Module ID should reflect --name and --version overrides") + assert.GreaterOrEqual(t, len(buildInfoModules[0].Dependencies), 1) +} + +// TestConanInstallRecipeInSubdir tests 'jf conan install ' where the recipe is not in cwd. +func TestConanInstallRecipeInSubdir(t *testing.T) { + initConanTest(t) + buildNumber := "1" + + projectPath := createConanProjectSubdir(t, "conan-subdir-install-test") + wd, err := os.Getwd() + require.NoError(t, err) + chdirCallback := clientTestUtils.ChangeDirWithCallback(t, wd, projectPath) + defer chdirCallback() + + configureConanRemote(t) + defer cleanupConanRemote() + + jfrogCli := coretests.NewJfrogCli(execMain, "jfrog", "") + args := []string{ + "conan", "install", "recipes/mylib", + "--build=missing", + "-r", tests.ConanVirtualRepo, + "--build-name=" + tests.ConanBuildName, + "--build-number=" + buildNumber, + } + require.NoError(t, jfrogCli.Exec(args...), "conan install with recipe in subdirectory should succeed") + + require.NoError(t, artifactoryCli.Exec("bp", tests.ConanBuildName, buildNumber)) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.ConanBuildName, artHttpDetails) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, tests.ConanBuildName, buildNumber) + require.NoError(t, err) + require.True(t, found, "build info was expected to be found") + + buildInfoModules := publishedBuildInfo.BuildInfo.Modules + require.Len(t, buildInfoModules, 1) + assert.Equal(t, buildinfo.Conan, buildInfoModules[0].Type) + assert.Equal(t, "cli-test-subdir-package:1.0.0", buildInfoModules[0].Id, + "Module ID should come from the subdirectory's conanfile.py") + assert.GreaterOrEqual(t, len(buildInfoModules[0].Dependencies), 1) +} + +// TestConanCreateRecipeInSubdir tests 'jf conan create ' where the recipe is not in cwd. +func TestConanCreateRecipeInSubdir(t *testing.T) { + initConanTest(t) + buildNumber := "1" + + projectPath := createConanProjectSubdir(t, "conan-subdir-create-test") + wd, err := os.Getwd() + require.NoError(t, err) + chdirCallback := clientTestUtils.ChangeDirWithCallback(t, wd, projectPath) + defer chdirCallback() + + configureConanRemote(t) + defer cleanupConanRemote() + + jfrogCli := coretests.NewJfrogCli(execMain, "jfrog", "") + createArgs := []string{ + "conan", "create", "recipes/mylib", + "--build=missing", + "--build-name=" + tests.ConanBuildName, + "--build-number=" + buildNumber, + } + require.NoError(t, jfrogCli.Exec(createArgs...), "conan create with recipe in subdirectory should succeed") + + require.NoError(t, artifactoryCli.Exec("bp", tests.ConanBuildName, buildNumber)) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.ConanBuildName, artHttpDetails) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, tests.ConanBuildName, buildNumber) + require.NoError(t, err) + require.True(t, found, "build info was expected to be found") + + buildInfoModules := publishedBuildInfo.BuildInfo.Modules + require.Len(t, buildInfoModules, 1) + assert.Equal(t, "cli-test-subdir-package:1.0.0", buildInfoModules[0].Id) + assert.GreaterOrEqual(t, len(buildInfoModules[0].Dependencies), 1) +} + +// TestConanInstallMultipleRequires tests --requires with multiple dependencies. +func TestConanInstallMultipleRequires(t *testing.T) { + initConanTest(t) + buildNumber := "1" + + tmpDir, cleanupCallback := coretests.CreateTempDirWithCallbackAndAssert(t) + t.Cleanup(cleanupCallback) + projectPath := filepath.Join(tmpDir, "multi-requires-test") + require.NoError(t, os.MkdirAll(projectPath, 0755)) + + wd, err := os.Getwd() + require.NoError(t, err) + chdirCallback := clientTestUtils.ChangeDirWithCallback(t, wd, projectPath) + defer chdirCallback() + + configureConanRemote(t) + defer cleanupConanRemote() + + jfrogCli := coretests.NewJfrogCli(execMain, "jfrog", "") + args := []string{ + "conan", "install", + "--requires", "zlib/1.3.1", + "--requires", "bzip2/1.0.8", + "--build", "missing", + "-r", tests.ConanVirtualRepo, + "--build-name=" + tests.ConanBuildName, + "--build-number=" + buildNumber, + } + require.NoError(t, jfrogCli.Exec(args...)) + + require.NoError(t, artifactoryCli.Exec("bp", tests.ConanBuildName, buildNumber)) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, tests.ConanBuildName, artHttpDetails) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, tests.ConanBuildName, buildNumber) + require.NoError(t, err) + require.True(t, found, "build info was expected to be found") + + buildInfoModules := publishedBuildInfo.BuildInfo.Modules + require.Len(t, buildInfoModules, 1) + assert.GreaterOrEqual(t, len(buildInfoModules[0].Dependencies), 2, + "Expected at least 2 dependencies (zlib + bzip2)") +} + // TestConanCreateWithProjectKey tests that 'jf conan create --project=' stores build info // in the correct local build dir (SHA includes the project key). func TestConanCreateWithProjectKey(t *testing.T) { diff --git a/go.mod b/go.mod index d6eaaee8c..7366970be 100644 --- a/go.mod +++ b/go.mod @@ -16,10 +16,10 @@ require ( github.com/docker/docker v28.5.2+incompatible github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/jfrog/archiver/v3 v3.6.3 - github.com/jfrog/build-info-go v1.13.1-0.20260216093441-40a4dc563294 + github.com/jfrog/build-info-go v1.13.1-0.20260313042712-238e6dca3dce github.com/jfrog/gofrog v1.7.6 github.com/jfrog/jfrog-cli-application v1.0.2-0.20260216085810-1ade6c26b3df - github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260310063831-ad6064f2f373 + github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260313044645-ed6f0a05bb5b github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260225195817-bc599cec3973 github.com/jfrog/jfrog-cli-evidence v0.8.3-0.20260202100913-d9ee9476845a github.com/jfrog/jfrog-cli-platform-services v1.10.1-0.20260306102152-984d60a80cec @@ -246,12 +246,14 @@ require ( //replace github.com/ktrysmt/go-bitbucket => github.com/ktrysmt/go-bitbucket v0.9.80 -//replace github.com/jfrog/jfrog-cli-core/v2 => ../jfrog-cli-core +// replace github.com/jfrog/jfrog-cli-artifactory => github.com/reshmifrog/jfrog-cli-artifactory v0.0.0-20260303084642-b208fbba798b // replace github.com/jfrog/jfrog-cli-artifactory => github.com/fluxxBot/jfrog-cli-artifactory v0.0.0-20260130044429-464a5025d08a //replace github.com/jfrog/build-info-go => github.com/fluxxBot/build-info-go v1.10.10-0.20260105070825-d3f36f619ba5 +// replace github.com/jfrog/build-info-go => github.com/reshmifrog/build-info-go v1.10.11-0.20260303032831-71878c7210bf + //replace github.com/jfrog/jfrog-cli-core/v2 => github.com/fluxxBot/jfrog-cli-core/v2 v2.58.1-0.20260105065921-c6488910f44c //replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.54.2-0.20251007084958-5eeaa42c31a6 diff --git a/go.sum b/go.sum index 973d139e2..643f26e7d 100644 --- a/go.sum +++ b/go.sum @@ -407,8 +407,8 @@ github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4= github.com/jfrog/archiver/v3 v3.6.3 h1:hkAmPjBw393tPmQ07JknLNWFNZjXdy2xFEnOW9wwOxI= github.com/jfrog/archiver/v3 v3.6.3/go.mod h1:5V9l+Fte30Y4qe9dUOAd3yNTf8lmtVNuhKNrvI8PMhg= -github.com/jfrog/build-info-go v1.13.1-0.20260216093441-40a4dc563294 h1:7aJGdrjibtWT1VPLH+GYyoZsAsoca8/fMrvGIvkZ8Fs= -github.com/jfrog/build-info-go v1.13.1-0.20260216093441-40a4dc563294/go.mod h1:+OCtMb22/D+u7Wne5lzkjJjaWr0LRZcHlDwTH86Mpwo= +github.com/jfrog/build-info-go v1.13.1-0.20260313042712-238e6dca3dce h1:Ozuq6iZEFbE8GNk5ROMa0w+v2kmeUdUj95gVN636Lus= +github.com/jfrog/build-info-go v1.13.1-0.20260313042712-238e6dca3dce/go.mod h1:+OCtMb22/D+u7Wne5lzkjJjaWr0LRZcHlDwTH86Mpwo= github.com/jfrog/froggit-go v1.21.1 h1:I/XUOO6GQ1d/rmBlM361F8T654C3ohIWrpw23xNL9JY= github.com/jfrog/froggit-go v1.21.1/go.mod h1:umBiakJB0CSPFfe0AHVaC3n9xsmUT7NGkDCny3bRchI= github.com/jfrog/go-mockhttp v0.3.1 h1:/wac8v4GMZx62viZmv4wazB5GNKs+GxawuS1u3maJH8= @@ -419,8 +419,8 @@ github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYL github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w= github.com/jfrog/jfrog-cli-application v1.0.2-0.20260216085810-1ade6c26b3df h1:raSyae8/h1y8HtzFLf7vZZj91fP/qD94AX+biwBJiqs= github.com/jfrog/jfrog-cli-application v1.0.2-0.20260216085810-1ade6c26b3df/go.mod h1:xum2HquWO5uExa/A7MQs3TgJJVEeoqTR+6Z4mfBr1Xw= -github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260310063831-ad6064f2f373 h1:9rgBl0MuJfPX6khjwai0jqwOOCkytTH0DOEcmih1PRQ= -github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260310063831-ad6064f2f373/go.mod h1:zjbDerW+Pin6VExtlgwRtpnvtI/ySJTnmqnOwXbsrmc= +github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260313044645-ed6f0a05bb5b h1:XTlhwNidgPYk/91FblSENm5/P9kAUkHSLUc3I7FRBdg= +github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260313044645-ed6f0a05bb5b/go.mod h1:kgw6gIQvJx9bCcOdtAGSUEiCz7nNQmaFbFvNg6byZ6I= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260225195817-bc599cec3973 h1:awB01Y4m0cWzmXuR3waf5IQnoQxDlbUmqT+FMWOpjbs= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260225195817-bc599cec3973/go.mod h1:yhi+XpiEx18a3t8CZ6M2VpAf3EGqKpBhTzoPBTFe0dk= github.com/jfrog/jfrog-cli-evidence v0.8.3-0.20260202100913-d9ee9476845a h1:lTOAhUjKcOmM/0Kbj4V+I/VHPlW7YNAhIEVpGnCM5mI= diff --git a/testdata/conan/conanproject-noname/conanfile.py b/testdata/conan/conanproject-noname/conanfile.py new file mode 100644 index 000000000..95662e919 --- /dev/null +++ b/testdata/conan/conanproject-noname/conanfile.py @@ -0,0 +1,11 @@ +from conan import ConanFile + + +class TestConan(ConanFile): + requires = "zlib/1.3.1" + + def build(self): + self.output.info("Building test package") + + def package(self): + pass diff --git a/testdata/conan/conanproject-subdir/recipes/mylib/conanfile.py b/testdata/conan/conanproject-subdir/recipes/mylib/conanfile.py new file mode 100644 index 000000000..bbe090795 --- /dev/null +++ b/testdata/conan/conanproject-subdir/recipes/mylib/conanfile.py @@ -0,0 +1,13 @@ +from conan import ConanFile + + +class TestConan(ConanFile): + name = "cli-test-subdir-package" + version = "1.0.0" + requires = "zlib/1.3.1" + + def build(self): + self.output.info("Building test package from subdirectory") + + def package(self): + pass