People can't use my v2+ semantic versioning release using gomodules - go

I am maintaining a company go library which uses Semantic Versioning for releases. I switched to go modules for dependency management within the library and created a new release after v2+. I used the first strategy documented here which involves modifying the go.mod file and import paths.
Now when people use the go get command (in a repo that is also using go modules) an error appears:
invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v3
Is anyone familiar with this issue?
To make things simpler I created a similar and simple example:
I have repo (github.com/Graphmasters/testing-gomod-versioning) with three files (not including .gitignore). These files are:
methods/method.go
package methods
func Method() {
println("Method")
}
main.go
package main
import (
"github.com/Graphmasters/testing-gomod-versioning/v3/methods"
)
func main() {
methods.Method()
}
go.mod
module github.com/Graphmasters/testing-gomod-versioning/v3
go 1.13
In the repo I created a release with the tag v3.0.0 based on the branch with this code.
The aforementioned error is encountered when the following command is run in a repo that is using go modules:
go get "github.com/Graphmasters/testing-gomod-versioning#v3.0.0"

The module name must be github.com/Graphmasters/testing-gomod-versioning/v3 or github.com/Graphmasters/testing-gomod-versioning.v3 and not github.com/Graphmasters/testing-gomod-versioning
Users should be able to do github.com/Graphmasters/testing-gomod-versioning/v3#v3.0.0 instead of github.com/Graphmasters/testing-gomod-versioning#v3.0.0
Example: You can check the mod file of the following v3 package - https://search.gocenter.io/gotest.tools~2Fv3/info?version=v3.0.0

Related

How do I stop the auto importing of imported item in go outside of my project?

I have my projects that have many packages which import each other and import outside packages. When I make a change to one of my low lever packages, and then push it to git it is fine and works in that section. When I go get it for use in another project that was working perfectly I now get this go get this error:
module declares its path as: github.com/xdg-go/scram
but was required as: github.com/xdg/scram
None of my code uses either of those directly. It looks like it automatically updated some lower external packages and broke things the used to then old import.
How do I either find out the package that is importing the wrong name or stop all auto-updates?
The go.mod file at github.com/xdg/scram declares itself as github.com/xdg-go/scram:
module github.com/xdg-go/scram
go 1.11
require (
github.com/xdg-go/stringprep v1.0.2
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
)
The go.mod file should be updated to reflect the correct import path.
Unfortunately if this module is for you an indirect dependency, the best fix possible is to update whatever project you import that is directly importing it.
When that is not an option, a solution to this error is to clone the problematic repository locally and use the replace directive in your go.mod file:
module mymodule
replace github.com/xdg/stringprep => ../strprep
go 1.16.2
require (
github.com/divjotarora/mgo v0.0.0-20190308170442-1d451d2a3149
)
where ../strprep is where the code of the required module exists in your local machine, relative to the go.mod file of your project.
The downside of this of course is that you have to replicate this palliative fix wherever you plan to go get your modules.
Note also:
divjotarora/mgo is just a random example of a project that imports one of those packages using their old import path.
I'm using xdg/stringprep as an example because I can't find modules that import xdg/scram instead, but apparently it suffers from the same issue
Beside, you can use:
go mod why <package> to find out why a certain package is listed as a dependency of your project
go mod graph to show the full dependency graph. The output is in <package> <requirement> format

Golang Module Use

I am trying to link to some code online: https://github.com/TheCacophonyProject/audiobait
I am helping out with this project and have altered that repository to create a new package called audiofilelibrary.
I am then trying to use that code in a very simple program:
package main
import (
"fmt"
"github.com/TheCacophonyProject/audiobait/audiofilelibrary"
"github.com/TheCacophonyProject/audiobait/playlist"
)
func main() {
audio := audioFileLibrary.AudioFileLibrary{}
fmt.Println(audio.soundsDirectory)
sched := playlist.Schedule{}
fmt.Println(sched.Description)
}
You'll see I'm importing 2 packages from that repository, audiofilelibrary and playlist. playlist works, audiofilelibrary does not. They seem to be coded in the same way.
This is the error I get:
$ go build
go: finding github.com/TheCacophonyProject/audiobait v2.0.0
go: finding github.com/nathan-osman/go-sunrise latest
go: finding github.com/TheCacophonyProject/audiobait/audiofilelibrary latest
build audiobaitpackagetest: cannot load
github.com/TheCacophonyProject/audiobait/audiofilelibrary:
cannot find module providing package
github.com/TheCacophonyProject/audiobait/audiofilelibrary
And this is my go.mod file, which is in a directory called audiobaitpackagetest:
module audiobaitpackagetest
go 1.13
require github.com/TheCacophonyProject/audiobait v0.0.0-20191013210352-81b0afd9a085
I created the module with the command go mod init audiobaitpackagetest.
How can I see the audiofilelibrary package please? As in, how can I import it into other code?
The code for this question is all here, so it can be easily cloned and run: https://github.com/Davo36/audiobaitpackagetest
Any help much appreciated.
You are using version v2.0.0 of github.com/TheCacophonyProject/audiobait.
This version doesn't contain audiofilelibrary package. But the master branch contains it.
You can change your go.mod file like this to use the master branch.
module audiobaitpackagetest
go 1.13
require github.com/TheCacophonyProject/audiobait master
Then run this commands:
go mod tidy
go mod vendor # if you want to vendor it

How to setup protobuf, grpc and Go modules in a monorepo?

I'm trying to create a microservice-based API in Go, very basic, just to learn some stuff. I have three main goals I have to achieve.
Monorepo.
Be able to use different back-end languages as need arises (ie. one microservice in Go, two in Node.js, one in Python).
Use gRPC.
Currently my structure looks like this (and is stored in ~/Projects/tkg, outside of GOPATH).
Each "service" should be a self-contained application written in a "whatever". As you can see I have a Go service and a React front-end application. Additionally there is a Makefile there that I want to use for building stuff, but I might move to shell scripts, Docker, whatever. Doesn't matter.
So now the question. How can I make generated proto files play well with this setup? I think I don't understand something about Go modules and packages because I cannot set it so articles.go (from cmd) can access the generated api/article.pb.go. How to do it?
// services/articles/go.mod
module tkg/services/articles
go 1.12
require (
github.com/golang/protobuf v1.3.2
google.golang.org/grpc v1.22.1
)
// services/articles/cmd/article.go
package main
import (
pb "tkg/services/articles/api/article"
)
type repository interface {
Create(*pb.Article) (*pb.Article, error)
}
func main() {
}
// services/articles/api/article.proto
syntax = "proto3";
package article;
option go_package = "tkg/services/articles/api/article";
...
// Makefile
build:
protoc services/articles/api/article.proto --go_out=.
I have tried various different package names in go.mod, different go_packages in the proto file, I had tried different protoc commands and paths. I bet this is silly and it's very obvious to someone who is well-versed in Go, but for someone from Node.js backgroud like me the inability to do import "../api/article.pb.go" is infuriating. :(
The error I am getting is: could not import tkg/services/articles/api/article (no parsed files for package tkg/services/articles/api/article). Of course with different values for package names. I've been trying to solve it for two days now.
How would you approach this problem?
If you are generating the .pb.go file in the same directory as the .proto file (recommended), then your import path should read:
import (
pb "tkg/services/articles/api"
)
(not tkg/services/articles/api/article.)
Go packages are collections of .go files in a single directory - each with the same package XYZ first line - where XYZ is the package name. So when importing a package, one uses the package base directory - not including any .go filenames.
Edit: (this was too long to fit into a comment):
I would step back and think about the base-directory of your entire project.
Standard go packages are usually single words like time, sync etc. because they are part of go's standard library. All other packages should have a full internet path. These typically match a git repo address (e.g. "github.com/boltdb/bolt") - but not always e.g. ("gopkg.in/yaml.v2"). This is actually superior to the centrally-hosted NPM package model - as it easily allows for pulling packages from any repo host. Also since repos are cloned to local disk - those same paths can exist on your local disk first (before they've been hosted on the internet, say for development purposes).
So I would suggest naming your local base-directory something like:
github.com/myname/myproj/tkg/services/...
and then ensure you import packages based on this directory structure e.g.
import "github.com/myname/myproj/tkg/services/api"
If a go build does not pick up the generated (.pb.go) code, then there is something up with your GOPATH or if using the new go-modules your go.mod setup.

How to find dependency causing "Sirupsen/logrus" vs. "sirupsen/logrus" unexpected module path error?

I am trying to convert https://github.com/appscode/voyager from glide to go mod.
I am getting an error like below:
go: github.com/Sirupsen/logrus#v1.4.1: parsing go.mod: unexpected module path "github.com/sirupsen/logrus"
go: error loading module requirements
How do I find out the source of this old Sirupsen module?
How do I find out the source of this old Sirupsen module?
Use the Go 1.13 beta (go get golang.org/dl/go1.13beta1 && go1.13beta1 download) or even better, try the latest Go on tip / master (go get golang.org/dl/gotip && gotip download).
Go 1.13 has improved error messages in general. It should help in your case, including most likely showing the import chain leading up to the error.
For example:
$ gotip build .
go: example.com/temp/mod imports
github.com/docker/libcompose/docker imports
github.com/Sirupsen/logrus: github.com/Sirupsen/logrus#v1.4.2: parsing go.mod:
module declares its path as: github.com/Sirupsen/logrus
but was required as: github.com/sirupsen/logrus
In that example, you can see that docker/libcompose/docker is importing the old and now incorrect uppercase version of Sirupsen/logrus.
The most common reason people see a Sirupsen/logrus vs. sirupsen/logrus case mismatch is when importing github.com/docker/docker or one of the other docker repos. Importing docker repos is a bit confusing with modules, including because:
The docker/docker repo does not follow semver.
There is a very old v1.13.1 semver tag on the docker/docker repo.
Even though it is a couple years old, it is still the "latest" semver tag on that repo, and hence that old version is picked by default by the go command if you don't ask for a more specific version.
That old docker/docker version imports the old and not incorrect uppercase Sirupsen/logrus, which can then trigger the error reported in the question above.
The docker client package has had breaking changes after v1.13.1.
There is generally confusion about docker/docker vs. docker/engine repositories, and about what import paths to use.
The docker repos do not have go.mod files.
For the docker/docker repo, the import path remains github.com/docker/docker, but it needs to come from github.com/docker/engine, so the recommended approach is often for a docker importer to do import "github.com/docker/docker" and edit their go.mod to something like this:
require (
github.com/docker/docker v1.13.1
)
replace github.com/docker/docker => github.com/docker/engine <tag-or-commit-hash>
Docker issue #39302 tracks trying to document how to import docker repos when using modules.

golang modules and local packages

I'm trying to understand how to organize my golang project using go1.11 modules. I tried several options, but none of them worked.
I have some code in the main package under the application folder and a local package that the main package uses.
$GOPATH
+ src
+ application/
+ main/
+ main.go
+ otherFileUnderMainPackage.go
+ aLocalPackage/
+ someCode.go
+ someCode_test.go
+ someMoreCode.go
+ someMoreCode_test.go
Files in the main package, imports ../aLocalPackage. When I compile by go build main/*.go it's working.
Then, I ran go mod init application: V.0.9.9 and got the go.mod file, but the build always fails. I always get error about not finding the local package: build application:V0.9.9/main: cannot find module for path _/.../src/application/aLocalPackage. I also tried to place the local package right under src/, place it under main/ etc. but none of these methods worked for me.
What is the way to use modules and local packages?
Thanks.
Relative import paths are not supported in module mode. You will need to update your import statements to use a full (absolute) import path.
You should also choose a module name other than application. Your module path should generally begin with a URL prefix that you control — either your own domain name, or a unique path such as github.com/$USER/$REPO.
I had some problems working with local packages myself.
There are two tricks to make it work:
you run "go build" in the package directory
This compiles the package and places it in the build cache.
This link about code organisation in go explains more.
You can identify where the cache is using:
>go env GOCACHE
/home/<user>/.cache/go-build
Import using a path relative to the project
I puzzled loads over what the correct import path was and finally discovered that go doc or go list will tell you.
>go doc
package docs // import "tools/src/hello/docs"
>go list
tools/src/hello/docs
For example. I have a hello world API project and was using swaggo to generate documentation which it does in a docs sub-directory.
To use it I add an import:
_ "tools/src/hello/docs"
For my case the _ is important as docs is not used directly but we its init() function to be invoked.
Now in hello/main.go I can add "tools/src/hello/docs" and it will import the correct package.
The path is relative to the location of go.mod if you have one.
I have tools/ here as I have a go.mod declaring "modules tools".
Modules are a different kettle of fish - see https://github.com/golang/go/wiki/Modules.
Recent versions of go (1.11 and later) can create a go.mod file which you may use to fix the version of a module that is used and avoid go's crazy default behaviour of just downloading the latest version of any package you import.
I have written a blogpost on how to start your first Go project using modules.
https://marcofranssen.nl/start-on-your-first-golang-project/
In general it boils down to just create a new folder somewhere on your system (doesn't have to be in GOPATH).
mkdir my-project
cd my-project
go mod init github.com/you-user/my-project
This will create the go.mod file. Now you can simply create your project layout and start building whatever you like.
Maybe one of my other blogs can inspire you a bit more on how to do things.
https://marcofranssen.nl/categories/software-development/golang/

Resources