-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
proposal: a version numbering scheme and release process for Go projects #12302
Comments
It would be easier to judge this proposal if it included examples from a specific extant tool that would work better with a standard versioning scheme. As it stands, the proposal's preface justifies versions, but not consistent versions. |
To be explicit, this proposal ties requires versions be assigned at the repository level, it cannot be assigned at the package level. Agree with @crawshaw observation. |
@kardianos this is correct. Go packages belong to projects which live inside vcs repositories. This is a proposal to release these projects by tagging those repositories with semver tags. |
@crawshaw thank you for your comments. To give two concrete examples: \1. For my project, gb I provide a helper plugin, gb-vendor, which assists users in maintaining the contents of the code they have vendored. gb-vendor also provides an update command, but at the moment the best we can do is update from the currently vendored revision to the latest on the branch, if users want something else they have to manually update to a different revision. This is because, given an arbitrary branch and revision, it is not possible to say "give me the latest stable version". Sure, if you knew the latest "blessed" revision, you could do that, which is effectively what gb-vendor users have to do now, but then again, if they already knew the revision they wanted to switch to, they wouldn't ask questions like "give me the latest stable version". \2. For my day job, both Debian and Ubuntu have a strong preference to only package released versions of software. Ubuntu want to make their distribution an excellent platform for Go developers by packaging up all the commonly used dependencies, as we do for other popular languages like Ruby and Python. At the moment Debian maintainers are forced to do things like this, which are of no use to anyone because it's a made up un released version number assigned by the packager, not the owner of the source code. Now, that is not to say that all projects do not have usable versions, docker, kubernetes, and coreos, the three biggest projects in Go, use the form I proposed above and that benefits all the downstream consumers of those projects.
If this proposal removed the use of semver, and made the version string opaque, that is to say |
As a Debian Developer, Go user, and Docker project maintainer, I'm definitely very +1 to explicit versioning. I'm not personally attached to any particular scheme (semver is nice), but having explicit points in time where a package maintainer has said "I feel good enough about my library/program at this particular point in time to attach some extra meaning to it" is really useful, even if they're simple monotonic increases like what systemd uses. As a simplistic example, it's easy for users to say "I'm on version 34 and hitting bug XYZ" and the maintainer can respond with something simple for users to understand like "that was fixed in version 36". Semver specifically is nice when used properly, but it does apply a light layer of "social contract" between package authors and consumers such that (for example) version 1.0.0 and version 1.0.1 are "compatible" (for varying values of compatible, I suppose). The fake VCS-based version numbers used in Debian can be useful ( |
So what does the implementation of this look like? Where would the convention be documented? Would it be enforced by the Go tool chain somewhere? Is this analogous to the vendor-spec proposal? |
I imagine the implementation would be a design document in the proposal repo, like the security policy.
In the document above.
Not at the moment. Releasing code is outside the purview of the go tool at the moment and go get has no capabilities to choose which tag to check out at the moment. However, there are many other tools, both in the Go sphere, and outside, that consume Go projects and will benefit from being able to identify released versions of Go projects.
Not directly. The vendor spec is about recording what is vendored into the local copy. This proposal is about providing a way for Go project owners to indicate which revisions of their repository they want to be considered "released", in the same way that we develop Go on master, but tag a specific revision when it's ready to be released. |
The security policy will be documented somewhere outside the proposal repo. Either the wiki or on the web site (probably the former). I would expect the same outcome both for this proposal and vendor-spec. I understand how this is distinct from vendor-spec. My question about vendor-spec was asking if this were basically "version-spec". I think that vendor-spec might be influenced by this proposal, though. |
I am sorry, this was my misunderstanding, I'm still getting used to the proposal process. I agree that the website, maybe in one of the 'how to write Go code' pages would be a good place for this information, or possibly on the wiki. For me, the location is not as important as establishing a single recommended way to tag a Go project in their repos.
I'm sorry for misunderstanding. I guess this is a version-spec if you want to think of it that way. I should add that in this initial proposal I have err'd on the side of brevity to focus on the outcomes, not the procedure. I fully expect that should this proposal move forward, the next step would be a design document as you outlined in the proposal process.
Possibly a bit, but I don't think either proposal should be dependant on one another. The former, this one, is about a format for a release tag on repositories, while the vendor-spec caters for tags, branches, and revisions equally, and it is hard to see this proposal designing a tag format that is impossible to express in the vendor-spec. Thanks Dave |
I've stated this elsewhere, but if a version was specified to be consistent I would prefer a spec that allowed sub-paths to be separately versioned. "websocket-v2.2.3" or "context-v1.0.0" in addition to the repo wide option specified above. |
I don't have any problem with the specifics of this proposal, I'm just a little confused by the scope. The go tool has opinions about Go packages and the layout of the repositories they exist in, but has no concept of a project. Introducing project-level versioning requires introducing the notion of a project. The kinds of questions I might ask about projects:
|
@crawshaw Dave has stated elsewhere that the framing is one version per VCS repository. So the repository becomes the "project". This is a stronger notion than even what the "vendor" folder implies as it defines a single root. |
That's fine, it's just that project needs to be defined before project versioning can be defined. That probably needs to happen as part of the proposal. |
This looks like the early days of ruby on rails. Before having bundler, we had to put dependencies in /vendor/plugins. It lasted for some years, then rubygems became the standard. The dependencies were defined in the code, and a rake task was used to install the deps: |
This is correct, the go tool does not have a concept of how the packages on your GOPATH came to be there, but With that said, any changes to the go tool are outside the scope of this proposal. I've updated the original proposal with a definition of a Go project.
No. Each repository is a versioned and released individually.
No. The contents of a repository are released together as a whole, golang.org/x/tools is a great example of that.
Unlimited. There is an unfortunate coincidence with the gb definition of a project. If you think it would help I can reword this proposal to remove all references to Project, and replace it with Remote Repository.
Go projects are named by the import prefix that is defined by their repository root. Import prefix and repository root are defined by the documentation on the go tool. |
@gravis thanks for your comments and your perspective. I agree that Go is lucky that we have always had a package namespace (although noting that Go packages are not hierarchical) so we can lean on this heavily. For example, what defines a project, and who gets to name a project ? Luckily Who owns the github.com/docker/docker project, and thus the github.com/docker/docker/... namespace ? It's who controls the docker repository on the docker account at github. Who owns the golang.org/x/tools project ? It's whoever controls the dns name for golang.org and can host a web server to serve a meta redirect. |
My 2 cents: There's not much here to disagree with (and yet...). I think versioning is good, but I also happen to work on a project that versions in exactly this way.
Without some hypothetical usages of this convention, it might be hard to justify. For example, could Those are more exciting than an abstract convention which, to be clear, is painfully obvious to me (but clearly not everyone). TL;DR +1 but how do we USE it? |
@thockin thanks for your comments. I understand your frustration that this does all appear to be hypothetical at the moment. My rational for starting as small as possible is (and I think well founded) that a proposal that introduced semver and required everyone to tag their repos and had to make a change to go get and had to fit into the overfull 1.6 release cycle would be viewed with blank stares. This is the smallest possible thing that I think can make the dependency management situation for Go programmers better. I think it is a reasonable thing that improves the life of Go developers and the ecosystem downstream from them even if the go tool does not grow to embrace it, as there are several dozen other competing Go dependency management tools in the market. With that said, here are a few concrete areas that would benefit immediately
|
Oh, sorry if I mis-communicated. I think this is obviously correct. I'm No "frustration" here, other than wanting to help get a resounding "YES" to On Tue, Aug 25, 2015 at 11:36 PM, Dave Cheney notifications@github.com
|
&tldr; +1 One question, why the I looked and npm (for Node.js) and composer (for PHP) the There are Go projects with and without the As one of the developers of Glide, another package manager, I can say that handling this well is already a request and need. Going beyond issues, such a distros, you can see what version of the project/package API you're using. If I've used a package who bumped their API version from 1.2.3 to 2.0.0 I need to know this because the API contract changed. Versioning can help with the API contract and expectations. |
To @mattfarina's point, SemVer 2.0 removed the requirement for the superfluous |
A few concerns:
|
@kostya-sh if the version number is in the import path, then every source file using the import must be updated every time the dependency is (which is a lot of churn and merge conflicts) IMO if two versions of a package are different enough to be used concurrently, they ought to live under separate paths anyhow (or use a scheme like gopkg.in), especially since using both concurrently is probably an edge case for most. |
This is why gopkg.in only versions to the major number. If I import On Wed, Aug 26, 2015 at 7:43 AM, Tianon Gravi notifications@github.com
|
@tianon, I didn't propose to include version number in the import path. What I said was that incompatible versions of the same package should be different packages (with different import paths). Though in practice this probably matters only for popular well established libraries used by many projects. E.g. Java protobuf 2.4 vs 2.5. Note that the major version is the same but they are still incompatible in a subtle way. If the goal of this proposal is to create a document describing best practices for versioning then it should cover topics that I raised including backward compatibility. A document describing best practices for versioning, releasing, using vcs, maintain backward compatibility, etc would be very useful. If the goal of this proposal is to make semver versions standard in the Go community then I think:
|
@technosophos @mattfarina thank you for your feedback. To reply specifically to your comments about the The preference for a If this proposal were amended to make the |
@kostya-sh thank you for your feedback. To address your points
I'm sorry but I do not agree with you. There must be only one copy (not version) of any package in a Go binary; the linker requires it. To subvert this by renaming the package, even well intentioned, so as to permit go get to have some way of identifying different major versions of packages, is in my opinion a mistake. To give some background: Canonical were, I believe, one of the first to attempt to use this method with the mgo driver back in August 2012 when we had to make an incompatible change to the API. At the time we thought were were rather clever, but since that time I have come to believe this was a mistake, for the following reasons:
I think java has made a serious mistake by developing more (OSGI) and more (Project Jigsaw) complicated methods of classpath resolution to continue to support multiple versions of a library in the same JVM runtime. This complexity is entirely self inflicted and not something I want to see in a Go dependency management solution.
I agree that for end user applications, projects which produce a program or server binary, versioning makes less sense, as by definition no code consumes them. However, there are many downstream consumers of all Go projects that do care about version numbers, operating system distributions are a major one. I don't think your examples provide a compelling exception to the rule to argue against the value of semver. |
@kostya-sh to address your points
These are good points, if this proposal moves forward to the design document stage it should address these points.
I disagree, as I mentioned about to @thockin this is the smallest possible proposal I can think of to make forward progress. Yes, larger proposals would be more comprehensive, but would take significantly longer to achieve consensus and would then be further delayed by a requirement to be scheduled into the Go release cycle -- do you really want to wait up to a year to see this implemented in a released version of Go ? This proposal is the smallest I can make. It pushes all the questions of what versioning means to an accepted standard, semver, which is widely used across languages who we consider to be contemporaries (or competitors) to Go, and lets us benefit from their experiences rather than reinventing what would likely be a very similar wheel. If you agree with that position, then this proposal boils down to a format for vcs tags that I believe can achieve consensus easily and can be of use immediately for all the tool makers, godoc.org maintainers, and operating system distros, in the Go ecosystem. Thanks Dave |
On Thu, Nov 26, 2015 at 7:51 PM, Axel Wagner notifications@github.com
I agree that releases and versions are different.
Note that, should versions support be added to standard Go tools, you will Also note that SemVer has nothing to do with this problem. |
Not really. My major objection is about the whole idea of defining "breakage" and "compatibility" in terms of an API in isolation, i.e. about the "semantic" part in "SemVer". I see the usefulness of versions to give human readable names to releases, I also acknowledge that it is useful to imply a total ordering on versions. But if you want to assign semantic meaning apart from that to a version, you would either a) have potentially false version-matches, e.g. I require 1.7.0 or above and 1.8.0 breaks me because the author considered a change-non-breaking but there is no such thing in go or b) have probable false version-mismatches, e.g. I require version 1.0 or above, the author did a minor change in the API that broke nothing in practice, but to avoid a) they chose to increment to version 2.0 which is assumed to break me as the major version increased. I think it's hard to reconcile any SemVer-equivalent versioning scheme with these concerns, while a purely chronological versioning scheme (e.g. every release increments a counter) that isn't used to make semantic deductions could. As such, a tool to help in determining the next version number can't really ameliorate my concerns. In fact, the mentioned blog posts and my position towards SemVer is born out of me trying to write exactly this tool about half a year ago. I realized half-way through that there is no useful (read: prevents breakages but does not restrict language use too much) notion of compatibility for go. So I maintain my position that the best way would be to at least not use semantic versions, but treat release-tags as convenience identifiers that have no meaning apart from that (and possibly a purely chronological ordering). I don't think that versions are the correct way to tackle the compatibility problem, but that this should rather be done by better tooling and conventions to work around that and actually look at the code that uses an API, instead of the API itself. A set of tools that helps you to choose the correct version to install and package based on the actual API and the code of the actual users of that API, instead of some ultimately heuristic number assigned to it. @perillo Thanks for your comments :) I have read the compatibility guarantee extensively, but I don't think it is a sufficient definition, because a) most community members I have talked to so far consider things that break this guarantee to be non-breaking and b) even the go stdlib constantly breaks it, if you are being precise. I see the go 1 compatibility guarantee more as a statement of intent then an actual definition of what compatibility means (and to be clear: That's still far better than anything else I've seen for other languages). I recommend reading the blog post I linked to earlier on why I think this needs more spelling out.
I respectfully disagree. It has everything to do with this problem, it is part of the proposal and my issues with the proposal are completely attributed to this.
Precisely. I wanted to demonstrate that it is possible to have releases without having versions (which is what I would prefer). |
@Merovius I work as a freelance developer. A client ask me a software, I develop it, release it and after some time I forget about it. Suppose after a year the client call me telling he need a new feature or a bug fix: do you think I want to spend more time than necessary trying to update everything to the latest revision, checking that it really works? SemVer does not solve the problem, but it, with the aid of good tools, will make my life better. |
@Merovius With respect, I believe you are letting the perfect become the enemy of the good. Semantic versioning is the de-facto standard for versioning in ~every programming ecosystem (to some order of approximation). Developers expect it, or something like it, when approaching this problem space. Its failures, which you identify, do not prevent it from being useful, as @perillo notes. And, it seems that adopting this proposal doesn't prevent package authors from opting out of versioning at their discretion, and asking their consumers to vendor at specific revisions. — What do you think? |
@peterbourgon |
s/required/specified/ |
@perillo But that isn't really an argument now, is it? SemVer does exactly zero to make that situation better. Just use the revision you used before, develop against that and if there were breakages, you need to figure that out either way. I don't understand what you are getting at with that. @peterbourgon Note, that I started not by demanding that this should be abolished (though I think it should), but by stating that someone suggesting SemVer should also give a definition of what that means. I firmly stand by this, I will be unhappy, but can accept SemVer as an 80% solution, but only if we collectively agree what kinds of changes will require an increment of which version number. Because a simple definition leads to counterproductive version numbers. |
Good news, then: this is already defined to a commonly-accepted level of precision in the spec:
|
@peterbourgon I don't understand why you'd think that's relevant to my points. I thought I made myself relatively clear before. I know and understand the SemVer spec, but if that's all the definition you are giv, then every API change in go is a major version increment. That is hardly a useful versioning scheme. To make SemVer useful for go, you need to define what "backwards-compatible" means, because that's less straightforward then you'd think and everyone seems to have a different opinion about that. |
@Merovius thank you for your comments. I can see you have strong views on versioning, releasing, and methodologies like semver itself. Like others who have replied, we'll have to agree to disagree, and as SemVer is key to this proposal, I'm sorry but I cannot accept your suggestions into this proposal. |
To repeat myself again: My suggestion was primarily to at least define what constitutes a "breaking change", or rather a "non-breaking change". I don't understand why this should be impossible or conflict with the target of using Semantic versioning, in fact I would think that it would promote the introduction of SemVer. I have strong opinions on the merits of SemVer, yes, but I agreed to disagree on those from the very beginning. But so far no one has even attempted to give this definition, acknowledge it's necessity or to give a reason to not give such a definition. Clarity on what constitutes a breakage seems like a hard requirement for introducing SemVer to me, because after all the spec references this term and only makes sense after this term is clear. I am going to leave this discussion now, because I feel unwanted and ignored. |
@Merovius I'm sorry you feel that your views are not being respected. If I have given that impression, please accept my apologies. With respect to your specific concerns about what defines "breaking or non breaking change", I hold it is whatever Semver says, which is clearly stated at the top of the summary section of http://semver.org/spec/v2.0.0.html. You argue that what constitutes a breaking change is much larger than what is commonly accepted, as pointed out by your well written article. As I said above, I agree completely with what you wrote, and see this as a point which tools can help as the rules for "breaking vs non breaking" are not ambiguous -- we already have this with the Go api tool, although i think you are arguing for some even more stringent, and that is also fine. In summary, I agree with your points on breaking changes being almost any addition to an existing Go type (sorry if I have not reproduced the depth of your argument), but that seems to me to be tangental to this proposal. This proposal is to adopt some kind of release process -- if there is no release process then arguing about the nuances of the application of Semver to Go APIs serves no purpose. Thanks Dave |
@Merovius, a few points.
|
For anyone who wants to back SemVer into their toolchains I wrote up a quick tutorial (with a package) for the Gopher Academy 2015 Advent |
This proposal would ratify what many people and tools are already doing. Docker, Kubernetes, and CoreOS were mentioned. When I wrote about tagging repositories over two years ago, there were already third-party tools that worked with the The fsnotify library currently uses gopkg.in to turn tagged releases into new import paths for each major version. One feature gopkg.in provides is the distinction between released code and what's sitting on master. The url http://gopkg.in/fsnotify.v1 retrieves the latest v1.x.y tag. Code sitting on master while preparing a release is not made available until tagged. It also has experimental support for prerelease versions. Adding a v2.0.0-unstable tag would provide an opt-in way to retrieve an upcoming release. While gopkg.in has been useful, I think it is quickly becoming unnecessary. Many people vendor code now, and GO15VENDOREXPERIMENT is further formalizing that recommendation. Everything gopkg.in provides can be replaced with tools such as Godep and gb _if_ they can retrieve the latest tag rather than master, or pull in prerelease versions or previous versions. Gopkg.in is built on the idea of taking a common VCS practice of tagging releases and providing multiple import paths, derived from the recommendation in the Go FAQ. @davecheney has already listed the issues his colleagues at Canonical had with the multiple import path approach. There are situations where creating an entirely new library with a new name is appropriate. But for bumping a major version to remove deprecated APIs, there are better alternatives to "create a new package with a new import path", and I believe the FAQ deserves an update. Providing more visibility into "a release process for Go repositories" will allow third-party tools to start expecting Updating GoDoc.org to show documentation for any version may or may not be worth the effort involved. A more reasonable start would be to simply display the version number for the most current release. That will help make this recommendation to tag releases more visible. The distinction between tagged and untagged repositories could also be used to help ranking, by boosting released libraries higher than hobby projects. What comes after that? I don't know the future, but I believe this is a good step, and one worth taking. Thanks @davecheney. |
@nathany If I understand what @rsc is say the issue is that adding SemVer as a recommendation without having part of the If community things that aren't going to be built directly into the tools aren't appropriate for this forum do we need something similar to the PHP FIG for the community? |
That sounds well meaning, but entirely too much bureaucracy. How about people just tag their releases ? |
Yes, my objection is that this proposal does not propose any actual changes to any part of Go. It is not actionable in its current form. I'm still not even sure it's a good idea, in large part because one way I evaluate whether something is a good idea is to understand its effects, and this proposal has no direct effects. Build a system that uses semantic versions effectively. Demonstrate what great tools can be built. Give people incentives, and they will tag their releases no matter what the Go team says. Certainly the Go team saying "you should do it this way" has not in the past been successful without these things (think not-vendoring). |
I feel that it is time to draw the discussion to a close. The proposal guidelines clearly state "a lack of agreement means [the proposal is] declined", as such it is appropriate that I withdraw this proposal. I want to extend my sincere thanks to all who have contributed to this debate. I remain passionate about improving the tools Go programmers have to manage package dependencies in large Go projects and your feedback has been invaluable to me and my future efforts. Thank you again Dave |
Fair enough Dave. Thanks for the time you spent on the proposal. I certainly agree that a solution to versioning would be great, and that SemVer seems like a very good basis for building such a solution. The devil is always in the details, of course. |
For the Versioning Numbering Cheme I would, any day, choose Explicit Versioning insted of Semantic Versioning. Why? It's so simple the first four words from the title of the link explain it for most of the developers. And besides that, no more ambiguity caused by the "Major" and "Minor" fields of the version number. Here's the promissed link: |
Preface
Go projects do not have version numbers in the way it is commonly understood by our counterparts in other languages communities. This is because there is no formalised notion of releasing a Go project. There is no process of taking an arbitrary vcs commit hash and assigning it a version number that is both meaningful for humans and machines.
Additionally, Operating System distributors such as Debian and Ubuntu strongly prefer to package released versions of a project, and are currently reduced to doing things like this.
To put it another way,
Go projects are commonly tracked in vcs repositories and derive their import prefix from their vcs location. Version control systems assign revision identifiers or hashes to various copies of the source they track over time. These vcs hashes are ideal for identifying a particular copy, or revision, of a Go project. However vcs hashes are less useful at answering other types of question like:
The aim of this proposal is to establish a single recommended procedure for releasing Go projects, in the same way that gofmt defines a single recommended way to format Go source code.
Proposal
This proposal seeks to establish a recommended version numbering scheme and minimal release process for Go projects.
A Go project is a collection of one or more Go packages whose source is tracked in a vcs repository.
A repository root, as defined by cmd/go, identifies both the unique import path prefix for the Go project, and the vcs repository that holds the project's source.
This proposal describes a release process for Go projects by tagging the repository which hold the project's code.
This process is intended to be light weight and will facilitate the creation of tools that automate the creation and consumption of released versions of Go projects.
Version numbering scheme
This proposal recommends that Go projects adopt the semantic versioning 2.0 standard for their version numbering scheme.
This recommendation is informed by the broad support for semantic versioning across our contemporaries like node.js (npm), rust (cargo), javascript (bower), and ruby (rubygems). Adherence to a commonly accepted ideal of what constitutes a major, minor, or patch release will allow Go programmers to benefit from the experiences of these other communities' dependency management ecosystems.
Tag format
Furthermore, this proposal recommends that Go projects adopt a process of releasing their software by applying a tag to their vcs repositories. The format of this tag is defined as
That is, the character
v
, U+0075, followed directly by a string which is compliant with the SemVer 2.0 standard. Tags which do not fit this format should be ignored for the purpose of determining which versions of a Go project are released.Out of scope
The following items are out of scope, but would be addressed in a later proposals:
Additionally, this proposal not seek to change the release process, or version numbering scheme for the Go (https://golang.org) distribution itself.
Thank you for your time.
The text was updated successfully, but these errors were encountered: