Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
cd98137
RTECO-1782: JFROG_RUN_NATIVE wins over a project config, and fix the …
bhanurp Sep 6, 2026
213b468
RTECO-1782: add dotnet FlexPack integration tests
bhanurp Sep 6, 2026
c8a0d0e
RTECO-1782: fix gosec and nilerr findings in the dotnet FlexPack tests
bhanurp Sep 6, 2026
b307d23
RTECO-1782: make the dotnet test project path absolute
bhanurp Sep 7, 2026
b49b0a5
RTECO-1782: assert the double-dash separator now works
bhanurp Sep 7, 2026
46846c3
RTECO-1782: fix JFROG_RUN_NATIVE leak and two dotnet test assertions
bhanurp Sep 7, 2026
e1f10ff
RTECO-1782: fix the remaining dotnet FlexPack test failures
bhanurp Sep 7, 2026
70b9678
RTECO-1782: point build-info-go and jfrog-cli-artifactory at the RTEC…
bhanurp Sep 7, 2026
abee838
Merge branch 'master' into RTECO-1782
bhanurp Sep 7, 2026
84d4a57
RTECO-1782: correct the pushed .snupkg path and fix four unrelated te…
bhanurp Sep 7, 2026
469d13c
RTECO-1782: collect the auto-pushed sibling .snupkg, fix the detailed…
bhanurp Sep 8, 2026
7b1cb7a
RTECO-1782: assert pack --include-symbols records the .snupkg
bhanurp Sep 8, 2026
bda6930
RTECO-1782: assert symbol packages by what the commands actually produce
bhanurp Sep 8, 2026
77c7551
RTECO-1782: call IsFlexPackEnabled directly, bump both dependencies
bhanurp Sep 8, 2026
ea38661
RTECO-1782: document which sub-commands --repo-resolve actually routes
bhanurp Sep 8, 2026
564110a
RTECO-1782: make the dotnet tests assert what they claim
bhanurp Sep 9, 2026
dba3587
RTECO-1782: rename a test variable gosec reads as a credential
bhanurp Sep 9, 2026
fad9ab5
Merge remote-tracking branch 'upstream/master' into RTECO-1782
bhanurp Sep 9, 2026
c3c2159
RTECO-1782: give the stamp-failure test a deploy repo so stamping act…
bhanurp Sep 9, 2026
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
32 changes: 28 additions & 4 deletions buildtools/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"strings"

dotnetutils "github.com/jfrog/build-info-go/build/utils/dotnet"
"github.com/jfrog/build-info-go/flexpack"
alpinecommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/alpine"
aptcommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/apt"
cargocommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/cargo"
Expand Down Expand Up @@ -1040,6 +1041,29 @@ func extractPnpmOptionsFromArgs(args []string) (serverDetails *coreConfig.Server
return serverDetails, cleanArgs, buildConfig, nil
}

// shouldRunNuGetFlexPack reports whether the FlexPack (native) path should handle a
// 'jf nuget' / 'jf dotnet' invocation.
//
// JFROG_RUN_NATIVE=true takes precedence over a per-project configuration file. Previously the
// gate was `ShouldRunNative(configFilePath) && !configExists`, so any leftover
// .jfrog/projects/{nuget,dotnet}.yaml silently forced the legacy path even with the
// environment variable set. That was invisible to the user, and because the legacy path does
// not recognise the native-only flags it forwarded them to MSBuild, surfacing as an opaque
// "MSBUILD : error MSB1001: Unknown switch --repo-resolve". The config file is now reported
// and ignored instead.
//
// configFilePath is only used for the warning message; pass configExists to say whether one
// was found. pmName names the package manager for the 'jf <pm>-config' hint.
func shouldRunNuGetFlexPack(configFilePath string, configExists bool, pmName string) bool {
if !flexpack.IsFlexPackEnabled() {
return false
}
if configExists {
log.Warn(fmt.Sprintf("JFROG_RUN_NATIVE=true, so the %s configuration at %q is being ignored and the command runs in native (FlexPack) mode. Unset JFROG_RUN_NATIVE to use the legacy 'jf %s-config' path.", pmName, configFilePath, pmName))
}
return true
}

func NugetCmd(c *cli.Context) error {
if show, err := cliutils.ShowCmdHelpIfNeeded(c, c.Args()); show || err != nil {
return err
Expand All @@ -1053,8 +1077,8 @@ func NugetCmd(c *cli.Context) error {
return err
}

// FlexPack bypasses all config file requirements (only when no config exists)
if artutils.ShouldRunNative(configFilePath) && !configExists {
// FlexPack bypasses all config file requirements. JFROG_RUN_NATIVE wins over a config file.
if shouldRunNuGetFlexPack(configFilePath, configExists, "nuget") {
return runNugetFlexPackCmd(c, dotnetutils.Nuget)
}

Expand Down Expand Up @@ -1108,8 +1132,8 @@ func DotnetCmd(c *cli.Context) error {
return err
}

// FlexPack bypasses all config file requirements (only when no config exists)
if artutils.ShouldRunNative(configFilePath) && !configExists {
// FlexPack bypasses all config file requirements. JFROG_RUN_NATIVE wins over a config file.
if shouldRunNuGetFlexPack(configFilePath, configExists, "dotnet") {
return runNugetFlexPackCmd(c, dotnetutils.DotnetCore)
}

Expand Down
37 changes: 23 additions & 14 deletions docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,27 +85,38 @@ func initNativeDockerWithArtTest(t *testing.T) func() {
}
// Create server config to use with the command.
createJfrogHomeConfig(t, true)
return func() {
// Restore the home dir through t.Cleanup rather than the returned closure. Callers receive
// that closure and defer it, but anything running between this line and their defer can
// Goexit - a t.Skip or a failed require in initDockerBuildTest's buildx setup - and the defer
// is then never registered, leaking JFROG_CLI_HOME_DIR into every later test in the binary.
// That is the same failure shape as the JFROG_RUN_NATIVE leak fixed in initDockerBuildTest.
// The returned func is kept so existing call sites need no change; it is now a no-op.
t.Cleanup(func() {
clientTestUtils.SetEnvAndAssert(t, coreutils.HomeDir, oldHomeDir)
}
})
return func() {}
}

// initDockerBuildTest initializes test environment for docker build tests with JFROG_RUN_NATIVE enabled
func initDockerBuildTest(t *testing.T) func() {
// Set JFROG_RUN_NATIVE=true for docker build tests
clientTestUtils.SetEnvAndAssert(t, "JFROG_RUN_NATIVE", "true")

// Initialize native docker test setup
// Initialize native docker test setup FIRST. It calls t.Skip when '-test.docker=true' is
// absent, and t.Skip runs runtime.Goexit: this function never returns, so the caller's
// 'defer cleanup()' is never registered. Anything set up before this line therefore leaks
// into every subsequent test in the binary - which is exactly what happened when
// JFROG_RUN_NATIVE was set above it, silently forcing later 'jf nuget'/'jf dotnet' tests
// down the FlexPack path.
cleanupNativeDocker := initNativeDockerWithArtTest(t)

// Set JFROG_RUN_NATIVE=true for docker build tests. Restored via t.Cleanup rather than the
// returned closure so it is undone even if a later helper below skips or fails the test.
clientTestUtils.SetEnvAndAssert(t, "JFROG_RUN_NATIVE", "true")
t.Cleanup(func() {
clientTestUtils.UnSetEnvAndAssert(t, "JFROG_RUN_NATIVE")
})

// if this is an external JFrog instance, no need to setup buildx with insecure registry
if strings.HasPrefix(*tests.JfrogUrl, "https://") {
return func() {
// Restore JFROG_RUN_NATIVE
clientTestUtils.UnSetEnvAndAssert(t, "JFROG_RUN_NATIVE")
// Run native docker cleanup
cleanupNativeDocker()
}
return cleanupNativeDocker
}
// Setup buildx builder with insecure registry config for localhost
builderName := "jfrog-test-builder"
Expand All @@ -115,8 +126,6 @@ func initDockerBuildTest(t *testing.T) func() {
return func() {
// Cleanup buildx builder
cleanupBuilder()
// Restore JFROG_RUN_NATIVE
clientTestUtils.UnSetEnvAndAssert(t, "JFROG_RUN_NATIVE")
// Run native docker cleanup
cleanupNativeDocker()
}
Expand Down
27 changes: 22 additions & 5 deletions docs/buildtools/dotnet/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,45 @@ func GetDescription() string {

func GetArguments() string {
return ` dotnet sub-command
Arguments and options for the dotnet command.`
The dotnet sub-command to run, with its arguments and options.
Supported sub-commands: restore, build, publish, pack, add, and
'nuget push' (see 'Common patterns' below).`
}

func GetAIDescription() string {
return `Run a .NET CLI command (restore, build, pack, push) through JFrog: package restoration is routed via Artifactory and optional build-info is collected.
return `Run a .NET CLI command (restore, build, publish, pack, add, nuget push) through JFrog: package restoration is routed via Artifactory and optional build-info is collected.

When to use:
- Building .NET Core/SDK projects that consume NuGet packages from Artifactory.
- Publishing a .nupkg to Artifactory with 'jf dotnet nuget push'.
- Capturing build-info for .NET pipelines.

Prerequisites:
- The .NET SDK installed (dotnet on PATH).
- 'jf dotnet-config' run once in the project directory.
- A configured server.
- Either JFROG_RUN_NATIVE=true (native/FlexPack mode, no per-project config needed), or
'jf dotnet-config' run once in the project directory (legacy mode).

Common patterns:
$ jf dotnet restore MyApp.sln
$ export JFROG_RUN_NATIVE=true
$ jf dotnet restore MyApp.sln --repo-resolve my-nuget-virtual --server-id my-server
$ jf dotnet build --build-name=my-app --build-number=4
$ jf dotnet pack --configuration Release
$ jf dotnet nuget push MyApp.1.0.0.nupkg --repo my-nuget-local --server-id my-server

Gotchas:
- 'jf dotnet-config' must be run first.
- 'jf dotnet-config' is optional when JFROG_RUN_NATIVE=true. In that mode a per-project
.jfrog/projects/dotnet.yaml is ignored (a warning is printed) and the native path is used.
- Without JFROG_RUN_NATIVE=true, 'jf dotnet-config' must be run first, and the native-only
flags --repo-resolve / --server-id are not supported.
- 'jf dotnet nuget push' is a two-token sub-command; plain 'jf dotnet push' is not a command.
- --repo-resolve routes the restore that a sub-command performs. restore, build, publish and
pack all restore (publish and pack implicitly, unless --no-restore is passed), so all four
honour it. 'dotnet add package' also restores, but the .NET SDK gives it no config-file
option, so --repo-resolve cannot be applied there; run 'jf dotnet restore' first.
- Build-info dependencies are collected for restore-family sub-commands, and artifacts for
pack and 'nuget push'. A pack that produces no package - for example every project already
up to date - records an empty module rather than failing.
- Mixing 'jf nuget' and 'jf dotnet' configs in the same directory can create confused resolution.

Related: jf dotnet-config, jf nuget`
Expand Down
10 changes: 8 additions & 2 deletions docs/buildtools/nuget/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,21 @@ When to use:

Prerequisites:
- A local nuget binary on PATH.
- 'jf nuget-config' run once in the project directory.
- A configured server.
- Either JFROG_RUN_NATIVE=true (native/FlexPack mode, no per-project config needed), or
'jf nuget-config' run once in the project directory (legacy mode).

Common patterns:
$ jf nuget restore MyApp.sln
$ jf nuget restore --build-name=my-app --build-number=2
$ export JFROG_RUN_NATIVE=true
$ jf nuget restore MyApp.sln --repo-resolve my-nuget-virtual --server-id my-server

Gotchas:
- 'jf nuget-config' must be run first.
- 'jf nuget-config' is optional when JFROG_RUN_NATIVE=true. In that mode a per-project
.jfrog/projects/nuget.yaml is ignored (a warning is printed) and the native path is used.
- Without JFROG_RUN_NATIVE=true, 'jf nuget-config' must be run first, and the native-only
flags --repo-resolve / --server-id are not supported.
- For .NET Core/SDK projects, prefer 'jf dotnet' instead.
- The nuget binary on Linux/macOS often comes from Mono and behaves differently than on Windows.

Expand Down
Loading
Loading