radekg / terraform-provisioner-ansible

Ansible with Terraform 0.14.x
Apache License 2.0
572 stars 100 forks source link

Cannot get latest version: module contains a go.mod file, so module path should be github.com/radekg/terraform-provisioner-ansible/v2 #153

Closed KateGo520 closed 4 years ago

KateGo520 commented 4 years ago

Background

The github.com/radekg/terraform-provisioner-ansible uses Go modules and the current release stream version is v2. 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. 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 anything later than github.com/radekg/terraform-provisioner-ansible@v2.3.0, which was the last version to not have modules. I consider this a pretty high severity issue since not doing so prevents any other Go project also using Go Modules to properly require radekg/terraform-provisioner-ansible on versions higher than v2.3.0 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 v2

SO anyone using Go modules will not be able to easily use any newer version of radekg/terraform-provisioner-ansible

Steps to Reproduce

  1. Under a project making use of Go modules, run go get targeting any version >= v2.3.1 of the radekg/terraform-provisioner-ansible:
$ go get github.com/radekg/terraform-provisioner-ansible@v2.3.3
go: finding github.com/radekg/terraform-provisioner-ansible v2.3.3
go: finding github.com/radekg/terraform-provisioner-ansible v2.3.3
go get github.com/radekg/terraform-provisioner-ansible@v2.3.3: github.com/radekg/terraform-provisioner-ansible@v2.3.3: invalid version: module contains a go.mod file, so major version must be compatible: should be v0 or v1, not v2

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/radekg/terraform-provisioner-ansible/v2 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 v2 as a dead version and bump to v3 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/radekg/terraform-provisioner-ansible@, 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/radekg/terraform-provisioner-ansible@ (4)Edit the go.mod file to put a comment about which version you actually used

This way seems good, but if the users try to use go get -u, they will get the old version and break again.

References

I can see these repos use github.com/radekg/terraform-provisioner-ansible in github.com: https://github.com/search?q=github.com%2Fradekg%2Fterraform-provisioner-ansible+language%3Ago&type=Code