diff --git a/artifactory_test.go b/artifactory_test.go index 9de331c31..18184cc7d 100644 --- a/artifactory_test.go +++ b/artifactory_test.go @@ -6922,6 +6922,51 @@ func terraformPublishModulesAndBuildInfo(t *testing.T, trPublishArgs []string) { assert.Len(t, buildInfo.Modules[0].Artifacts, 3) } +func TestTerraformPublishWithLocalGitVcsProps(t *testing.T) { + initArtifactoryTest(t, terraformMinArtifactoryVersion) + defer cleanArtifactoryTest() + createJfrogHomeConfig(t, true) + + buildNumber := "local-git-1" + buildName := tests.RtBuildName1 + "-local-git" + + cleanupEnv := tests.SetupLocalGitVcsEnv(t) + defer cleanupEnv() + + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails) + + projectPath := prepareTerraformProject("terraformproject", t, true) + tests.CopyGitFixtureIntoProject(t, projectPath) + + wd, err := os.Getwd() + require.NoError(t, err) + awsDir := filepath.Join(projectPath, "aws") + chdirCallback := clientTestUtils.ChangeDirWithCallback(t, wd, awsDir) + defer chdirCallback() + + trPublishArgs := []string{ + "terraform", "publish", + "--namespace=namespace", "--provider=provider", "--tag=tag", + "--exclusions=*test*", + "--build-name=" + buildName, "--build-number=" + buildNumber, + "--module=my-tr-module-local-git", + } + require.NoError(t, platformCli.WithoutCredentials().Exec(trPublishArgs...)) + require.NoError(t, artifactoryCli.Exec("bp", buildName, buildNumber)) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, buildName, buildNumber) + require.NoError(t, err) + require.True(t, found) + + serviceManager, err := utils.CreateServiceManager(serverDetails, 3, 1000, false) + require.NoError(t, err) + + count := tests.ValidateLocalGitVcsPropsOnBuildInfoArtifacts(t, serviceManager, publishedBuildInfo, tests.TerraformRepo, + tests.VcsFixtureMainURL, tests.VcsFixtureMainRevision, tests.VcsFixtureMainBranch) + assert.Greater(t, count, 0) +} + func prepareTerraformProject(projectName string, t *testing.T, copyDirs bool) string { projectPath := filepath.Join(tests.GetTestResourcesPath(), "terraform", projectName) testdataTarget := filepath.Join(tests.Out, "terraformProject") diff --git a/docker_test.go b/docker_test.go index f0ac37a0a..56a111c14 100644 --- a/docker_test.go +++ b/docker_test.go @@ -1574,6 +1574,55 @@ CMD ["echo", "Hello from CI VCS test"]`, baseImage) assert.Greater(t, artifactCount, 0, "No artifacts in build info") } +// TestDockerPushWithLocalGitVcsProps verifies local git VCS props on Docker artifacts +// when running build-publish with VCS collection enabled and no CI env. +func TestDockerPushWithLocalGitVcsProps(t *testing.T) { + cleanup := initDockerBuildTest(t) + defer cleanup() + + buildName := "docker-local-git-test" + buildNumber := "1" + + cleanupEnv := tests.SetupLocalGitVcsEnv(t) + defer cleanupEnv() + + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails) + + registryHost := *tests.ContainerRegistry + if parsedURL, err := url.Parse(registryHost); err == nil && parsedURL.Host != "" { + registryHost = parsedURL.Host + } + imageName := path.Join(registryHost, tests.OciLocalRepo, "test-local-git-docker") + imageTag := imageName + ":v1" + + workspace, err := filepath.Abs(tests.Out) + require.NoError(t, err) + require.NoError(t, fileutils.CreateDirIfNotExist(workspace)) + tests.CopyGitFixtureIntoProject(t, workspace) + + baseImage := path.Join(registryHost, tests.OciRemoteRepo, "alpine:latest") + dockerfileContent := fmt.Sprintf("FROM %s\nCMD [\"echo\", \"local git vcs test\"]", baseImage) + dockerfilePath := filepath.Join(workspace, "Dockerfile") + require.NoError(t, os.WriteFile(dockerfilePath, []byte(dockerfileContent), 0o644)) //#nosec G703 -- test code, path built from test workspace + + runJfrogCli(t, "rt", "bc", buildName, buildNumber) + runJfrogCli(t, "docker", "build", "-t", imageTag, "--push", "-f", dockerfilePath, + "--build-name="+buildName, "--build-number="+buildNumber, workspace) + runRt(t, "build-publish", buildName, buildNumber, "--dot-git-path", workspace) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, buildName, buildNumber) + require.NoError(t, err) + require.True(t, found) + + serviceManager, err := utils.CreateServiceManager(serverDetails, 3, 1000, false) + require.NoError(t, err) + + count := tests.ValidateLocalGitVcsPropsOnBuildInfoArtifacts(t, serviceManager, publishedBuildInfo, tests.OciLocalRepo, + tests.VcsFixtureMainURL, tests.VcsFixtureMainRevision, tests.VcsFixtureMainBranch) + assert.Greater(t, count, 0) +} + // TestSetupDockerCommand verifies `jf setup docker --url ...` end-to-end. // // Guards RTECO-1352: configureContainer (in jfrog-cli-artifactory) used to read diff --git a/go.mod b/go.mod index 33db2e74c..e19d86a6a 100644 --- a/go.mod +++ b/go.mod @@ -242,7 +242,8 @@ require ( sigs.k8s.io/yaml v1.6.0 // indirect ) -// replace github.com/jfrog/jfrog-cli-artifactory => github.com/jfrog/jfrog-cli-artifactory main +// attiasas:expend_vsc_detection_for_container +replace github.com/jfrog/jfrog-cli-artifactory => github.com/attiasas/jfrog-cli-artifactory v0.0.0-20260702092235-dd9a29acd55e //replace github.com/gfleury/go-bitbucket-v1 => github.com/gfleury/go-bitbucket-v1 v0.0.0-20230825095122-9bc1711434ab diff --git a/go.sum b/go.sum index e1815deb4..90ebde4c2 100644 --- a/go.sum +++ b/go.sum @@ -67,6 +67,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/attiasas/jfrog-cli-artifactory v0.0.0-20260702092235-dd9a29acd55e h1:Mq096taLoChWpl88DJJrLQx6pVkXhDs5rS1EqJhGeww= +github.com/attiasas/jfrog-cli-artifactory v0.0.0-20260702092235-dd9a29acd55e/go.mod h1:VqV0Bed11HoBlugAEGa3RumbwnDVslEf0gKocTzLs9s= github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8= github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc= github.com/aws/aws-sdk-go-v2/config v1.32.17 h1:FpL4/758/diKwqbytU0prpuiu60fgXKUWCpDJtApclU= @@ -406,8 +408,6 @@ 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.20260621072921-cadb78770a3e h1:jUfQzLCVbUazw7FEXf3+57vQheDSHa/Px/Gp4pf/sNI= github.com/jfrog/jfrog-cli-application v1.0.2-0.20260621072921-cadb78770a3e/go.mod h1:p8yLtbmCxxQucIbLZKnWu0F+EDtj6NLXbRQCEK/nb6o= -github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260701085637-6ba50cd3676f h1:PMq0iTjH/H40BEL/RzBwXFt7JMb+CQBaVmScdbZaeRI= -github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260701085637-6ba50cd3676f/go.mod h1:VqV0Bed11HoBlugAEGa3RumbwnDVslEf0gKocTzLs9s= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260624085155-5ba797de2616 h1:bioFXGzf3pF2qnC3LZD1S1saWiHSekL4vdsDSWksj/4= github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260624085155-5ba797de2616/go.mod h1:9R90mhbczGXwW5EGlDs7F08ejQU/xdoDhYHMvzBiqgE= github.com/jfrog/jfrog-cli-evidence v0.9.5-0.20260618135203-4d2bdd4ee35f h1:MV4BATdkEoUYJmdPDvaB9EBb8JQZg28n/K4X7dcmyAY= diff --git a/helm_test.go b/helm_test.go index a472b2967..aa051ba33 100644 --- a/helm_test.go +++ b/helm_test.go @@ -958,6 +958,99 @@ func TestHelmBuildPublishWithCIVcsProps(t *testing.T) { assert.Greater(t, artifactCount, 0, "No artifacts were validated for CI VCS properties") } +// TestHelmPushWithLocalGitVcsProps verifies local git VCS props on Helm artifacts +// when running build-publish with VCS collection enabled and no CI env. +func TestHelmPushWithLocalGitVcsProps(t *testing.T) { + initHelmTest(t) + defer cleanHelmTest(t) + + buildName := tests.HelmBuildName + "-local-git" + buildNumber := "1" + + cleanupEnv := tests.SetupLocalGitVcsEnv(t) + defer cleanupEnv() + + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails) + + chartDir := createTestHelmChartWithDependencies(t, "test-chart-local-git", "0.2.0") + defer func() { + if err := os.RemoveAll(chartDir); err != nil { + t.Logf("Warning: Failed to remove test chart directory %s: %v", chartDir, err) + } + }() + tests.CopyGitFixtureIntoProject(t, chartDir) + + originalDir, err := os.Getwd() + require.NoError(t, err) + defer func() { + if err := os.Chdir(originalDir); err != nil { + t.Logf("Warning: Failed to change back to original directory: %v", err) + } + }() + require.NoError(t, os.Chdir(chartDir)) + + helmCmd := exec.Command("helm", "dependency", "update") + helmCmd.Dir = chartDir + require.NoError(t, helmCmd.Run(), "helm dependency update should succeed") + + jfrogCli := coreTests.NewJfrogCli(execMain, "jfrog", "") + require.NoError(t, jfrogCli.Exec("helm", "package", ".", + "--build-name="+buildName, "--build-number="+buildNumber), "helm package should succeed") + + chartFiles, err := filepath.Glob(filepath.Join(chartDir, "*.tgz")) + require.NoError(t, err) + require.NotEmpty(t, chartFiles, "Chart package file should be created") + chartFile := filepath.Base(chartFiles[0]) + + parsedURL, err := url.Parse(serverDetails.ArtifactoryUrl) + require.NoError(t, err) + registryHost := parsedURL.Host + registryURL := fmt.Sprintf("oci://%s/%s", registryHost, tests.HelmLocalRepo) + + if !isRepoExist(tests.HelmLocalRepo) { + t.Skipf("Repository %s does not exist. Skipping test.", tests.HelmLocalRepo) + } + + err = loginHelmRegistry(t, registryHost) + if err != nil { + errorMsg := strings.ToLower(err.Error()) + if strings.Contains(errorMsg, "account temporarily locked") { + t.Skip("Artifactory account is temporarily locked. Skipping test.") + } + if strings.Contains(errorMsg, "http response to https") || + strings.Contains(errorMsg, "tls: first record does not look like a tls handshake") { + t.Skip("Helm registry login failed due to HTTPS/HTTP mismatch. Skipping test.") + } + } + require.NoError(t, err, "helm registry login should succeed") + + err = jfrogCli.Exec("helm", "push", chartFile, registryURL, + "--build-name="+buildName, "--build-number="+buildNumber) + if err != nil { + errorMsg := strings.ToLower(err.Error()) + if strings.Contains(errorMsg, "404") || + strings.Contains(errorMsg, "not found") || + strings.Contains(errorMsg, "exit status 1") { + t.Skip("OCI registry API not accessible (404). Skipping test.") + } + } + require.NoError(t, err, "helm push should succeed") + + require.NoError(t, artifactoryCli.Exec("bp", buildName, buildNumber)) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, buildName, buildNumber) + require.NoError(t, err) + require.True(t, found) + + serviceManager, err := utils.CreateServiceManager(serverDetails, 3, 1000, false) + require.NoError(t, err) + + count := tests.ValidateLocalGitVcsPropsOnBuildInfoArtifacts(t, serviceManager, publishedBuildInfo, tests.HelmLocalRepo, + tests.VcsFixtureMainURL, tests.VcsFixtureMainRevision, tests.VcsFixtureMainBranch) + assert.Greater(t, count, 0) +} + // InitHelmTests initializes Helm tests func InitHelmTests() { initArtifactoryCli() diff --git a/huggingface_test.go b/huggingface_test.go index f71ad8ac9..4c78b390b 100644 --- a/huggingface_test.go +++ b/huggingface_test.go @@ -10,9 +10,11 @@ import ( "strings" "testing" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" coreTests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" + "github.com/jfrog/jfrog-cli/inttestutils" "github.com/jfrog/jfrog-cli/utils/tests" clientTestUtils "github.com/jfrog/jfrog-client-go/utils/tests" "github.com/stretchr/testify/assert" @@ -867,6 +869,53 @@ func InitHuggingFaceTests() { createRequiredRepos() } +func TestHuggingFaceUploadWithLocalGitVcsProps(t *testing.T) { + initHuggingFaceTest(t) + defer cleanHuggingFaceTest(t) + checkHuggingFaceHubAvailable(t) + + buildName := tests.HuggingFaceBuildName + "-local-git" + buildNumber := "1" + + cleanupEnv := tests.SetupLocalGitVcsEnv(t) + defer cleanupEnv() + + inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails) + defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails) + + tempDir, err := os.MkdirTemp("", "hf-local-git-*") + require.NoError(t, err) + t.Cleanup(func() { _ = os.RemoveAll(tempDir) }) + tests.CopyGitFixtureIntoProject(t, tempDir) + + require.NoError(t, os.WriteFile(filepath.Join(tempDir, "config.json"), + []byte(`{"model_type": "local-git-vcs"}`), 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(tempDir, "model.bin"), + []byte("model"), 0o644)) + + jfrogCli := coreTests.NewJfrogCli(execMain, "jfrog", "") + args := []string{ + "hf", "u", tempDir, "test-org/test-local-git-model", + "--repo-type=model", + "--build-name=" + buildName, + "--build-number=" + buildNumber, + "--repo-key=" + tests.HuggingFaceLocalRepo, + } + require.NoError(t, jfrogCli.Exec(args...)) + require.NoError(t, jfrogCli.Exec("rt", "bp", buildName, buildNumber, "--dot-git-path", tempDir)) + + publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, buildName, buildNumber) + require.NoError(t, err) + require.True(t, found) + + serviceManager, err := utils.CreateServiceManager(serverDetails, 3, 1000, false) + require.NoError(t, err) + + count := tests.ValidateLocalGitVcsPropsOnBuildInfoArtifacts(t, serviceManager, publishedBuildInfo, tests.HuggingFaceLocalRepo, + tests.VcsFixtureMainURL, tests.VcsFixtureMainRevision, tests.VcsFixtureMainBranch) + assert.Greater(t, count, 0) +} + // CleanHuggingFaceTests cleans up after HuggingFace tests func CleanHuggingFaceTests() { deleteCreatedRepos() diff --git a/utils/tests/artifact_props.go b/utils/tests/artifact_props.go index 172e2aadf..948ea84f8 100644 --- a/utils/tests/artifact_props.go +++ b/utils/tests/artifact_props.go @@ -19,6 +19,12 @@ func ArtifactFullPath(a buildinfo.Artifact, defaultRepo string) string { if repo == "" { repo = defaultRepo } + if path == "" { + if repo != "" { + return repo + } + return "" + } if repo != "" { return repo + "/" + path } diff --git a/utils/tests/artifact_props_test.go b/utils/tests/artifact_props_test.go index aaf8bbe01..0086818ad 100644 --- a/utils/tests/artifact_props_test.go +++ b/utils/tests/artifact_props_test.go @@ -55,3 +55,13 @@ func TestArtifactItemPath_DoesNotDoubleAppendName(t *testing.T) { } assert.Equal(t, "mvn-local/com/foo/1.0/foo.jar", ArtifactItemPath(a, "")) } + +func TestArtifactFullPath_EmptyPathReturnsRepoOnly(t *testing.T) { + a := buildinfo.Artifact{Path: "", Name: "config.json"} + assert.Equal(t, "my-repo", ArtifactFullPath(a, "my-repo")) +} + +func TestArtifactItemPath_EmptyPathDoesNotDoubleSlash(t *testing.T) { + a := buildinfo.Artifact{Path: "", Name: "config.json"} + assert.Equal(t, "my-repo/config.json", ArtifactItemPath(a, "my-repo")) +}