1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-01-16 05:16:08 +02:00

Fixed validation for possibleValues option (#3228)

* Fixed validation for possibleValues option

* Change oneof-custom to possible-values

* go generate

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
Siarhei Pazdniakou 2021-11-15 12:06:48 +01:00 committed by GitHub
parent f431054b6f
commit e97242b7e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 122 additions and 59 deletions

View File

@ -19,7 +19,7 @@ type abapAddonAssemblyKitPublishTargetVectorOptions struct {
AbapAddonAssemblyKitEndpoint string `json:"abapAddonAssemblyKitEndpoint,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
TargetVectorScope string `json:"targetVectorScope,omitempty" validate:"oneof=T P"`
TargetVectorScope string `json:"targetVectorScope,omitempty" validate:"possible-values=T P"`
MaxRuntimeInMinutes int `json:"maxRuntimeInMinutes,omitempty"`
PollingIntervalInSeconds int `json:"pollingIntervalInSeconds,omitempty"`
AddonDescriptor string `json:"addonDescriptor,omitempty"`

View File

@ -18,11 +18,11 @@ import (
)
type artifactPrepareVersionOptions struct {
BuildTool string `json:"buildTool,omitempty" validate:"oneof=custom docker dub golang gradle maven mta npm pip sbt yarn"`
BuildTool string `json:"buildTool,omitempty" validate:"possible-values=custom docker dub golang gradle maven mta npm pip sbt yarn"`
CommitUserName string `json:"commitUserName,omitempty"`
CustomVersionField string `json:"customVersionField,omitempty"`
CustomVersionSection string `json:"customVersionSection,omitempty"`
CustomVersioningScheme string `json:"customVersioningScheme,omitempty" validate:"oneof=docker maven pep440 semver2"`
CustomVersioningScheme string `json:"customVersioningScheme,omitempty" validate:"possible-values=docker maven pep440 semver2"`
DockerVersionSource string `json:"dockerVersionSource,omitempty"`
FetchCoordinates bool `json:"fetchCoordinates,omitempty"`
FilePath string `json:"filePath,omitempty"`
@ -36,7 +36,7 @@ type artifactPrepareVersionOptions struct {
UnixTimestamp bool `json:"unixTimestamp,omitempty"`
Username string `json:"username,omitempty"`
VersioningTemplate string `json:"versioningTemplate,omitempty"`
VersioningType string `json:"versioningType,omitempty" validate:"oneof=cloud cloud_noTag library"`
VersioningType string `json:"versioningType,omitempty" validate:"possible-values=cloud cloud_noTag library"`
}
type artifactPrepareVersionCommonPipelineEnvironment struct {

View File

@ -18,7 +18,7 @@ import (
)
type batsExecuteTestsOptions struct {
OutputFormat string `json:"outputFormat,omitempty" validate:"oneof=tap junit"`
OutputFormat string `json:"outputFormat,omitempty" validate:"possible-values=tap junit"`
Repository string `json:"repository,omitempty"`
TestPackage string `json:"testPackage,omitempty"`
TestPath string `json:"testPath,omitempty"`

View File

@ -39,7 +39,7 @@ type checkmarxExecuteScanOptions struct {
VulnerabilityThresholdHigh int `json:"vulnerabilityThresholdHigh,omitempty"`
VulnerabilityThresholdLow int `json:"vulnerabilityThresholdLow,omitempty"`
VulnerabilityThresholdMedium int `json:"vulnerabilityThresholdMedium,omitempty"`
VulnerabilityThresholdResult string `json:"vulnerabilityThresholdResult,omitempty" validate:"oneof=FAILURE"`
VulnerabilityThresholdResult string `json:"vulnerabilityThresholdResult,omitempty" validate:"possible-values=FAILURE"`
VulnerabilityThresholdUnit string `json:"vulnerabilityThresholdUnit,omitempty"`
IsOptimizedAndScheduled bool `json:"isOptimizedAndScheduled,omitempty"`
}

View File

@ -21,15 +21,15 @@ type detectExecuteScanOptions struct {
Token string `json:"token,omitempty"`
CodeLocation string `json:"codeLocation,omitempty"`
ProjectName string `json:"projectName,omitempty"`
Scanners []string `json:"scanners,omitempty"`
Scanners []string `json:"scanners,omitempty" validate:"possible-values=signature source"`
ScanPaths []string `json:"scanPaths,omitempty"`
DependencyPath string `json:"dependencyPath,omitempty"`
Unmap bool `json:"unmap,omitempty"`
ScanProperties []string `json:"scanProperties,omitempty"`
ServerURL string `json:"serverUrl,omitempty"`
Groups []string `json:"groups,omitempty"`
FailOn []string `json:"failOn,omitempty"`
VersioningModel string `json:"versioningModel,omitempty" validate:"oneof=major major-minor semantic full"`
FailOn []string `json:"failOn,omitempty" validate:"possible-values=ALL BLOCKER CRITICAL MAJOR MINOR NONE"`
VersioningModel string `json:"versioningModel,omitempty" validate:"possible-values=major major-minor semantic full"`
Version string `json:"version,omitempty"`
CustomScanVersion string `json:"customScanVersion,omitempty"`
ProjectSettingsFile string `json:"projectSettingsFile,omitempty"`

View File

@ -60,7 +60,7 @@ type fortifyExecuteScanOptions struct {
DeltaMinutes int `json:"deltaMinutes,omitempty"`
SpotCheckMinimum int `json:"spotCheckMinimum,omitempty"`
FprDownloadEndpoint string `json:"fprDownloadEndpoint,omitempty"`
VersioningModel string `json:"versioningModel,omitempty" validate:"oneof=major major-minor semantic full"`
VersioningModel string `json:"versioningModel,omitempty" validate:"possible-values=major major-minor semantic full"`
PythonInstallCommand string `json:"pythonInstallCommand,omitempty"`
ReportTemplateID int `json:"reportTemplateId,omitempty"`
FilterSetTitle string `json:"filterSetTitle,omitempty"`

View File

@ -22,9 +22,9 @@ type gctsCreateRepositoryOptions struct {
Host string `json:"host,omitempty"`
Client string `json:"client,omitempty"`
RemoteRepositoryURL string `json:"remoteRepositoryURL,omitempty"`
Role string `json:"role,omitempty" validate:"oneof=SOURCE TARGET"`
Role string `json:"role,omitempty" validate:"possible-values=SOURCE TARGET"`
VSID string `json:"vSID,omitempty"`
Type string `json:"type,omitempty" validate:"oneof=GIT"`
Type string `json:"type,omitempty" validate:"possible-values=GIT"`
}
// GctsCreateRepositoryCommand Creates a Git repository on an ABAP system

View File

@ -23,9 +23,9 @@ type gctsDeployOptions struct {
Client string `json:"client,omitempty"`
Commit string `json:"commit,omitempty"`
RemoteRepositoryURL string `json:"remoteRepositoryURL,omitempty"`
Role string `json:"role,omitempty" validate:"oneof=SOURCE TARGET"`
Role string `json:"role,omitempty" validate:"possible-values=SOURCE TARGET"`
VSID string `json:"vSID,omitempty"`
Type string `json:"type,omitempty" validate:"oneof=GIT"`
Type string `json:"type,omitempty" validate:"possible-values=GIT"`
Branch string `json:"branch,omitempty"`
Scope string `json:"scope,omitempty"`
Rollback bool `json:"rollback,omitempty"`

View File

@ -22,7 +22,7 @@ type githubSetCommitStatusOptions struct {
Description string `json:"description,omitempty"`
Owner string `json:"owner,omitempty"`
Repository string `json:"repository,omitempty"`
Status string `json:"status,omitempty" validate:"oneof=failure pending success"`
Status string `json:"status,omitempty" validate:"possible-values=failure pending success"`
TargetURL string `json:"targetUrl,omitempty"`
Token string `json:"token,omitempty"`
}

View File

@ -28,7 +28,7 @@ type gitopsUpdateDeploymentOptions struct {
ChartPath string `json:"chartPath,omitempty"`
HelmValues []string `json:"helmValues,omitempty"`
DeploymentName string `json:"deploymentName,omitempty"`
Tool string `json:"tool,omitempty" validate:"oneof=kubectl helm"`
Tool string `json:"tool,omitempty" validate:"possible-values=kubectl helm"`
}
// GitopsUpdateDeploymentCommand Updates Kubernetes Deployment Manifest in an Infrastructure Git Repository

View File

@ -18,7 +18,7 @@ import (
type integrationArtifactResourceOptions struct {
APIServiceKey string `json:"apiServiceKey,omitempty"`
IntegrationFlowID string `json:"integrationFlowId,omitempty"`
Operation string `json:"operation,omitempty" validate:"oneof=create update delete"`
Operation string `json:"operation,omitempty" validate:"possible-values=create update delete"`
ResourcePath string `json:"resourcePath,omitempty"`
}

View File

@ -28,7 +28,7 @@ type kubernetesDeployOptions struct {
ContainerRegistrySecret string `json:"containerRegistrySecret,omitempty"`
CreateDockerRegistrySecret bool `json:"createDockerRegistrySecret,omitempty"`
DeploymentName string `json:"deploymentName,omitempty"`
DeployTool string `json:"deployTool,omitempty" validate:"oneof=kubectl helm helm3"`
DeployTool string `json:"deployTool,omitempty" validate:"possible-values=kubectl helm helm3"`
ForceUpdates bool `json:"forceUpdates,omitempty"`
HelmDeployWaitSeconds int `json:"helmDeployWaitSeconds,omitempty"`
HelmValues []string `json:"helmValues,omitempty"`
@ -41,7 +41,7 @@ type kubernetesDeployOptions struct {
Namespace string `json:"namespace,omitempty"`
TillerNamespace string `json:"tillerNamespace,omitempty"`
DockerConfigJSON string `json:"dockerConfigJSON,omitempty"`
DeployCommand string `json:"deployCommand,omitempty" validate:"oneof=apply replace"`
DeployCommand string `json:"deployCommand,omitempty" validate:"possible-values=apply replace"`
}
// KubernetesDeployCommand Deployment to Kubernetes test or production namespace within the specified Kubernetes cluster.

View File

@ -23,7 +23,7 @@ type mtaBuildOptions struct {
Version string `json:"version,omitempty"`
Extensions string `json:"extensions,omitempty"`
Jobs int `json:"jobs,omitempty"`
Platform string `json:"platform,omitempty" validate:"oneof=CF NEO XSA"`
Platform string `json:"platform,omitempty" validate:"possible-values=CF NEO XSA"`
ApplicationName string `json:"applicationName,omitempty"`
Source string `json:"source,omitempty"`
Target string `json:"target,omitempty"`

View File

@ -16,8 +16,8 @@ import (
)
type nexusUploadOptions struct {
Version string `json:"version,omitempty" validate:"oneof=nexus2 nexus3"`
Format string `json:"format,omitempty" validate:"oneof=maven npm"`
Version string `json:"version,omitempty" validate:"possible-values=nexus2 nexus3"`
Format string `json:"format,omitempty" validate:"possible-values=maven npm"`
Url string `json:"url,omitempty"`
MavenRepository string `json:"mavenRepository,omitempty"`
NpmRepository string `json:"npmRepository,omitempty"`

View File

@ -23,7 +23,7 @@ type protecodeExecuteScanOptions struct {
ScanImage string `json:"scanImage,omitempty"`
DockerRegistryURL string `json:"dockerRegistryUrl,omitempty"`
DockerConfigJSON string `json:"dockerConfigJSON,omitempty"`
CleanupMode string `json:"cleanupMode,omitempty" validate:"oneof=none binary complete"`
CleanupMode string `json:"cleanupMode,omitempty" validate:"possible-values=none binary complete"`
FilePath string `json:"filePath,omitempty"`
IncludeLayers bool `json:"includeLayers,omitempty"`
TimeoutMinutes string `json:"timeoutMinutes,omitempty"`

View File

@ -24,7 +24,7 @@ type sonarExecuteScanOptions struct {
Organization string `json:"organization,omitempty"`
CustomTLSCertificateLinks []string `json:"customTlsCertificateLinks,omitempty"`
SonarScannerDownloadURL string `json:"sonarScannerDownloadUrl,omitempty"`
VersioningModel string `json:"versioningModel,omitempty" validate:"oneof=major major-minor semantic full"`
VersioningModel string `json:"versioningModel,omitempty" validate:"possible-values=major major-minor semantic full"`
Version string `json:"version,omitempty"`
CustomScanVersion string `json:"customScanVersion,omitempty"`
ProjectKey string `json:"projectKey,omitempty"`
@ -37,7 +37,7 @@ type sonarExecuteScanOptions struct {
ChangeID string `json:"changeId,omitempty"`
ChangeBranch string `json:"changeBranch,omitempty"`
ChangeTarget string `json:"changeTarget,omitempty"`
PullRequestProvider string `json:"pullRequestProvider,omitempty" validate:"oneof=GitHub"`
PullRequestProvider string `json:"pullRequestProvider,omitempty" validate:"possible-values=GitHub"`
Owner string `json:"owner,omitempty"`
Repository string `json:"repository,omitempty"`
GithubToken string `json:"githubToken,omitempty"`

View File

@ -16,7 +16,7 @@ import (
)
type vaultRotateSecretIdOptions struct {
SecretStore string `json:"secretStore,omitempty" validate:"oneof=jenkins ado"`
SecretStore string `json:"secretStore,omitempty" validate:"possible-values=jenkins ado"`
JenkinsURL string `json:"jenkinsUrl,omitempty"`
JenkinsCredentialDomain string `json:"jenkinsCredentialDomain,omitempty"`
JenkinsUsername string `json:"jenkinsUsername,omitempty"`

View File

@ -55,7 +55,7 @@ type whitesourceExecuteScanOptions struct {
Timeout int `json:"timeout,omitempty"`
UserToken string `json:"userToken,omitempty"`
VersioningModel string `json:"versioningModel,omitempty"`
VulnerabilityReportFormat string `json:"vulnerabilityReportFormat,omitempty" validate:"oneof=xlsx json xml"`
VulnerabilityReportFormat string `json:"vulnerabilityReportFormat,omitempty" validate:"possible-values=xlsx json xml"`
VulnerabilityReportTitle string `json:"vulnerabilityReportTitle,omitempty"`
ProjectSettingsFile string `json:"projectSettingsFile,omitempty"`
GlobalSettingsFile string `json:"globalSettingsFile,omitempty"`

View File

@ -21,8 +21,8 @@ type xsDeployOptions struct {
DeployOpts string `json:"deployOpts,omitempty"`
OperationIDLogPattern string `json:"operationIdLogPattern,omitempty"`
MtaPath string `json:"mtaPath,omitempty"`
Action string `json:"action,omitempty" validate:"oneof=NONE Resume Abort Retry"`
Mode string `json:"mode,omitempty" validate:"oneof=NONE DEPLOY BG_DEPLOY"`
Action string `json:"action,omitempty" validate:"possible-values=NONE Resume Abort Retry"`
Mode string `json:"mode,omitempty" validate:"possible-values=NONE DEPLOY BG_DEPLOY"`
OperationID string `json:"operationId,omitempty"`
APIURL string `json:"apiUrl,omitempty"`
Username string `json:"username,omitempty"`

View File

@ -70,7 +70,7 @@ type {{ .StepName }}Options struct {
{{ if ne (has $value.Name $names) true -}}
{{ $names | last }}{{ $value.Name | golangName }} {{ $value.Type }} ` + "`json:\"{{$value.Name}},omitempty\"" +
"{{ if or $value.PossibleValues $value.MandatoryIf}} validate:\"" +
"{{ if $value.PossibleValues }}oneof={{ range $i,$a := $value.PossibleValues }}{{if gt $i 0 }} {{ end }}{{.}}{{ end }}{{ end }}" +
"{{ if $value.PossibleValues }}possible-values={{ range $i,$a := $value.PossibleValues }}{{if gt $i 0 }} {{ end }}{{.}}{{ end }}{{ end }}" +
"{{ if and $value.PossibleValues $value.MandatoryIf }},{{ end }}" +
"{{ if $value.MandatoryIf }}required_if={{ range $i,$a := $value.MandatoryIf }}{{ if gt $i 0 }} {{ end }}{{ $a.Name | title }} {{ $a.Value }}{{ end }}{{ end }}" +
"\"{{ end }}`" + `

View File

@ -20,9 +20,9 @@ import (
type testStepOptions struct {
Param0 string `json:"param0,omitempty"`
Param1 string `json:"param1,omitempty" validate:"oneof=value1 value2 value3"`
Param1 string `json:"param1,omitempty" validate:"possible-values=value1 value2 value3"`
Param2 string `json:"param2,omitempty" validate:"required_if=Param1 value1"`
Param3 string `json:"param3,omitempty" validate:"oneof=value1 value2 value3,required_if=Param1 value1 Param2 value2"`
Param3 string `json:"param3,omitempty" validate:"possible-values=value1 value2 value3,required_if=Param1 value1 Param2 value2"`
}

View File

@ -19,9 +19,9 @@ import (
type testStepOptions struct {
Param0 string `json:"param0,omitempty"`
Param1 string `json:"param1,omitempty" validate:"oneof=value1 value2 value3"`
Param1 string `json:"param1,omitempty" validate:"possible-values=value1 value2 value3"`
Param2 string `json:"param2,omitempty" validate:"required_if=Param1 value1"`
Param3 string `json:"param3,omitempty" validate:"oneof=value1 value2 value3,required_if=Param1 value1 Param2 value2"`
Param3 string `json:"param3,omitempty" validate:"possible-values=value1 value2 value3,required_if=Param1 value1 Param2 value2"`
}

View File

@ -2,7 +2,9 @@ package validation
import (
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/go-playground/locales/en"
@ -26,6 +28,7 @@ type validationOption func(*validation) error
func New(opts ...validationOption) (*validation, error) {
validator := valid.New()
validator.RegisterValidation("possible-values", isPossibleValues)
enTranslator := en.New()
universalTranslator := ut.New(enTranslator, enTranslator)
translator, found := universalTranslator.GetTranslator("en")
@ -60,19 +63,19 @@ func WithJSONNamesForStructFields() validationOption {
func WithPredefinedErrorMessages() validationOption {
translations := []Translation{
{
Tag: "oneof",
Tag: "possible-values",
RegisterFn: func(ut ut.Translator) error {
return ut.Add("oneof", "The {0} must use the following values: {1}. ", true)
return ut.Add("possible-values", "The {0} must use the following values: {1}", true)
},
TranslationFn: func(ut ut.Translator, fe valid.FieldError) string {
t, _ := ut.T("oneof", fe.Field(), fe.Param())
t, _ := ut.T("possible-values", fe.Field(), fe.Param())
return t
},
}, {
Tag: "required_if",
RegisterFn: func(ut ut.Translator) error {
// TODO: Improve the message for condition required_if for several fields
return ut.Add("required_if", "The {0} is required since the {1} is {2}. ", true)
return ut.Add("required_if", "The {0} is required since the {1} is {2}", true)
},
TranslationFn: func(ut ut.Translator, fe valid.FieldError) string {
params := []string{fe.Field()}
@ -107,7 +110,7 @@ func (v *validation) ValidateStruct(s interface{}) error {
return err
}
for _, err := range errs.(valid.ValidationErrors) {
errStr += err.Translate(v.Translator)
errStr += err.Translate(v.Translator) + ". "
}
return errors.New(errStr)
}
@ -126,3 +129,41 @@ func registerTranslations(translations []Translation, validator *valid.Validate,
}
return nil
}
func isPossibleValues(fl valid.FieldLevel) bool {
vals := strings.Split(strings.TrimSpace(fl.Param()), " ")
field := fl.Field()
switch field.Kind() {
case reflect.String:
val := field.String()
// Empty value can be used
vals = append(vals, "")
return contains(vals, val)
case reflect.Int:
val := strconv.FormatInt(field.Int(), 10)
return contains(vals, val)
case reflect.Slice:
slice, ok := field.Interface().([]string)
if !ok {
panic("Only []string can be used as slice type")
}
for _, val := range slice {
if !contains(vals, val) {
return false
}
}
return true
default:
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
}
func contains(slice []string, str string) bool {
for _, v := range slice {
if v == str {
return true
}
}
return false
}

View File

@ -9,10 +9,11 @@ import (
)
type testStruct struct {
Field1 int `json:"field1,omitempty" validate:"eq=1"`
Field2 string `json:"field2,omitempty" validate:"oneof=value1 value2 value3"`
Field3 string `json:"field3,omitempty" validate:"required_if=Field1 1 Field4 test"`
Field4 string `json:"field4,omitempty"`
Field1 int `json:"field1,omitempty" validate:"eq=1"`
Field2 string `json:"field2,omitempty" validate:"possible-values=value1 value2 value3"`
Field3 string `json:"field3,omitempty" validate:"required_if=Field1 1 Field4 test"`
Field4 string `json:"field4,omitempty"`
Field5 []string `json:"field5,omitempty" validate:"possible-values=val1 val2 val3 val4"`
}
func TestValidateStruct(t *testing.T) {
@ -24,6 +25,19 @@ func TestValidateStruct(t *testing.T) {
Field2: "value1",
Field3: "field3",
Field4: "test",
Field5: []string{"val1", "val2", "val3"},
}
err = validation.ValidateStruct(tStruct)
assert.NoError(t, err)
})
t.Run("success case - empty values for string and []string", func(t *testing.T) {
validation, err := New(WithPredefinedErrorMessages(), WithJSONNamesForStructFields())
assert.NoError(t, err)
tStruct := testStruct{
Field1: 1,
Field3: "field3",
Field4: "test",
}
err = validation.ValidateStruct(tStruct)
assert.NoError(t, err)
@ -36,11 +50,13 @@ func TestValidateStruct(t *testing.T) {
Field1: 1,
Field2: "value4",
Field4: "test",
Field5: []string{"val1", "val2", "val5"},
}
err = validation.ValidateStruct(testStruct)
assert.Error(t, err)
assert.Contains(t, err.Error(), "Key: 'testStruct.Field2' Error:Field validation for 'Field2' failed on the 'oneof'")
assert.Contains(t, err.Error(), "tagKey: 'testStruct.Field3' Error:Field validation for 'Field3' failed on the 'required_if' tag")
assert.Contains(t, err.Error(), "Key: 'testStruct.Field2' Error:Field validation for 'Field2' failed on the 'possible-values' tag.")
assert.Contains(t, err.Error(), "Key: 'testStruct.Field3' Error:Field validation for 'Field3' failed on the 'required_if' tag.")
assert.Contains(t, err.Error(), "Key: 'testStruct.Field5' Error:Field validation for 'Field5' failed on the 'possible-values' tag.")
})
t.Run("error case - predefined error messages without naming fields from json tags", func(t *testing.T) {
@ -50,11 +66,13 @@ func TestValidateStruct(t *testing.T) {
Field1: 1,
Field2: "value4",
Field4: "test",
Field5: []string{"val1", "val2", "val5"},
}
err = validation.ValidateStruct(testStruct)
assert.Error(t, err)
assert.Contains(t, err.Error(), "The Field2 must use the following values: value1 value2 value3.")
assert.Contains(t, err.Error(), "The Field3 is required since the Field1 is 1.")
assert.Contains(t, err.Error(), "The Field5 must use the following values: val1 val2 val3 val4.")
})
t.Run("failed case - predefined error messages with naming fields from json tags", func(t *testing.T) {
@ -64,28 +82,30 @@ func TestValidateStruct(t *testing.T) {
Field1: 1,
Field2: "value4",
Field4: "test",
Field5: []string{"val1", "val2", "val5"},
}
err = validation.ValidateStruct(testStruct)
assert.Error(t, err)
assert.Contains(t, err.Error(), "The field2 must use the following values: value1 value2 value3.")
assert.Contains(t, err.Error(), "The field3 is required since the Field1 is 1.")
assert.Contains(t, err.Error(), "The field5 must use the following values: val1 val2 val3 val4.")
})
t.Run("failed case - custom error messages", func(t *testing.T) {
translations := []Translation{
{
Tag: "oneof",
Tag: "possible-values",
RegisterFn: func(ut ut.Translator) error {
return ut.Add("oneof", "Custom error message for {0}. ", true)
return ut.Add("possible-values", "Custom error message for {0}", true)
},
TranslationFn: func(ut ut.Translator, fe valid.FieldError) string {
t, _ := ut.T("oneof", fe.Field())
t, _ := ut.T("possible-values", fe.Field())
return t
},
}, {
Tag: "required_if",
RegisterFn: func(ut ut.Translator) error {
return ut.Add("required_if", "Custom error message for {0}. ", true)
return ut.Add("required_if", "Custom error message for {0}", true)
},
TranslationFn: func(ut ut.Translator, fe valid.FieldError) string {
t, _ := ut.T("required_if", fe.Field())
@ -99,10 +119,12 @@ func TestValidateStruct(t *testing.T) {
Field1: 1,
Field2: "value4",
Field4: "test",
Field5: []string{"val1", "val2", "val5"},
}
err = validation.ValidateStruct(testStruct)
assert.Error(t, err)
assert.Contains(t, err.Error(), "Custom error message for Field2")
assert.Contains(t, err.Error(), "Custom error message for Field3")
assert.Contains(t, err.Error(), "Custom error message for Field5")
})
}

View File

@ -65,9 +65,9 @@ spec:
type: "[]string"
default:
- signature
# possibleValues:
# - signature
# - source
possibleValues:
- signature
- source
scope:
- PARAMETERS
- STAGES
@ -146,13 +146,13 @@ spec:
type: "[]string"
default:
- BLOCKER
# possibleValues:
# - ALL
# - BLOCKER
# - CRITICAL
# - MAJOR
# - MINOR
# - NONE
possibleValues:
- ALL
- BLOCKER
- CRITICAL
- MAJOR
- MINOR
- NONE
scope:
- PARAMETERS
- STAGES