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: go.mod versioning is inconsistent #30146

Closed
nim-nim opened this issue Feb 9, 2019 · 9 comments
Closed

cmd/go: go.mod versioning is inconsistent #30146

nim-nim opened this issue Feb 9, 2019 · 9 comments

Comments

@nim-nim
Copy link

nim-nim commented Feb 9, 2019

v prefixing is just a stupid git tag convention, that is not used by everyone, since nothing git side actually parses or enforces this convention. And many software projects do not use it. And someday someone will add actual support for versions in git since pretty much everyone need it and pretty much everyone need to distinguish those from free-form tags, and lax conventions are not a good way to build robust tooling.

But, the original go.mod proposal decided to enshrine this idiotic needless prefix in its syntax, including in the json outputted by go mod edit -fmt -json, even though this structure (unlike git) actually includes specific version objects, and (unlike git) does not need any v hack to mark that a version field is actually a version field (and that requires custom parsing on top of the json parsing just to pull out the actual semver version human use)

But, go modules can not even use this convention consistently, we have now a Go object, that contains a something which is obviously a version, using a completely different syntax.

Please make up your mind and use regular syntax that does not require multiple levels of parser quirks

@mvdan
Copy link
Member

mvdan commented Feb 9, 2019

If you're going to make a proposal to change how modules work, I'd suggest refraining from using words like "stupid" and "idiotic", and sentences like "please make up your mind".

And someday someone will add actual support for versions in git since pretty much everyone need it and pretty much everyone need to distinguish those from free-form tags

Can you back this up with any particular proposal or upstream plan to change git? Also note that Go supports many other source control managers, such as Mercurial and Subversion. So the specific features of Git aren't that important.

I'm also not sure I understand what the problem is with a v prefix. Sure, the prefix is not part of semver, but it clarifies that a string is a version and it's trivial to skip.

In particular, for large breaking changes like this one, you should open a proposal issue, detailing why the benefits of the proposed change greatly outweigh the downsides such as breaking backwards compatibility.

@nim-nim
Copy link
Author

nim-nim commented Feb 9, 2019

Can you back this up with any particular proposal or upstream plan to change git? Also note that Go supports many other source control managers, such as Mercurial and Subversion. So the specific features of Git aren't that important.

That's somewhat inconsistent with using a v prefix to mark versions, as v only exists as an example in a git man page (not even as something in the git code) and this git man page example, that a lot of projects do not apply, has spread all over the go module syntax.

I'm also not sure I understand what the problem is with a v prefix. Sure, the prefix is not part of semver, but it clarifies that a string is a version and it's trivial to ski

go mod edit -fmt -json already outputs a field named Version. The field content does not need to clarify it is a version. But anyway if go mod edit -fmt -json insists in putting versions in a Version field and then tagging a second time the version with a v inside the field, please make it use the same syntax for the Go version element (Version field and needless v decorator if you like it)

@thepudds
Copy link
Contributor

thepudds commented Feb 9, 2019

Hi @nim-nim, I think you are making multiple points here, and I just wanted to add a comment in response to only some portions of what you have said.

When it comes to the v versus no v in VCS tags representing semver versions, I have certainly seen reasonable people have different opinions on what is "best", what is "encouraged", and even what is "permitted" under semver.

That said, I will share my personal understanding, which is in semver there is a distinction drawn between:

  1. a "semantic version" (where a leading "v" is not part of a "semantic version"), vs.
  2. the mechanism for encoding a "semantic version" into a VCS tag (where a leading "v" is allowed)

In other words, under that interpretation, a leading "v" in a VCS tags is a common and allowed way to encode a semantic version into a VCS tag (although not a universal choice, and not required).

One hint is the master branch for github.com/semver/semver contains this statement as part of an FAQ that was added a few years ago:

prefixing a semantic version with a "v" is a common way (in English) to indicate it is a version number. Abbreviating "version" as "v" is often seen with version control. Example: git tag v1.2.3 -m "Release version 1.2.3", in which case "v1.2.3" is a tag name and the semantic version is "1.2.3".

That certainly suggests to me that a leading v for a semver VCS tag is not only allowed, but also common, and not tied specifically to git.

However, that FAQ is only on the semver master as far as I am aware, and I have also seen reasonable people come to different conclusions even after reading that particular FAQ.

Setting aside for the moment what the best encoding might be, it seems reasonable to me that the go tool has made a choice about a canonical encoding of semantic versions into VCS tags in terms of how they are recorded in a go.mod file. For the go tool, that choice is a leading v for VCS tags representing semver versions.

However, note that tags like 1.2.3 (without a v) can still be used, although they will not be treated as semantic versions by the go tool. Instead, go get foo@1.2.3 (note no v) and go get foo@sometag are treated as "module queries", and are often recorded as "pseudo-versions". To give a quick concrete example, if you do the following from within a module (note no v in 0.0.3):

  $ go get github.com/jondot/groundcontrol@0.0.3

The result is recorded in the go.mod file as the following pseudo-version, which includes the date and commit hash:

  github.com/jondot/groundcontrol v0.0.0-20130702202810-bf0b23022af7 

That behavior is covered in more detail in the "Module Queries" section of the go command documentation.

That said, a module should still be tagged in VCS with a leading "v" when released in order for the 'go' tool to be able to properly interpret the tag as a semantic version.

Regarding how that version information should be represented in the JSON returned by go mod edit -json, I guess I can see both sides of the argument, but it also seems to me to be a reasonable choice to have the VCS-encoded representation be the string representation returned in the JSON, including because that is how it is recorded in the go.mod file, and in general go mod edit -json does not "interpret" the information in a go.mod file as much as something like go list -m all. As the edit in go mod edit -json might suggest, it is more about editing a go.mod file and less about interpreting a go.mod file. This is also suggested by the go mod edit documentation, such as:

go mod edit provides a command-line interface for editing go.mod, for use primarily by tools or scripts. It reads only go.mod; it does not look up information about the modules involved.

and a bit later (under the require discussion):

These flags are mainly for tools that understand the module graph. Users should prefer 'go get path@version' or 'go get path@none', which make other go.mod adjustments as needed...

Separately, I think you might also be commenting on the new go directive in 1.12 that shows the version of the Go language used by the files within that module (e.g., from the 1.12 release notes)? If so, I believe the go tool chain is explicit that its versioning scheme for Go releases does not follow semver. For example, go1.11 and go1.12 are referred to as "major releases" (which is not what semver would say). I haven't gone back to double-check the history carefully, but I think Go might either pre-date semver, or they might both have come into existence within a year or two of each other, which says to me that it is not a shock that Go releases have not historically followed semver. There is always room for discussion about changing things going forward, but then there is a balancing act between consistency with what has been done historically, the cost of change, and the benefit of change.

Finally, I am just a member of the broader community myself, so please do not give too much weight to anything I have said here. ;-)

@nim-nim
Copy link
Author

nim-nim commented Feb 9, 2019

Hi @thepudds

That certainly suggests to me that a leading v for a semver VCS tag is not only allowed, but also common, and not tied specifically to git.

And the example you quote points directly to the git history of the git project… v before versions didn't exist before git implemented tags without bothering to distinguish versions, and Linus Torvalds just prefixed his version tags with v to workaround this deficiency (and then gave it as example in a git man page).

And, as an aside, there is nothing in git that makes sure a tag starting with v is a version (counter examples are easy to find), or that it is a semver if it is a version (the v-prefixed tags Linus uses are most definitely not semvers since they have weird things like -rcX postfixes)

So the whole house of cards just rests on a misinterpretation of a quick and dirty workaround by Linus Torvalds (I initially wrote hack but that would imply v prefixing was backed by some code git side. It definitely is not).

But, anyway, one should not need to write pages of scholarly text to justify syntax quirks, go.mod is not a centuries old human language, with entrenched practices, and lots of history behind each wart, it's brand new, the Go element in it has not even hit a stable release so far, there's no reason for it to adopt a syntax different from how other versions are expressed in the rest of the module file before the paint is even wet.

(As a human, I find your scholarly explanations interesting and well written. As a go.mod user, I just want the syntax to be regular, easy to use, and be done with it).

@oiooj oiooj added the modules label Feb 10, 2019
@bcmills bcmills changed the title go.mod versioning is inconsistent cmd/go: go.mod versioning is inconsistent Feb 12, 2019
@bcmills
Copy link
Contributor

bcmills commented Feb 12, 2019

You haven't actually mentioned what about this is “inconsistent” — as far as I can see, cmd/go consistently uses the v prefix (on VCS tags, on the command line, and in go.mod files).

Module support has been available since Go 1.11 and there are many go.mod files already out in the world, so at this point any change to the format needs a much more compelling justification than aesthetic preferences. This bike-shed is already painted; we're not repainting it arbitrarily.

@bcmills bcmills closed this as completed Feb 12, 2019
@nim-nim
Copy link
Author

nim-nim commented Feb 12, 2019

The version of the new Go element does not use the version syntax of existing go.mod elements.

@bcmills
Copy link
Contributor

bcmills commented Feb 12, 2019

That's because it indicates the version of the Go language in use, and versions of the Go language itself have never followed semantic versioning.

(If you believe that the language spec itself should be semantically versioned, that's a separate proposal to file — but, again, you'd need to show a compelling benefit based on more than just aesthetic preferences.)

@bvisness
Copy link

@bcmills As much as I dislike resurrecting an angry thread, I wanted to ask if you thought it would be possible in the future for the go module solver to detect semantic versions that don't start with a v. I know it's a common convention, but it is unfortunately not a convention that we follow at my company.

The reason I ask is that dep did understand semantic versions without a v, thanks to its use of Masterminds/semver. Now in the process of switching to modules we are finding that we will either have to put up with pseudo-versions or switch our tag convention (which will inevitably break some of our internal processes).

@bcmills
Copy link
Contributor

bcmills commented May 15, 2019

@bvisness, if you have concrete examples of use of tags without the "v" prefix on existing Go projects, please open a new issue to discuss.

(Just to set expectations, though, I still think it's unlikely that we'll support them — what would happen if a repo had both a v1.0.0 tag and a 1.0.0 tag, but at different commits?)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants