@@ -243,7 +243,7 @@ func runRelease(w io.Writer, dir string, args []string) (success bool, err error
243243type moduleInfo struct {
244244 modRoot string // module root directory
245245 repoRoot string // repository root directory (may be "")
246- modPath string // module path
246+ modPath string // module path in go.mod
247247 version string // resolved version or "none"
248248 versionQuery string // a query like "latest" or "dev-branch", if specified
249249 versionInferred bool // true if the version was unspecified and inferred
@@ -393,7 +393,9 @@ func loadLocalModule(modRoot, repoRoot, version string) (m moduleInfo, err error
393393// loadDownloadedModule downloads a module and loads information about it and
394394// its packages from the module cache.
395395//
396- // modPath is the module's path.
396+ // modPath is the module path used to fetch the module. The module's path in
397+ // go.mod (m.modPath) may be different, for example in a soft fork intended as
398+ // a replacement.
397399//
398400// version is the version to load. It may be "none" (indicating nothing should
399401// be loaded), "" (the highest available version below max should be used), a
@@ -403,9 +405,6 @@ func loadLocalModule(modRoot, repoRoot, version string) (m moduleInfo, err error
403405// to max will not be considered. Typically, loadDownloadedModule is used to
404406// load the base version, and max is the release version.
405407func loadDownloadedModule (modPath , version , max string ) (m moduleInfo , err error ) {
406- // TODO(#39666): support downloaded modules that are "soft forks", where the
407- // module path in go.mod is different from modPath.
408-
409408 // Check the module path and version.
410409 // If the version is a query, resolve it to a canonical version.
411410 m = moduleInfo {modPath : modPath }
@@ -414,10 +413,10 @@ func loadDownloadedModule(modPath, version, max string) (m moduleInfo, err error
414413 }
415414
416415 var ok bool
417- _ , m .modPathMajor , ok = module .SplitPathVersion (m . modPath )
416+ _ , m .modPathMajor , ok = module .SplitPathVersion (modPath )
418417 if ! ok {
419418 // we just validated the path above.
420- panic (fmt .Sprintf ("could not find version suffix in module path %q" , m . modPath ))
419+ panic (fmt .Sprintf ("could not find version suffix in module path %q" , modPath ))
421420 }
422421
423422 if version == "none" {
@@ -457,12 +456,27 @@ func loadDownloadedModule(modPath, version, max string) (m moduleInfo, err error
457456 m .version = version
458457 }
459458
460- // Load packages.
459+ // Download the module into the cache and load the mod file.
460+ // Note that goModPath is $GOMODCACHE/cache/download/$modPath/@v/$version.mod,
461+ // which is not inside modRoot. This is what the go command uses. Even if
462+ // the module didn't have a go.mod file, one will be synthesized there.
461463 v := module.Version {Path : modPath , Version : m .version }
462- if m .modRoot , err = downloadModule (v ); err != nil {
464+ if m .modRoot , m .goModPath , err = downloadModule (v ); err != nil {
465+ return moduleInfo {}, err
466+ }
467+ if m .goModData , err = ioutil .ReadFile (m .goModPath ); err != nil {
468+ return moduleInfo {}, err
469+ }
470+ if m .goModFile , err = modfile .ParseLax (m .goModPath , m .goModData , nil ); err != nil {
463471 return moduleInfo {}, err
464472 }
465- tmpLoadDir , tmpGoModData , tmpGoSumData , err := prepareLoadDir (nil , modPath , m .modRoot , m .version , true )
473+ if m .goModFile .Module == nil {
474+ return moduleInfo {}, fmt .Errorf ("%s: missing module directive" , m .goModPath )
475+ }
476+ m .modPath = m .goModFile .Module .Mod .Path
477+
478+ // Load packages.
479+ tmpLoadDir , tmpGoModData , tmpGoSumData , err := prepareLoadDir (nil , m .modPath , m .modRoot , m .version , true )
466480 if err != nil {
467481 return moduleInfo {}, err
468482 }
@@ -471,23 +485,10 @@ func loadDownloadedModule(modPath, version, max string) (m moduleInfo, err error
471485 err = fmt .Errorf ("removing temporary load directory: %v" , err )
472486 }
473487 }()
474- if m .pkgs , _ , err = loadPackages (modPath , m .modRoot , tmpLoadDir , tmpGoModData , tmpGoSumData ); err != nil {
488+ if m .pkgs , _ , err = loadPackages (m . modPath , m .modRoot , tmpLoadDir , tmpGoModData , tmpGoSumData ); err != nil {
475489 return moduleInfo {}, err
476490 }
477491
478- // Attempt to load the mod file, if it exists.
479- m .goModPath = filepath .Join (m .modRoot , "go.mod" )
480- if m .goModData , err = ioutil .ReadFile (m .goModPath ); err != nil && ! os .IsNotExist (err ) {
481- return moduleInfo {}, fmt .Errorf ("reading go.mod: %v" , err )
482- }
483- if err == nil {
484- m .goModFile , err = modfile .ParseLax (m .goModPath , m .goModData , nil )
485- if err != nil {
486- return moduleInfo {}, err
487- }
488- }
489- // The modfile might not exist, leading to err != nil. That's OK - continue.
490-
491492 return m , nil
492493}
493494
@@ -578,10 +579,12 @@ func makeReleaseReport(base, release moduleInfo) (report, error) {
578579 }
579580 }
580581
581- if release .version != "" {
582- r .validateVersion ()
583- } else if r .similarModPaths () {
584- r .suggestVersion ()
582+ if r .canVerifyReleaseVersion () {
583+ if release .version == "" {
584+ r .suggestReleaseVersion ()
585+ } else {
586+ r .validateReleaseVersion ()
587+ }
585588 }
586589
587590 return r , nil
@@ -825,7 +828,7 @@ func copyModuleToTempDir(modPath, modRoot string) (dir string, err error) {
825828
826829// downloadModule downloads a specific version of a module to the
827830// module cache using 'go mod download'.
828- func downloadModule (m module.Version ) (modRoot string , err error ) {
831+ func downloadModule (m module.Version ) (modRoot , goModPath string , err error ) {
829832 defer func () {
830833 if err != nil {
831834 err = & downloadError {m : m , err : cleanCmdError (err )}
@@ -840,7 +843,7 @@ func downloadModule(m module.Version) (modRoot string, err error) {
840843 // If it didn't read go.mod in this case, we wouldn't need a temp directory.
841844 tmpDir , err := ioutil .TempDir ("" , "gorelease-download" )
842845 if err != nil {
843- return "" , err
846+ return "" , "" , err
844847 }
845848 defer os .Remove (tmpDir )
846849 cmd := exec .Command ("go" , "mod" , "download" , "-json" , "--" , m .Path + "@" + m .Version )
@@ -850,26 +853,26 @@ func downloadModule(m module.Version) (modRoot string, err error) {
850853 if err != nil {
851854 var ok bool
852855 if xerr , ok = err .(* exec.ExitError ); ! ok {
853- return "" , err
856+ return "" , "" , err
854857 }
855858 }
856859
857860 // If 'go mod download' exited unsuccessfully but printed well-formed JSON
858861 // with an error, return that error.
859- parsed := struct { Dir , Error string }{}
862+ parsed := struct { Dir , GoMod , Error string }{}
860863 if jsonErr := json .Unmarshal (out , & parsed ); jsonErr != nil {
861864 if xerr != nil {
862- return "" , cleanCmdError (xerr )
865+ return "" , "" , cleanCmdError (xerr )
863866 }
864- return "" , jsonErr
867+ return "" , "" , jsonErr
865868 }
866869 if parsed .Error != "" {
867- return "" , errors .New (parsed .Error )
870+ return "" , "" , errors .New (parsed .Error )
868871 }
869872 if xerr != nil {
870- return "" , cleanCmdError (xerr )
873+ return "" , "" , cleanCmdError (xerr )
871874 }
872- return parsed .Dir , nil
875+ return parsed .Dir , parsed . GoMod , nil
873876}
874877
875878// prepareLoadDir creates a temporary directory and a go.mod file that requires
0 commit comments