diff --git a/.github/workflows/nugetTests.yml b/.github/workflows/nugetTests.yml index fd8ee9ca1..74605fbeb 100644 --- a/.github/workflows/nugetTests.yml +++ b/.github/workflows/nugetTests.yml @@ -54,7 +54,7 @@ jobs: - name: Install NuGet uses: nuget/setup-nuget@v2 with: - nuget-version: '6.x' + nuget-version: '8.x' - name: Setup Go with cache uses: jfrog/.github/actions/install-go-with-cache@main diff --git a/artifactory/cli.go b/artifactory/cli.go index edcd7a286..8b1496451 100644 --- a/artifactory/cli.go +++ b/artifactory/cli.go @@ -1871,7 +1871,7 @@ func buildScanLegacyCmd(c *cli.Context) error { func checkBuildScanError(err error) error { // If the build was found vulnerable, exit with ExitCodeVulnerableBuild. - if err == utils.GetBuildScanError() { + if errors.Is(err, utils.GetBuildScanError()) { return coreutils.CliError{ExitCode: coreutils.ExitCodeVulnerableBuild, ErrorMsg: err.Error()} } // If the scan operation failed, for example due to HTTP timeout, exit with ExitCodeError. diff --git a/buildtools/cli.go b/buildtools/cli.go index 61f07754f..ac8f55ef8 100644 --- a/buildtools/cli.go +++ b/buildtools/cli.go @@ -4,7 +4,11 @@ import ( "errors" "fmt" "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/python" + "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/setup" + "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" "github.com/jfrog/jfrog-cli-security/utils/techutils" + setupdocs "github.com/jfrog/jfrog-cli/docs/buildtools/setup" "os" "strconv" "strings" @@ -65,11 +69,21 @@ import ( ) const ( - buildToolsCategory = "Build Tools" + buildToolsCategory = "Package Managers:" ) func GetCommands() []cli.Command { return cliutils.GetSortedCommands(cli.CommandsByName{ + { + Name: "setup", + Flags: cliutils.GetCommandFlags(cliutils.Setup), + Usage: setupdocs.GetDescription(), + HelpName: corecommon.CreateUsage("setup", setupdocs.GetDescription(), setupdocs.Usage), + ArgsUsage: common.CreateEnvVars(), + UsageText: setupdocs.GetArguments(), + BashComplete: corecommon.CreateBashCompletionFunc(setup.GetSupportedPackageManagersList()...), + Action: setupCmd, + }, { Name: "mvn-config", Aliases: []string{"mvnc"}, @@ -929,6 +943,63 @@ func NpmPublishCmd(c *cli.Context) (err error) { return } +func setupCmd(c *cli.Context) (err error) { + if c.NArg() > 1 { + return cliutils.WrongNumberOfArgumentsHandler(c) + } + var packageManager project.ProjectType + packageManagerStr := c.Args().Get(0) + // If the package manager was provided as an argument, validate it. + if packageManagerStr != "" { + packageManager = project.FromString(packageManagerStr) + if !setup.IsSupportedPackageManager(packageManager) { + return cliutils.PrintHelpAndReturnError(fmt.Sprintf("The package manager %s is not supported", packageManagerStr), c) + } + } else { + // If the package manager wasn't provided as an argument, select it interactively. + packageManager, err = selectPackageManagerInteractively() + if err != nil { + return + } + } + setupCmd := setup.NewSetupCommand(packageManager) + artDetails, err := cliutils.CreateArtifactoryDetailsByFlags(c) + if err != nil { + return err + } + repoName := c.String("repo") + if repoName != "" { + // If a repository was provided, validate it exists in Artifactory. + if err = validateRepoExists(repoName, artDetails); err != nil { + return err + } + } + setupCmd.SetServerDetails(artDetails).SetRepoName(repoName).SetProjectKey(cliutils.GetProject(c)) + return commands.Exec(setupCmd) +} + +// validateRepoExists checks if the specified repository exists in Artifactory. +func validateRepoExists(repoName string, artDetails *coreConfig.ServerDetails) error { + serviceDetails, err := artDetails.CreateArtAuthConfig() + if err != nil { + return err + } + return utils.ValidateRepoExists(repoName, serviceDetails) +} + +func selectPackageManagerInteractively() (selectedPackageManager project.ProjectType, err error) { + var selected string + var selectableItems []ioutils.PromptItem + for _, packageManager := range setup.GetSupportedPackageManagersList() { + selectableItems = append(selectableItems, ioutils.PromptItem{Option: packageManager, TargetValue: &selected}) + } + err = ioutils.SelectString(selectableItems, "Please select a package manager to set up:", false, func(item ioutils.PromptItem) { + *item.TargetValue = item.Option + selectedPackageManager = project.FromString(*item.TargetValue) + }) + return +} + func GetNpmConfigAndArgs(c *cli.Context) (configFilePath string, args []string, err error) { configFilePath, err = getProjectConfigPathOrThrow(project.Npm, "npm", "npm-config") if err != nil { diff --git a/buildtools/help.go b/buildtools/help.go index 2b2f3b092..db4d9c71e 100644 --- a/buildtools/help.go +++ b/buildtools/help.go @@ -2,11 +2,11 @@ package buildtools import ( corecommon "github.com/jfrog/jfrog-cli-core/v2/docs/common" + "github.com/jfrog/jfrog-cli/docs/artifactory/npmpublish" "github.com/jfrog/jfrog-cli/docs/buildtools/dockerpull" "github.com/jfrog/jfrog-cli/docs/buildtools/dockerpush" "github.com/jfrog/jfrog-cli/docs/buildtools/npmci" "github.com/jfrog/jfrog-cli/docs/buildtools/npminstall" - "github.com/jfrog/jfrog-cli/docs/buildtools/npmpublish" "github.com/jfrog/jfrog-cli/docs/common" "github.com/jfrog/jfrog-cli/utils/cliutils" "github.com/urfave/cli" diff --git a/docs/buildtools/setup/help.go b/docs/buildtools/setup/help.go new file mode 100644 index 000000000..66f9fbfb3 --- /dev/null +++ b/docs/buildtools/setup/help.go @@ -0,0 +1,18 @@ +package setup + +import ( + "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/setup" + "strings" +) + +var Usage = []string{"setup [command options]", + "setup [command options]"} + +func GetDescription() string { + return "An interactive command to configure your local package manager (e.g., npm, pip) to work with JFrog Artifactory." +} + +func GetArguments() string { + return ` package manager + The package manager to configure. Supported package managers are: ` + strings.Join(setup.GetSupportedPackageManagersList(), ", ") + "." +} diff --git a/go.mod b/go.mod index b13ffded1..663401224 100644 --- a/go.mod +++ b/go.mod @@ -11,9 +11,9 @@ replace ( ) require ( - github.com/agnivade/levenshtein v1.2.0 + github.com/agnivade/levenshtein v1.2.1 github.com/buger/jsonparser v1.1.1 - github.com/docker/docker v27.3.1+incompatible + github.com/docker/docker v27.5.1+incompatible github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 github.com/jfrog/archiver/v3 v3.6.1 github.com/jfrog/build-info-go v1.10.8 @@ -26,7 +26,7 @@ require ( github.com/jszwec/csvutil v1.10.0 github.com/manifoldco/promptui v0.9.0 github.com/stretchr/testify v1.10.0 - github.com/testcontainers/testcontainers-go v0.34.0 + github.com/testcontainers/testcontainers-go v0.35.0 github.com/urfave/cli v1.22.16 github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c @@ -44,6 +44,7 @@ require ( github.com/VividCortex/ewma v1.2.0 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/andybalholm/brotli v1.1.0 // indirect + github.com/apache/camel-k/v2 v2.5.0 // indirect github.com/beevik/etree v1.4.0 // indirect github.com/c-bata/go-prompt v0.2.6 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect @@ -69,6 +70,7 @@ require ( github.com/go-git/go-git/v5 v5.13.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-logr/zapr v1.3.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.1 // indirect @@ -76,17 +78,20 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/go-github/v56 v56.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gookit/color v1.5.4 // indirect github.com/grokify/mogo v0.64.12 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jedib0t/go-pretty/v6 v6.6.5 // indirect github.com/jfrog/froggit-go v1.16.2 // indirect github.com/jfrog/go-mockhttp v0.3.1 // indirect github.com/jfrog/jfrog-apps-config v1.0.1 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect @@ -107,6 +112,8 @@ require ( github.com/moby/sys/user v0.1.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/nwaples/rardecode v1.1.3 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -136,6 +143,7 @@ require ( github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.19.0 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect @@ -149,41 +157,46 @@ require ( github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.31.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect - go.opentelemetry.io/otel/metric v1.31.0 // indirect - go.opentelemetry.io/otel/sdk v1.31.0 // indirect - go.opentelemetry.io/otel/trace v1.31.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect + go.opentelemetry.io/otel/trace v1.34.0 // indirect go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.32.0 // indirect golang.org/x/mod v0.22.0 // indirect golang.org/x/net v0.34.0 // indirect - golang.org/x/oauth2 v0.20.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.29.0 // indirect golang.org/x/term v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/time v0.5.0 // indirect + golang.org/x/time v0.7.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.29.7 // indirect + k8s.io/apimachinery v0.29.7 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/utils v0.0.0-20240310230437-4693a0247e57 // indirect + sigs.k8s.io/controller-runtime v0.17.5 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250130104846-27e495de291e -replace github.com/jfrog/jfrog-cli-artifactory => github.com/jfrog/jfrog-cli-artifactory v0.1.12-0.20250128042424-bb6a289e237c +replace github.com/jfrog/jfrog-cli-artifactory => github.com/jfrog/jfrog-cli-artifactory v0.1.12-0.20250130144915-01446cff31ac replace github.com/jfrog/jfrog-cli-security => github.com/jfrog/jfrog-cli-security v1.14.2-0.20250130082759-0d5b0bef7b8e -// replace github.com/jfrog/jfrog-cli-security => github.com/EyalDelarea/jfrog-cli-security v0.0.0-20241121103043-02719f295f02 - replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20250126110945-81abbdde452f // replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20241220065541-91828d43d8b9 // replace github.com/jfrog/gofrog => github.com/jfrog/gofrog dev - -// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250101110857-b26e9a6644c6 - -// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20250112155823-f3d607f5d854 diff --git a/go.sum b/go.sum index b4a4e5d43..aa5339289 100644 --- a/go.sum +++ b/go.sum @@ -19,12 +19,14 @@ github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1o github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= -github.com/agnivade/levenshtein v1.2.0 h1:U9L4IOT0Y3i0TIlUIDJ7rVUziKi/zPbrJGaFrtYH3SY= -github.com/agnivade/levenshtein v1.2.0/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= +github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= +github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/apache/camel-k/v2 v2.5.0 h1:voFPrxhuaedKn68RerS+QkXYXyZ+5tBfVaAc7QYOgks= +github.com/apache/camel-k/v2 v2.5.0/go.mod h1:vLrJAJAp9EGxY54cUR7VHzIF70JHfFzk4OOaYRfLr44= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= @@ -72,8 +74,8 @@ github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7c github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= -github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8= +github.com/docker/docker v27.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -112,8 +114,12 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 h1:FWNFq4fM1wPfcK40yHE5UO3RUdSNPaBC+j3PokzA6OQ= github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -138,6 +144,11 @@ github.com/google/go-github/v56 v56.0.0 h1:TysL7dMa/r7wsQi44BjqlwaHvwlFlqkK8CtBW github.com/google/go-github/v56 v56.0.0/go.mod h1:D8cdcX98YWJvi7TLo7zM4/h8ZTx6u6fwGEkCdisopo0= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -145,8 +156,8 @@ github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/grokify/mogo v0.64.12 h1:BNrZ1qBFuX4qu5722CW6qtqu/mrrsZ3bhKu/w1KowKg= github.com/grokify/mogo v0.64.12/go.mod h1:lDhfYIiOhJo7C2U3aL00PlUU9gLvmTONi4MdIWoGmGM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= @@ -155,6 +166,8 @@ github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISH github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jedib0t/go-pretty/v6 v6.6.5 h1:9PgMJOVBedpgYLI56jQRJYqngxYAAzfEUua+3NgSqAo= @@ -171,8 +184,8 @@ github.com/jfrog/gofrog v1.7.6 h1:QmfAiRzVyaI7JYGsB7cxfAJePAZTzFz0gRWZSE27c6s= github.com/jfrog/gofrog v1.7.6/go.mod h1:ntr1txqNOZtHplmaNd7rS4f8jpA5Apx8em70oYEe7+4= github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYLipdsOFMY= github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w= -github.com/jfrog/jfrog-cli-artifactory v0.1.12-0.20250128042424-bb6a289e237c h1:9975QDk6vBZG7vjsKVCuQB56r4xxeoYHHjmTzxbd4H8= -github.com/jfrog/jfrog-cli-artifactory v0.1.12-0.20250128042424-bb6a289e237c/go.mod h1:/sP5tyuFpH9WJp0+vztczuXcxIYHlMye0CDWCxhy4/M= +github.com/jfrog/jfrog-cli-artifactory v0.1.12-0.20250130144915-01446cff31ac h1:hi+n0WMoO1jiakEQEgaW7fK2enJkKnzJl2sE5VSDnGE= +github.com/jfrog/jfrog-cli-artifactory v0.1.12-0.20250130144915-01446cff31ac/go.mod h1:EMeIMynEg9T4ZY8ugzj76+fO/dR0cy8FNuvUfybL29w= github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250130104846-27e495de291e h1:cJJxXI45QLJsaCr5ChOTToCJpLoRTBGlXu/Z6DZB9jk= github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250130104846-27e495de291e/go.mod h1:3vP0hv13zJYvhXlgKIXmWSN8ADvGUQgxVVCqcO8hOeM= github.com/jfrog/jfrog-cli-platform-services v1.6.0 h1:2fBIDxnQaFWStZqMEUI2I3nkNjDmknxxHcmpeLxtocc= @@ -181,6 +194,8 @@ github.com/jfrog/jfrog-cli-security v1.14.2-0.20250130082759-0d5b0bef7b8e h1:h+c github.com/jfrog/jfrog-cli-security v1.14.2-0.20250130082759-0d5b0bef7b8e/go.mod h1:nFW0dGvSCRD8pZ35tOH9WFANvlEI8Sg1YpD+uM8uxD4= github.com/jfrog/jfrog-client-go v1.28.1-0.20250126110945-81abbdde452f h1:2IIy3XfvmEp5zJgakKZiyKGGeVyDsouwYmtD+4QiVd4= github.com/jfrog/jfrog-client-go v1.28.1-0.20250126110945-81abbdde452f/go.mod h1:ohIfKpMBCQsE9kunrKQ1wvoExpqsPLaluRFO186B5EM= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jszwec/csvutil v1.10.0 h1:upMDUxhQKqZ5ZDCs/wy+8Kib8rZR8I8lOR34yJkdqhI= github.com/jszwec/csvutil v1.10.0/go.mod h1:/E4ONrmGkwmWsk9ae9jpXnv9QT8pLHEPcCirMFhxG9I= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= @@ -252,12 +267,19 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY= +github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw= +github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= +github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -290,8 +312,8 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= @@ -323,6 +345,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -334,6 +358,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= @@ -342,8 +367,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= -github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo= -github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ= +github.com/testcontainers/testcontainers-go v0.35.0 h1:uADsZpTKFAtp8SLK+hMwSaa+X+JiERHtd4sQAFmXeMo= +github.com/testcontainers/testcontainers-go v0.35.0/go.mod h1:oEVBj5zrfJTrgjwONs1SsRbnBtH9OKl+IGl3UMcr2B4= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= @@ -380,26 +405,32 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= -go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4= -go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= -go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= -go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= -go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= -go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= -go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= -go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= -go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -436,8 +467,9 @@ golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -499,8 +531,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -516,25 +548,28 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20240930140551-af27646dc61f h1:mCJ6SGikSxVlt9scCayUl2dMq0msUgmBArqRY6umieI= -google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= -google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA= +google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:Ic02D47M+zbarjYYUlK57y316f2MoN0gjAwI3f2S95o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= +google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -542,3 +577,19 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +k8s.io/api v0.29.7 h1:Q2/thp7YYESgy0MGzxT9RvA/6doLJHBXSFH8GGLxSbc= +k8s.io/api v0.29.7/go.mod h1:mPimdbyuIjwoLtBEVIGVUYb4BKOE+44XHt/n4IqKsLA= +k8s.io/apimachinery v0.29.7 h1:ICXzya58Q7hyEEfnTrbmdfX1n1schSepX2KUfC2/ykc= +k8s.io/apimachinery v0.29.7/go.mod h1:i3FJVwhvSp/6n8Fl4K97PJEP8C+MM+aoDq4+ZJBf70Y= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= +k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/controller-runtime v0.17.5 h1:1FI9Lm7NiOOmBsgTV36/s2XrEFXnO2C4sbg/Zme72Rw= +sigs.k8s.io/controller-runtime v0.17.5/go.mod h1:N0jpP5Lo7lMTF9aL56Z/B2oWBJjey6StQM0jRbKQXtY= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/go_test.go b/go_test.go index 7b329c4e9..7e37d7e40 100644 --- a/go_test.go +++ b/go_test.go @@ -2,6 +2,9 @@ package main import ( "fmt" + "github.com/jfrog/jfrog-client-go/http/httpclient" + "github.com/stretchr/testify/require" + "net/http" "os" "os/exec" "path/filepath" @@ -383,3 +386,37 @@ func cleanGoCache(t *testing.T) { cmd.Env = append(cmd.Env, "GOPATH="+os.Getenv("GOPATH")) assert.NoError(t, cmd.Run()) } + +func TestSetupGoCommand(t *testing.T) { + _, cleanUpFunc := initGoTest(t) + defer cleanUpFunc() + + // Create a Go project + wd, err := os.Getwd() + assert.NoError(t, err) + chdir := clientTestUtils.ChangeDirWithCallback(t, wd, t.TempDir()) + defer chdir() + assert.NoError(t, exec.Command("go", "mod", "init", "test-proj").Run()) + + // Validate that the module does not exist in the cache before running the test. + client, err := httpclient.ClientBuilder().Build() + assert.NoError(t, err) + moduleCacheUrl := serverDetails.ArtifactoryUrl + tests.GoRemoteRepo + "-cache/github.com/shirou/gopsutil/v4/@v/v4.24.12.zip" + _, _, err = client.GetRemoteFileDetails(moduleCacheUrl, artHttpDetails) + assert.ErrorContains(t, err, "404") + + jfrogCli := coretests.NewJfrogCli(execMain, "jfrog", "") + // Please notice that we configure the Go virtual repository (that points to the remote repository), + // because go doesn't support resolving directly from remote repertoires. (https://jfrog.com/help/r/jfrog-artifactory-documentation/set-up-remote-go-repositories) + require.NoError(t, execGo(jfrogCli, "setup", "go", "--repo="+tests.GoVirtualRepo)) + + err = exec.Command("go", "get", "github.com/shirou/gopsutil/v4").Run() + assert.NoError(t, err) + + // Validate that the module exists in the cache after running the test. + // That means that the setup command worked and the 'go get' resolved the module from Artifactory. + _, res, err := client.GetRemoteFileDetails(moduleCacheUrl, artHttpDetails) + if assert.NoError(t, err, "Failed to find the artifact in the cache: "+moduleCacheUrl) { + assert.Equal(t, http.StatusOK, res.StatusCode) + } +} diff --git a/maven_test.go b/maven_test.go index e76382ba5..51571b14d 100644 --- a/maven_test.go +++ b/maven_test.go @@ -6,8 +6,13 @@ import ( commonCliUtils "github.com/jfrog/jfrog-cli-core/v2/common/cliutils" outputFormat "github.com/jfrog/jfrog-cli-core/v2/common/format" "github.com/jfrog/jfrog-cli-core/v2/common/project" + "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" "github.com/jfrog/jfrog-cli/utils/cliutils" + "github.com/jfrog/jfrog-client-go/http/httpclient" + "github.com/stretchr/testify/require" + "net/http" "os" + "os/exec" "path/filepath" "strings" "testing" @@ -361,3 +366,72 @@ func beforeRunMaven(t *testing.T, createProjectFunction func(*testing.T) string, assert.NoError(t, os.Rename(filepath.Join(destPath, configFileName), filepath.Join(destPath, "maven.yaml"))) return projDir } + +func TestSetupMavenCommand(t *testing.T) { + homeDir, err := os.UserHomeDir() + assert.NoError(t, err) + restoreFunc := prepareMavenSetupTest(t, homeDir) + defer func() { + restoreFunc() + }() + // Validate that the artifact does not exist in the cache before running the test. + client, err := httpclient.ClientBuilder().Build() + assert.NoError(t, err) + + moduleCacheUrl := serverDetails.ArtifactoryUrl + tests.MvnRemoteRepo + "-cache/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar" + _, _, err = client.GetRemoteFileDetails(moduleCacheUrl, artHttpDetails) + assert.ErrorContains(t, err, "404") + + jfrogCli := coreTests.NewJfrogCli(execMain, "jfrog", "") + require.NoError(t, execGo(jfrogCli, "setup", "maven", "--repo="+tests.MvnRemoteRepo)) + + // Remove the artifact from the .m2 cache to force artifactory resolve. + assert.NoError(t, os.RemoveAll(filepath.Join(homeDir, ".m2", "repository", "commons-collections", "commons-collections"))) + + // Run `mvn install` to resolve the artifact from Artifactory and force it to be downloaded. + output, err := exec.Command("mvn", "dependency:get", + "-DgroupId=commons-collections", + "-DartifactId=commons-collections", + "-Dversion=3.2.1", "-X").Output() + log.Info(string(output)) + assert.NoError(t, err, fmt.Sprintf("%s\n%q", string(output), err)) + + // Validate that the artifact exists in the cache after running the test. + // This confirms that the setup command worked and the artifact was resolved from Artifactory. + _, res, err := client.GetRemoteFileDetails(moduleCacheUrl, artHttpDetails) + if assert.NoError(t, err, "Failed to find the artifact in the cache: "+moduleCacheUrl) { + assert.Equal(t, http.StatusOK, res.StatusCode) + } +} + +func prepareMavenSetupTest(t *testing.T, homeDir string) func() { + initMavenTest(t, false) + settingsXml := filepath.Join(homeDir, ".m2", "settings.xml") + + // Back up the existing settings.xml file and ensure restoration after the test. + restoreSettingsXml, err := ioutils.BackupFile(settingsXml, ".settings.xml.backup") + require.NoError(t, err) + defer func() { + assert.NoError(t, restoreSettingsXml()) + }() + + wd, err := os.Getwd() + assert.NoError(t, err) + tempDir := t.TempDir() + assert.NoError(t, os.Chdir(tempDir)) + + // Run mvn to create a minimal project structure + err = exec.Command("mvn", "archetype:generate", + "-DgroupId=com.example", + "-DartifactId=mock-project", + "-Dversion=1.0-SNAPSHOT", + "-DinteractiveMode=false").Run() + assert.NoError(t, err) + + restoreDir := clientTestUtils.ChangeDirWithCallback(t, wd, filepath.Join(tempDir, "mock-project")) + + return func() { + assert.NoError(t, restoreSettingsXml()) + restoreDir() + } +} diff --git a/npm_test.go b/npm_test.go index 3bad72905..e4fba64fd 100644 --- a/npm_test.go +++ b/npm_test.go @@ -4,6 +4,9 @@ import ( "fmt" "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/generic" "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" + "github.com/jfrog/jfrog-client-go/http/httpclient" + "github.com/stretchr/testify/require" + "net/http" "os" "os/exec" "path/filepath" @@ -769,3 +772,26 @@ func assertNpmPublishResultFiles(t *testing.T, npmpCmd *npm.NpmPublishCommand) ( assert.NotNil(t, files) return files } + +func TestSetupNpmCommand(t *testing.T) { + initNpmTest(t) + // Validate that the module does not exist in the cache before running the test. + client, err := httpclient.ClientBuilder().Build() + assert.NoError(t, err) + moduleCacheUrl := serverDetails.ArtifactoryUrl + tests.NpmRemoteRepo + "-cache/chalk-animation/-/chalk-animation-2.0.3.tgz" + _, _, err = client.GetRemoteFileDetails(moduleCacheUrl, artHttpDetails) + assert.ErrorContains(t, err, "404") + + jfrogCli := coretests.NewJfrogCli(execMain, "jfrog", "") + require.NoError(t, execGo(jfrogCli, "setup", "npm", "--repo="+tests.NpmRemoteRepo)) + + // Run 'npm install' to resolve the module from Artifactory and force it to be downloaded from Artifactory. + output, err := exec.Command("npm", "install", "chalk-animation@2.0.3", "--cache", t.TempDir(), "--prefix", t.TempDir()).Output() + assert.NoError(t, err, fmt.Sprintf("%s\n%q", string(output), err)) + // Validate that the module exists in the cache after running the test. + // That means that the setup command worked and the 'go get' resolved the module from Artifactory. + _, res, err := client.GetRemoteFileDetails(moduleCacheUrl, artHttpDetails) + if assert.NoError(t, err, "Failed to find the artifact in the cache: "+moduleCacheUrl) { + assert.Equal(t, http.StatusOK, res.StatusCode) + } +} diff --git a/nuget_test.go b/nuget_test.go index bbcca133c..6986bda6a 100644 --- a/nuget_test.go +++ b/nuget_test.go @@ -2,7 +2,13 @@ package main import ( "encoding/xml" + "fmt" + "github.com/jfrog/jfrog-cli-core/v2/utils/ioutils" + "github.com/jfrog/jfrog-client-go/http/httpclient" + "github.com/jfrog/jfrog-client-go/utils/io" + "net/http" "os" + "os/exec" "path/filepath" "strconv" "strings" @@ -209,7 +215,7 @@ type testInitNewConfigDescriptor struct { func TestInitNewConfig(t *testing.T) { baseRtUrl := "http://some/url" expectedV2Url := baseRtUrl + "/api/nuget" - expectedV3Url := baseRtUrl + "/api/nuget/v3" + expectedV3Url := baseRtUrl + "/api/nuget/v3/index.json" testsSuites := []testInitNewConfigDescriptor{ {"useNugetAddSourceV2", true, expectedV2Url}, {"useNugetAddSourceV3", false, expectedV3Url}, @@ -281,3 +287,90 @@ type PackageSources struct { type PackageSourceCredentials struct { JFrogCli []PackageSources `xml:">add"` } + +func TestSetupNugetCommand(t *testing.T) { + testSetupCommand(t, project.Nuget) +} + +func TestSetupDotnetCommand(t *testing.T) { + testSetupCommand(t, project.Dotnet) +} + +func testSetupCommand(t *testing.T, packageManager project.ProjectType) { + initNugetTest(t) + restoreFunc := prepareSetupTest(t, packageManager) + defer func() { + restoreFunc() + }() + // Validate that the package does not exist in the cache before running the test. + client, err := httpclient.ClientBuilder().Build() + assert.NoError(t, err) + + // We use different versions of the Nunit package for Nuget and Dotnet to differentiate between the two tests. + version := "4.0.0" + if packageManager == project.Dotnet { + version = "4.1.0" + } + moduleCacheUrl := serverDetails.ArtifactoryUrl + tests.NugetRemoteRepo + "-cache/nunit." + version + ".nupkg" + _, _, err = client.GetRemoteFileDetails(moduleCacheUrl, artHttpDetails) + assert.ErrorContains(t, err, "404") + + jfrogCli := coreTests.NewJfrogCli(execMain, "jfrog", "") + require.NoError(t, execGo(jfrogCli, "setup", packageManager.String(), "--repo="+tests.NugetRemoteRepo)) + + // Run install some random (Nunit) package to test the setup command. + var output []byte + if packageManager == project.Dotnet { + output, err = exec.Command(packageManager.String(), "add", "package", "NUnit", "--version", version).Output() + } else { + output, err = exec.Command(packageManager.String(), "install", "NUnit", "-Version", version, "-OutputDirectory", t.TempDir(), "-NoHttpCache").Output() + } + assert.NoError(t, err, fmt.Sprintf("%s\n%q", string(output), err)) + + // Validate that the package exists in the cache after running the test. + // That means that the setup command worked and the package resolved from Artifactory. + _, res, err := client.GetRemoteFileDetails(moduleCacheUrl, artHttpDetails) + if assert.NoError(t, err, "Failed to find the artifact in the cache: "+moduleCacheUrl) { + assert.Equal(t, http.StatusOK, res.StatusCode) + } +} + +func prepareSetupTest(t *testing.T, packageManager project.ProjectType) func() { + homeDir, err := os.UserHomeDir() + assert.NoError(t, err) + var nugetConfigDir string + switch { + case io.IsWindows(): + nugetConfigDir = filepath.Join("AppData", "Roaming") + case packageManager == project.Nuget: + nugetConfigDir = ".config" + default: + nugetConfigDir = ".nuget" + } + + wd, err := os.Getwd() + assert.NoError(t, err) + restoreDir := clientTestUtils.ChangeDirWithCallback(t, wd, t.TempDir()) + + // Back up the existing NuGet.config and ensure restoration after the test. + restoreConfigFunc, err := ioutils.BackupFile(filepath.Join(homeDir, nugetConfigDir, "NuGet", "NuGet.Config"), packageManager.String()+".config.backup") + require.NoError(t, err) + + if packageManager == project.Dotnet { + // Dotnet requires creating a new project to install packages. + assert.NoError(t, exec.Command(packageManager.String(), "new", "console").Run()) + // Clear the NuGet cache to ensure the package is resolved from Artifactory. + assert.NoError(t, exec.Command(packageManager.String(), "nuget", "locals", "all", "--clear").Run()) + // Remove the default nuget.org source to force resolving the package from Artifactory. + // We ignore the error since the source might not exist. + _ = exec.Command(packageManager.String(), "nuget", "remove", "source", "nuget.org").Run() + } else { + // Remove the default nuget.org source to force resolving the package from Artifactory. + // We ignore the error since the source might not exist. + _ = exec.Command(packageManager.String(), "sources", "remove", "-name", "nuget.org").Run() + } + return func() { + assert.NoError(t, restoreConfigFunc()) + restoreDir() + } +} diff --git a/pip_test.go b/pip_test.go index 43a583f67..53de3db1a 100644 --- a/pip_test.go +++ b/pip_test.go @@ -1,12 +1,16 @@ package main import ( + "fmt" biutils "github.com/jfrog/build-info-go/utils" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" coretests "github.com/jfrog/jfrog-cli-core/v2/utils/tests" "github.com/jfrog/jfrog-cli-security/commands/audit/sca/python" + "github.com/jfrog/jfrog-client-go/http/httpclient" clientTestUtils "github.com/jfrog/jfrog-client-go/utils/tests" + "net/http" "os" + "os/exec" "path/filepath" "strconv" "testing" @@ -269,3 +273,33 @@ func testTwineCmd(t *testing.T, projectPath, buildNumber, expectedModuleId strin assert.Len(t, twineModule.Artifacts, expectedArtifacts) assert.Equal(t, expectedModuleId, twineModule.Id) } + +func TestSetupPipCommand(t *testing.T) { + if !*tests.TestPip { + t.Skip("Skipping Pip test. To run Pip test add the '-test.pip=true' option.") + } + createJfrogHomeConfig(t, true) + // Set custom pip.conf file. + t.Setenv("PIP_CONFIG_FILE", filepath.Join(t.TempDir(), "pip.conf")) + + // Validate that the package does not exist in the cache before running the test. + client, err := httpclient.ClientBuilder().Build() + assert.NoError(t, err) + packageCacheUrl := serverDetails.ArtifactoryUrl + tests.PypiRemoteRepo + "-cache/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl" + + _, _, err = client.GetRemoteFileDetails(packageCacheUrl, artHttpDetails) + assert.ErrorContains(t, err, "404") + + jfrogCli := coretests.NewJfrogCli(execMain, "jfrog", "") + require.NoError(t, execGo(jfrogCli, "setup", "pip", "--repo="+tests.PypiRemoteRepo)) + + // Run 'pip install' to resolve the package from Artifactory and force it to be cached. + output, err := exec.Command("pip", "install", "--target", t.TempDir(), "--no-cache-dir", "pefile==2024.8.26").CombinedOutput() + assert.NoError(t, err, fmt.Sprintf("%s\n%q", string(output), err)) + + // Validate that the package exists in the cache after running the test. + _, res, err := client.GetRemoteFileDetails(packageCacheUrl, artHttpDetails) + if assert.NoError(t, err, "Failed to find the package in the cache: "+packageCacheUrl) { + assert.Equal(t, http.StatusOK, res.StatusCode) + } +} diff --git a/pipenv_test.go b/pipenv_test.go index 807690135..a0151ed0e 100644 --- a/pipenv_test.go +++ b/pipenv_test.go @@ -1,8 +1,12 @@ package main import ( + "fmt" biutils "github.com/jfrog/build-info-go/utils" + "github.com/jfrog/jfrog-client-go/http/httpclient" + "net/http" "os" + "os/exec" "path/filepath" "strconv" "testing" @@ -133,3 +137,42 @@ func initPipenvTest(t *testing.T) { require.True(t, isRepoExist(tests.PipenvRemoteRepo), "Pypi test remote repository doesn't exist.") require.True(t, isRepoExist(tests.PipenvVirtualRepo), "Pypi test virtual repository doesn't exist.") } + +func TestSetupPipenvCommand(t *testing.T) { + if !*tests.TestPipenv { + t.Skip("Skipping Pipenv test. To run Pipenv test add the '-test.pipenv=true' option.") + } + createJfrogHomeConfig(t, true) + // Change dir to temp dir to run the pipenv install in a clean environment. + wd, err := os.Getwd() + assert.NoError(t, err, "Failed to get current dir") + chdir := clientTestUtils.ChangeDirWithCallback(t, wd, t.TempDir()) + defer chdir() + + // Set custom pip.conf file. + t.Setenv("PIP_CONFIG_FILE", filepath.Join(t.TempDir(), "pip.conf")) + + // Validate that the package does not exist in the cache before running the test. + client, err := httpclient.ClientBuilder().Build() + assert.NoError(t, err) + packageCacheUrl := serverDetails.ArtifactoryUrl + tests.PipenvRemoteRepo + "-cache/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl" + + _, _, err = client.GetRemoteFileDetails(packageCacheUrl, artHttpDetails) + assert.ErrorContains(t, err, "404") + + // Set PIP_NO_CACHE_DIR to 'off' to force resolving the package from Artifactory. + unset := clientTestUtils.SetEnvWithCallbackAndAssert(t, "PIP_NO_CACHE_DIR", "1") + defer unset() + jfrogCli := coreTests.NewJfrogCli(execMain, "jfrog", "") + require.NoError(t, execGo(jfrogCli, "setup", "pipenv", "--repo="+tests.PipenvRemoteRepo)) + + // Run 'pip install' to resolve the package from Artifactory and force it to be cached. + output, err := exec.Command("pipenv", "install", "pefile==2024.8.26").CombinedOutput() + assert.NoError(t, err, fmt.Sprintf("%s\n%q", string(output), err)) + + // Validate that the package exists in the cache after running the test. + _, res, err := client.GetRemoteFileDetails(packageCacheUrl, artHttpDetails) + if assert.NoError(t, err, "Failed to find the package in the cache: "+packageCacheUrl) { + assert.Equal(t, http.StatusOK, res.StatusCode) + } +} diff --git a/utils/cliutils/commandsflags.go b/utils/cliutils/commandsflags.go index 8005a28a7..9a3fe4311 100644 --- a/utils/cliutils/commandsflags.go +++ b/utils/cliutils/commandsflags.go @@ -14,11 +14,9 @@ import ( const ( // CLI base commands keys - Setup = "setup" Intro = "intro" // Artifactory's Commands Keys - DeleteConfig = "delete-config" Upload = "upload" Download = "download" Move = "move" @@ -35,6 +33,7 @@ const ( BuildAddGit = "build-add-git" BuildCollectEnv = "build-collect-env" GitLfsClean = "git-lfs-clean" + Setup = "setup" Mvn = "mvn" MvnConfig = "mvn-config" CocoapodsConfig = "cocoapods-config" @@ -108,8 +107,9 @@ const ( JpdDelete = "jpd-delete" // Config commands keys - AddConfig = "config-add" - EditConfig = "config-edit" + AddConfig = "config-add" + EditConfig = "config-edit" + DeleteConfig = "delete-config" // Project commands keys InitProject = "project-init" @@ -587,6 +587,7 @@ const ( lcDryRun = lifecyclePrefix + dryRun lcIncludeRepos = lifecyclePrefix + IncludeRepos lcExcludeRepos = lifecyclePrefix + ExcludeRepos + setupRepo = repo ) var flagsMap = map[string]cli.Flag{ @@ -1723,6 +1724,10 @@ var flagsMap = map[string]cli.Flag{ Name: Reference, Usage: "[Default: false] Generate a Reference Token (alias to Access Token) in addition to the full token (available from Artifactory 7.38.10)` `", }, + setupRepo: cli.StringFlag{ + Name: repo, + Usage: "[Optional] Specifies the Artifactory repository name for the selected package manager, replacing the interactive repository selection.` `", + }, } var commandFlags = map[string][]string{ @@ -2091,6 +2096,9 @@ var commandFlags = map[string][]string{ SyncStatus: { branch, repository, serverId, }, + Setup: { + serverId, url, user, password, accessToken, sshPassphrase, sshKeyPath, ClientCertPath, ClientCertKeyPath, Project, setupRepo, + }, } func GetCommandFlags(cmd string) []cli.Flag {