Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions artifactory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
49 changes: 49 additions & 0 deletions docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

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
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ require (
sigs.k8s.io/yaml v1.6.0 // indirect
)

// attiasas:expend_vsc_detection_for_container
replace github.com/jfrog/jfrog-cli-artifactory => github.com/attiasas/jfrog-cli-artifactory v0.0.0-20260618090105-893dad1b8438

//replace github.com/gfleury/go-bitbucket-v1 => github.com/gfleury/go-bitbucket-v1 v0.0.0-20230825095122-9bc1711434ab

//replace github.com/ktrysmt/go-bitbucket => github.com/ktrysmt/go-bitbucket v0.9.80
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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-20260618090105-893dad1b8438 h1:dhl2mW0l41Fq3QfVzq7MiGE8PTvt42pI2oiiYnwk9i4=
github.com/attiasas/jfrog-cli-artifactory v0.0.0-20260618090105-893dad1b8438/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=
Expand Down Expand Up @@ -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.20260617073349-d68ee3120aa8 h1:FG+SfgPgrIuBHSos4sw4KNZq2MKxebbCZ6KZZRfaYcs=
github.com/jfrog/jfrog-cli-application v1.0.2-0.20260617073349-d68ee3120aa8/go.mod h1:p8yLtbmCxxQucIbLZKnWu0F+EDtj6NLXbRQCEK/nb6o=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260618051529-1b76b6ad2606 h1:hlc8XoqySjbrvKKjxswyXQ/q5I0Px9FcZpVZUTd+T3M=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260618051529-1b76b6ad2606/go.mod h1:VqV0Bed11HoBlugAEGa3RumbwnDVslEf0gKocTzLs9s=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260615072209-8ccac4f0072e h1:E3B8OyEkCsdEdGsZifTphBDUPrd00yKoemL9+l25Qj8=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260615072209-8ccac4f0072e/go.mod h1:9R90mhbczGXwW5EGlDs7F08ejQU/xdoDhYHMvzBiqgE=
github.com/jfrog/jfrog-cli-evidence v0.9.5-0.20260601141509-8df6c9a4bc9b h1:V0FxnU3xh29y8yJHWymm6rPr1MrjG1DdPQlr3ckImwk=
Expand Down
93 changes: 93 additions & 0 deletions helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
49 changes: 49 additions & 0 deletions huggingface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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))

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()
Expand Down
88 changes: 88 additions & 0 deletions utils/tests/artifact_props.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package tests

import (
"strings"
"testing"

buildinfo "github.com/jfrog/build-info-go/entities"
"github.com/jfrog/jfrog-client-go/artifactory"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// ArtifactFullPath builds the Artifactory item path for GetItemProps.
// When OriginalDeploymentRepo is empty (common with Gradle extractor build-info),
// defaultRepo is used as the repository prefix.
func ArtifactFullPath(a buildinfo.Artifact, defaultRepo string) string {
path := strings.TrimPrefix(a.Path, "/")
repo := a.OriginalDeploymentRepo
if repo == "" {
repo = defaultRepo
}
if repo != "" {
return repo + "/" + path
}
return path
}

// ArtifactItemPath returns the Artifactory item path for GetItemProps.
// When Name is set and not already part of Path (e.g. UV stores Path as a directory),
// Name is appended as the filename segment.
func ArtifactItemPath(a buildinfo.Artifact, defaultRepo string) string {
fullPath := ArtifactFullPath(a, defaultRepo)
if a.Name == "" {
return fullPath
}
if strings.HasSuffix(fullPath, "/"+a.Name) || strings.HasSuffix(fullPath, a.Name) {
return fullPath
}
return fullPath + "/" + a.Name
}

// ValidateLocalGitVcsPropsOnBuildInfoArtifacts fetches props for each build-info artifact
// and asserts local-git VCS fields. Returns the number of artifacts validated.
func ValidateLocalGitVcsPropsOnBuildInfoArtifacts(
t *testing.T,
serviceManager artifactory.ArtifactoryServicesManager,
publishedBuildInfo *buildinfo.PublishedBuildInfo,
defaultRepo string,
expectedURL, expectedRevision, expectedBranch string,
) int {
t.Helper()
require.NotNil(t, publishedBuildInfo)

count := 0
for _, module := range publishedBuildInfo.BuildInfo.Modules {
for _, artifact := range module.Artifacts {
fullPath := ArtifactItemPath(artifact, defaultRepo)
if fullPath == "" {
continue
}

props, err := serviceManager.GetItemProps(fullPath)
require.NoError(t, err, "GetItemProps failed for %s", fullPath)
if props == nil {
assert.Fail(t, "Properties are nil for artifact: %s", fullPath)
continue
}

assert.Contains(t, props.Properties, "vcs.url", "Missing vcs.url on %s", artifact.Name)
assert.Contains(t, props.Properties["vcs.url"], expectedURL, "Wrong vcs.url on %s", artifact.Name)

assert.Contains(t, props.Properties, "vcs.revision", "Missing vcs.revision on %s", artifact.Name)
assert.Contains(t, props.Properties["vcs.revision"], expectedRevision, "Wrong vcs.revision on %s", artifact.Name)

if expectedBranch != "" {
assert.Contains(t, props.Properties, "vcs.branch", "Missing vcs.branch on %s", artifact.Name)
assert.Contains(t, props.Properties["vcs.branch"], expectedBranch, "Wrong vcs.branch on %s", artifact.Name)
}

// Local-git-only: provider/org/repo must NOT appear when CI is cleared
_, hasProvider := props.Properties["vcs.provider"]
assert.False(t, hasProvider, "vcs.provider should not be set on %s in local-git-only mode", artifact.Name)

count++
}
}
return count
}
Loading
Loading