diff --git a/common/cliutils/spec.go b/common/cliutils/spec.go new file mode 100644 index 000000000..35122e163 --- /dev/null +++ b/common/cliutils/spec.go @@ -0,0 +1,81 @@ +package cliutils + +import ( + speccore "github.com/jfrog/jfrog-cli-core/v2/common/spec" + "github.com/jfrog/jfrog-cli-core/v2/plugins/components" + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "strings" +) + +func GetSpec(c *components.Context, isDownload, overrideFieldsIfSet bool) (specFiles *speccore.SpecFiles, err error) { + specFiles, err = speccore.CreateSpecFromFile(c.GetStringFlagValue("spec"), coreutils.SpecVarsStringToMap(c.GetStringFlagValue("spec-vars"))) + if err != nil { + return nil, err + } + if isDownload { + trimPatternPrefix(specFiles) + } + if overrideFieldsIfSet { + overrideSpecFields(c, specFiles) + } + return +} + +func overrideSpecFields(c *components.Context, specFiles *speccore.SpecFiles) { + for i := 0; i < len(specFiles.Files); i++ { + OverrideFieldsIfSet(specFiles.Get(i), c) + } +} + +func trimPatternPrefix(specFiles *speccore.SpecFiles) { + for i := 0; i < len(specFiles.Files); i++ { + specFiles.Get(i).Pattern = strings.TrimPrefix(specFiles.Get(i).Pattern, "/") + } +} + +func OverrideFieldsIfSet(spec *speccore.File, c *components.Context) { + overrideArrayIfSet(&spec.Exclusions, c, "exclusions") + overrideArrayIfSet(&spec.SortBy, c, "sort-by") + overrideIntIfSet(&spec.Offset, c, "offset") + overrideIntIfSet(&spec.Limit, c, "limit") + overrideStringIfSet(&spec.SortOrder, c, "sort-order") + overrideStringIfSet(&spec.Props, c, "props") + overrideStringIfSet(&spec.TargetProps, c, "target-props") + overrideStringIfSet(&spec.ExcludeProps, c, "exclude-props") + overrideStringIfSet(&spec.Build, c, "build") + overrideStringIfSet(&spec.Project, c, "project") + overrideStringIfSet(&spec.ExcludeArtifacts, c, "exclude-artifacts") + overrideStringIfSet(&spec.IncludeDeps, c, "include-deps") + overrideStringIfSet(&spec.Bundle, c, "bundle") + overrideStringIfSet(&spec.Recursive, c, "recursive") + overrideStringIfSet(&spec.Flat, c, "flat") + overrideStringIfSet(&spec.Explode, c, "explode") + overrideStringIfSet(&spec.BypassArchiveInspection, c, "bypass-archive-inspection") + overrideStringIfSet(&spec.Regexp, c, "regexp") + overrideStringIfSet(&spec.IncludeDirs, c, "include-dirs") + overrideStringIfSet(&spec.ValidateSymlinks, c, "validate-symlinks") + overrideStringIfSet(&spec.Symlinks, c, "symlinks") + overrideStringIfSet(&spec.Transitive, c, "transitive") + overrideStringIfSet(&spec.PublicGpgKey, c, "gpg-key") +} + +// If `fieldName` exist in the cli args, read it to `field` as a string. +func overrideStringIfSet(field *string, c *components.Context, fieldName string) { + if c.IsFlagSet(fieldName) { + *field = c.GetStringFlagValue(fieldName) + } +} + +// If `fieldName` exist in the cli args, read it to `field` as an array split by `;`. +func overrideArrayIfSet(field *[]string, c *components.Context, fieldName string) { + if c.IsFlagSet(fieldName) { + *field = append([]string{}, strings.Split(c.GetStringFlagValue(fieldName), ";")...) + } +} + +// If `fieldName` exist in the cli args, read it to `field` as a int. +func overrideIntIfSet(field *int, c *components.Context, fieldName string) { + if c.IsFlagSet(fieldName) { + *field, _ = c.GetIntFlagValue(fieldName) + } +} diff --git a/common/cliutils/summary/summary.go b/common/cliutils/summary/summary.go new file mode 100644 index 000000000..62411a629 --- /dev/null +++ b/common/cliutils/summary/summary.go @@ -0,0 +1,128 @@ +package summary + +import ( + "encoding/json" + clientutils "github.com/jfrog/jfrog-client-go/utils" + "github.com/jfrog/jfrog-client-go/utils/errorutils" + "github.com/jfrog/jfrog-client-go/utils/log" + "strings" +) + +type StatusType int + +const ( + Success StatusType = iota + Failure +) + +var StatusTypes = []string{ + "success", + "failure", +} + +func (statusType StatusType) MarshalJSON() ([]byte, error) { + return json.Marshal(StatusTypes[statusType]) +} + +func (statusType *StatusType) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + switch strings.ToLower(s) { + default: + *statusType = Failure + case "success": + *statusType = Success + + } + return nil +} + +func NewBuildInfoSummary(success, failed int, sha256 string, err error) *BuildInfoSummary { + summaryReport := GetSummaryReport(success, failed, false, err) + buildInfoSummary := BuildInfoSummary{Summary: *summaryReport, Sha256Array: []Sha256{}} + if success == 1 { + buildInfoSummary.AddSha256(sha256) + } + return &buildInfoSummary +} + +func (summary *Summary) Marshal() ([]byte, error) { + return json.Marshal(summary) +} + +func (bis *BuildInfoSummary) Marshal() ([]byte, error) { + return json.Marshal(bis) +} + +type Summary struct { + Status StatusType `json:"status"` + Totals *Totals `json:"totals"` +} + +type Totals struct { + Success int `json:"success"` + Failure int `json:"failure"` +} + +type BuildInfoSummary struct { + Summary + Sha256Array []Sha256 `json:"files"` +} + +type Sha256 struct { + Sha256Str string `json:"sha256"` +} + +func (bis *BuildInfoSummary) AddSha256(sha256Str string) { + sha256 := Sha256{Sha256Str: sha256Str} + bis.Sha256Array = append(bis.Sha256Array, sha256) +} + +func GetSummaryReport(success, failed int, failNoOp bool, err error) *Summary { + summary := &Summary{Totals: &Totals{}} + if err != nil || failed > 0 || (success == 0 && failNoOp) { + summary.Status = Failure + } else { + summary.Status = Success + } + summary.Totals.Success = success + summary.Totals.Failure = failed + return summary +} + +func PrintBuildInfoSummaryReport(succeeded bool, sha256 string, originalErr error) error { + success, failed := 1, 0 + if !succeeded { + success, failed = 0, 1 + } + buildInfoSummary, mErr := CreateBuildInfoSummaryReportString(success, failed, sha256, originalErr) + if mErr != nil { + return summaryPrintError(mErr, originalErr) + } + log.Output(buildInfoSummary) + return summaryPrintError(mErr, originalErr) +} + +func CreateBuildInfoSummaryReportString(success, failed int, sha256 string, err error) (string, error) { + buildInfoSummary := NewBuildInfoSummary(success, failed, sha256, err) + buildInfoSummaryContent, mErr := buildInfoSummary.Marshal() + if errorutils.CheckError(mErr) != nil { + return "", mErr + } + return clientutils.IndentJson(buildInfoSummaryContent), mErr +} + +// Print summary report. +// a given non-nil error will pass through and be returned as is if no other errors are raised. +// In case of a nil error, the current function error will be returned. +func summaryPrintError(summaryError, originalError error) error { + if originalError != nil { + if summaryError != nil { + log.Error(summaryError) + } + return originalError + } + return summaryError +} diff --git a/plugins/common/utils.go b/plugins/common/utils.go index 06250f6ce..1f7655c9b 100644 --- a/plugins/common/utils.go +++ b/plugins/common/utils.go @@ -1,6 +1,8 @@ package common import ( + "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + clientutils "github.com/jfrog/jfrog-client-go/utils" "sort" "strconv" "strings" @@ -100,3 +102,25 @@ func buildAndSortFlags(keys []string, flagsMap map[string]components.Flag) (flag sort.Slice(flags, func(i, j int) bool { return flags[i].GetName() < flags[j].GetName() }) return } + +// This function indicates whether the command should be executed without +// confirmation warning or not. +// If the --quiet option was sent, it is used to determine whether to prompt the confirmation or not. +// If not, the command will prompt the confirmation, unless the CI environment variable was set to true. +func GetQuietValue(c *components.Context) bool { + if c.IsFlagSet("quiet") { + return c.GetBoolFlagValue("quiet") + } + + return getCiValue() +} + +// Return true if the CI environment variable was set to true. +func getCiValue() bool { + var ci bool + var err error + if ci, err = clientutils.GetBoolEnvValue(coreutils.CI, false); err != nil { + return false + } + return ci +} diff --git a/plugins/components/commandcomp.go b/plugins/components/commandcomp.go index 361f9533c..ca1efb766 100644 --- a/plugins/components/commandcomp.go +++ b/plugins/components/commandcomp.go @@ -171,6 +171,18 @@ func SetHiddenStrFlag() StringFlagOption { } } +func SetMandatoryFalse() StringFlagOption { + return func(f *StringFlag) { + f.Mandatory = false + } +} + +func WithBoolDefaultValueFalse() BoolFlagOption { + return func(f *BoolFlag) { + f.DefaultValue = false + } +} + type BoolFlag struct { BaseFlag DefaultValue bool @@ -201,3 +213,17 @@ func SetHiddenBoolFlag() BoolFlagOption { f.Hidden = true } } + +func (c *Context) WithDefaultIntFlagValue(flagName string, defValue int) (value int, err error) { + value = defValue + if c.IsFlagSet(flagName) { + var parsed int64 + parsed, err = strconv.ParseInt(c.GetStringFlagValue(flagName), 0, 64) + if err != nil { + err = fmt.Errorf("can't parse int flag '%s': %w", flagName, err) + return + } + value = int(parsed) + } + return +}