golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
122.71k stars 17.5k forks source link

proposal: a version numbering scheme and release process for Go projects #12302

Closed davecheney closed 8 years ago

davecheney commented 9 years ago

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

v<semver>

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.

crawshaw commented 9 years ago

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.

kardianos commented 9 years ago

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.

davecheney commented 9 years ago

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.

davecheney commented 9 years ago

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.

@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.

As it stands, the proposal's preface justifies versions, but not consistent versions.

If this proposal removed the use of semver, and made the version string opaque, that is to say v<x.y.z> where x, y and z were not specified, would you be more favourable to this propsal ?

tianon commented 9 years ago

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 (0.0~git20150526.1.5478c06-1 for example), but IMO should only be necessary for snapshots between releases (such as 1.2.3~git20150526.1.5478c06-1).

adg commented 9 years ago

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?

davecheney commented 9 years ago

So what does the implementation of this look like?

I imagine the implementation would be a design document in the proposal repo, like the security policy.

Where would the convention be documented?

In the document above.

Would it be enforced by the Go tool chain somewhere?

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.

Is this analogous to the vendor-spec proposal?

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.

adg commented 9 years ago

I imagine the implementation would be a design document in the proposal repo, like the security policy.

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.

davecheney commented 9 years ago

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 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 understand how this is distinct from vendor-spec. My question about vendor-spec was asking if this were basically "version-spec".

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.

I think that vendor-spec might be influenced by this proposal, though.

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

kardianos commented 9 years ago

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.

crawshaw commented 9 years ago

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:

kardianos commented 9 years ago

@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.

crawshaw commented 9 years ago

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.

gravis commented 9 years ago

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: rake gems:install (<= search for issues with that on google...) It introduced a lot of issues, because the gem (ruby packages) were installed using the application itself. Of course, sometimes, the app couldn't load enough code to install the gems, and the user was stuck. Then, bundler was designed, an independent tool, reading one config file (Gemfile). The locked versions are saved to Gemfile.lock, and installed most of the time in a dedicated "gemset" (a GOPATH). I writing all of this, because it seems go is heading the same way, and will spend months/years to adopt what the other languages figured out in the last years ;) What go could do better, is the namespace of packages, because the source of the package is obviously explicit. There's no need for a central registry, VCS tags are more than enough.

davecheney commented 9 years ago

@crawshaw

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.

This is correct, the go tool does not have a concept of how the packages on your GOPATH came to be there, but go get does. Before fetching, go get must canonicalise the import path, find some prefix of the path you provided you gave it to the location of a remote repository, which it fetches in its entirety. It is this import prefix, or what the Go tool calls, the repository root, that is a project.

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.

The kinds of questions I might ask about projects:

  • Can a project span repositories?

No. Each repository is a versioned and released individually.

  • Can a single repository contain multiple projects?

No. The contents of a repository are released together as a whole, golang.org/x/tools is a great example of that.

  • How many main packages can be in a project?

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.

  • What names a project?

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.

davecheney commented 9 years ago

@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 go get already defines the rules for what is a remote package and how it is fetched, so questions of ownership can be punted to a 3rd party.

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.

thockin commented 9 years ago

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.

With that said, any changes to the go tool are outside the scope of this proposal.

Without some hypothetical usages of this convention, it might be hard to justify. For example, could go get HYPOTHETICALLY take a version string and fetch that specific revision? Could godep or gb vendor HYPOTHETICALLY take a version to import and/or rewrite imports (gopkg.in style) to versioned?

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?

davecheney commented 9 years ago

@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

thockin commented 9 years ago

Oh, sorry if I mis-communicated. I think this is obviously correct. I'm just a concrete sort of fellow, so having a mental model of what this would enable helps me see the purpose. I assume I am not alone.

No "frustration" here, other than wanting to help get a resounding "YES" to something like this.

On Tue, Aug 25, 2015 at 11:36 PM, Dave Cheney notifications@github.com wrote:

@thockin https://github.com/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

  • Debian and other operating systems could use this information today.
  • I plan to rev the manifest format that gb-vendor uses to include the tag information so I can offer my users a real upgrade command, not just one that grabs the latest head of the branch they are on.
  • godoc.org can show users the docs for the version of the package they are using, not just show the latest that was in the upstream repo.

— Reply to this email directly or view it on GitHub https://github.com/golang/go/issues/12302#issuecomment-134858484.

mattfarina commented 9 years ago

&tldr; +1

One question, why the v at the start of the version number? Should that be required or optional?

I looked and npm (for Node.js) and composer (for PHP) the v is optional. In others such as Cargo (Rust) or Bower (JavaScript) I don't see any mention of v. It appears to not be used.

There are Go projects with and without the v prefix today. Can it be optional?

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.

technosophos commented 9 years ago

To @mattfarina's point, SemVer 2.0 removed the requirement for the superfluous v. I don't see a compelling reason to require it in this context.

kostya-sh commented 9 years ago

A few concerns:

  1. I beleive that incompatible versions of the same library should use different import paths. Otherwise they cannot co-exist as dependencies of a single project. Having them tagged with two different tags is not enough or even harmful.

    There a lot of examples of Java libraries where following this simple rule would have made life of library and application developers much easier. E.g. protobuf 2.4 vs 2.5, various versions of asm library, hadoop-1 vs hadoop-2, various versions of jetty, etc.

  2. Very often for applications (not libraries) it makes little sense to use semver. Something like build number + git hash works well enough. Think about version numbers of such applications like Chrome, Firefox, systemd, less, etc.
tianon commented 9 years ago

@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.

thockin commented 9 years ago

This is why gopkg.in only versions to the major number. If I import libfoo.v1 and libfoo.v2 at the same time, I have to rename something. If the tooling doesn't handle it well, users do their own thing and everyone ends up with bespoke vendoring scripts. Puke.

On Wed, Aug 26, 2015 at 7:43 AM, Tianon Gravi notifications@github.com wrote:

@kostya-sh https://github.com/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.

— Reply to this email directly or view it on GitHub https://github.com/golang/go/issues/12302#issuecomment-135044682.

kostya-sh commented 9 years ago

@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:

davecheney commented 9 years ago

@technosophos @mattfarina thank you for your feedback. To reply specifically to your comments about the v prefix. This was the most contentious part of the discussion on go-pm that preceeded this proposal.

The preference for a v prefix comes from observations that three of the biggest Go projects, Docker, Kubernetes, and CoreOs all use that variation, it is also widely used by our language contemporaries like Rust, Nodejs and Bower (javascript). With that said, I'm sure an equal number of prominent examples could be found that do not have a v prefix.

If this proposal were amended to make the v prefix optional, would that be acceptable ?

davecheney commented 9 years ago

@kostya-sh thank you for your feedback. To address your points

I beleive that incompatible versions of the same library should use different import paths. Otherwise they cannot co-exist as dependencies of a single project. Having them tagged with two different tags is not enough or even harmful.

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:

  1. Putting the major version in the API is not sufficient for a repeatable build, at best it only guides Go get to the major API version. It does not give Go get sufficient information to fetch a specific release version or a specific revision. Using these versioned import paths, the Juju developers still had to develop an additional tool to make sure everyone had the same revision of every dependency checked out.
  2. Encoding a version number in the import path has a high operational overhead, I recently saw a patch from a co-worker that touched 220 files to update a dependency that used this format via the gopkg.in proxy. What is worse, this changed from v5 to v6-unstable, so you just know that in a week or so another 220 file patch will be coming to remove the -unstable prefix.
  3. Encoding a version number in the import path has a high cost for new adopters of the language. You have to find every reference in your project to one versioned import path, and replace it with another, even in the face of conditional compilation, even in tests, and so forth. As someone who is passionate about teaching newcomers about Go, the conceptual burden of educating newcomers about this requirement would be far to high.
  4. Finally, even with the most rigorous development standards for their own code, Go developers are still at risk from the dependencies they rely on not getting it right. With versioned import paths it is very easy to see two arms of a dependency graph importing different versions of a database driver who's init() function registers the driver. Have a read of the documentation for sql.Register. This is not a hypothetical problem, and one that must be prevented at all costs.

There a lot of examples of Java libraries where following this simple rule would have made life of library and application developers much easier. E.g. protobuf 2.4 vs 2.5, various versions of asm library, hadoop-1 vs hadoop-2, various versions of jetty, etc.

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.

Very often for applications (not libraries) it makes little sense to use semver. Something like build number + git hash works well enough. Think about version numbers of such applications like Chrome, Firefox, systemd, less, etc.

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.

davecheney commented 9 years ago

@kostya-sh to address your points

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.

These are good points, if this proposal moves forward to the design document stage it should address these points.

If the goal of this proposal is to make semver versions standard in the Go community then I think: tools support should come first. gofmt mentioned in the proposal is the excellent example why it is fairly easy to enforce the version format but it is much more difficult or even impossible to make people follow the rules behind it

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

kostya-sh commented 9 years ago

@davecheney, I guess I didn't express myself clear enough. I agree with you that any kind of automated way of adding versions to the import paths is not the best way to solve backward (in)compatibility problems. Something like libv5, libv6, libv100 is certainly not what I want to see in Go projects.

Maintaining backward compatibility and using different import path for incompatible versions should be responsibility of package authors. Good example: go/types from Go 1.5 is incompatible with the original version, but it is not a big problem because import paths are different, application developers are free to choose one or another depending on their requirements.

However if a package changes in a backward incompatible way between v1 and v2 and keeps using the same import path then burden of resolving dependency mess is on users of the package. I am not aware of Go examples, but there are plenty in Java world (just because it is more widely used), I mentioned few of them in my previous comments.

I just wanted to suggest that raising awareness about these problems among package developers would be a good thing.

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.

My examples were referring to a single class loader (no OSGI). You will be surprised how many similarities Go and Java have in package/library management. I would say that within a single class loader they are equivalent:

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 ?

I am just a bit skeptical that the proposal alone would be enough. I might be wrong about that though as Go community seems to be quite united.

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.

Unfortunately dealing with backward (in)compatibility is not as simple as enforcing semver and vcs tag format.

Very interesting study of libraries in the maven central repository that contains majority of open source Java libraries: http://avandeursen.com/2014/10/09/semantic-versioning-in-maven-central-breaking-changes/ . Almost 24% of patch updates introduced binary (detectable by tools) incompatibility!

Please treat my comments not as arguments against the proposal but as feedback and food for thoughts.

kostya-sh commented 9 years ago

Also how would this proposal allow to version golang.org/x packages?

davecheney commented 9 years ago

@kostya-sh sorry for not addressing every one of your points

However if a package changes in a backward incompatible way between v1 and v2 and keeps using the same import path then burden of resolving dependency mess is on users of the package.

Yes, and this will always be true, and this will always be true if we have a release process and version numbers, or continue to muddle along using vcs revisions as a proxy.

I just wanted to suggest that raising awareness about these problems among package developers would be a good thing.

I agree, and think that semver is a concrete and well understood standard that works well. Do you think that Go should develop its own version numbering scheme ? What benefits do you think that would have over semver ?

My examples were referring to a single class loader (no OSGI). You will be surprised how many similarities Go and Java have in package/library management. I would say that within a single class loader they are equivalent:

Yes, the linking model for java, with its class path and the Go toolchain are quite similar and I draw a lot of inspiration from my work with Java and Maven in the past.

I am just a bit skeptical that the proposal alone would be enough. I might be wrong about that though as Go community seems to be quite united.

It's absolutely not enough. This proposal is just the start, more will follow if this one is accepted, but I belive that this is the place to start.

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. Unfortunately dealing with backward (in)compatibility is not as simple as enforcing semver and vcs tag format.

Could you please expand on this point and provide some specifics.

Very interesting study of libraries in the maven central repository that contains majority of open source Java libraries: http://avandeursen.com/2014/10/09/semantic-versioning-in-maven-central-breaking-changes/ . Almost 24% of patch updates introduced binary (detectable by tools) incompatibility!

To cut to the chase, semver is not a magic bullet, it cannot force developers to do the right thing, only incentivise them to do the right thing. I believe that this property would hold true no matter what version number methodology was proposed, semver or something of our own concoction.

I think there is a lot of benefit from working from a position of assuming Go programmers want to do the right thing, not engineer a straight jacket process which inhibits them from doing the wrong thing.

As you mentioned above social pressure work well in the Go community, I point to the ubiquitous success of gofmt as an example. Code that is no go formatted is considered my many to be a first order indicator of a lack of quality.

Similarly, adherence to a commonly accepted ideal of what constitutes semver's major, minor and patch release definitions will come through the same social pressures, and we all benefit from a shared vocabulary across our counterparts in node, ruby and rust.

Please treat my comments not as arguments against the proposal but as feedback and food for thoughts.

Thank you for your continued feedback, I appreciate your experience and it is very valuable to me.

kardianos commented 9 years ago

@kostya-sh This proposal would not allow effective versioning of the golang.org/x packages because those repositories contain packages that will version at vastly different rates. This proposal explicitly defines the unit of version to equal the repository. For instance golang.org/x/crypto/ssh will version differently then golang.org/crypto/md4, or golang.org/x/net/context will version much more slowly then golang.org/x/net/websocket.

In previously conversations regarding this proposal it was commented that the golang.org/x repos were really too large/mixed and should be more granular ideally.

davecheney commented 9 years ago

Also how would this proposal allow to version golang.org/x packages?

@kostya-sh Yes, should this proposal be accepted, I believe these projects should adopt the version number format and provide consumers with released versions via tags.

davecheney commented 9 years ago

@kardianos I understand that you want to version Go repositories on a per package basis. I recognise the rational for that, and the possibilities that would unlock.

I also recognise that this would be much harder to explain to newcomers, much more nuanced for toolmakers, and ultimately a far more complex solution than I think is necessary.

If developers are unhappy with the granularity of a single version number series per repository, they should split the unrelated pieces out into independent repositories.

If this should be done for your examples of the crypto and net projects is outside the scope of this proposal.

Thank you

Dave

philips commented 9 years ago

+1 on this proposal. It would be very helpful for a community convention to be established. Today CoreOS projects like etcd, rkt, and flannel, depend on a number of Go libraries. And it would be great if there was an overall community convention to make regular library releases so instead of selecting the version based on what master was whenever our team imported the library with godep we could start relying on a git tag instead.

kostya-sh commented 9 years ago

I agree, and think that semver is a concrete and well understood standard that works well. Do you think that Go should develop its own version numbering scheme ? What benefits do you think that would have over semver ?

I think that it doesn't matter much what version numbering scheme is used. However when there is a possibility that two incompatible versions of the same package are used as dependencies of a single project (in semver terms libfoo 1.x and libfoo 2.y) then having libfooone x and libfootwo y is easier to deal with. So semver way of dealing with breaking changes by incrementing major version doesn't work in all cases.

I understand that this is not applicable to all packages and cannot be enforced thus this is just a recommendation.

I point to the ubiquitous success of gofmt as an example. Code that is no go formatted is considered my many to be a first order indicator of a lack of quality.

I think you are mixing the cause and effect here. I believe that the only reason of a single formatting style for Go code is the existence of gofmt. The tool came first and no formal document describing formatting rules was necessary. Compare this with PEP-8 and python.

Why no one tags their repositories now (is it true btw?)? Could it be because there are no tools that support tags?

davecheney commented 9 years ago

Why no one tags their repositories now (is it true btw?)? Could it be because there are no tools that support tags?

This is almost certainly the case. Right now, few Go projects have a release process, and those that do use a tag format of their choosing. Because of this, no tools exist to mechanically consume release tags (although many tools exist that leave the problem of choosing the tag, branch or revision entirely to the user), hence there is no impetus to do releases.

I think we're both saying the same thing, we both want to break this cycle. You want a tool to be written first, and I want agreement on the format first, then the tool. I think my approach has a higher chance of achieving consensus as it requires no code change (yet), and will enable the entire Go ecosystem to benefit as soon as it is adopted, not when the tool, and I'm assuming you mean the go tool inside the Go distribution itself, ships.

peterbourgon commented 9 years ago

A strong +1 to the proposal. It would be wonderful to provide consumers of Go kit with version semantics, and the most widely-adopted way of doing that now (gopkg.in) is unsuitable for a variety of reasons.

I would also like to see a larger proposal, including some suggestions (if not spec implementations) for tool integration. But I defer to @davecheney's preference for a smaller scope. SemVer 2.0 is the obvious choice for schema, and versioning whole repositories strikes a good balance between versatility and simplicity.

@kostya-sh

However when there is a possibility that two incompatible versions of the same package are used as dependencies of a single project (in semver terms libfoo 1.x and libfoo 2.y) . . .

This is a distraction, because—as I understand it—it categorically can't be allowed to occur. Two versions of the same package can't be imported into the same dependency graph, because of issues like the double-driver-registration problem enumerated by @davecheney above.

kostya-sh commented 9 years ago

A strong +1 to the proposal. It would be wonderful to provide consumers of Go kit with version semantics, and the most widely-adopted way of doing that now (gopkg.in) is unsuitable for a variety of reasons.

What are the problems with gopkg.in? Understanding them will allow to address them in this or any subsequent proposals.

There are no tags in https://github.com/go-kit/kit repo? Is it because the existing tools (like godep or gb-vendor) do not support them? Should the support for tags be added to these tools then?

This is a distraction, because—as I understand it—it categorically can't be allowed to occur.

There is no way to enforce it. While not common I can imagine it can occur in practice. Imagine the following hypothetical example:

What should I do now?

gopkg.in is an attempt to provide different import paths for invompatible versions of the same package.

peterbourgon commented 9 years ago

@kostya-sh we should take this discussion offline. Feel free to ping me on gophers.slack.com, same username.

mattfarina commented 9 years ago

@davecheney how shall we proceed? Can I help?

technosophos commented 9 years ago

@davecheney (and @mattfarina): I'm not going to get too worked up about the v prefix. But my feeling is that if the version standard upon which we are basing the proposal makes the v optional, we probably should too.

That said, I am still 100% behind this proposal, even as is. Please let me know if you need any help, even if it's just evangelizing the idea.

vbatts commented 9 years ago

github inline (not tree threading) comments are rough. Here we go.

I am +1 Golang versioning has been a point of contention in fedora packaging guidelines for golang as well.

Some thoughts. In keeping with semver, and helping to approach the "latest" question, the tagging deduction ought to define greatest in the current point provided. Example go get -version v2 ... pull the explicit tag v2 or v2.y[.z] if present, go get -version v2.1 ... would match v2.1 or v2.1.z if present, and so on. This is was a hold-back on gopkg.in for some.

Also, this semantic would only be on go get, not build, install? I don't see this being a layout consideration for ./pkg, only processing on the cvs fetched. A later call like go get -u -v3 ... would fetch and checkout the matched or greatest semver tag, right?

mattfarina commented 9 years ago

@vbatts this proposal doesn't include changes to go get. How about we get this proposal in first and then we explore what we can do with it. There are a bunch of directions we can go (and I really want to see some improvements to go get). Can we get this idea in, at a basic level, and then iterate?

vbatts commented 9 years ago

@mattfarina right right. My thoughts jumped ahead [in excitement]. I know it's out of scope for this.

All-in-all in setting an expectation for projects is understandable. It could not be enforced, only utilized if present. So having it documented in wiki would be best-effort for adoption until proposals for the next items in scope happen.

+1 from me

bketelsen commented 9 years ago

Strong +1 from me. This base will allow much needed tooling in the Go ecosystem.

technosophos commented 9 years ago

@vbatts does raise an interesting thing that we might at least consider for this spec. Should this proposal defined what "v1.2" and "v2" mean? For purely numeric calculations, I have seen the internals of various package managers do some interesting things to give these symbols meaning (v1 == v1.9999.9999 or v2.-1). And since version number comparison is a natural offshoot of this spec, it might behoove us to make an explicit decision now, even if the explicit decision is that the question is out of scope.

Related, semver does mention pre-release versions, but only gives "alpha" as an example. Is there any use trying to be more explicit here? I think alpha, beta, and rcN are pretty standard.

davecheney commented 9 years ago

Thank you to everyone who contributed to the discussion. In accordance with the proposal process I have drafted a design document. You can find this draft available here

https://go-review.googlesource.com/14008

davecheney commented 9 years ago

@technosophos semver defines how two versions are compared, I don't believe this proposal needs to augment that.

gopherbot commented 9 years ago

CL https://golang.org/cl/14008 mentions this issue.