Skip to content

Commit ee6636b

Browse files
authored
add nix package manager support (#3471)
1 parent 5f7509e commit ee6636b

17 files changed

Lines changed: 1753 additions & 13 deletions

File tree

.github/workflows/nixTests.yml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: Nix Tests
2+
on:
3+
workflow_dispatch:
4+
inputs:
5+
jfrog_url:
6+
description: "External JFrog Platform URL. Leave empty for local Artifactory."
7+
type: string
8+
required: false
9+
default: ""
10+
jfrog_admin_token:
11+
description: "Admin token for external JFrog Platform."
12+
type: string
13+
required: false
14+
default: ""
15+
push:
16+
branches:
17+
- "master"
18+
pull_request_target:
19+
types: [labeled]
20+
branches:
21+
- "master"
22+
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.ref }}
25+
cancel-in-progress: true
26+
jobs:
27+
Nix-Tests:
28+
name: Nix tests (${{ matrix.os.name }})
29+
if: github.event_name == 'workflow_dispatch' || github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'safe to test')
30+
strategy:
31+
fail-fast: false
32+
matrix:
33+
os:
34+
- name: ubuntu
35+
version: 24.04
36+
- name: macos
37+
version: 14
38+
# Windows omitted: Nix does not have first-class Windows support.
39+
runs-on: ${{ matrix.os.name }}-${{ matrix.os.version }}
40+
steps:
41+
- name: Skip macOS - JGC-413
42+
if: matrix.os.name == 'macos'
43+
run: |
44+
echo "::warning::JGC-413 - Skip until artifactory bootstrap in osx is fixed"
45+
exit 0
46+
47+
- name: Checkout code
48+
if: matrix.os.name != 'macos'
49+
uses: actions/checkout@v6
50+
with:
51+
ref: ${{ github.event.pull_request.head.sha || github.ref }}
52+
53+
- name: Setup FastCI
54+
if: matrix.os.name != 'macos'
55+
uses: jfrog-fastci/fastci@v1
56+
with:
57+
github_token: ${{ secrets.GITHUB_TOKEN }}
58+
fastci_otel_token: ${{ secrets.FASTCI_TOKEN }}
59+
60+
- name: Setup Go with cache
61+
if: matrix.os.name != 'macos'
62+
uses: jfrog/.github/actions/install-go-with-cache@main
63+
64+
- name: Install Nix
65+
if: matrix.os.name != 'macos'
66+
uses: cachix/install-nix-action@v31
67+
with:
68+
extra_nix_config: |
69+
experimental-features = nix-command flakes
70+
71+
- name: Install local Artifactory
72+
if: matrix.os.name != 'macos'
73+
uses: jfrog/.github/actions/install-local-artifactory@main
74+
with:
75+
RTLIC: ${{ secrets.RTLIC }}
76+
JFROG_URL: ${{ inputs.jfrog_url }}
77+
JFROG_ADMIN_TOKEN: ${{ inputs.jfrog_admin_token }}
78+
RT_CONNECTION_TIMEOUT_SECONDS: '1200'
79+
80+
- name: Run Nix tests
81+
if: matrix.os.name != 'macos'
82+
run: >-
83+
go test -v github.com/jfrog/jfrog-cli --timeout 0 --test.nix
84+
${{ env.JFROG_TESTS_IS_EXTERNAL == 'true' && format('--jfrog.url={0} --jfrog.adminToken={1}', env.JFROG_TESTS_URL, env.JFROG_TESTS_LOCAL_ACCESS_TOKEN) || '' }}

buildtools/cli.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"fmt"
66
conancommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/conan"
7+
nixcommand "github.com/jfrog/jfrog-cli-artifactory/artifactory/commands/nix"
78
"io/fs"
89
"os"
910
"os/exec"
@@ -67,6 +68,7 @@ import (
6768
huggingfaceuploaddocs "github.com/jfrog/jfrog-cli/docs/buildtools/huggingfaceupload"
6869
mvndoc "github.com/jfrog/jfrog-cli/docs/buildtools/mvn"
6970
"github.com/jfrog/jfrog-cli/docs/buildtools/mvnconfig"
71+
"github.com/jfrog/jfrog-cli/docs/buildtools/nix"
7072
"github.com/jfrog/jfrog-cli/docs/buildtools/npmcommand"
7173
"github.com/jfrog/jfrog-cli/docs/buildtools/npmconfig"
7274
nugetdocs "github.com/jfrog/jfrog-cli/docs/buildtools/nuget"
@@ -409,6 +411,19 @@ func GetCommands() []cli.Command {
409411
Category: buildToolsCategory,
410412
Action: ConanCmd,
411413
},
414+
{
415+
Name: "nix",
416+
Hidden: true,
417+
Flags: cliutils.GetCommandFlags(cliutils.Nix),
418+
Usage: nix.GetDescription(),
419+
HelpName: corecommon.CreateUsage("nix", nix.GetDescription(), nix.Usage),
420+
UsageText: nix.GetArguments(),
421+
ArgsUsage: common.CreateEnvVars(),
422+
SkipFlagParsing: true,
423+
BashComplete: corecommon.CreateBashCompletionFunc(),
424+
Category: buildToolsCategory,
425+
Action: NixCmd,
426+
},
412427
{
413428
Name: "ruby-config",
414429
Flags: cliutils.GetCommandFlags(cliutils.RubyConfig),
@@ -2010,6 +2025,53 @@ func ConanCmd(c *cli.Context) error {
20102025
return commands.Exec(conanCommand)
20112026
}
20122027

2028+
func NixCmd(c *cli.Context) error {
2029+
if show, err := cliutils.ShowCmdHelpIfNeeded(c, c.Args()); show || err != nil {
2030+
return err
2031+
}
2032+
if c.NArg() < 1 {
2033+
return cliutils.WrongNumberOfArgumentsHandler(c)
2034+
}
2035+
2036+
args := cliutils.ExtractCommand(c)
2037+
2038+
// The first arg determines which native tool to run:
2039+
// jf nix nix-channel --add ... → nativeTool="nix-channel", args=["--add", ...]
2040+
// jf nix nix-env -iA ... → nativeTool="nix-env", args=["-iA", ...]
2041+
// jf nix nix-build '<nixpkgs>' → nativeTool="nix-build", args=["'<nixpkgs>'", ...]
2042+
// jf nix copy --to ... → nativeTool="copy" (runs as "nix copy"), args=["--to", ...]
2043+
nativeTool, remainingArgs := getCommandName(args)
2044+
2045+
// Extract --server-id flag before passing to native tool
2046+
var serverID string
2047+
var err error
2048+
remainingArgs, serverID, err = coreutils.ExtractServerIdFromCommand(remainingArgs)
2049+
if err != nil {
2050+
return fmt.Errorf("failed to extract server ID: %w", err)
2051+
}
2052+
2053+
// Extract build flags (--build-name, --build-number, --module, --project)
2054+
filteredArgs, buildConfiguration, err := build.ExtractBuildDetailsFromArgs(remainingArgs)
2055+
if err != nil {
2056+
return err
2057+
}
2058+
2059+
cmd := nixcommand.NewNixCommand().SetNativeTool(nativeTool).SetArgs(filteredArgs).SetBuildConfiguration(buildConfiguration)
2060+
2061+
// Pass server details — use --server-id if provided, otherwise default
2062+
var serverDetails *coreConfig.ServerDetails
2063+
if serverID != "" {
2064+
serverDetails, err = coreConfig.GetSpecificConfig(serverID, false, false)
2065+
} else {
2066+
serverDetails, err = coreConfig.GetDefaultServerConf()
2067+
}
2068+
if err == nil && serverDetails != nil {
2069+
cmd.SetServerDetails(serverDetails)
2070+
}
2071+
2072+
return commands.Exec(cmd)
2073+
}
2074+
20132075
func pythonCmd(c *cli.Context, projectType project.ProjectType) error {
20142076
if show, err := cliutils.ShowCmdHelpIfNeeded(c, c.Args()); show || err != nil {
20152077
return err

docs/buildtools/nix/help.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package nix
2+
3+
var Usage = []string{"nix <native-command> <args> [command options]"}
4+
5+
func GetDescription() string {
6+
return "Run native nix commands with build-info support."
7+
}
8+
9+
func GetArguments() string {
10+
return ` nix native-command
11+
Wraps native Nix commands (nix-channel, nix-env, nix-build, nix copy)
12+
with build-info collection. All args are passed through to the native tool.
13+
14+
Examples:
15+
- jf nix nix-channel --add https://server/artifactory/api/nix/repo/channels/nixos-25.11 nixpkgs
16+
- jf nix nix-channel --update
17+
- jf nix nix-env -iA nixpkgs.hello --build-name=my-build --build-number=1
18+
- jf nix nix-build '<nixpkgs>' -A hello --build-name=my-build --build-number=1
19+
- jf nix copy --to "http://user:pass@server/artifactory/api/nix/repo/" ./result --build-name=my-build --build-number=1`
20+
}

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ require (
1616
github.com/docker/docker v28.5.2+incompatible
1717
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1
1818
github.com/jfrog/archiver/v3 v3.6.3
19-
github.com/jfrog/build-info-go v1.13.1-0.20260521104402-1e35b9b5b0c6
19+
github.com/jfrog/build-info-go v1.13.1-0.20260526201157-3dd942bd9e1f
2020
github.com/jfrog/gofrog v1.7.6
2121
github.com/jfrog/jfrog-cli-application v1.0.2-0.20260511133105-55a0ab56fd64
22-
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260520131142-ef80a14dd499
23-
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260520130103-75be6a23c54b
22+
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260527043943-fdf755c4f4c2
23+
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260522091649-43f236276873
2424
github.com/jfrog/jfrog-cli-evidence v0.9.4
2525
github.com/jfrog/jfrog-cli-platform-services v1.10.1-0.20260430094150-ce7d9b371c6f
2626
github.com/jfrog/jfrog-cli-security v1.29.0

go.sum

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,8 @@ github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP
406406
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
407407
github.com/jfrog/archiver/v3 v3.6.3 h1:hkAmPjBw393tPmQ07JknLNWFNZjXdy2xFEnOW9wwOxI=
408408
github.com/jfrog/archiver/v3 v3.6.3/go.mod h1:5V9l+Fte30Y4qe9dUOAd3yNTf8lmtVNuhKNrvI8PMhg=
409-
github.com/jfrog/build-info-go v1.13.1-0.20260521104402-1e35b9b5b0c6 h1:x9UKlP7rEzCYS/Z8IP0I+Oy8PTPpOxFy8qpMeRMbrwo=
410-
github.com/jfrog/build-info-go v1.13.1-0.20260521104402-1e35b9b5b0c6/go.mod h1:CYRUCvLKfyARjoJXLWAxce1qNUxTEtbRKAARkV42vpE=
409+
github.com/jfrog/build-info-go v1.13.1-0.20260526201157-3dd942bd9e1f h1:2f9rUp14HdL8SD84/3Vu1UOmn71OIX7MxmHLW4VCjwM=
410+
github.com/jfrog/build-info-go v1.13.1-0.20260526201157-3dd942bd9e1f/go.mod h1:CYRUCvLKfyARjoJXLWAxce1qNUxTEtbRKAARkV42vpE=
411411
github.com/jfrog/froggit-go v1.22.0 h1:eeN5F8sOUo+h2cXkzArAu4nvSdjkDTAZtgqwrct70qg=
412412
github.com/jfrog/froggit-go v1.22.0/go.mod h1:wRDryqyp3oe+eHgME2mpnEQmO8XBECIPagFwj0nHmdI=
413413
github.com/jfrog/go-mockhttp v0.3.1 h1:/wac8v4GMZx62viZmv4wazB5GNKs+GxawuS1u3maJH8=
@@ -418,18 +418,16 @@ github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYL
418418
github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w=
419419
github.com/jfrog/jfrog-cli-application v1.0.2-0.20260511133105-55a0ab56fd64 h1:bxcy1v1LXQV4T0kVU1duWQr3h7vKfHyMD1B+IuFLWUw=
420420
github.com/jfrog/jfrog-cli-application v1.0.2-0.20260511133105-55a0ab56fd64/go.mod h1:cKqb/JgN+XuD4RhOxvSZnyGyXw3cJsTZfQT3rk9MCho=
421-
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260520131142-ef80a14dd499 h1:wkhhrH5nIpCFM61z2mEGXnFuk44FQMPmGudDzmPZuV8=
422-
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260520131142-ef80a14dd499/go.mod h1:g8hvUcVJs26a+3F6X4+Cthx5q4LeLrlPsekn0vxPYU0=
423-
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260520130103-75be6a23c54b h1:Bi0dfWKDANYjzV7xVH1eV2LdNdJAE259IXPjX6IDAO0=
424-
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260520130103-75be6a23c54b/go.mod h1:D9afcOJmauUYcQZ3WGDg7HejyoBmCQr2XrwXHeN1YY8=
421+
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260527043943-fdf755c4f4c2 h1:acwlLYjjglecqjXXgj2JoM1bUhH/dDMpLpJXrBfvyqU=
422+
github.com/jfrog/jfrog-cli-artifactory v0.8.1-0.20260527043943-fdf755c4f4c2/go.mod h1:T5HDtDxHlUZWF4LQnmF2kiyFyd8yLOf3K618BsG0CWk=
423+
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260522091649-43f236276873 h1:6X1Hwu0st7c9gbFoIj1fc8qjoQ3wAHWX2qo7K9IxWgU=
424+
github.com/jfrog/jfrog-cli-core/v2 v2.60.1-0.20260522091649-43f236276873/go.mod h1:D9afcOJmauUYcQZ3WGDg7HejyoBmCQr2XrwXHeN1YY8=
425425
github.com/jfrog/jfrog-cli-evidence v0.9.4 h1:RAqZYaH2RrzmhW+bGA7dx/yTqa4X1fZ4/5V7VVMSJtc=
426426
github.com/jfrog/jfrog-cli-evidence v0.9.4/go.mod h1:nLSLqLIhQz1Hi2n+KjHZTyK1mcmPLevv41LjItLswmE=
427427
github.com/jfrog/jfrog-cli-platform-services v1.10.1-0.20260430094150-ce7d9b371c6f h1:M1cesbKYSznwPA76dNctjCELxGx34TSSjwoYnJm9/6Y=
428428
github.com/jfrog/jfrog-cli-platform-services v1.10.1-0.20260430094150-ce7d9b371c6f/go.mod h1:JUdq/dQoNscpta62FDCAcaSVbvcCOr5VkH8UeGTG1HQ=
429429
github.com/jfrog/jfrog-cli-security v1.29.0 h1:TN2OCA5i/iPbikQWzSwVqGvySvIvw1P6rPga+DbVBOI=
430430
github.com/jfrog/jfrog-cli-security v1.29.0/go.mod h1:q38TPlxortIJvbyD3u9P9UhHwyx007tEb9WbXlXw2E0=
431-
github.com/jfrog/jfrog-client-go v1.55.1-0.20260518090239-a4f67e2bd8cb h1:ew1foDyxCyqKbSz06ybrrHruf4OIbhti/YLwaa0J8dI=
432-
github.com/jfrog/jfrog-client-go v1.55.1-0.20260518090239-a4f67e2bd8cb/go.mod h1:sCE06+GngPoyrGO0c+vmhgMoVSP83UMNiZnIuNPzU8U=
433431
github.com/jfrog/jfrog-client-go v1.55.1-0.20260522071027-8b60a715d6e4 h1:ujVu255rk51l9Uz1t75DdsVoa2MH+lYNV2cB2xDWjPM=
434432
github.com/jfrog/jfrog-client-go v1.55.1-0.20260522071027-8b60a715d6e4/go.mod h1:k3PqoFpS6XDt9/4xg3pS8J8JUvxtaz1w2vdTdodknGk=
435433
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=

main_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func setupIntegrationTests() {
6767
InitArtifactoryTests()
6868
}
6969

70-
if *tests.TestNpm || *tests.TestPnpm || *tests.TestGradle || *tests.TestMaven || *tests.TestGo || *tests.TestNuget || *tests.TestPip || *tests.TestPipenv || *tests.TestPoetry || *tests.TestConan || *tests.TestHelm || *tests.TestUv || (*tests.TestArtifactory && !*tests.TestArtifactoryProxy) || *tests.TestArtifactoryProject {
70+
if *tests.TestNpm || *tests.TestPnpm || *tests.TestGradle || *tests.TestMaven || *tests.TestGo || *tests.TestNuget || *tests.TestPip || *tests.TestPipenv || *tests.TestPoetry || *tests.TestConan || *tests.TestHelm || *tests.TestUv || *tests.TestNix || (*tests.TestArtifactory && !*tests.TestArtifactoryProxy) || *tests.TestArtifactoryProject {
7171
InitBuildToolsTests()
7272
}
7373
if *tests.TestDocker || *tests.TestPodman || *tests.TestDockerScan {
@@ -109,7 +109,7 @@ func tearDownIntegrationTests() {
109109
if (*tests.TestArtifactory && !*tests.TestArtifactoryProxy) || *tests.TestArtifactoryProject {
110110
CleanArtifactoryTests()
111111
}
112-
if *tests.TestNpm || *tests.TestPnpm || *tests.TestGradle || *tests.TestMaven || *tests.TestGo || *tests.TestNuget || *tests.TestPip || *tests.TestPipenv || *tests.TestPoetry || *tests.TestConan || *tests.TestHelm || *tests.TestDocker || *tests.TestPodman || *tests.TestDockerScan || (*tests.TestArtifactory && !*tests.TestArtifactoryProxy) || *tests.TestArtifactoryProject {
112+
if *tests.TestNpm || *tests.TestPnpm || *tests.TestGradle || *tests.TestMaven || *tests.TestGo || *tests.TestNuget || *tests.TestPip || *tests.TestPipenv || *tests.TestPoetry || *tests.TestConan || *tests.TestHelm || *tests.TestNix || *tests.TestDocker || *tests.TestPodman || *tests.TestDockerScan || (*tests.TestArtifactory && !*tests.TestArtifactoryProxy) || *tests.TestArtifactoryProject {
113113
CleanBuildToolsTests()
114114
}
115115
if *tests.TestDistribution {

0 commit comments

Comments
 (0)