@@ -144,7 +144,13 @@ func parameterDataSource() *schema.Resource {
144
144
input = & envValue
145
145
}
146
146
147
- value , diags := parameter .ValidateInput (input )
147
+ var previous * string
148
+ envPreviousValue , ok := os .LookupEnv (ParameterEnvironmentVariablePrevious (parameter .Name ))
149
+ if ok {
150
+ previous = & envPreviousValue
151
+ }
152
+
153
+ value , diags := parameter .ValidateInput (input , previous )
148
154
if diags .HasError () {
149
155
return diags
150
156
}
@@ -395,7 +401,7 @@ func valueIsType(typ OptionType, value string) error {
395
401
return nil
396
402
}
397
403
398
- func (v * Parameter ) ValidateInput (input * string ) (string , diag.Diagnostics ) {
404
+ func (v * Parameter ) ValidateInput (input * string , previous * string ) (string , diag.Diagnostics ) {
399
405
var err error
400
406
var optionType OptionType
401
407
@@ -442,7 +448,7 @@ func (v *Parameter) ValidateInput(input *string) (string, diag.Diagnostics) {
442
448
forcedValue = * value
443
449
}
444
450
445
- d := v .validValue (forcedValue , optionType , optionValues , valuePath )
451
+ d := v .validValue (forcedValue , previous , optionType , optionValues , valuePath )
446
452
if d .HasError () {
447
453
return "" , d
448
454
}
@@ -506,7 +512,7 @@ func (v *Parameter) ValidOptions(optionType OptionType) (map[string]struct{}, di
506
512
return optionValues , nil
507
513
}
508
514
509
- func (v * Parameter ) validValue (value string , optionType OptionType , optionValues map [string ]struct {}, path cty.Path ) diag.Diagnostics {
515
+ func (v * Parameter ) validValue (value string , previous * string , optionType OptionType , optionValues map [string ]struct {}, path cty.Path ) diag.Diagnostics {
510
516
// name is used for constructing more precise error messages.
511
517
name := "Value"
512
518
if path .Equals (defaultValuePath ) {
@@ -573,7 +579,7 @@ func (v *Parameter) validValue(value string, optionType OptionType, optionValues
573
579
574
580
if len (v .Validation ) == 1 {
575
581
validCheck := & v .Validation [0 ]
576
- err := validCheck .Valid (v .Type , value )
582
+ err := validCheck .Valid (v .Type , value , previous )
577
583
if err != nil {
578
584
return diag.Diagnostics {
579
585
{
@@ -589,7 +595,7 @@ func (v *Parameter) validValue(value string, optionType OptionType, optionValues
589
595
return nil
590
596
}
591
597
592
- func (v * Validation ) Valid (typ OptionType , value string ) error {
598
+ func (v * Validation ) Valid (typ OptionType , value string , previous * string ) error {
593
599
if typ != OptionTypeNumber {
594
600
if ! v .MinDisabled {
595
601
return fmt .Errorf ("a min cannot be specified for a %s type" , typ )
@@ -639,6 +645,28 @@ func (v *Validation) Valid(typ OptionType, value string) error {
639
645
if v .Monotonic != "" && v .Monotonic != ValidationMonotonicIncreasing && v .Monotonic != ValidationMonotonicDecreasing {
640
646
return fmt .Errorf ("number monotonicity can be either %q or %q" , ValidationMonotonicIncreasing , ValidationMonotonicDecreasing )
641
647
}
648
+
649
+ switch v .Monotonic {
650
+ case "" :
651
+ // No monotonicity check
652
+ case ValidationMonotonicIncreasing , ValidationMonotonicDecreasing :
653
+ if previous != nil { // Only check if previous value exists
654
+ previousNum , err := strconv .Atoi (* previous )
655
+ if err != nil {
656
+ return fmt .Errorf ("previous value %q is not a number" , * previous )
657
+ }
658
+
659
+ if v .Monotonic == ValidationMonotonicIncreasing && ! (num >= previousNum ) {
660
+ return fmt .Errorf ("parameter value '%d' must be equal or greater than previous value: %d" , num , previousNum )
661
+ }
662
+
663
+ if v .Monotonic == ValidationMonotonicDecreasing && ! (num <= previousNum ) {
664
+ return fmt .Errorf ("parameter value '%d' must be equal or lower than previous value: %d" , num , previousNum )
665
+ }
666
+ }
667
+ default :
668
+ return fmt .Errorf ("number monotonicity can be either %q or %q" , ValidationMonotonicIncreasing , ValidationMonotonicDecreasing )
669
+ }
642
670
case OptionTypeListString :
643
671
var listOfStrings []string
644
672
err := json .Unmarshal ([]byte (value ), & listOfStrings )
@@ -666,6 +694,15 @@ func ParameterEnvironmentVariable(name string) string {
666
694
return "CODER_PARAMETER_" + hex .EncodeToString (sum [:])
667
695
}
668
696
697
+ // ParameterEnvironmentVariablePrevious returns the environment variable to
698
+ // specify for a parameter's previous value. This is used for workspace
699
+ // subsequent builds after the first. Primarily to validate monotonicity in the
700
+ // `validation` block.
701
+ func ParameterEnvironmentVariablePrevious (name string ) string {
702
+ sum := sha256 .Sum256 ([]byte (name ))
703
+ return "CODER_PARAMETER_PREVIOUS_" + hex .EncodeToString (sum [:])
704
+ }
705
+
669
706
func takeFirstError (errs ... error ) error {
670
707
for _ , err := range errs {
671
708
if err != nil {
0 commit comments