Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,10 @@ require (

// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20250529104758-6d769a684388

replace github.com/jfrog/jfrog-cli-artifactory => github.com/jfrog/jfrog-cli-artifactory v0.3.3-0.20250623095509-b3fe2c4681ad
replace github.com/jfrog/jfrog-cli-artifactory => ../jfrog-cli-artifactory

replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250629143350-c43614bbffcd
replace github.com/jfrog/jfrog-cli-core/v2 => ../jfrog-cli-core

replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20250629142537-bb24db402fe1
replace github.com/jfrog/jfrog-client-go => ../jfrog-client-go

//replace github.com/jfrog/jfrog-cli-security => github.com/jfrog/jfrog-cli-security v1.17.2-0.20250511132918-d9cc4cd50020
6 changes: 0 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,10 @@ 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.3.3-0.20250623095509-b3fe2c4681ad h1:cnbcCK0VTHdLdmmv/9fYTRjuR1ewrYBW/S87pVE+d+s=
github.com/jfrog/jfrog-cli-artifactory v0.3.3-0.20250623095509-b3fe2c4681ad/go.mod h1:hnXaevmDyQpyhpH5kwDufIjUUXXuKs54i+AX2CEywKE=
github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250629143350-c43614bbffcd h1:1Nw+HKbtQZGEogerQBNM77RvbUwHYNKFNYJk4lmNF9w=
github.com/jfrog/jfrog-cli-core/v2 v2.31.1-0.20250629143350-c43614bbffcd/go.mod h1:BkDHfCVecjcRNC+aqmHtTrKe+/K8MyjzmHYe5rER5Yg=
github.com/jfrog/jfrog-cli-platform-services v1.10.0 h1:O+N/VAF+QjFvq9xkHpmzKLcdl9aJu3IP204Su0L14rw=
github.com/jfrog/jfrog-cli-platform-services v1.10.0/go.mod h1:qbu4iqBST9x8LgD8HhzUm91iOB3vHqtoGmaxOnmw0ok=
github.com/jfrog/jfrog-cli-security v1.19.0 h1:4qggon1biuOvjMjHZ5IWDA4Mh+qp2qecWEdeX6s4Xv8=
github.com/jfrog/jfrog-cli-security v1.19.0/go.mod h1:QMoGTGfKMSnXOuWv3/IclZU+M/AshoJMt68Ft6l7EdE=
github.com/jfrog/jfrog-client-go v1.28.1-0.20250629142537-bb24db402fe1 h1:0t6dQHoalUDNVrfZujD3iCmDGLDl+ndHclFkmONSpq0=
github.com/jfrog/jfrog-client-go v1.28.1-0.20250629142537-bb24db402fe1/go.mod h1:1v0eih4thdPA4clBo9TuvAMT25sGDr1IQJ81DXQ/lBY=
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=
Expand Down
67 changes: 67 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ package main
import (
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"github.com/agnivade/levenshtein"
gofrogcmd "github.com/jfrog/gofrog/io"
artifactoryCLI "github.com/jfrog/jfrog-cli-artifactory/cli"
"github.com/jfrog/jfrog-cli-core/v2/common/build"
"github.com/jfrog/jfrog-cli-core/v2/common/project"
corecommon "github.com/jfrog/jfrog-cli-core/v2/docs/common"
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
coreconfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
Expand All @@ -28,6 +32,7 @@ import (
"github.com/jfrog/jfrog-cli/general/summary"
"github.com/jfrog/jfrog-cli/general/token"
"github.com/jfrog/jfrog-cli/missioncontrol"
"github.com/jfrog/jfrog-cli/newImpl"
"github.com/jfrog/jfrog-cli/pipelines"
"github.com/jfrog/jfrog-cli/plugins"
"github.com/jfrog/jfrog-cli/plugins/utils"
Expand Down Expand Up @@ -128,13 +133,75 @@ func execMain() error {
if err = setUberTraceIdToken(); err != nil {
clientlog.Warn("failed generating a trace ID token:", err.Error())
}
if os.Getenv("JFROG_RUN_NATIVE") == "true" {
// If the JFROG_RUN_NATIVE environment variable is set to true, we run the new implementation.
// This is used for testing purposes.
if err = runNativeImplementation(ctx); err != nil {
clientlog.Error("Failed to run native implementation:", err)
os.Exit(1)
}
os.Exit(0)
}
return nil
}

app.CommandNotFound = func(c *cli.Context, command string) {
err := runNativeImplementation(c)
if err != nil {
clientlog.Error("Failed to run native implementation:", err)
os.Exit(1)
}
os.Exit(0)
}

err = app.Run(args)
logTraceIdOnFailure(err)
return err
}

func runNativeImplementation(ctx *cli.Context) error {
// extract the build name and number from the command arguments
args, buildArgs, err := build.ExtractBuildDetailsFromArgs(ctx.Args())
if len(args) < 2 {
return errors.New("jfrog jf " + strings.Join(args, " ") + " not specified")
}
buildName, err := buildArgs.GetBuildName()
buildNumber, err := buildArgs.GetBuildNumber()

// create config if it doesn't exist
confType := args[0]
if confType == "bundle" {
confType = "gem"
}
err = cliutils.CreateConfigCmd(ctx, project.FromString(confType))
if err != nil {
return err
}
Comment on lines +176 to +179

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
err = cliutils.CreateConfigCmd(ctx, project.FromString(confType))
if err != nil {
return err
}
if !configExists(confType) {
err = cliutils.CreateConfigCmd(ctx, project.FromString(confType))
if err != nil {
return fmt.Errorf("failed to create config: %w", err)
}
}


err = RunActions(args)

if err != nil {
return err
}

if buildName != "" && buildNumber != "" {
err = newImpl.GetBuildInfoForUploadedArtifacts(args[2], buildArgs)
}

return err
}

func RunActions(args []string) error {
executableCommand := append([]string{}, args[2:]...)
command := gofrogcmd.NewCommand(args[0], args[1], executableCommand)
_, _, _, err := gofrogcmd.RunCmdWithOutputParser(command, true)
if err != nil {
clientlog.Error("Error occurred while running command: ", err)
os.Exit(1)
}
return err
}

// This command generates and sets an Uber Trace ID token which will be attached as a header to every request.
// This allows users to easily identify which logs on the server side are related to the command executed by the CLI.
func setUberTraceIdToken() error {
Expand Down
148 changes: 148 additions & 0 deletions newImpl/utilityImpls.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package newImpl

import (
"errors"
"fmt"
buildinfo "github.com/jfrog/build-info-go/entities"
"github.com/jfrog/jfrog-cli-core/v2/artifactory/utils"
buildUtils "github.com/jfrog/jfrog-cli-core/v2/common/build"
"github.com/jfrog/jfrog-cli-core/v2/common/project"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/artifactory/services"
serviceutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
specutils "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
"github.com/jfrog/jfrog-client-go/utils/io/content"
"github.com/jfrog/jfrog-client-go/utils/log"
)

type aqlResult struct {
Results []*serviceutils.ResultItem `json:"results,omitempty"`
}

func GetFiles(pkgManager, fileUploaded string) ([]string, error) {
switch pkgManager {
case "gem":
return []string{fileUploaded + ".gem", fileUploaded + ".gemspec.rz", fileUploaded}, nil
default:
return []string{}, errors.New("unsupported package manager")
}
}

func GetBuildInfoForUploadedArtifacts(uploadedFile string, buildConfiguration *buildUtils.BuildConfiguration) error {
repoConfig, err := extractRepositoryConfig()
if err != nil {
return err
}
serverDetails, err := repoConfig.ServerDetails()
if err != nil {
return err
}
err = saveBuildInfo(serverDetails, repoConfig.TargetRepo(), uploadedFile, buildConfiguration)
return err
}
Comment on lines +31 to +42

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logs and the error messages can be updated,

func GetBuildInfoForUploadedArtifacts(uploadedFile string, buildConfiguration *buildUtils.BuildConfiguration) error {
	log.Info("Extracting repository configuration for build info...")
	repoConfig, err := extractRepositoryConfig()
	if err != nil {
		log.Error("Failed to extract repository configuration: ", err)
		return fmt.Errorf("extractRepositoryConfig failed: %w", err)
	}

	log.Info("Retrieving server details...")
	serverDetails, err := repoConfig.ServerDetails()
	if err != nil {
		log.Error("Failed to retrieve server details: ", err)
		return fmt.Errorf("ServerDetails extraction failed: %w", err)
	}

	log.Infof("Saving build info for uploaded file: %s", uploadedFile)
	err = saveBuildInfo(serverDetails, repoConfig.TargetRepo(), uploadedFile, buildConfiguration)
	if err != nil {
		log.Error("Failed to save build info: ", err)
		return fmt.Errorf("saveBuildInfo failed: %w", err)
	}

	log.Info("Successfully saved build info for uploaded artifact.")
	return nil
}


func saveBuildInfo(serverDetails *config.ServerDetails, searchRepo string, fileName string, buildConfiguration *buildUtils.BuildConfiguration) error {
servicesManager, err := utils.CreateServiceManager(serverDetails, -1, 0, false)
if err != nil {
return err
}

var buildProps string
var searchReader *content.ContentReader
var buildName, buildNumber string
buildName, err = buildConfiguration.GetBuildName()
if err != nil {
return err
}
buildNumber, err = buildConfiguration.GetBuildNumber()
if err != nil {
return err
}
buildProject := buildConfiguration.GetProject()

buildProps, err = getBuildPropsForArtifact(buildName, buildNumber, buildProject)
if err != nil {
return err
}

searchQuery := CreateAqlQueryForSearch(searchRepo, fileName)
searchParams := services.SearchParams{
CommonParams: &specutils.CommonParams{
Aql: specutils.Aql{
ItemsFind: searchQuery,
},
},
}
searchReader, err = servicesManager.SearchFiles(searchParams)
if err != nil {
log.Error("Failed to get uploaded npm package: ", err.Error())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message is specific to npm, but the function is generic.
We can update it to generic message: "Failed to get uploaded package: ..."

return err
}

propsParams := services.PropsParams{
Reader: searchReader,
Props: buildProps,
}
_, err = servicesManager.SetProps(propsParams)
if err != nil {
log.Warn("Unable to set build properties: ", err, "\nThis may cause build to not properly link with artifact, please add build name and build number properties on the tarball artifact manually")
}
buildInfoArtifacts, err := utils.ConvertArtifactsSearchDetailsToBuildInfoArtifacts(searchReader)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if needed we can check for errors after converting artifacts before proceeding

err = createBuildInfo(buildName, buildNumber, buildProject, buildConfiguration.GetModule(), buildInfoArtifacts)
if err != nil {
return err
}
return nil
}

func getBuildPropsForArtifact(buildName, buildNumber, project string) (string, error) {
err := buildUtils.SaveBuildGeneralDetails(buildName, buildNumber, project)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider logging if saving general details fails.

if err != nil {
return "", err
}
return buildUtils.CreateBuildProperties(buildName, buildNumber, project)
}

func createBuildInfo(buildName, buildNumber, project, moduleName string, artifacts []buildinfo.Artifact) error {
buildInfoService := buildUtils.CreateBuildInfoService()
build, err := buildInfoService.GetOrCreateBuildWithProject(buildName, buildNumber, project)
if err != nil {
return err
}
err = build.AddArtifacts(moduleName, "generic", artifacts...)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some Improvements:

  • We can add error context if adding artifacts fails.
  • We can add logging for successful artifact addition.

return err
}

func extractRepositoryConfig() (*project.RepositoryConfig, error) {
prefix := project.ProjectConfigDeployerPrefix
configFilePath, exists, err := project.GetProjectConfFilePath(project.Gem)
if !exists {
return nil, fmt.Errorf("project configuration file not found for %s", project.Gem)
}
if err != nil {
return nil, err
}
vConfig, err := project.ReadConfigFile(configFilePath, project.YAML)
if err != nil {
return nil, err
}
Comment on lines +125 to +128

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can validate config file contents before proceeding.

repoConfig, err := project.GetRepoConfigByPrefix(configFilePath, prefix, vConfig)
if err != nil {
return nil, err
}
return repoConfig, nil
}

func CreateAqlQueryForSearch(repo, file string) string {
itemsPart :=
`{` +
`"repo": "%s",` +
`"$or": [{` +
`"$and":[{` +
`"path": {"$match": "*"},` +
`"name": {"$match": "%s"}` +
`}]` +
`}]` +
`}`
return fmt.Sprintf(itemsPart, repo, file)
}
6 changes: 3 additions & 3 deletions utils/cliutils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,9 +476,9 @@ func OverrideFieldsIfSet(spec *speccore.File, c *cli.Context) {
}

func CreateConfigCmd(c *cli.Context, confType project.ProjectType) error {
if c.NArg() != 0 {
return WrongNumberOfArgumentsHandler(c)
}
//if c.NArg() != 0 {
// return WrongNumberOfArgumentsHandler(c)
//}
return commonCommands.CreateBuildConfig(c, confType)
}

Expand Down