64
64
// "latest", or "none". If the version is "none", gorelease will not compare the
65
65
// current version against any previous version; it will only validate the
66
66
// current version. This is useful for checking the first release of a new major
67
- // version. If -base is not specified, gorelease will attempt to infer a base
68
- // version from the -version flag and available released versions.
67
+ // version. The version may be preceded by a different module path and an '@',
68
+ // like -base=example.com/mod/[email protected] . This is useful to compare against
69
+ // an earlier major version or a fork. If -base is not specified, gorelease will
70
+ // attempt to infer a base version from the -version flag and available released
71
+ // versions.
69
72
//
70
73
// -version=version: The proposed version to be released. If specified,
71
74
// gorelease will confirm whether this version is consistent with changes made
@@ -160,8 +163,8 @@ func runRelease(w io.Writer, dir string, args []string) (success bool, err error
160
163
fs := flag .NewFlagSet ("gorelease" , flag .ContinueOnError )
161
164
fs .Usage = func () {}
162
165
fs .SetOutput (ioutil .Discard )
163
- var baseVersion , releaseVersion string
164
- fs .StringVar (& baseVersion , "base" , "" , "previous version to compare against" )
166
+ var baseOpt , releaseVersion string
167
+ fs .StringVar (& baseOpt , "base" , "" , "previous version to compare against" )
165
168
fs .StringVar (& releaseVersion , "version" , "" , "proposed version to be released" )
166
169
if err := fs .Parse (args ); err != nil {
167
170
return false , & usageError {err : err }
@@ -170,6 +173,7 @@ func runRelease(w io.Writer, dir string, args []string) (success bool, err error
170
173
if len (fs .Args ()) > 0 {
171
174
return false , usageErrorf ("no arguments allowed" )
172
175
}
176
+
173
177
if releaseVersion != "" {
174
178
if semver .Build (releaseVersion ) != "" {
175
179
return false , usageErrorf ("release version %q is not a canonical semantic version: build metadata is not supported" , releaseVersion )
@@ -178,12 +182,26 @@ func runRelease(w io.Writer, dir string, args []string) (success bool, err error
178
182
return false , usageErrorf ("release version %q is not a canonical semantic version" , releaseVersion )
179
183
}
180
184
}
181
- if baseVersion != "" && semver .Canonical (baseVersion ) == baseVersion && releaseVersion != "" {
182
- if cmp := semver .Compare (baseVersion , releaseVersion ); cmp == 0 {
183
- return false , usageErrorf ("-base and -version must be different" )
184
- } else if cmp > 0 {
185
- return false , usageErrorf ("base version (%q) must be lower than release version (%q)" , baseVersion , releaseVersion )
185
+
186
+ var baseModPath , baseVersion string
187
+ if at := strings .Index (baseOpt , "@" ); at >= 0 {
188
+ baseModPath = baseOpt [:at ]
189
+ baseVersion = baseOpt [at + 1 :]
190
+ } else if dot , slash := strings .Index (baseOpt , "." ), strings .Index (baseOpt , "/" ); dot >= 0 && slash >= 0 && dot < slash {
191
+ baseModPath = baseOpt
192
+ } else {
193
+ baseVersion = baseOpt
194
+ }
195
+ if baseModPath == "" {
196
+ if baseVersion != "" && semver .Canonical (baseVersion ) == baseVersion && releaseVersion != "" {
197
+ if cmp := semver .Compare (baseOpt , releaseVersion ); cmp == 0 {
198
+ return false , usageErrorf ("-base and -version must be different" )
199
+ } else if cmp > 0 {
200
+ return false , usageErrorf ("base version (%q) must be lower than release version (%q)" , baseVersion , releaseVersion )
201
+ }
186
202
}
203
+ } else if baseModPath != "" && baseVersion == "none" {
204
+ return false , usageErrorf (`base version (%q) cannot have version "none" with explicit module path` , baseOpt )
187
205
}
188
206
189
207
// Find the local module and repository root directories.
@@ -201,8 +219,12 @@ func runRelease(w io.Writer, dir string, args []string) (success bool, err error
201
219
202
220
// Find the base version if there is one, download it, and load packages from
203
221
// the module cache.
204
- baseModPath := release .modPath // TODO(golang.org/issue/39666): allow different module path
205
- base , err := loadDownloadedModule (baseModPath , baseVersion , releaseVersion )
222
+ var max string
223
+ if baseModPath == "" {
224
+ baseModPath = release .modPath
225
+ max = releaseVersion
226
+ }
227
+ base , err := loadDownloadedModule (baseModPath , baseVersion , max )
206
228
if err != nil {
207
229
return false , err
208
230
}
@@ -381,6 +403,9 @@ func loadLocalModule(modRoot, repoRoot, version string) (m moduleInfo, err error
381
403
// to max will not be considered. Typically, loadDownloadedModule is used to
382
404
// load the base version, and max is the release version.
383
405
func 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
+
384
409
// Check the module path and version.
385
410
// If the version is a query, resolve it to a canonical version.
386
411
m = moduleInfo {modPath : modPath }
@@ -474,18 +499,12 @@ func loadDownloadedModule(modPath, version, max string) (m moduleInfo, err error
474
499
// version control tag to use (with an appropriate prefix, for modules not
475
500
// in the repository root directory).
476
501
func makeReleaseReport (base , release moduleInfo ) (report , error ) {
477
- if base .modPath != release .modPath {
478
- // TODO(golang.org/issue/39666): allow base and release path to be different.
479
- panic (fmt .Sprintf ("base module path %q is different than release module path %q" , base .modPath , release .modPath ))
480
- }
481
- modPath := release .modPath
482
-
483
502
// Compare each pair of packages.
484
503
// Ignore internal packages.
485
504
// If we don't have a base version to compare against,
486
505
// just check the new packages for errors.
487
506
shouldCompare := base .version != "none"
488
- isInternal := func (pkgPath string ) bool {
507
+ isInternal := func (modPath , pkgPath string ) bool {
489
508
if ! hasPathPrefix (pkgPath , modPath ) {
490
509
panic (fmt .Sprintf ("package %s not in module %s" , pkgPath , modPath ))
491
510
}
@@ -501,17 +520,17 @@ func makeReleaseReport(base, release moduleInfo) (report, error) {
501
520
base : base ,
502
521
release : release ,
503
522
}
504
- for _ , pair := range zipPackages (base .pkgs , release .pkgs ) {
523
+ for _ , pair := range zipPackages (base .modPath , base . pkgs , release . modPath , release .pkgs ) {
505
524
basePkg , releasePkg := pair .base , pair .release
506
525
switch {
507
526
case releasePkg == nil :
508
527
// Package removed
509
- if ! isInternal (basePkg .PkgPath ) || len (basePkg .Errors ) > 0 {
528
+ if internal := isInternal (base . modPath , basePkg .PkgPath ); ! internal || len (basePkg .Errors ) > 0 {
510
529
pr := packageReport {
511
530
path : basePkg .PkgPath ,
512
531
baseErrors : basePkg .Errors ,
513
532
}
514
- if ! isInternal ( basePkg . PkgPath ) {
533
+ if ! internal {
515
534
pr .Report = apidiff.Report {
516
535
Changes : []apidiff.Change {{
517
536
Message : "package removed" ,
@@ -524,12 +543,12 @@ func makeReleaseReport(base, release moduleInfo) (report, error) {
524
543
525
544
case basePkg == nil :
526
545
// Package added
527
- if ! isInternal (releasePkg .PkgPath ) && shouldCompare || len (releasePkg .Errors ) > 0 {
546
+ if internal := isInternal (release . modPath , releasePkg .PkgPath ); ! internal && shouldCompare || len (releasePkg .Errors ) > 0 {
528
547
pr := packageReport {
529
548
path : releasePkg .PkgPath ,
530
549
releaseErrors : releasePkg .Errors ,
531
550
}
532
- if ! isInternal ( releasePkg . PkgPath ) && shouldCompare {
551
+ if ! internal && shouldCompare {
533
552
// If we aren't comparing against a base version, don't say
534
553
// "package added". Only report packages with errors.
535
554
pr .Report = apidiff.Report {
@@ -544,7 +563,10 @@ func makeReleaseReport(base, release moduleInfo) (report, error) {
544
563
545
564
default :
546
565
// Matched packages
547
- if ! isInternal (basePkg .PkgPath ) && basePkg .Name != "main" && releasePkg .Name != "main" {
566
+ // Both packages are internal or neither; we only consider path components
567
+ // after the module path.
568
+ internal := isInternal (release .modPath , releasePkg .PkgPath )
569
+ if ! internal && basePkg .Name != "main" && releasePkg .Name != "main" {
548
570
pr := packageReport {
549
571
path : basePkg .PkgPath ,
550
572
baseErrors : basePkg .Errors ,
@@ -558,7 +580,7 @@ func makeReleaseReport(base, release moduleInfo) (report, error) {
558
580
559
581
if release .version != "" {
560
582
r .validateVersion ()
561
- } else {
583
+ } else if r . similarModPaths () {
562
584
r .suggestVersion ()
563
585
}
564
586
@@ -1056,24 +1078,27 @@ type packagePair struct {
1056
1078
// If a package is in one list but not the other (because it was added or
1057
1079
// removed between releases), a pair will be returned with a nil
1058
1080
// base or release field.
1059
- func zipPackages (basePkgs , releasePkgs []* packages.Package ) []packagePair {
1081
+ func zipPackages (baseModPath string , basePkgs [] * packages. Package , releaseModPath string , releasePkgs []* packages.Package ) []packagePair {
1060
1082
baseIndex , releaseIndex := 0 , 0
1061
1083
var pairs []packagePair
1062
1084
for baseIndex < len (basePkgs ) || releaseIndex < len (releasePkgs ) {
1063
1085
var basePkg , releasePkg * packages.Package
1086
+ var baseSuffix , releaseSuffix string
1064
1087
if baseIndex < len (basePkgs ) {
1065
1088
basePkg = basePkgs [baseIndex ]
1089
+ baseSuffix = trimPathPrefix (basePkg .PkgPath , baseModPath )
1066
1090
}
1067
1091
if releaseIndex < len (releasePkgs ) {
1068
1092
releasePkg = releasePkgs [releaseIndex ]
1093
+ releaseSuffix = trimPathPrefix (releasePkg .PkgPath , releaseModPath )
1069
1094
}
1070
1095
1071
1096
var pair packagePair
1072
- if basePkg != nil && (releasePkg == nil || basePkg . PkgPath < releasePkg . PkgPath ) {
1097
+ if basePkg != nil && (releasePkg == nil || baseSuffix < releaseSuffix ) {
1073
1098
// Package removed
1074
1099
pair = packagePair {basePkg , nil }
1075
1100
baseIndex ++
1076
- } else if releasePkg != nil && (basePkg == nil || releasePkg . PkgPath < basePkg . PkgPath ) {
1101
+ } else if releasePkg != nil && (basePkg == nil || releaseSuffix < baseSuffix ) {
1077
1102
// Package added
1078
1103
pair = packagePair {nil , releasePkg }
1079
1104
releaseIndex ++
0 commit comments