mirror of
https://github.com/helmfile/helmfile.git
synced 2026-10-08 15:42:44 +02:00
Implement OCI chart digest support for helm chart pinning
Co-authored-by: yxxhero <11087727+yxxhero@users.noreply.github.com>
This commit is contained in:
co-authored by
yxxhero
parent
b95d617b96
commit
1f786a3662
+54
-3
@@ -4071,9 +4071,60 @@ func (st *HelmState) getOCIQualifiedChartName(release *ReleaseSpec, helm helmexe
|
||||
|
||||
var qualifiedChartName, chartName string
|
||||
if strings.HasPrefix(release.Chart, "oci://") {
|
||||
parts := strings.Split(release.Chart, "/")
|
||||
chartName = parts[len(parts)-1]
|
||||
qualifiedChartName = strings.Replace(fmt.Sprintf("%s:%s", release.Chart, chartVersion), "oci://", "", 1)
|
||||
// Parse the chart URL to detect existing version/digest information
|
||||
chartURL := release.Chart
|
||||
urlWithoutProtocol := strings.TrimPrefix(chartURL, "oci://")
|
||||
|
||||
// Check for digest (@sha256:...)
|
||||
digestIndex := strings.Index(urlWithoutProtocol, "@")
|
||||
hasDigest := digestIndex != -1
|
||||
|
||||
// Check for version tag (:version)
|
||||
var versionInURL string
|
||||
if hasDigest {
|
||||
// Check for version before digest (e.g., chart:1.0.0@sha256:...)
|
||||
beforeDigest := urlWithoutProtocol[:digestIndex]
|
||||
if colonIndex := strings.LastIndex(beforeDigest, ":"); colonIndex > strings.LastIndex(beforeDigest, "/") {
|
||||
versionInURL = beforeDigest[colonIndex+1:]
|
||||
}
|
||||
} else {
|
||||
// Check for version at end (e.g., chart:1.0.0)
|
||||
if colonIndex := strings.LastIndex(urlWithoutProtocol, ":"); colonIndex > strings.LastIndex(urlWithoutProtocol, "/") {
|
||||
versionInURL = urlWithoutProtocol[colonIndex+1:]
|
||||
}
|
||||
}
|
||||
|
||||
// Determine effective chart version and build qualified name
|
||||
if hasDigest || versionInURL != "" {
|
||||
// Chart URL already contains version/digest, use as-is without adding version
|
||||
qualifiedChartName = urlWithoutProtocol
|
||||
|
||||
// Extract chart name from URL
|
||||
parts := strings.Split(urlWithoutProtocol, "/")
|
||||
chartNamePart := parts[len(parts)-1]
|
||||
|
||||
// Remove version/digest from chart name for extraction
|
||||
if hasDigest {
|
||||
chartNamePart = strings.Split(chartNamePart, "@")[0]
|
||||
}
|
||||
if colonIndex := strings.LastIndex(chartNamePart, ":"); colonIndex > 0 {
|
||||
chartNamePart = chartNamePart[:colonIndex]
|
||||
}
|
||||
chartName = chartNamePart
|
||||
|
||||
// Set effective version for return (use version from URL if available, otherwise indicate digest)
|
||||
if versionInURL != "" {
|
||||
chartVersion = versionInURL
|
||||
} else {
|
||||
// For digest-only, extract digest as version for helm compatibility
|
||||
chartVersion = urlWithoutProtocol[digestIndex:]
|
||||
}
|
||||
} else {
|
||||
// No version/digest in URL, use explicit version
|
||||
parts := strings.Split(urlWithoutProtocol, "/")
|
||||
chartName = parts[len(parts)-1]
|
||||
qualifiedChartName = fmt.Sprintf("%s:%s", urlWithoutProtocol, chartVersion)
|
||||
}
|
||||
} else {
|
||||
var repo *RepositorySpec
|
||||
repo, chartName = st.GetRepositoryAndNameFromChartName(release.Chart)
|
||||
|
||||
@@ -3310,6 +3310,87 @@ func TestGetOCIQualifiedChartName(t *testing.T) {
|
||||
{"registry/chart-path/chart-name", "chart-name", ""},
|
||||
},
|
||||
},
|
||||
{
|
||||
state: HelmState{
|
||||
ReleaseSetSpec: ReleaseSetSpec{
|
||||
Repositories: []RepositorySpec{},
|
||||
Releases: []ReleaseSpec{
|
||||
{
|
||||
Chart: "oci://ghcr.io/nginxinc/charts/nginx-ingress:2.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
helmVersion: "3.13.3",
|
||||
expected: []struct {
|
||||
qualifiedChartName string
|
||||
chartName string
|
||||
chartVersion string
|
||||
}{
|
||||
{"ghcr.io/nginxinc/charts/nginx-ingress:2.0.0", "nginx-ingress", "2.0.0"},
|
||||
},
|
||||
},
|
||||
{
|
||||
state: HelmState{
|
||||
ReleaseSetSpec: ReleaseSetSpec{
|
||||
Repositories: []RepositorySpec{},
|
||||
Releases: []ReleaseSpec{
|
||||
{
|
||||
Chart: "oci://ghcr.io/nginxinc/charts/nginx-ingress@sha256:87ad282a8e7cc31913ce0543de2933ddb3f3eba80d6e5285f33b62ed720fc085",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
helmVersion: "3.13.3",
|
||||
expected: []struct {
|
||||
qualifiedChartName string
|
||||
chartName string
|
||||
chartVersion string
|
||||
}{
|
||||
{"ghcr.io/nginxinc/charts/nginx-ingress@sha256:87ad282a8e7cc31913ce0543de2933ddb3f3eba80d6e5285f33b62ed720fc085", "nginx-ingress", "@sha256:87ad282a8e7cc31913ce0543de2933ddb3f3eba80d6e5285f33b62ed720fc085"},
|
||||
},
|
||||
},
|
||||
{
|
||||
state: HelmState{
|
||||
ReleaseSetSpec: ReleaseSetSpec{
|
||||
Repositories: []RepositorySpec{},
|
||||
Releases: []ReleaseSpec{
|
||||
{
|
||||
Chart: "oci://ghcr.io/nginxinc/charts/nginx-ingress:2.0.0@sha256:87ad282a8e7cc31913ce0543de2933ddb3f3eba80d6e5285f33b62ed720fc085",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
helmVersion: "3.13.3",
|
||||
expected: []struct {
|
||||
qualifiedChartName string
|
||||
chartName string
|
||||
chartVersion string
|
||||
}{
|
||||
{"ghcr.io/nginxinc/charts/nginx-ingress:2.0.0@sha256:87ad282a8e7cc31913ce0543de2933ddb3f3eba80d6e5285f33b62ed720fc085", "nginx-ingress", "2.0.0"},
|
||||
},
|
||||
},
|
||||
{
|
||||
state: HelmState{
|
||||
ReleaseSetSpec: ReleaseSetSpec{
|
||||
Repositories: []RepositorySpec{},
|
||||
Releases: []ReleaseSpec{
|
||||
{
|
||||
Chart: "oci://ghcr.io/nginxinc/charts/nginx-ingress",
|
||||
Version: "@sha256:87ad282a8e7cc31913ce0543de2933ddb3f3eba80d6e5285f33b62ed720fc085",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
helmVersion: "3.13.3",
|
||||
expected: []struct {
|
||||
qualifiedChartName string
|
||||
chartName string
|
||||
chartVersion string
|
||||
}{
|
||||
{"ghcr.io/nginxinc/charts/nginx-ingress:@sha256:87ad282a8e7cc31913ce0543de2933ddb3f3eba80d6e5285f33b62ed720fc085", "nginx-ingress", "@sha256:87ad282a8e7cc31913ce0543de2933ddb3f3eba80d6e5285f33b62ed720fc085"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
Reference in New Issue
Block a user