Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/go: unknown revision when using semver tag for module in subdirectory #31045

Closed
burnson opened this issue Mar 26, 2019 · 3 comments

Comments

Projects
None yet
2 participants
@burnson
Copy link

commented Mar 26, 2019

What version of Go are you using (go version)?

$ go version
go version go1.11.5 darwin/amd64

Does this issue reproduce with the latest release?

Yes. It also reproduces with go1.12beta2.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/username/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/username/go"
GOPROXY=""
GORACE=""
GOROOT="/Users/username/Homebrew/Cellar/go/1.11.5/libexec"
GOTMPDIR=""
GOTOOLDIR="/Users/username/Homebrew/Cellar/go/1.11.5/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/v2/2k1mwftj6dv08m7kq2q9lbh40000gn/T/go-build582638908=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

In a local go module, I tried to require a specific tagged version of a go module available from a subdirectory in a remote repo. go build returns an error giving unknown revision. When I remove the require and let it figure out the dependency automatically, it adds the module to the go.mod using a pseudo-version despite being able to use a tagged version when requiring a separate module that resides at the same remote repo's root. Here is a complete repro using github.com/burnson/gomoduletest as the remote repo. Step 1 creates the remote repo from scratch and Step 2 reproduces the pseudo-version behavior and build error when an explicit tag is used instead.

##
## STEP 1: create a remote repo with a module at the
##         repo root and a module in a subdirectory
##         (skip this if you want to repro with the
##         the GitHub repo provided at $TEST_REPO)
##

# A repo you have write access to
TEST_REPO=burnson/gomoduletest

# Do this in a scratch directory
cd $(mktemp -d)
echo "Creating repo from here:"
pwd

# Make a git repo
mkdir gomoduletest
cd gomoduletest
git init

# Add a module at the repo root
cat >go.mod <<EOF
module github.com/$TEST_REPO
EOF

# Create a simple package that returns the package name
cat >gomoduletest.go <<EOF
package gomoduletest

func Package() string {
	return "gomoduletest"
}
EOF

# Check the gomoduletest build
go build

# Now add a new module to a subdirectory
mkdir subpackage
cd subpackage
cat >go.mod <<EOF
module github.com/$TEST_REPO/subpackage
EOF

# Create a simple package that returns the package name
cat >subpackage.go <<EOF
package subpackage

func Package() string {
	return "subpackage"
}
EOF

# Check the subpackage build
go build

# What does everything look like so far?
cd ..
find *

# Commit what we have and tag as v1.0.0.
git add .
git commit -m 'v1.0.0 release'
git tag v1.0.0

# Push this repo to github
git remote add origin git@github.com:$TEST_REPO.git
git push -fu origin master
git push -f --tags

##
## STEP 2: create a local go module that makes use of
##         both of the modules created in the remote
##         repo above
##

# The repo created above
TEST_REPO=burnson/gomoduletest

# Do this in a new scratch directory
cd $(mktemp -d)
echo "Creating local go module from here:"
pwd
mkdir localmodule
cd localmodule

# Create a go module file for the test program
cat >go.mod <<EOF
module my/program
EOF

# Create a test program that uses both modules
# and calls the Package() func
cat >main.go <<EOF
package main

import (
	"fmt"

	rootpackage "github.com/$TEST_REPO"
	"github.com/$TEST_REPO/subpackage"
)

func main() {
	fmt.Println(rootpackage.Package())
	fmt.Println(subpackage.Package())
}
EOF

# Build the program
go build

echo
echo "Test program source:"
cat main.go

# Run the program
echo
echo "Test program output:"
./program

# Check the contents of the go.mod file now:
echo
echo "Test program go.mod:"
cat go.mod

# Replace the pseudo-version with the v1.0.0 tag:
cat >go.mod <<EOF
module my/program

require (
	github.com/$TEST_REPO v1.0.0
	github.com/$TEST_REPO/subpackage v1.0.0
)
EOF

echo
echo "Edited go.mod forcing v1.0.0 for subpackage:"
cat go.mod

# Try building
echo
echo "Building with tagged version:"
go build

What did you expect to see?

In the local module test, I expected to see go build tag subpackage with the v1.0.0 semver tag I pushed to the remote repo in go.mod. Furthermore, when I edit go.mod to explicitly use v1.0.0, I expect it to find the revision when I go build.

What did you see instead?

go build finds the subpackage module but writes it using a pseudo-version in go.mod. If I override that with the tagged version v1.0.0, I get an unknown revision error. However, the revision is detected for the module that resides at the remote repo root, which is a contradiction.

...
Test program source:
package main

import (
	"fmt"

	rootpackage "github.com/burnson/gomoduletest"
	"github.com/burnson/gomoduletest/subpackage"
)

func main() {
	fmt.Println(rootpackage.Package())
	fmt.Println(subpackage.Package())
}

Test program output:
gomoduletest
subpackage

Test program go.mod:
module my/program

require (
	github.com/burnson/gomoduletest v1.0.0
	github.com/burnson/gomoduletest/subpackage v0.0.0-20190326022552-ee56fd37aed9
)

Edited go.mod forcing v1.0.0 for subpackage:
module my/program

require (
	github.com/burnson/gomoduletest v1.0.0
	github.com/burnson/gomoduletest/subpackage v1.0.0
)

Building with tagged version:
go: finding github.com/burnson/gomoduletest/subpackage v1.0.0
go: github.com/burnson/gomoduletest/subpackage@v1.0.0: unknown revision subpackage/v1.0.0
go: error loading module requirements
@jayconrod

This comment has been minimized.

Copy link
Contributor

commented Mar 26, 2019

It looks like the tag prefix is missing for the nested module. Each module in a repository has a separate namespace of versions, distinguished by a subdirectory prefix. So for the module, github.com/burnson/gomoduletest/subpackage in the repository github.com/burnson/gomoduletest, the prefix should be subpackage/, and the full tag should be subpackage/v1.0.0. The tag v1.0.0 without a prefix is a version for the module at the root of the repository.

This behavior is described on the Modules wiki, which is probably the best source of information on this subject. I don't believe go help modules actually describes this, so I'll mark this as a documentation bug.

@jayconrod jayconrod added this to the Go1.13 milestone Mar 26, 2019

@jayconrod jayconrod self-assigned this Mar 26, 2019

@jayconrod

This comment has been minimized.

Copy link
Contributor

commented Mar 26, 2019

On second thought, go help modules may not be the best place for this. It says very little about repositories and publishing releases.

I've added a section to the wiki, Publishing a Release that gives more specific instructions.

@jayconrod jayconrod closed this Mar 26, 2019

@burnson

This comment has been minimized.

Copy link
Author

commented Mar 27, 2019

Ah, this is what I overlooked from my initial readthrough of the Modules wiki:

Version tags for modules below the root of the repository must include the relative directory as a prefix.

Thanks for the additional clarification on the wiki.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.