Skip to content

Commit

Permalink
Utils enhancements to allow go support for JFrog Curation (#1187)
Browse files Browse the repository at this point in the history
  • Loading branch information
asafambar committed Jun 9, 2024
1 parent fdc77c0 commit f80a1af
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 35 deletions.
22 changes: 11 additions & 11 deletions artifactory/commands/golang/go.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,12 @@ func (gc *GoCommand) run() (err error) {
if err != nil {
return
}
repoUrl, err := goutils.GetArtifactoryRemoteRepoUrl(resolverDetails, gc.resolverParams.TargetRepo())
// If noFallback=false, missing packages will be fetched directly from VCS
repoUrl, err := goutils.GetArtifactoryRemoteRepoUrl(resolverDetails, gc.resolverParams.TargetRepo(), goutils.GoProxyUrlParams{Direct: !gc.noFallback})
if err != nil {
return
}
// If noFallback=false, missing packages will be fetched directly from VCS
if !gc.noFallback {
repoUrl += "|direct"
}

err = biutils.RunGo(gc.goArg, repoUrl)
if errorutils.CheckError(err) != nil {
err = coreutils.ConvertExitCodeError(err)
Expand Down Expand Up @@ -330,19 +328,21 @@ func buildPackageVersionRequest(name, branchName string) string {
return path.Join(packageVersionRequest, "latest.info")
}

func SetArtifactoryAsResolutionServer(serverDetails *config.ServerDetails, depsRepo string) (err error) {
err = setGoProxy(serverDetails, depsRepo)
if err != nil {
func SetArtifactoryAsResolutionServer(serverDetails *config.ServerDetails, depsRepo string, goProxyParams goutils.GoProxyUrlParams) (err error) {
if err = setGoProxy(serverDetails, depsRepo, goProxyParams); err != nil {
err = fmt.Errorf("failed while setting Artifactory as a dependencies resolution registry: %s", err.Error())
}
return
}

func setGoProxy(server *config.ServerDetails, remoteGoRepo string) error {
repoUrl, err := goutils.GetArtifactoryRemoteRepoUrl(server, remoteGoRepo)
func setGoProxy(server *config.ServerDetails, remoteGoRepo string, goProxyParams goutils.GoProxyUrlParams) error {
repoUrl, err := goutils.GetArtifactoryRemoteRepoUrl(server, remoteGoRepo, goProxyParams)
if err != nil {
return err
}
repoUrl += "|direct"
return os.Setenv("GOPROXY", repoUrl)
}

func SetGoModCache(cacheFolder string) error {
return os.Setenv("GOMODCACHE", cacheFolder)
}
12 changes: 11 additions & 1 deletion artifactory/commands/golang/go_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package golang
import (
"fmt"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
goutils "github.com/jfrog/jfrog-cli-core/v2/utils/golang"
testsutils "github.com/jfrog/jfrog-client-go/utils/tests"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -60,9 +61,18 @@ func TestSetArtifactoryAsResolutionServer(t *testing.T) {
cleanup := testsutils.SetEnvWithCallbackAndAssert(t, "GOPROXY", "")
defer cleanup()

assert.NoError(t, SetArtifactoryAsResolutionServer(server, repo))
assert.NoError(t, SetArtifactoryAsResolutionServer(server, repo, goutils.GoProxyUrlParams{Direct: true}))

serverUrlWithoutHttp := strings.TrimPrefix(server.ArtifactoryUrl, "http://")
expectedGoProxy := fmt.Sprintf("http://%s:%s@%sapi/go/%s|direct", server.User, server.Password, serverUrlWithoutHttp, repo)
assert.Equal(t, expectedGoProxy, os.Getenv("GOPROXY"))

// Verify that the EndpointPrefix value is correctly added to the GOPROXY.
// In this test case, the endpoint prefix is set to api/curation/audit/.
// This parameter allows downloading dependencies from a custom API instead of the default one.
assert.NoError(t, SetArtifactoryAsResolutionServer(server, repo, goutils.GoProxyUrlParams{Direct: true, EndpointPrefix: coreutils.CurationPassThroughApi}))

serverUrlWithoutHttp = strings.TrimPrefix(server.ArtifactoryUrl, "http://")
expectedGoProxy = fmt.Sprintf("http://%s:%s@%sapi/curation/audit/api/go/%s|direct", server.User, server.Password, serverUrlWithoutHttp, repo)
assert.Equal(t, expectedGoProxy, os.Getenv("GOPROXY"))
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,6 @@ require (

replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04

// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev
replace github.com/jfrog/build-info-go => github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371

// replace github.com/jfrog/gofrog => github.com/jfrog/gofrog v1.3.3-0.20231223133729-ef57bd08cedc
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer5
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/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371 h1:U7bqNQ40AfeC55m9v9r8vy/Iza4xrUJiJ2DYcE031Oo=
github.com/asafambar/build-info-go v1.8.9-0.20240530151827-93c25df23371/go.mod h1:5TH6zBwOpQxGXgn+WX4OlH4q5P4k1zE1sFksU5VDhbE=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
Expand Down Expand Up @@ -91,8 +93,6 @@ github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+
github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w=
github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI=
github.com/jfrog/build-info-go v1.9.27 h1:7RWJcajqtNNbGHuYkgOLUIG7mmRKF0yxC7mvYAbdVlU=
github.com/jfrog/build-info-go v1.9.27/go.mod h1:8T7/ajM9aGshvgpwCtXwIFpyF/R6CEn4W+/FLryNXWw=
github.com/jfrog/gofrog v1.7.2 h1:VkAaA/9tmbw27IqgUOmaZWnO6ATUqL3vRzDnsROKATw=
github.com/jfrog/gofrog v1.7.2/go.mod h1:WJFk88SR9Sr9mKl1bQBig7DmSdXiBGKV3WhL9O6jL9w=
github.com/jfrog/jfrog-client-go v1.28.1-0.20240530101935-539b5837ce04 h1:ERLE/L7YPr6aCUTeAnE8SXU5VOZHd5/XK16rM1TEpts=
Expand Down
42 changes: 26 additions & 16 deletions utils/golang/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"io"
"net/url"
"os/exec"
"path"
"strings"
)

type GoCmdConfig struct {
Expand Down Expand Up @@ -83,33 +85,41 @@ func GetModuleName(projectDir string) (string, error) {
return path, nil
}

func GetDependenciesList(projectDir string) (map[string]bool, error) {
deps, err := utils.GetDependenciesList(projectDir, log.Logger)
if err != nil {
return nil, errorutils.CheckError(err)
}
return deps, nil
type GoProxyUrlParams struct {
// Fallback to retrieve the modules directly from the source if
// the module failed to be retrieved from the proxy.
// add |direct to the end of the url.
// example: https://gocenter.io|direct
Direct bool
// The path from baseUrl to the standard Go repository path
// URL structure: <baseUrl>/<EndpointPrefix>/api/go/<repoName>
EndpointPrefix string
}

func GetDependenciesGraph(projectDir string) (map[string][]string, error) {
deps, err := utils.GetDependenciesGraph(projectDir, log.Logger)
if err != nil {
return nil, errorutils.CheckError(err)
func (gdu *GoProxyUrlParams) BuildUrl(url *url.URL, repoName string) string {
url.Path = path.Join(url.Path, gdu.EndpointPrefix, "api/go/", repoName)

return gdu.addDirect(url.String())
}

func (gdu *GoProxyUrlParams) addDirect(url string) string {
if gdu.Direct && !strings.HasSuffix(url, "|direct") {
return url + "|direct"
}
return deps, nil
return url
}

func GetArtifactoryRemoteRepoUrl(serverDetails *config.ServerDetails, repo string) (string, error) {
func GetArtifactoryRemoteRepoUrl(serverDetails *config.ServerDetails, repo string, goProxyParams GoProxyUrlParams) (string, error) {
authServerDetails, err := serverDetails.CreateArtAuthConfig()
if err != nil {
return "", err
}
return getArtifactoryApiUrl(repo, authServerDetails)
return getArtifactoryApiUrl(repo, authServerDetails, goProxyParams)
}

// Gets the URL of the specified repository Go API in Artifactory.
// The URL contains credentials (username and access token or password).
func getArtifactoryApiUrl(repoName string, details auth.ServiceDetails) (string, error) {
func getArtifactoryApiUrl(repoName string, details auth.ServiceDetails, goProxyParams GoProxyUrlParams) (string, error) {
rtUrl, err := url.Parse(details.GetUrl())
if err != nil {
return "", errorutils.CheckError(err)
Expand All @@ -129,6 +139,6 @@ func getArtifactoryApiUrl(repoName string, details auth.ServiceDetails) (string,
if password != "" {
rtUrl.User = url.UserPassword(username, password)
}
rtUrl.Path += "api/go/" + repoName
return rtUrl.String(), nil

return goProxyParams.BuildUrl(rtUrl, repoName), nil
}
56 changes: 52 additions & 4 deletions utils/golang/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-client-go/artifactory/auth"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"net/url"
"testing"
)

Expand All @@ -13,7 +15,7 @@ func TestGetArtifactoryRemoteRepoUrl(t *testing.T) {
AccessToken: "eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA",
}
repoName := "test-repo"
repoUrl, err := GetArtifactoryRemoteRepoUrl(server, repoName)
repoUrl, err := GetArtifactoryRemoteRepoUrl(server, repoName, GoProxyUrlParams{})
assert.NoError(t, err)
assert.Equal(t, "https://test:eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA@server.com/artifactory/api/go/test-repo", repoUrl)
}
Expand All @@ -25,15 +27,22 @@ func TestGetArtifactoryApiUrl(t *testing.T) {
// Test username and password
details.SetUser("frog")
details.SetPassword("passfrog")
url, err := getArtifactoryApiUrl("test-repo", details)
url, err := getArtifactoryApiUrl("test-repo", details, GoProxyUrlParams{})
assert.NoError(t, err)
assert.Equal(t, "https://frog:passfrog@test.com/artifactory/api/go/test-repo", url)

// Test username and password with EndpointPrefix and direct
details.SetUser("frog")
details.SetPassword("passfrog")
url, err = getArtifactoryApiUrl("test-repo", details, GoProxyUrlParams{EndpointPrefix: "test", Direct: true})
assert.NoError(t, err)
assert.Equal(t, "https://frog:passfrog@test.com/artifactory/test/api/go/test-repo|direct", url)

// Test access token
// Set fake access token with username "test"
details.SetUser("")
details.SetAccessToken("eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA")
url, err = getArtifactoryApiUrl("test-repo", details)
url, err = getArtifactoryApiUrl("test-repo", details, GoProxyUrlParams{})
assert.NoError(t, err)
assert.Equal(t, "https://test:eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA@test.com/artifactory/api/go/test-repo", url)

Expand All @@ -42,7 +51,46 @@ func TestGetArtifactoryApiUrl(t *testing.T) {
// Expect username to be "frog"
details.SetUser("frog")
details.SetAccessToken("eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA")
url, err = getArtifactoryApiUrl("test-repo", details)
url, err = getArtifactoryApiUrl("test-repo", details, GoProxyUrlParams{})
assert.NoError(t, err)
assert.Equal(t, "https://frog:eyJ0eXAiOiJKV1QifQ.eyJzdWIiOiJmYWtlXC91c2Vyc1wvdGVzdCJ9.MTIzNDU2Nzg5MA@test.com/artifactory/api/go/test-repo", url)
}

func TestGoProxyUrlParams_BuildUrl(t *testing.T) {
tests := []struct {
name string
RepoName string
Direct bool
EndpointPrefix string
ExpectedUrl string
}{
{
name: "Url Without direct or Prefix",
RepoName: "go",
ExpectedUrl: "https://test/api/go/go",
},
{
name: "Url With direct",
RepoName: "go",
Direct: true,
ExpectedUrl: "https://test/api/go/go|direct",
},
{
name: "Url With Prefix",
RepoName: "go",
EndpointPrefix: "prefix",
ExpectedUrl: "https://test/prefix/api/go/go",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
remoteUrl, err := url.Parse("https://test")
require.NoError(t, err)
gdu := &GoProxyUrlParams{
Direct: tt.Direct,
EndpointPrefix: tt.EndpointPrefix,
}
assert.Equalf(t, tt.ExpectedUrl, gdu.BuildUrl(remoteUrl, tt.RepoName), "BuildUrl(%v, %v)", remoteUrl, tt.RepoName)
})
}
}

0 comments on commit f80a1af

Please sign in to comment.