@@ -13,6 +13,17 @@ import (
1313 "github.com/blang/semver/v4"
1414)
1515
16+ type VariableCondition string
17+
18+ const (
19+ EqualTo VariableCondition = "equals"
20+ NotEqualTo VariableCondition = "notequals"
21+ )
22+
23+ func (v VariableCondition ) String () string {
24+ return string (v )
25+ }
26+
1627const draftConfigFile = "draft.yaml"
1728
1829type VariableValidator func (string ) error
@@ -32,16 +43,16 @@ type DraftConfig struct {
3243}
3344
3445type BuilderVar struct {
35- Name string `yaml:"name"`
36- ConditionalRef BuilderVarConditionalReference `yaml:"conditionalReference "`
37- Default BuilderVarDefault `yaml:"default"`
38- Description string `yaml:"description"`
39- ExampleValues [] string `yaml:"exampleValues"`
40- AllowedValues [] string `yaml:"allowedValues"`
41- Type string `yaml:"type"`
42- Kind string `yaml:"kind"`
43- Value string `yaml:"value"`
44- Versions string `yaml:"versions"`
46+ Name string `yaml:"name"`
47+ ActiveWhenConstraints [] ActiveWhenConstraint `yaml:"activeWhen "`
48+ Default BuilderVarDefault `yaml:"default"`
49+ Description string `yaml:"description"`
50+ ExampleValues [] string `yaml:"exampleValues"`
51+ AllowedValues [] string `yaml:"allowedValues"`
52+ Type string `yaml:"type"`
53+ Kind string `yaml:"kind"`
54+ Value string `yaml:"value"`
55+ Versions string `yaml:"versions"`
4556}
4657
4758// BuilderVarDefault holds info on the default value of a variable
@@ -51,10 +62,11 @@ type BuilderVarDefault struct {
5162 Value string `yaml:"value"`
5263}
5364
54- // BuilderVarConditionalReference holds a reference to a variable thats value can effect usage/validation/transformation of the associated variable
55- type BuilderVarConditionalReference struct {
56- ReferenceVar string `yaml:"referenceVar"`
57- ConditionValue string `yaml:"conditionValue"`
65+ // ActiveWhenConstraints holds information on when a variable is actively used by a template based off other variable values
66+ type ActiveWhenConstraint struct {
67+ VariableName string `yaml:"variableName"`
68+ Value string `yaml:"value"`
69+ Condition VariableCondition `yaml:"condition"`
5870}
5971
6072func NewConfigFromFS (fileSys fs.FS , path string ) (* DraftConfig , error ) {
@@ -190,6 +202,28 @@ func (d *DraftConfig) ApplyDefaultVariables() error {
190202 variable .Value = defaultVal
191203 }
192204
205+ if len (variable .ActiveWhenConstraints ) > 0 {
206+ isVarActive := true
207+ for _ , activeWhen := range variable .ActiveWhenConstraints {
208+ refVar , err := d .GetVariable (activeWhen .VariableName )
209+ if err != nil {
210+ return fmt .Errorf ("unable to get ActiveWhen reference variable: %w" , err )
211+ }
212+
213+ isConditionTrue , err := d .CheckActiveWhenConstraint (refVar , activeWhen )
214+ if err != nil {
215+ return fmt .Errorf ("unable to check ActiveWhen constraint: %w" , err )
216+ }
217+
218+ if ! isConditionTrue {
219+ isVarActive = false
220+ }
221+ }
222+ if ! isVarActive {
223+ continue
224+ }
225+ }
226+
193227 if variable .Value == "" {
194228 if variable .Default .Value != "" {
195229 log .Infof ("Variable %s defaulting to value %s" , variable .Name , variable .Default .Value )
@@ -246,6 +280,28 @@ func (d *DraftConfig) ApplyDefaultVariablesForVersion(version string) error {
246280 variable .Value = defaultVal
247281 }
248282
283+ if len (variable .ActiveWhenConstraints ) > 0 {
284+ isVarActive := true
285+ for _ , activeWhen := range variable .ActiveWhenConstraints {
286+ refVar , err := d .GetVariable (activeWhen .VariableName )
287+ if err != nil {
288+ return fmt .Errorf ("unable to get ActiveWhen reference variable: %w" , err )
289+ }
290+
291+ isConditionTrue , err := d .CheckActiveWhenConstraint (refVar , activeWhen )
292+ if err != nil {
293+ return fmt .Errorf ("unable to check ActiveWhen constraint: %w" , err )
294+ }
295+
296+ if ! isConditionTrue {
297+ isVarActive = false
298+ }
299+ }
300+ if ! isVarActive {
301+ continue
302+ }
303+ }
304+
249305 if variable .Value == "" {
250306 if variable .Default .Value != "" {
251307 log .Infof ("Variable %s defaulting to value %s" , variable .Name , variable .Default .Value )
@@ -260,6 +316,36 @@ func (d *DraftConfig) ApplyDefaultVariablesForVersion(version string) error {
260316 return nil
261317}
262318
319+ func (d * DraftConfig ) CheckActiveWhenConstraint (refVar * BuilderVar , activeWhen ActiveWhenConstraint ) (bool , error ) {
320+ checkValue := refVar .Value
321+ if checkValue == "" {
322+ if refVar .Default .Value != "" {
323+ checkValue = refVar .Default .Value
324+ }
325+
326+ if refVar .Default .ReferenceVar != "" {
327+ refValue , err := d .recurseReferenceVars (refVar , refVar , true )
328+ if err != nil {
329+ return false , err
330+ }
331+ if refValue == "" {
332+ return false , errors .New ("reference variable has no value" )
333+ }
334+
335+ checkValue = refValue
336+ }
337+ }
338+
339+ switch activeWhen .Condition {
340+ case EqualTo :
341+ return checkValue == activeWhen .Value , nil
342+ case NotEqualTo :
343+ return checkValue != activeWhen .Value , nil
344+ }
345+
346+ return false , nil
347+ }
348+
263349// recurseReferenceVars recursively checks each variable's ReferenceVar if it doesn't have a custom input. If there's no more ReferenceVars, it will return the default value of the last ReferenceVar.
264350func (d * DraftConfig ) recurseReferenceVars (referenceVar * BuilderVar , variableCheck * BuilderVar , isFirst bool ) (string , error ) {
265351 if ! isFirst && referenceVar .Name == variableCheck .Name {
@@ -321,20 +407,33 @@ func (d *DraftConfig) DeepCopy() *DraftConfig {
321407
322408func (bv * BuilderVar ) DeepCopy () * BuilderVar {
323409 newVar := & BuilderVar {
324- Name : bv .Name ,
325- Default : bv .Default ,
326- Description : bv .Description ,
327- Type : bv .Type ,
328- Kind : bv .Kind ,
329- Value : bv .Value ,
330- Versions : bv .Versions ,
331- ExampleValues : make ([]string , len (bv .ExampleValues )),
410+ Name : bv .Name ,
411+ Default : bv .Default ,
412+ Description : bv .Description ,
413+ Type : bv .Type ,
414+ Kind : bv .Kind ,
415+ Value : bv .Value ,
416+ Versions : bv .Versions ,
417+ ExampleValues : make ([]string , len (bv .ExampleValues )),
418+ AllowedValues : make ([]string , len (bv .AllowedValues )),
419+ ActiveWhenConstraints : make ([]ActiveWhenConstraint , len (bv .ActiveWhenConstraints )),
332420 }
333-
421+ for i , awc := range bv .ActiveWhenConstraints {
422+ newVar .ActiveWhenConstraints [i ] = * awc .DeepCopy ()
423+ }
424+ copy (newVar .AllowedValues , bv .AllowedValues )
334425 copy (newVar .ExampleValues , bv .ExampleValues )
335426 return newVar
336427}
337428
429+ func (awc ActiveWhenConstraint ) DeepCopy () * ActiveWhenConstraint {
430+ return & ActiveWhenConstraint {
431+ VariableName : awc .VariableName ,
432+ Value : awc .Value ,
433+ Condition : awc .Condition ,
434+ }
435+ }
436+
338437// TemplateVariableRecorder is an interface for recording variables that are read using draft configs
339438type TemplateVariableRecorder interface {
340439 Record (key , value string )
0 commit comments