schema/v1/outputs.go (124 lines of code) (raw):

package schema import ( "encoding/json" "fmt" "reflect" "google.golang.org/protobuf/types/known/structpb" "gitlab.com/gitlab-org/step-runner/proto" ) type Outputs map[string]Output // Output describes a single step output. type Output struct { // Default is the default output value. Default any `json:"default,omitempty" yaml:"default,omitempty" mapstructure:"default,omitempty"` // Sensitive implies the output is of sensitive nature and effort should be made // to prevent accidental disclosure. Sensitive *bool `json:"sensitive,omitempty" yaml:"sensitive,omitempty" mapstructure:"sensitive,omitempty"` // Type is the value type of the output. Type *OutputType `json:"type,omitempty" yaml:"type,omitempty" mapstructure:"type,omitempty"` } func (o *Output) compile() (*proto.Spec_Content_Output, error) { protoOutput, err := o.compileToProto() if err != nil { return nil, err } err = o.verifyDefaultValueMatchesType(protoOutput) if err != nil { return nil, err } return protoOutput, nil } func (o *Output) compileToProto() (*proto.Spec_Content_Output, error) { protoOutput := &proto.Spec_Content_Output{} if o.Type == nil { return nil, fmt.Errorf("missing output type") } switch *o.Type { case OutputTypeBoolean: protoOutput.Type = proto.ValueType_boolean case OutputTypeArray: protoOutput.Type = proto.ValueType_array case OutputTypeNumber: protoOutput.Type = proto.ValueType_number case OutputTypeString: protoOutput.Type = proto.ValueType_string case OutputTypeStruct: protoOutput.Type = proto.ValueType_struct default: return nil, fmt.Errorf("unsupported output type: %v", o.Type) } if o.Default != nil { protoV, err := (&valueCompiler{o.Default}).compile() if err != nil { return nil, fmt.Errorf("compiling default %v: %w", o.Default, err) } protoOutput.Default = protoV } if o.Sensitive != nil && *o.Sensitive { protoOutput.Sensitive = true } return protoOutput, nil } func (o *Output) verifyDefaultValueMatchesType(protoOutput *proto.Spec_Content_Output) error { if o.Default == nil || protoOutput.Default == nil { return nil } if o.Type == nil { return nil } var defaultType OutputType switch *o.Type { case OutputTypeBoolean: if _, ok := protoOutput.Default.Kind.(*structpb.Value_BoolValue); ok { defaultType = OutputTypeBoolean } case OutputTypeArray: if _, ok := protoOutput.Default.Kind.(*structpb.Value_ListValue); ok { defaultType = OutputTypeArray } case OutputTypeNumber: if _, ok := protoOutput.Default.Kind.(*structpb.Value_NumberValue); ok { defaultType = OutputTypeNumber } case OutputTypeString: if _, ok := protoOutput.Default.Kind.(*structpb.Value_StringValue); ok { defaultType = OutputTypeString } case OutputTypeStruct: if _, ok := protoOutput.Default.Kind.(*structpb.Value_StructValue); ok { defaultType = OutputTypeStruct } default: return fmt.Errorf("unsupported type: %v", o.Type) } if defaultType != *o.Type { return fmt.Errorf("output type %v and default value type %v must match", o.Type, defaultType) } return nil } type OutputType string const OutputTypeArray OutputType = "array" const OutputTypeBoolean OutputType = "boolean" const OutputTypeNumber OutputType = "number" const OutputTypeString OutputType = "string" const OutputTypeStruct OutputType = "struct" var enumValues_OutputType = []any{ "string", "number", "boolean", "struct", "array", } // UnmarshalJSON implements json.Unmarshaler. func (j *OutputType) UnmarshalJSON(b []byte) error { var v string if err := json.Unmarshal(b, &v); err != nil { return err } var ok bool for _, expected := range enumValues_OutputType { if reflect.DeepEqual(v, expected) { ok = true break } } if !ok { return fmt.Errorf("invalid value (expected one of %#v): %#v", enumValues_OutputType, v) } *j = OutputType(v) return nil }