From 468cacd4cad53d7e857b0364cb00e10442146563 Mon Sep 17 00:00:00 2001 From: Pete Davison Date: Wed, 1 Jul 2026 14:39:29 +0000 Subject: [PATCH] feat: improvement to warning when experiments are stable --- experiments/errors.go | 8 ++++-- experiments/experiment.go | 56 ++++++++++++++++++++++++++++---------- experiments/experiments.go | 17 ++++++------ 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/experiments/errors.go b/experiments/errors.go index 68a5f8b8..41fde8ef 100644 --- a/experiments/errors.go +++ b/experiments/errors.go @@ -1,6 +1,7 @@ package experiments import ( + "cmp" "fmt" "strconv" "strings" @@ -24,12 +25,15 @@ func (err InvalidValueError) Error() string { } type InactiveError struct { - Name string + Name string + Reason string } func (err InactiveError) Error() string { + reason := cmp.Or(err.Reason, "is inactive and cannot be enabled") return fmt.Sprintf( - "task: Experiment %q is inactive and cannot be enabled", + "task: Experiment %q %s", err.Name, + reason, ) } diff --git a/experiments/experiment.go b/experiments/experiment.go index 2546b0a9..34d882a5 100644 --- a/experiments/experiment.go +++ b/experiments/experiment.go @@ -9,27 +9,54 @@ import ( ) type Experiment struct { - Name string // The name of the experiment. - AllowedValues []int // The values that can enable this experiment. - Value int // The version of the experiment that is enabled. + Name string // The name of the experiment. + AllowedValues []int // The values that can enable this experiment. + Value int // The version of the experiment that is enabled. + InactiveReason string // If not active, the reason why it is inactive. +} + +func getValue(xName string, config *ast.TaskRC) int { + var value int + if config != nil { + value = config.Experiments[xName] + } + if value == 0 { + value, _ = strconv.Atoi(getEnv(xName)) + } + return value } // New creates a new experiment with the given name and sets the values that can // enable it. func New(xName string, config *ast.TaskRC, allowedValues ...int) Experiment { - var value int - if config != nil { - value = config.Experiments[xName] - } - - if value == 0 { - value, _ = strconv.Atoi(getEnv(xName)) - } - x := Experiment{ Name: xName, AllowedValues: allowedValues, - Value: value, + Value: getValue(xName, config), + } + xList = append(xList, x) + return x +} + +// NewStable creates a new experiment that is stable and no longer needs to be +// enabled. It will always be inactive and cannot be enabled. +func NewStable(xName string, config *ast.TaskRC) Experiment { + x := Experiment{ + Name: xName, + Value: getValue(xName, config), + InactiveReason: "is stable and no longer needs to be enabled", + } + xList = append(xList, x) + return x +} + +// NewAbandoned creates a new experiment that has been abandoned and is no +// longer supported. It will always be inactive and cannot be enabled. +func NewAbandoned(xName string, config *ast.TaskRC) Experiment { + x := Experiment{ + Name: xName, + Value: getValue(xName, config), + InactiveReason: "has been abandoned and is no longer supported", } xList = append(xList, x) return x @@ -46,7 +73,8 @@ func (x Experiment) Active() bool { func (x Experiment) Valid() error { if !x.Active() && x.Value != 0 { return &InactiveError{ - Name: x.Name, + Name: x.Name, + Reason: x.InactiveReason, } } if !x.Enabled() && x.Value != 0 { diff --git a/experiments/experiments.go b/experiments/experiments.go index 3e14d39a..77421740 100644 --- a/experiments/experiments.go +++ b/experiments/experiments.go @@ -16,16 +16,16 @@ const envPrefix = "TASK_X_" // Active experiments. var ( - GentleForce Experiment - RemoteTaskfiles Experiment - EnvPrecedence Experiment + GentleForce Experiment + EnvPrecedence Experiment ) // Inactive experiments. These are experiments that cannot be enabled, but are // preserved for error handling. var ( - AnyVariables Experiment - MapVariables Experiment + AnyVariables Experiment + MapVariables Experiment + RemoteTaskfiles Experiment ) // An internal list of all the initialized experiments used for iterating. @@ -41,10 +41,11 @@ func ParseWithConfig(dir string, config *ast.TaskRC) { readDotEnv(dir) // Initialize the experiments GentleForce = New("GENTLE_FORCE", config, 1) - RemoteTaskfiles = New("REMOTE_TASKFILES", config, 1) EnvPrecedence = New("ENV_PRECEDENCE", config, 1) - AnyVariables = New("ANY_VARIABLES", config) - MapVariables = New("MAP_VARIABLES", config) + // Inactive experiments + AnyVariables = NewStable("ANY_VARIABLES", config) + MapVariables = NewStable("MAP_VARIABLES", config) + RemoteTaskfiles = NewStable("REMOTE_TASKFILES", config) } // Validate checks if any experiments have been enabled while being inactive.