elliotchance / gedcom

👪 A Go library and CLI tools for encoding, decoding, traversing, merging, comparing, querying and publishing GEDCOM files.
MIT License
94 stars 21 forks source link

Cannot get latest version: module contains a go.mod file, so module path should be github.com/elliotchance/gedcom/v39 #313

Closed KateGo520 closed 8 months ago

KateGo520 commented 3 years ago

Background

The github.com/elliotchance/gedcom uses Go modules and the current release stream version is v39. It must comply with the specification of "Releasing Modules for v2 or higher" available in the Modules documentation and enforced since the most recent versions of Go. The module path should be “github.com/elliotchance/gedcom/v39”. Quoting the specification:

A package that has opted in to modules must include the major version in the import path to import any v2+ modules To preserve import compatibility, the go command requires that modules with major version v2 or later use a module path with that major version as the final element. For example, version v2.0.0 of example.com/m must instead use module path example.com/m/v2. https://github.com/golang/go/wiki/Modules#releasing-modules-v2-or-higher

Using go get (under go1.13 and go1.14) does not work for github.com/elliotchance/gedcom@v39.5.3 . I consider this a pretty high severity issue since not doing so prevents any other Go project also using Go Modules to properly require elliotchance/gedcom on version v39.5.3 as a dependency, resulting in errors like:

invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v39

SO anyone using Go modules will not be able to easily use any newer version of elliotchance/gedcom

Steps to Reproduce

Under a project making use of Go modules, run go get targeting any version >= v38.0.1 of the elliotchance/gedcom:

$ go get github.com/elliotchance/gedcom@v38.0.1
go get github.com/elliotchance/gedcom@v38.0.1: github.com/elliotchance/gedcom@v38.0.1: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v38

Solution

1. Kill the go.mod files.

This would push them back to not being managed by Go modules (instead of incorrectly using Go modules). Importing specific versions would work, but they'd receive the +incompatible prefix and would need to be manually upgraded.

Probably best option short-term -- better to not use Go modules than use it incorrectly. Also, best option for older branches/versions that aren't maintained.

2. Make breaking changes

Patch the go.mod file to declare the module as github.com/elliotchance/gedcom/v39 as per the specs. AND adjust all internal imports.

There are two alternative mechanisms to release a v2 or higher module. Note that with both techniques, the new module release becomes available to consumers when the module author pushes the new tags. Using the example of creating a v3.0.0 release, the two options are:

Major branch: Update the go.mod file to include a /v3 at the end of the module path in the module directive (e.g., module github.com/my/module/v3). Update import statements within the module to also use /v3 (e.g., import "github.com/my/module/v3/mypkg"). Tag the release with v3.0.0.

  • Go versions 1.9.7+, 1.10.3+, and 1.11 are able to properly consume and build a v2+ module created using this approach without requiring updates to consumer code that has not yet opted in to modules (as described in the "Semantic Import Versioning" section above).
  • A community tool github.com/marwan-at-work/mod helps automate this procedure. See the repository or the community tooling FAQ below for an overview.
  • To avoid confusion with this approach, consider putting the v3.. commits for the module on a separate v3 branch.
  • Note: creating a new branch is not required. If instead you have been previously releasing on master and would prefer to tag v3.0.0 on master, that is a viable option. (However, be aware that introducing an incompatible API change in master can cause issues for non-modules users who issue a go get -u given the go tool is not aware of semver prior to Go 1.11 or when module mode is not enabled in Go 1.11+).
  • Pre-existing dependency management solutions such as dep currently can have problems consuming a v2+ module created in this way. See for example dep#1962.

Major subdirectory: Create a new v3 subdirectory (e.g., my/module/v3) and place a new go.mod file in that subdirectory. The module path must end with /v3. Copy or move the code into the v3 subdirectory. Update import statements within the module to also use /v3 (e.g., import "github.com/my/module/v3/mypkg"). Tag the release with v3.0.0.

  • This provides greater backwards-compatibility. In particular, Go versions older than 1.9.7 and 1.10.3 are also able to properly consume and build a v2+ module created using this approach.
  • A more sophisticated approach here could exploit type aliases (introduced in Go 1.9) and forwarding shims between major versions residing in different subdirectories. This can provide additional compatibility and allow one major version to be implemented in terms of another major version but would entail more work for a module author. An in-progress tool to automate this is goforward. Please see here for more details and rationale, along with a functioning initial version of goforward.
  • Pre-existing dependency management solutions such as dep should be able to consume a v2+ module created in this way.

3. Major version bump / repository change

Leave v39 as a dead version and bump to v40 with the path changes.

4. Remain unchanged

Don’t want to fix it. Not intended to be used as a library and does not make any guarantees about the API.

5. Let the user change

The standard rule of go modules conflicts with your development mode. So you can’t comply with the specification of "Releasing Modules for v2 or higher" available in the Modules documentation. Regardless, since it's against one of the design choices of Go, it'll be a bit of a hack. Instead of go get github.com/elliotchance/gedcom@version-tag, the install procedure would be something like: (1)Search for the tag you want (in browser) (2)Get the commit hash for the tag you want (3)Run go get github.com/elliotchance/gedcom@commit-hash (4)Edit the go.mod file to put a comment about which version you actually used

References

KateGo520 commented 3 years ago

@elliotchance @jazzboME Could you help me review this issue? Thx :p

elliotchance commented 3 years ago

Thanks for the detailed information. Since I have no intend to support anything other than the latest release, removing the go.mod seems the most reasonable. I'm happy for you to put in a PR.

KateGo520 commented 3 years ago

@elliotchance Thank you for your contribution

mattjohnsonpint commented 9 months ago

Any update here? I tried go get github.com/elliotchance/gedcom , but it installs v38.0.0+incompatible, not the latest v39.

elliotchance commented 9 months ago

@mattjohnsonpint what happens if you try go get github.com/elliotchance/gedcom@v39.5.3?

mattjohnsonpint commented 9 months ago
go get github.com/elliotchance/gedcom@v39.5.3

gives:

go: github.com/elliotchance/gedcom@v39.5.3: invalid version: module contains a go.mod file, so module path must match major version ("github.com/elliotchance/gedcom/v39")

So I tried also:

go get github.com/elliotchance/gedcom/v39

but that gives:

go: module github.com/elliotchance/gedcom@upgrade found (v38.0.0+incompatible), but does not contain package github.com/elliotchance/gedcom/v39

Not sure what else to try. This is with Go 1.21.3 on MacOS.

elliotchance commented 8 months ago

I don't think resetting the versioning to 1.x makes sense. So the only reasonable option here it to move it into a v39 directory. Feel free to submit a PR.

mattjohnsonpint commented 8 months ago

First time doing something like this, so I hope I got it right. All modules build, and all tests pass.

Locally it works great, using a replace statement in my own project's go.mod:

replace github.com/elliotchance/gedcom/v39 => ../gedcom

Which I should be able to remove once this is merged.

mattjohnsonpint commented 8 months ago

It worked. I can now simply do:

go get github.com/elliotchance/gedcom/v39 

And in my go.mod, it adds:

require github.com/elliotchance/gedcom/v39 v39.6.0

Now I can import just fine and it works:

import "github.com/elliotchance/gedcom/v39"

Thanks!