Search code examples
goartifactory

How to use gocenter remote Artifactory repo for local dependency resolution?


I am new to go and trying to use a gocenter remote repo (Artifactory 6.8) for dependency resolution. Despite setting GOPROXY env var my gocenter-cache repo remains empty.

Here's my go code.

package main

import (
        "fmt"
        "github.com/naoina/go-stringutil"
)

func main() {
        var str string = "hello_world_go"
        fmt.Println(stringutil.ToUpperCamelCase(str)) //prints HelloWorldGo
}

The dependency I am trying to resolve is here: https://search.gocenter.io/github.com~2Fnaoina~2Fgo-stringutil/versions

Here's my GOPROXY env var:

$ echo $GOPROXY
https://<<my Artifactory URL>>/api/go/gocenter

Here's a truncated version of the gocenter repo definition. I used the jfrog docs for setting this up:

{
  "key" : "gocenter",
  "packageType" : "go",
  "url" : "https://gocenter.io/",
  "rclass" : "remote"
}

When I run "go get" the dependency resolves...

$ go get -v github.com/naoina/go-stringutil
github.com/naoina/go-stringutil (download)

but gocenter-cache is empty, telling me it wasn't used.

{
  "repo" : "gocenter-cache",
  "path" : "/",
  "created" : "2019-04-17T16:35:37.586Z",
  "lastModified" : "2019-04-17T16:35:37.586Z",
  "lastUpdated" : "2019-04-17T16:35:37.586Z",
  "children" : [ ],
  "uri" : "https://<<REDACTED>>/api/storage/gocenter-cache"
}

Perhaps my "go get" should have a different target? I am just using what exists in gocenter: https://search.gocenter.io/github.com~2Fnaoina~2Fgo-stringutil/versions

Any help in pointing out what I am doing wrong would be greatly appreciated. I haven't gone into modules yet or anything like that, as I am an artifactory admin and not a go developer. I am just trying to prototype this functionality so we can help advise our users with what to do.

--UPDATE: I found https://golang.org/cmd/go/#hdr-Module_proxy_protocol and then tried this:

$ echo $GOPROXY; go get $GOPROXY/github.com/naoina/go-stringutil
https://<<REDACTED>>/api/go/gocenter
package https:/<<REDACTED>>/api/go/gocenter/github.com/naoina/go-stringutil: https:/<<REDACTED>>/api/go/gocenter/github.com/naoina/go-stringutil: invalid import path: malformed import path "https:/<<REDACTED>>/api/go/gocenter/github.com/naoina/go-stringutil": invalid char ':'

So the colon between my protocol and my url is an invalid character? Also why is it removing one of my forward slashes?

--UPDATE2: I got "go mod init" to work, kind of:

$ go mod init
go: creating new go.mod: module example/hello
$ ls
go.mod  hello.go
$ go build
build example/hello: cannot load github.com/naoina/go-stringutil: cannot find module providing package github.com/naoina/go-stringutil
$ cat go.mod
module example/hello

go 1.12
$ echo $GOPROXY
https://<<REDACTED>>/api/go/gocenter

--UPDATE 3:

$ cat go.mod
module example/hello

go 1.12

require github.com/naoina/go-stringutil v0.1.0

$ go build
hello.go:6:2: cannot find package "github.com/naoina/go-stringutil" in any of:
        C:\Go\src\github.com\naoina\go-stringutil (from $GOROOT)
        C:\Users\samuelm\go\src\github.com\naoina\go-stringutil (from $GOPATH)

$ echo $GOPROXY
https://<<REDACTED>>/api/go/gocenter

--UPDATE 4: it appears I'm still not using modules?

$ go list -m all
go list -m: not using modules

--UPDATE 5, re: retgits Your steps helped, but I'm still not all the way there.

$ find .
.
./bin
./src
./src/example.com
./src/example.com/hello
./src/example.com/hello/hello.go

$ cd src/

$ go mod init example.com/hello
go: creating new go.mod: module example.com/hello

$ cat go.mod
module example.com/hello

go 1.12

$ go get -v github.com/naoina/go-stringutil
Fetching https://<<REDACTED>>/api/go/gocenter/github.com/naoina/go-stringutil/@v/list
Fetching https://<<REDACTED>>/api/go/gocenter/github.com/naoina/@v/list
Fetching https://<<REDACTED>>/api/go/gocenter/github.com/@v/list
go get github.com/naoina/go-stringutil: unexpected status (https://<<REDACTED>>/api/go/gocenter/github.com/naoina/go-stringutil/@v/list): 404 Not Found

$ go build example.com/hello
can't load package: package example.com/hello: unknown import path "example.com/hello": cannot find module providing package example.com/hello

$ cd example.com/hello/

$ go build
build example.com/hello/example.com/hello: cannot load github.com/naoina/go-stringutil: cannot find module providing package github.com/naoina/go-stringutil

I am not providing credentials in my GOPROXY, because our end-users do not have accounts, we're inside a firewalled env and allow full anon read access. If we have to provide user accts then we cannot support Go.

--FINAL UPDATE: Removing my local proxy resolved the 404 issue, retgits solution works.


Solution

  • You mentioned you're not a Go developer so let me walk you through all the steps. I realize it might be a little overkill to some of the devs here, but it might help you.

    Depending on where you've put your source code you will need to set the environment variable GO111MODULE. Since go 1.11 it's recommended to not put your source code in your $GOPATH anymore. If you put your code there and want to use Go modules you'll have to set the GO111MODULE to true (personally I keep all my Go code outside of the $GOPATH). On Windows you'll have to create the environment variable first and set it accordingly (and restart your terminal).

    To create a Go module you'll have to run the command go mod init <name of your module>. In my case, I've ran the command go mod init github.com/retgits/bla which created a go.mod file with

    module github.com/retgits/bla
    
    go 1.12
    

    Adding modules will now be as simple as running go get. If you want to use GoCenter or Artifactory to help resolve your modules.

    To help resolve modules there are two options you might want to look at:

    • Using a utility called goc
    • Setting up a remote and virtual proxy

    Using goc

    The goc utility automatically sets GOPROXY to GoCenter, bypassing other proxies like Artifactory. The current behavior of the Go client is to look at one single proxy and fail your build if not all modules are resolved from there. goc will look at GoCenter first and if the module isn't in GoCenter it will get the module from its original place (like GitHub)

    Using Artifactory

    If you want to use Artifactory to resolve, and cache, your Go modules you'll have to create a remote repository with the settings for GoCenter (which are in the documentation as you mentioned). You'll have to include that remote repository into a virtual one for it to work.

    Setting GoCenter as GOPROXY

    A third option would be to only use GoCenter (the public registry created by JFrog), but that might defeat your original question:

    export GOPROXY="https://gocenter.io"
    go get -v github.com/naoina/go-stringutil
    

    No matter which of the options you choose it will update the go.mod to

    module github.com/retgits/bla
    
    go 1.12
    
    require github.com/naoina/go-stringutil v0.1.0 // indirect
    

    The indirect is because I've not yet created a .go file with the code that uses this import.

    If I now create a main.go sample with

    package main
    
    import (
        "fmt"
    
        "github.com/naoina/go-stringutil"
    )
    
    func main() {
        str := stringutil.ToSnakeCase("HelloWorld")
        fmt.Println(str)
    }
    // Running go run main.go would result in
    // hello_world
    

    it will remove the indirect from the go.mod file because I now have code that relies on my module.