Skip to content
Closed
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ require (
github.com/jfrog/build-info-go v1.13.1-0.20261028123549-f0cd26bfc2de
github.com/jfrog/gofrog v1.7.7
github.com/jfrog/jfrog-cli-application v1.0.2-0.20260917110731-d7783acedd8c
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20261101122816-c0098229a376
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20261103060251-30c80a7deec4
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20261102064148-e4c77ed13cc6
github.com/jfrog/jfrog-cli-evidence v0.11.1-0.20261026075204-fdf3635939c5
github.com/jfrog/jfrog-cli-platform-services v1.10.1-0.20261030162302-b4948e3a2cb1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,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.20260917110731-d7783acedd8c h1:B/svbJcwCMHjeC+HqpzH9yEC7GEvOj3HPotYpG4Ga7A=
github.com/jfrog/jfrog-cli-application v1.0.2-0.20260917110731-d7783acedd8c/go.mod h1:RHjDVsgfIE+6N49R1t1nBjbK2Je4VTN7CQm9OlwtFnQ=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20261101122816-c0098229a376 h1:KSmFFkmKixtromy54jI0MM5dZ8NIxGi+0sm/he2YXA4=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20261101122816-c0098229a376/go.mod h1:94/aLloMSK6avu4umcJS3DJ6IuGM5K10PwZ6kDqgzSo=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20261103060251-30c80a7deec4 h1:Z4WqOlZZe3NA02ekqFrbSNlO8hkdGPHn/PuWq1sb+CA=
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20261103060251-30c80a7deec4/go.mod h1:94/aLloMSK6avu4umcJS3DJ6IuGM5K10PwZ6kDqgzSo=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20261102064148-e4c77ed13cc6 h1:7Jdj+FiaMN5jiQ94+Xlehf9OSLqSbAqAvO44XB9d7E4=
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20261102064148-e4c77ed13cc6/go.mod h1:dxy3GflCOX9kGxcdEkCXWhV+EMUAGBWO+CY5fGjWcCQ=
github.com/jfrog/jfrog-cli-evidence v0.11.1-0.20261026075204-fdf3635939c5 h1:PpGuelKEDO9ktDr90lCTDpg5jMMBuG1lS8Q4mhgegY0=
Expand Down
87 changes: 71 additions & 16 deletions helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1090,23 +1090,38 @@ func TestHelmPushWithMultiLevelSubpath(t *testing.T) {
}

func runHelmSubpathPushTest(t *testing.T, subpath, buildName, chartName, chartVersion string) {
buildInfo := pushHelmChartAndGetBuildInfo(t, subpath, buildName, chartName, chartVersion, skipOnRegistryFlake)

validateHelmBuildInfo(t, buildInfo, buildName, true, false)
assertOCIArtifactsUnderSubpath(t, buildInfo,
subpath+"/"+chartName+"/"+chartVersion)
}

// Values of the tolerateRegistryFlakes argument of pushHelmChartAndGetBuildInfo.
const (
skipOnRegistryFlake = true
failOnAnyPushError = false
)

// pushHelmChartAndGetBuildInfo packages a test chart, pushes it with 'jf helm push' and returns the published build info.
// With tolerateRegistryFlakes, push errors that look like an unavailable OCI registry skip the test instead of failing it.
func pushHelmChartAndGetBuildInfo(t *testing.T, subpath, buildName, chartName, chartVersion string, tolerateRegistryFlakes bool) buildinfo.BuildInfo {
Comment thread
bhanurp marked this conversation as resolved.
Resolved
const buildNumber = "1"

chartFile, chartDir, restoreCwd := packageHelmChartForPush(t, chartName, chartVersion)
defer restoreCwd()
// Restore the working directory before removing the chart directory: Windows cannot remove the current directory.
defer func() {
if err := os.RemoveAll(chartDir); err != nil {
t.Logf("Warning: Failed to remove test chart directory %s: %v", chartDir, err)
}
}()
defer restoreCwd()

registryHost, registryURL := helmSubpathRegistryURL(t, subpath)
if !isRepoExist(tests.HelmLocalRepo) {
t.Skipf("Repository %s does not exist. Skipping test.", tests.HelmLocalRepo)
}
if !loginHelmRegistryOrSkip(t, registryHost) {
return
}
loginHelmRegistryOrSkip(t, registryHost)

jfrogCli := coreTests.NewJfrogCli(execMain, "jfrog", "")
pushArgs := []string{
Expand All @@ -1115,19 +1130,62 @@ func runHelmSubpathPushTest(t *testing.T, subpath, buildName, chartName, chartVe
"--build-number=" + buildNumber,
}
if err := jfrogCli.Exec(pushArgs...); err != nil {
maybeSkipHelmPushFlake(t, err)
require.NoError(t, err, "helm push to subpath %q should succeed", subpath)
if tolerateRegistryFlakes {
maybeSkipHelmPushFlake(t, err)
}
require.NoError(t, err, "helm push of chart %s:%s to %q should succeed", chartName, chartVersion, subpath)
}

assert.NoError(t, artifactoryCli.Exec("bp", buildName, buildNumber))

publishedBuildInfo, found, err := tests.GetBuildInfo(serverDetails, buildName, buildNumber)
require.NoError(t, err, "Failed to get build info")
require.True(t, found, "build info should be found")
return publishedBuildInfo.BuildInfo
}

validateHelmBuildInfo(t, publishedBuildInfo.BuildInfo, buildName, true, false)
assertOCIArtifactsUnderSubpath(t, publishedBuildInfo.BuildInfo,
subpath+"/"+chartName+"/"+chartVersion)
// TestHelmPushWithSemVerBuildMetadata verifies that 'jf helm push' collects build info for a chart version with
// SemVer build metadata. Helm stores such a version under the OCI tag with '+' replaced by '_',
// so the pushed artifacts must be found in the '_' folder, while the module id keeps the real version.
// A failed push is never skipped here, so the regression cannot pass as a skipped test.
// The usual skips for a missing repository or an unusable registry login still apply.
func TestHelmPushWithSemVerBuildMetadata(t *testing.T) {
initHelmTest(t)
defer cleanHelmTest(t)

testCases := []struct {
name string
subpath string
chartName string
chartVersion string
expectedFolder string
}{
{"no subpath", "", "semver-meta-chart", "1.2.3+abc1234", "semver-meta-chart/1.2.3_abc1234"},
{"with subpath", "org/team-delta", "semver-meta-sub-chart", "103.287.0+0b2041e", "org/team-delta/semver-meta-sub-chart/103.287.0_0b2041e"},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
buildName := tests.HelmBuildName + "-push-" + testCase.chartName
inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails)
defer inttestutils.DeleteBuild(serverDetails.ArtifactoryUrl, buildName, artHttpDetails)
buildInfo := pushHelmChartAndGetBuildInfo(t, testCase.subpath, buildName, testCase.chartName, testCase.chartVersion, failOnAnyPushError)

validateHelmBuildInfo(t, buildInfo, buildName, true, false)
module := buildInfo.Modules[0]
assert.Equal(t, testCase.chartName+":"+testCase.chartVersion, module.Id, "module id must keep the original chart version")
require.NotEmpty(t, module.Artifacts, "helm module must contain the pushed OCI artifacts")
assertOCIArtifactsUnderSubpath(t, buildInfo, testCase.expectedFolder)

// The build properties are set on the same folder, so they must be found on its manifest.
serviceManager, err := utils.CreateServiceManager(serverDetails, 3, 1000, false)
require.NoError(t, err)
props, err := serviceManager.GetItemProps(tests.HelmLocalRepo + "/" + testCase.expectedFolder + "/manifest.json")
require.NoError(t, err)
require.NotNil(t, props, "manifest.json under the '_' tag folder has no properties")
assert.Contains(t, props.Properties["build.name"], buildName)
assert.Contains(t, props.Properties["build.number"], "1")
})
}
}

func TestHelmPushModuleCoexistenceAfterExistingModule(t *testing.T) {
Expand All @@ -1152,20 +1210,18 @@ func TestHelmPushModuleCoexistenceAfterExistingModule(t *testing.T) {
), "rt build-add-dependencies should seed the build with a non-helm module")

chartFile, chartDir, restoreCwd := packageHelmChartForPush(t, chartName, chartVersion)
defer restoreCwd()
defer func() {
if err := os.RemoveAll(chartDir); err != nil {
t.Logf("Warning: Failed to remove test chart directory %s: %v", chartDir, err)
}
}()
defer restoreCwd()

registryHost, registryURL := helmSubpathRegistryURL(t, "")
if !isRepoExist(tests.HelmLocalRepo) {
t.Skipf("Repository %s does not exist. Skipping test.", tests.HelmLocalRepo)
}
if !loginHelmRegistryOrSkip(t, registryHost) {
return
}
loginHelmRegistryOrSkip(t, registryHost)

jfrogCli := coreTests.NewJfrogCli(execMain, "jfrog", "")
pushArgs := []string{
Expand Down Expand Up @@ -1242,14 +1298,13 @@ func helmSubpathRegistryURL(t *testing.T, subpath string) (registryHost, registr
return registryHost, registryURL
}

func loginHelmRegistryOrSkip(t *testing.T, registryHost string) bool {
func loginHelmRegistryOrSkip(t *testing.T, registryHost string) {
err := loginHelmRegistry(t, registryHost)
if err == nil {
return true
return
}
maybeSkipHelmLoginFlake(t, err)
require.NoError(t, err, "helm registry login should succeed")
return false
}

func maybeSkipHelmLoginFlake(t *testing.T, err error) {
Expand Down
Loading