This commit is contained in:
Zubair Haque 2025-10-27 09:57:26 -04:00 committed by GitHub
commit 47d3a4f240
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 95 additions and 7 deletions

View File

@ -47,6 +47,7 @@ func NewApplyCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&applyOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present")
f.BoolVar(&applyOptions.SkipNeeds, "skip-needs", true, `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`)
f.BoolVar(&applyOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
f.BoolVar(&applyOptions.EnforceNeedsAreInstalled, "enforce-needs-are-installed", false, "enforce that all 'needs' dependencies are installable before applying changes")
f.BoolVar(&applyOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
f.BoolVar(&applyOptions.SkipDiffOnInstall, "skip-diff-on-install", false, "Skips running helm-diff on releases being newly installed on this apply. Useful when the release manifests are too huge to be reviewed, or it's too time-consuming to diff at all")
f.BoolVar(&applyOptions.IncludeTests, "include-tests", false, "enable the diffing of the helm test hooks")

View File

@ -40,6 +40,7 @@ func NewDiffCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&diffOptions.SkipNeeds, "skip-needs", true, `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`)
f.BoolVar(&diffOptions.IncludeTests, "include-tests", false, "enable the diffing of the helm test hooks")
f.BoolVar(&diffOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
f.BoolVar(&diffOptions.EnforceNeedsAreInstalled, "enforce-needs-are-installed", false, "enforce that all 'needs' dependencies are installable before applying changes")
f.BoolVar(&diffOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
f.BoolVar(&diffOptions.SkipDiffOnInstall, "skip-diff-on-install", false, "Skips running helm-diff on releases being newly installed on this apply. Useful when the release manifests are too huge to be reviewed, or it's too time-consuming to diff at all")
f.BoolVar(&diffOptions.ShowSecrets, "show-secrets", false, "do not redact secret values in the output. should be used for debug purpose only")

View File

@ -41,6 +41,7 @@ func NewSyncCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&syncOptions.SkipCRDs, "skip-crds", false, "if set, no CRDs will be installed on sync. By default, CRDs are installed if not already present")
f.BoolVar(&syncOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
f.BoolVar(&syncOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
f.BoolVar(&syncOptions.EnforceNeedsAreInstalled, "enforce-needs-are-installed", false, "enforce that all 'needs' dependencies are installable before applying changes")
f.BoolVar(&syncOptions.HideNotes, "hide-notes", false, "add --hide-notes flag to helm")
f.BoolVar(&syncOptions.TakeOwnership, "take-ownership", false, `add --take-ownership flag to helm`)
f.BoolVar(&syncOptions.SyncReleaseLabels, "sync-release-labels", false, "sync release labels to the target release")

View File

@ -43,6 +43,7 @@ func NewTemplateCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.BoolVar(&templateOptions.SkipNeeds, "skip-needs", true, `do not automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided. Defaults to true when --include-needs or --include-transitive-needs is not provided`)
f.BoolVar(&templateOptions.IncludeNeeds, "include-needs", false, `automatically include releases from the target release's "needs" when --selector/-l flag is provided. Does nothing when --selector/-l flag is not provided`)
f.BoolVar(&templateOptions.IncludeTransitiveNeeds, "include-transitive-needs", false, `like --include-needs, but also includes transitive needs (needs of needs). Does nothing when --selector/-l flag is not provided. Overrides exclusions of other selectors and conditions.`)
f.BoolVar(&templateOptions.EnforceNeedsAreInstalled, "enforce-needs-are-installed", false, "enforce that all 'needs' dependencies are installable before applying changes")
f.BoolVar(&templateOptions.SkipCleanup, "skip-cleanup", false, "Stop cleaning up temporary values generated by helmfile and helm-secrets. Useful for debugging. Don't use in production for security")
f.BoolVar(&templateOptions.NoHooks, "no-hooks", false, "do not template files made by hooks.")
f.StringVar(&templateOptions.PostRenderer, "post-renderer", "", `pass --post-renderer to "helm template" or "helm upgrade --install"`)

View File

@ -1979,19 +1979,34 @@ func (a *App) withNeeds(r *Run, c DAGConfig, includeDisabled bool, f func(*state
includeNeeds = true
}
batches, err := st.PlanReleases(state.PlanOptions{Reverse: false, SelectedReleases: selectedReleases, IncludeNeeds: includeNeeds, IncludeTransitiveNeeds: c.IncludeTransitiveNeeds(), SkipNeeds: c.SkipNeeds()})
batches, err := st.PlanReleases(state.PlanOptions{
Reverse: false,
SelectedReleases: selectedReleases,
IncludeNeeds: includeNeeds,
IncludeTransitiveNeeds: c.IncludeTransitiveNeeds(),
SkipNeeds: c.SkipNeeds(),
})
if err != nil {
return false, []error{err}
}
var selectedReleasesWithNeeds []state.ReleaseSpec
for _, rs := range batches {
for _, r := range rs {
selectedReleasesWithNeeds = append(selectedReleasesWithNeeds, r.ReleaseSpec)
}
}
if c.EnforceNeedsAreInstalled() {
for _, r := range toRender {
visited := make(map[string]bool)
if depErr := st.HasTransitiveDependencyWithInstalledFalse(r, visited); depErr != nil {
return false, []error{fmt.Errorf("Release %s has a transitive dependency %s marked as installed=false", depErr.Release.Name, depErr.Dependency.Name)}
}
}
}
var toRender []state.ReleaseSpec
releasesToUninstall := map[string]state.ReleaseSpec{}

View File

@ -2104,11 +2104,12 @@ type configImpl struct {
skipSchemaValidation bool
skipRefresh bool
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
skipCharts bool
kubeVersion string
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
enforceNeedsAreInstalled bool
skipCharts bool
kubeVersion string
}
func (c configImpl) Selectors() []string {
@ -2318,6 +2319,10 @@ func (a applyConfig) SkipNeeds() bool {
return a.skipNeeds
}
func (a applyConfig) EnforceNeedsAreInstalled() bool {
return a.enforceNeedsAreInstalled
}
func (a applyConfig) IncludeNeeds() bool {
return a.includeNeeds || a.IncludeTransitiveNeeds()
}

View File

@ -242,6 +242,7 @@ type DAGConfig interface {
SkipNeeds() bool
IncludeNeeds() bool
IncludeTransitiveNeeds() bool
EnforceNeedsAreInstalled() bool
}
type WriteValuesConfigProvider interface {

View File

@ -28,6 +28,8 @@ type ApplyOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is true if the transitive needs should be included
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled is true if we should error if/when there are unmeetable dependencies
EnforceNeedsAreInstalled bool
// SkipDiffOnInstall is true if the diff should be skipped on install
SkipDiffOnInstall bool
// DiffArgs is the list of arguments to pass to the helm-diff.
@ -139,6 +141,11 @@ func (a *ApplyImpl) IncludeTransitiveNeeds() bool {
return a.ApplyOptions.IncludeTransitiveNeeds
}
// EnforceNeedsAreInstalled is true we should error if/when there are unmeetable dependencies
func (a *ApplyImpl) EnforceNeedsAreInstalled() bool {
return a.ApplyOptions.EnforceNeedsAreInstalled
}
// ShowSecrets returns the show secrets.
func (a *ApplyImpl) ShowSecrets() bool {
return a.ApplyOptions.ShowSecrets

View File

@ -18,6 +18,8 @@ type DiffOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is the include transitive needs flag
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled is the enforce needs are installed flag
EnforceNeedsAreInstalled bool
// SkipDiffOnInstall is the skip diff on install flag
SkipDiffOnInstall bool
// ShowSecrets is the show secrets flag
@ -87,6 +89,11 @@ func (t *DiffImpl) IncludeTransitiveNeeds() bool {
return t.DiffOptions.IncludeTransitiveNeeds
}
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
func (t *DiffImpl) EnforceNeedsAreInstalled() bool {
return t.DiffOptions.EnforceNeedsAreInstalled
}
// Set returns the Set
func (t *DiffImpl) Set() []string {
return t.DiffOptions.Set

View File

@ -14,6 +14,8 @@ type LintOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is the include transitive needs flag
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled is the enforce needs are installed flag
EnforceNeedsAreInstalled bool
// SkipDeps is the skip deps flag
}
@ -66,6 +68,11 @@ func (l *LintImpl) IncludeTransitiveNeeds() bool {
return l.LintOptions.IncludeTransitiveNeeds
}
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
func (l *LintImpl) EnforceNeedsAreInstalled() bool {
return l.LintOptions.EnforceNeedsAreInstalled
}
// SkipNeeds returns the skip needs
func (l *LintImpl) SkipNeeds() bool {
if !l.IncludeNeeds() {

View File

@ -16,6 +16,8 @@ type SyncOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is the include transitive needs flag
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled indicates whether to error when there are unmeetable dependencies
EnforceNeedsAreInstalled bool
// SkipCrds is the skip crds flag
SkipCRDs bool
// Wait is the wait flag
@ -82,6 +84,11 @@ func (t *SyncImpl) IncludeTransitiveNeeds() bool {
return t.SyncOptions.IncludeTransitiveNeeds
}
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
func (t *SyncImpl) EnforceNeedsAreInstalled() bool {
return t.SyncOptions.EnforceNeedsAreInstalled
}
// Set returns the Set
func (t *SyncImpl) Set() []string {
return t.SyncOptions.Set

View File

@ -30,6 +30,8 @@ type TemplateOptions struct {
IncludeNeeds bool
// IncludeTransitiveNeeds is the include transitive needs flag
IncludeTransitiveNeeds bool
// EnforceNeedsAreInstalled indicates whether to error when there are unmeetable dependencies
EnforceNeedsAreInstalled bool
// No-Hooks is the no hooks flag
NoHooks bool
// SkipCleanup is the skip cleanup flag
@ -158,3 +160,8 @@ func (t *TemplateImpl) KubeVersion() string {
func (t *TemplateImpl) ShowOnly() []string {
return t.TemplateOptions.ShowOnly
}
// EnforceNeedsAreInstalled errors if the transitive dependencies are not installable
func (t *TemplateImpl) EnforceNeedsAreInstalled() bool {
return t.TemplateOptions.EnforceNeedsAreInstalled
}

View File

@ -2657,6 +2657,34 @@ func (st *HelmState) UpdateDeps(helm helmexec.Interface, includeTransitiveNeeds
return nil
}
// DependencyError holds information about a release and its dependency that is not installed.
type DependencyError struct {
Release ReleaseSpec
Dependency ReleaseSpec
}
// hasTransitiveDependencyWithInstallFalse checks if a release has a transitive dependency with Install set to false.
func (st *HelmState) HasTransitiveDependencyWithInstalledFalse(release ReleaseSpec, visited map[string]bool) *DependencyError {
if visited[release.Name] {
return nil
}
visited[release.Name] = true
for _, dep := range release.Needs {
for _, r := range st.Releases {
if r.Name == dep {
if r.Installed != nil && !*r.Installed {
return &DependencyError{Release: release, Dependency: r}
}
if depErr := st.HasTransitiveDependencyWithInstalledFalse(r, visited); depErr != nil {
return depErr
}
}
}
}
return nil
}
// find "Chart.yaml"
func findChartDirectory(topLevelDir string) (string, error) {
var files []string