Skip to content

Commit cbfcb89

Browse files
committed
Refactor FlexPack business logic to jfrog-cli-artifactory
- Move FlexPack command handling from main.go to jfrog-cli-artifactory - Remove business logic functions (runNativeImplementation, RunActions, etc.) - Simplify main.go to focus on CLI routing only - Keep minimal import for GetJfrogCliArtifactoryApp compatibility - Successfully builds and runs basic CLI functionality This follows the established pattern where: - jfrog-cli: Command routing and CLI setup - jfrog-cli-artifactory: Business logic for Artifactory commands - build-info-go: Core FlexPack implementations
1 parent 0ef65b4 commit cbfcb89

File tree

5 files changed

+27
-613
lines changed

5 files changed

+27
-613
lines changed

buildtools/cli.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,19 @@ func MvnCmd(c *cli.Context) (err error) {
516516
return err
517517
}
518518

519+
// FlexPack bypasses all config file requirements
520+
if os.Getenv("JFROG_RUN_NATIVE") == "true" {
521+
// Extract build configuration for FlexPack
522+
args := cliutils.ExtractCommand(c)
523+
filteredMavenArgs, buildConfiguration, err := build.ExtractBuildDetailsFromArgs(args)
524+
if err != nil {
525+
return err
526+
}
527+
// Create Maven command with empty config for FlexPack
528+
mvnCmd := mvn.NewMvnCommand().SetConfigPath("").SetGoals(filteredMavenArgs).SetConfiguration(buildConfiguration)
529+
return commands.Exec(mvnCmd)
530+
}
531+
519532
configFilePath, err := getProjectConfigPathOrThrow(project.Maven, "mvn", "mvn-config")
520533
if err != nil {
521534
return err

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ require (
1818
github.com/jfrog/archiver/v3 v3.6.1
1919
github.com/jfrog/build-info-go v1.11.0
2020
github.com/jfrog/gofrog v1.7.6
21-
github.com/jfrog/jfrog-cli-artifactory v0.7.3-0.20250919153452-dd92b2c8f024
21+
github.com/jfrog/jfrog-cli-artifactory v0.7.2
2222
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20250918084044-2eb3f15d08c1
2323
github.com/jfrog/jfrog-cli-platform-services v1.10.0
2424
github.com/jfrog/jfrog-cli-security v1.21.7
@@ -245,10 +245,12 @@ require (
245245
sigs.k8s.io/yaml v1.6.0 // indirect
246246
)
247247

248-
replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20250924104816-8f9261b993f4
248+
replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go v1.8.9-0.20250930092857-a56dbf4eb2dc
249249

250250
// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 v2.59.2-0.20250804083101-9cf424ecc926
251251

252252
// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20250812100044-b52afcc698c1
253253

254254
//replace github.com/jfrog/jfrog-cli-security => github.com/jfrog/jfrog-cli-security v1.17.2-0.20250511132918-d9cc4cd50020
255+
256+
replace github.com/jfrog/jfrog-cli-artifactory => github.com/agrasth/jfrog-cli-artifactory v0.2.2-0.20250930094644-9d0943a5a09d

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH
5151
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
5252
github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM=
5353
github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
54+
github.com/agrasth/jfrog-cli-artifactory v0.2.2-0.20250930094644-9d0943a5a09d h1:wgov003q7ArqXhot//sfQRnC1/AhZsD7lZ0mUt/+big=
55+
github.com/agrasth/jfrog-cli-artifactory v0.2.2-0.20250930094644-9d0943a5a09d/go.mod h1:gbom3hWJBhL219fs1M1dRsn3STlKRRGNdcM6AzDhD2Y=
5456
github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
5557
github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
5658
github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ=
@@ -351,8 +353,8 @@ github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHT
351353
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
352354
github.com/jfrog/archiver/v3 v3.6.1 h1:LOxnkw9pOn45DzCbZNFV6K0+6dCsQ0L8mR3ZcujO5eI=
353355
github.com/jfrog/archiver/v3 v3.6.1/go.mod h1:VgR+3WZS4N+i9FaDwLZbq+jeU4B4zctXL+gL4EMzfLw=
354-
github.com/jfrog/build-info-go v1.8.9-0.20250924104816-8f9261b993f4 h1:UJ8QflsHBEdZLq5dfoFzzf6kgc+IxSe6dtZxVN/TDXY=
355-
github.com/jfrog/build-info-go v1.8.9-0.20250924104816-8f9261b993f4/go.mod h1:szdz9+WzB7+7PGnILLUgyY+OF5qD5geBT7UGNIxibyw=
356+
github.com/jfrog/build-info-go v1.8.9-0.20250930092857-a56dbf4eb2dc h1:hBGJss5QFTi39YxCKFSfW1TcbASEKqC9HLPgnsTN+1w=
357+
github.com/jfrog/build-info-go v1.8.9-0.20250930092857-a56dbf4eb2dc/go.mod h1:szdz9+WzB7+7PGnILLUgyY+OF5qD5geBT7UGNIxibyw=
356358
github.com/jfrog/froggit-go v1.20.3 h1:U3HHT0+AEHUVSSyQBbagQR4fLRqGqzSptPujDZuuDTk=
357359
github.com/jfrog/froggit-go v1.20.3/go.mod h1:obSG1SlsWjktkuqmKtpq7MNTTL63e0ot+ucTnlOMV88=
358360
github.com/jfrog/go-mockhttp v0.3.1 h1:/wac8v4GMZx62viZmv4wazB5GNKs+GxawuS1u3maJH8=
@@ -361,8 +363,6 @@ github.com/jfrog/gofrog v1.7.6 h1:QmfAiRzVyaI7JYGsB7cxfAJePAZTzFz0gRWZSE27c6s=
361363
github.com/jfrog/gofrog v1.7.6/go.mod h1:ntr1txqNOZtHplmaNd7rS4f8jpA5Apx8em70oYEe7+4=
362364
github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYLipdsOFMY=
363365
github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w=
364-
github.com/jfrog/jfrog-cli-artifactory v0.7.3-0.20250919153452-dd92b2c8f024 h1:LWmb50WFKV8V59jmB8+/KD3TI26KmNrJnMwSf/0CEuU=
365-
github.com/jfrog/jfrog-cli-artifactory v0.7.3-0.20250919153452-dd92b2c8f024/go.mod h1:N1nn6tNbyAjtdhLp89tO1CstT+iWcQSzAJGvAml7Deg=
366366
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20250918084044-2eb3f15d08c1 h1:Gu9GT06M9OH7E7rhNYF1tXoaMQhZOmzpaBDmJcwkUgc=
367367
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20250918084044-2eb3f15d08c1/go.mod h1:nir0kLxfelcpFsXHVztjCxFIoONWyMbTXnL5dyHcZHI=
368368
github.com/jfrog/jfrog-cli-platform-services v1.10.0 h1:O+N/VAF+QjFvq9xkHpmzKLcdl9aJu3IP204Su0L14rw=

main.go

Lines changed: 4 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ import (
1111
"strings"
1212

1313
"github.com/agnivade/levenshtein"
14-
"github.com/jfrog/build-info-go/flexpack"
15-
gofrogcmd "github.com/jfrog/gofrog/io"
1614
artifactoryCLI "github.com/jfrog/jfrog-cli-artifactory/cli"
17-
"github.com/jfrog/jfrog-cli-core/v2/common/build"
1815
corecommon "github.com/jfrog/jfrog-cli-core/v2/docs/common"
1916
"github.com/jfrog/jfrog-cli-core/v2/plugins/components"
2017
coreconfig "github.com/jfrog/jfrog-cli-core/v2/utils/config"
@@ -40,7 +37,6 @@ import (
4037
"github.com/jfrog/jfrog-cli/pipelines"
4138
"github.com/jfrog/jfrog-cli/plugins"
4239
"github.com/jfrog/jfrog-cli/plugins/utils"
43-
"github.com/jfrog/jfrog-cli/utils/buildinfo"
4440
"github.com/jfrog/jfrog-cli/utils/cliutils"
4541
"github.com/jfrog/jfrog-client-go/http/httpclient"
4642
clientutils "github.com/jfrog/jfrog-client-go/utils"
@@ -134,38 +130,13 @@ func execMain() error {
134130
if err = setUberTraceIdToken(); err != nil {
135131
clientlog.Warn("failed generating a trace ID token:", err.Error())
136132
}
137-
if flexpack.IsFlexPackEnabled() {
138-
// If the JFROG_RUN_NATIVE environment variable is set to true, we run the new implementation
139-
// but only for package manager commands, not for JFrog CLI commands
140-
args := ctx.Args()
141-
if args.Present() && len(args) > 0 {
142-
firstArg := args.Get(0)
143-
if isPackageManagerCommand(firstArg) {
144-
if err = runNativeImplementation(ctx); err != nil {
145-
clientlog.Error("Failed to run native implementation:", err)
146-
return err
147-
}
148-
// Native implementation completed successfully
149-
return nil
150-
}
151-
}
152-
// For non-package-manager commands, continue with normal CLI processing
153-
}
133+
// FlexPack native implementation is now handled through the existing buildtools CLI
134+
// Maven FlexPack works the same way as Poetry FlexPack - through jf mvn commands
154135
return nil
155136
}
156137

157138
app.CommandNotFound = func(c *cli.Context, command string) {
158-
// Try to handle as native package manager command only when JFROG_RUN_NATIVE is true
159-
if flexpack.IsFlexPackEnabled() && isPackageManagerCommand(command) {
160-
clientlog.Debug("Attempting to handle as native package manager command:", command)
161-
err := runNativeImplementation(c)
162-
if err != nil {
163-
clientlog.Error("Failed to run native implementation:", err)
164-
os.Exit(1)
165-
}
166-
os.Exit(0)
167-
}
168-
139+
// FlexPack native implementation is now handled through existing buildtools CLI
169140
// Original behavior for unknown commands
170141
_, err = fmt.Fprintf(c.App.Writer, "'%s %s' is not a jf command. See --help\n", c.App.Name, command)
171142
if err != nil {
@@ -194,13 +165,7 @@ func execMain() error {
194165
// Check if native implementation completed successfully
195166
if err == nil {
196167
displaySurveyLinkIfNeeded()
197-
// Exit normally if native implementation ran successfully
198-
if flexpack.IsFlexPackEnabled() && len(args) > 1 && isPackageManagerCommand(args[1]) {
199-
// Only exit if we're not in a test environment
200-
if !isTestEnvironment() {
201-
os.Exit(0)
202-
}
203-
}
168+
// FlexPack native implementation is now handled through existing buildtools CLI
204169
}
205170
return err
206171
}
@@ -224,165 +189,6 @@ func displaySurveyLinkIfNeeded() {
224189
fmt.Fprintln(os.Stderr, "\n💬 Help us improve JFrog CLI! \033]8;;https://www.surveymonkey.com/r/JFCLICLI\033\\https://www.surveymonkey.com/r/JFCLICLI\033]8;;\033\\")
225190
}
226191

227-
func runNativeImplementation(ctx *cli.Context) error {
228-
clientlog.Debug("Starting native implementation...")
229-
230-
// Extract the build name and number from the command arguments
231-
args, buildArgs, err := build.ExtractBuildDetailsFromArgs(ctx.Args())
232-
if err != nil {
233-
clientlog.Error("Failed to extract build details from args: ", err)
234-
return fmt.Errorf("ExtractBuildDetailsFromArgs failed: %w", err)
235-
}
236-
237-
if len(args) < 2 {
238-
return fmt.Errorf("insufficient arguments: expected at least package-manager and command, got %v", args)
239-
}
240-
241-
packageManager := args[0]
242-
command := args[1]
243-
clientlog.Debug("Executing native command: " + packageManager + " " + command)
244-
245-
buildName, err := buildArgs.GetBuildName()
246-
if err != nil {
247-
clientlog.Error("Failed to get build name: ", err)
248-
return fmt.Errorf("GetBuildName failed: %w", err)
249-
}
250-
251-
buildNumber, err := buildArgs.GetBuildNumber()
252-
if err != nil {
253-
clientlog.Error("Failed to get build number: ", err)
254-
return fmt.Errorf("GetBuildNumber failed: %w", err)
255-
}
256-
257-
// Execute the native command
258-
err = RunActions(args)
259-
if err != nil {
260-
clientlog.Error("Failed to run actions: ", err)
261-
return fmt.Errorf("RunActions failed: %w", err)
262-
}
263-
264-
// Collect build info if build name and number are provided
265-
if buildName != "" && buildNumber != "" {
266-
clientlog.Info("Collecting build info for executed command...")
267-
workingDir := ctx.GlobalString("working-dir")
268-
if workingDir == "" {
269-
workingDir = "."
270-
}
271-
272-
// Use the enhanced build info collection that supports Poetry
273-
err = buildinfo.GetBuildInfoForPackageManager(packageManager, workingDir, buildArgs)
274-
if err != nil {
275-
clientlog.Error("Failed to collect build info: ", err)
276-
return fmt.Errorf("GetBuildInfoForPackageManager failed: %w", err)
277-
}
278-
}
279-
280-
clientlog.Info("Native implementation completed successfully.")
281-
return nil
282-
}
283-
284-
// isPackageManagerCommand checks if the command is a supported package manager
285-
func isPackageManagerCommand(command string) bool {
286-
supportedPackageManagers := []string{"poetry", "pip", "pipenv", "gem", "bundle", "npm", "yarn", "gradle", "mvn", "maven", "nuget", "go"}
287-
for _, pm := range supportedPackageManagers {
288-
if command == pm {
289-
return true
290-
}
291-
}
292-
return false
293-
}
294-
295-
// cleanProgressOutput handles carriage returns and progress updates properly
296-
func cleanProgressOutput(output string) string {
297-
if output == "" {
298-
return ""
299-
}
300-
301-
// First, split by both \n and \r to handle all line breaks
302-
lines := strings.FieldsFunc(output, func(c rune) bool {
303-
return c == '\n' || c == '\r'
304-
})
305-
306-
var cleanedLines []string
307-
var progressLines = make(map[string]string) // Track progress lines by filename
308-
309-
for _, line := range lines {
310-
line = strings.TrimSpace(line)
311-
if line == "" {
312-
continue
313-
}
314-
315-
// Check if this is a progress line (contains % and "Uploading")
316-
if strings.Contains(line, "Uploading") && strings.Contains(line, "%") {
317-
// Extract filename for tracking progress
318-
if strings.Contains(line, " - Uploading ") {
319-
parts := strings.Split(line, " - Uploading ")
320-
if len(parts) == 2 {
321-
filename := strings.Split(parts[1], " ")[0]
322-
progressLines[filename] = line
323-
continue
324-
}
325-
}
326-
}
327-
328-
// Add non-progress lines immediately
329-
cleanedLines = append(cleanedLines, line)
330-
}
331-
332-
// Add final progress states
333-
for _, progressLine := range progressLines {
334-
cleanedLines = append(cleanedLines, progressLine)
335-
}
336-
337-
if len(cleanedLines) > 0 {
338-
return strings.Join(cleanedLines, "\n") + "\n"
339-
}
340-
return ""
341-
}
342-
343-
func RunActions(args []string) error {
344-
if len(args) < 2 {
345-
return fmt.Errorf("insufficient arguments for RunActions: expected at least 2, got %d", len(args))
346-
}
347-
348-
packageManager := args[0]
349-
subCommand := args[1]
350-
executableCommand := append([]string{}, args[2:]...)
351-
352-
clientlog.Debug("Executing command: " + packageManager + " " + subCommand)
353-
command := gofrogcmd.NewCommand(packageManager, subCommand, executableCommand)
354-
355-
// Use RunCmdWithOutputParser but handle the output better
356-
clientlog.Debug("Executing command: " + packageManager + " " + subCommand + " " + strings.Join(executableCommand, " "))
357-
stdout, stderr, exitOk, err := gofrogcmd.RunCmdWithOutputParser(command, false)
358-
if err != nil {
359-
clientlog.Error("Command execution failed: ", err)
360-
if stdout != "" {
361-
clientlog.Error("Command stdout: ", stdout)
362-
}
363-
if stderr != "" {
364-
clientlog.Error("Command stderr: ", stderr)
365-
}
366-
return fmt.Errorf("command '%s %s %s' failed (exitOk=%t): %w", packageManager, subCommand, strings.Join(executableCommand, " "), exitOk, err)
367-
}
368-
369-
// Print stdout directly without parsing to preserve Poetry's output format
370-
if stdout != "" {
371-
fmt.Print(stdout)
372-
}
373-
374-
// Also print stderr, but clean it up for progress information
375-
if stderr != "" {
376-
cleanStderr := cleanProgressOutput(stderr)
377-
if cleanStderr != "" {
378-
fmt.Print(cleanStderr)
379-
}
380-
}
381-
382-
clientlog.Debug("Command executed successfully")
383-
return nil
384-
}
385-
386192
// This command generates and sets an Uber Trace ID token which will be attached as a header to every request.
387193
// This allows users to easily identify which logs on the server side are related to the command executed by the CLI.
388194
func setUberTraceIdToken() error {

0 commit comments

Comments
 (0)