From 830c7fead2e006501df3c453f05e8a8721a0bdd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86gir=20M=C3=A1ni=20Hauksson?= <54936225+sourcehawk@users.noreply.github.com> Date: Tue, 2 Jun 2026 01:10:16 +0200 Subject: [PATCH] feat(feature): add NewBooleanGate convenience constructor NewBooleanGate(enabled) is shorthand for NewVersionGate("", nil).When(enabled): a gate with no version constraints whose result is driven solely by a boolean. It expresses flag-toggled mutations and resources more directly than spelling out an empty version gate, and still returns a *VersionGate so further conditions compose with When. Co-Authored-By: Claude Opus 4.8 (1M context) --- pkg/feature/feature.go | 11 +++++++++++ pkg/feature/feature_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/pkg/feature/feature.go b/pkg/feature/feature.go index 3b5ae876..d7b57083 100644 --- a/pkg/feature/feature.go +++ b/pkg/feature/feature.go @@ -88,6 +88,17 @@ func NewVersionGate(currentVersion string, versionConstraints []VersionConstrain } } +// NewBooleanGate creates a VersionGate that is enabled only when enabled is true. +// +// It is shorthand for NewVersionGate("", nil).When(enabled): a gate with no +// version constraints whose result is driven solely by the boolean. Use it for a +// mutation or resource toggled by a spec flag rather than an application version. +// Because it returns a *VersionGate, further conditions can still be composed with +// When. +func NewBooleanGate(enabled bool) *VersionGate { + return NewVersionGate("", nil).When(enabled) +} + // When adds a boolean condition that must be true for the gate to be enabled. // // Calls are additive: all values passed through When must be true for Enabled() diff --git a/pkg/feature/feature_test.go b/pkg/feature/feature_test.go index ef620313..f185084b 100644 --- a/pkg/feature/feature_test.go +++ b/pkg/feature/feature_test.go @@ -163,6 +163,36 @@ func TestVersionGate_WhenChaining(t *testing.T) { assert.False(t, enabled) } +func TestNewBooleanGate(t *testing.T) { + tests := []struct { + name string + enabled bool + want bool + }{ + {name: "enabled", enabled: true, want: true}, + {name: "disabled", enabled: false, want: false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gate := NewBooleanGate(tt.enabled) + enabled, err := gate.Enabled() + assert.NoError(t, err) + assert.Equal(t, tt.want, enabled) + }) + } +} + +func TestNewBooleanGate_Chainable(t *testing.T) { + // NewBooleanGate returns a *VersionGate, so additional When conditions still + // compose: every condition must be true for the gate to be enabled. + gate := NewBooleanGate(true).When(false) + + enabled, err := gate.Enabled() + assert.NoError(t, err) + assert.False(t, enabled) +} + func TestMutation_ApplyIntent(t *testing.T) { const newValue = "new-value" type testObj struct {