mirror of
https://github.com/coder/coder.git
synced 2025-07-06 15:41:45 +00:00
* feat: influence parameter defaults through cli flag/env Add a --parameter-default flag / CODER_RICH_PARAMETER_DEFAULT environment variable which overrides default values suggested for parameters. This allows scripts or middleware wrapping the CLI to substitute defaults for parameter values beyond those defined at the template level. For example, Git repository/branch parameters can be given defaults based on the current checkout, or default parameter values can be parsed out of files inside the repo. * Rename defaults arg to defaultOverrides
130 lines
3.6 KiB
Go
130 lines
3.6 KiB
Go
package cli
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"golang.org/x/xerrors"
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"github.com/coder/coder/v2/codersdk"
|
|
"github.com/coder/serpent"
|
|
)
|
|
|
|
// workspaceParameterFlags are used by commands processing rich parameters and/or build options.
|
|
type workspaceParameterFlags struct {
|
|
promptBuildOptions bool
|
|
buildOptions []string
|
|
|
|
richParameterFile string
|
|
richParameters []string
|
|
richParameterDefaults []string
|
|
|
|
promptRichParameters bool
|
|
}
|
|
|
|
func (wpf *workspaceParameterFlags) allOptions() []serpent.Option {
|
|
options := append(wpf.cliBuildOptions(), wpf.cliParameters()...)
|
|
options = append(options, wpf.cliParameterDefaults()...)
|
|
return append(options, wpf.alwaysPrompt())
|
|
}
|
|
|
|
func (wpf *workspaceParameterFlags) cliBuildOptions() []serpent.Option {
|
|
return serpent.OptionSet{
|
|
{
|
|
Flag: "build-option",
|
|
Env: "CODER_BUILD_OPTION",
|
|
Description: `Build option value in the format "name=value".`,
|
|
Value: serpent.StringArrayOf(&wpf.buildOptions),
|
|
},
|
|
{
|
|
Flag: "build-options",
|
|
Description: "Prompt for one-time build options defined with ephemeral parameters.",
|
|
Value: serpent.BoolOf(&wpf.promptBuildOptions),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (wpf *workspaceParameterFlags) cliParameters() []serpent.Option {
|
|
return serpent.OptionSet{
|
|
serpent.Option{
|
|
Flag: "parameter",
|
|
Env: "CODER_RICH_PARAMETER",
|
|
Description: `Rich parameter value in the format "name=value".`,
|
|
Value: serpent.StringArrayOf(&wpf.richParameters),
|
|
},
|
|
serpent.Option{
|
|
Flag: "rich-parameter-file",
|
|
Env: "CODER_RICH_PARAMETER_FILE",
|
|
Description: "Specify a file path with values for rich parameters defined in the template.",
|
|
Value: serpent.StringOf(&wpf.richParameterFile),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (wpf *workspaceParameterFlags) cliParameterDefaults() []serpent.Option {
|
|
return serpent.OptionSet{
|
|
serpent.Option{
|
|
Flag: "parameter-default",
|
|
Env: "CODER_RICH_PARAMETER_DEFAULT",
|
|
Description: `Rich parameter default values in the format "name=value".`,
|
|
Value: serpent.StringArrayOf(&wpf.richParameterDefaults),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (wpf *workspaceParameterFlags) alwaysPrompt() serpent.Option {
|
|
return serpent.Option{
|
|
Flag: "always-prompt",
|
|
Description: "Always prompt all parameters. Does not pull parameter values from existing workspace.",
|
|
Value: serpent.BoolOf(&wpf.promptRichParameters),
|
|
}
|
|
}
|
|
|
|
func asWorkspaceBuildParameters(nameValuePairs []string) ([]codersdk.WorkspaceBuildParameter, error) {
|
|
var params []codersdk.WorkspaceBuildParameter
|
|
for _, nameValue := range nameValuePairs {
|
|
split := strings.SplitN(nameValue, "=", 2)
|
|
if len(split) < 2 {
|
|
return nil, xerrors.Errorf("format key=value expected, but got %s", nameValue)
|
|
}
|
|
params = append(params, codersdk.WorkspaceBuildParameter{
|
|
Name: split[0],
|
|
Value: split[1],
|
|
})
|
|
}
|
|
return params, nil
|
|
}
|
|
|
|
func parseParameterMapFile(parameterFile string) (map[string]string, error) {
|
|
parameterFileContents, err := os.ReadFile(parameterFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
mapStringInterface := make(map[string]interface{})
|
|
err = yaml.Unmarshal(parameterFileContents, &mapStringInterface)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
parameterMap := map[string]string{}
|
|
for k, v := range mapStringInterface {
|
|
switch val := v.(type) {
|
|
case string, bool, int:
|
|
parameterMap[k] = fmt.Sprintf("%v", val)
|
|
case []interface{}:
|
|
b, err := json.Marshal(&val)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
parameterMap[k] = string(b)
|
|
default:
|
|
return nil, xerrors.Errorf("invalid parameter type: %T", v)
|
|
}
|
|
}
|
|
return parameterMap, nil
|
|
}
|