You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +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:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							f431054b6f
						
					
				
				
					commit
					e97242b7e7
				
			| @@ -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"` | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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"` | ||||
| } | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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"` | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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"` | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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"` | ||||
|   | ||||
| @@ -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 }}`" + ` | ||||
|   | ||||
| @@ -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"` | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -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"` | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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") | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user