How to set Go vanity import URL to repository subdirectory in a monorepo?

Issue

I’m working with a monorepo that is organized by language at the top level, so all Go modules are located in the go directory in the repository root. I want to set up a vanity import URL that points to the go directory rather than the repository root so that the go/ does not need to be included in the import path.

Current file structure:

/
  go/
    module1/
    module2/

Desired import format:

import (
    "go.example.com/module1"
    "go.example.com/module2"
)

currently possible but not desired:

import (
    "go.example.com/go/module1"
    "go.example.com/go/module2"
)

According to the docs the format for the <meta> element at go.example.com should be of the form:

<meta name="go-import" content="import-prefix vcs repo-root">

So in this case I would have:

<meta name="go-import" content="go.example.com git github.com/example/repo">

This translates the path following the import-prefix to a path relative to the root directory of the repository, so that go.example.com/this/path looks for the this/path directory in the repo. I would like instead for the path to be relative to the go directory in the repo instead of the repo root.

Is there any way to inform go get that the paths following go.example.com should be relative to github.com/example/repo/go rather than just github.com/example/repo?

Solution

Not directly, but there are workarounds.

From this issue in golang/go:

[…] there is currently no way for the HTTPS server to indicate that the module is offset by the prefix src/go, since that is not a part of the Go package path. This layout is just not going to work with the go command’s built-in git support.

With the go command’s built-in git support, import specs start with the URL of the repository and are followed by a path to the desired package. Therefore paths must be relative to the repository root. With a vanity import path you can make the path longer if desired, but not shorter (e.g. example.com/pkg).

So the following is the shortest possible import path without a workaround: go.example.com/go/<module>.


Workarounds

For the truly dedicated.

These involve a bit of setup and extra handling and might not be worth it just for the aesthetics of the import path.

There are two approaches I’ve worked out (and one semi-solution that probably won’t work with a large number of modules). The first is setting up a module proxy. The second is creating another repo that copies from the go directory and importing from there.

Use replace in go.mod

This one is pretty simple, you can make the base import path anything you like and just replace it in the go.mod file.

Downside is this gets complicated to manage with many interdependent modules (as discussed in the linked article in the next section). Also feels less special and the burden is on the importing project to set up rather than the imported project.

Go Module Proxy

This article(gist) does a nice job explaining the approach.

go get uses the GOPROXY environment variable to decide where to look to find and resolve packages. The basic idea is to set up a proxy server that knows how to translate the public module name and get the relevant code from the actual repo, then put the URL of that server in the GOPROXY variable.

Extra care is needed with this approach for private modules/repositories as you’ll have to handle authentication as well.

Copy Git Repository

The final approach is to copy the contents of the go directory to another repo, which can be automated with GitHub Actions or similar.

To preserve version tags (if used) and branches (although not commit hashes), you can use git filter-repo to rewrite history so that the go directory is actually the package root (and always has been): git filter-repo --subdirectory-filter go/.

Then just set the vanity go-import tag to:

<meta name="go-import" content="go.example.com git github.com/example/repo-go">

(where the original repo was github.com/example/repo).

Answered By – Henry Woody

Answer Checked By – Mildred Charles (GoLangFix Admin)

Leave a Reply

Your email address will not be published.