|
5 | 5 | "encoding/json" |
6 | 6 | "errors" |
7 | 7 | "fmt" |
| 8 | + "strings" |
8 | 9 |
|
9 | 10 | "github.com/blang/semver/v4" |
10 | 11 | "golang.org/x/text/cases" |
@@ -208,24 +209,55 @@ func (destination *DeclarativeConfig) Merge(src *DeclarativeConfig) { |
208 | 209 | destination.Deprecations = append(destination.Deprecations, src.Deprecations...) |
209 | 210 | } |
210 | 211 |
|
211 | | -type CompositeVersion struct { |
212 | | - Version semver.Version |
213 | | - Release semver.Version |
214 | | -} |
| 212 | +type Release []semver.PRVersion |
215 | 213 |
|
216 | | -func (cv *CompositeVersion) Compare(other *CompositeVersion) int { |
217 | | - if cv.Version.NE(other.Version) { |
218 | | - return cv.Version.Compare(other.Version) |
| 214 | +func (r Release) Compare(other Release) int { |
| 215 | + if len(r) == 0 && len(other) > 0 { |
| 216 | + return -1 |
219 | 217 | } |
220 | | - hasrelease := len(cv.Release.Pre) > 0 |
221 | | - otherhasrelease := len(other.Release.Pre) > 0 |
222 | | - if hasrelease && !otherhasrelease { |
| 218 | + if len(other) == 0 && len(r) > 0 { |
223 | 219 | return 1 |
224 | 220 | } |
225 | | - if !hasrelease && otherhasrelease { |
226 | | - return -1 |
| 221 | + a := semver.Version{Pre: r} |
| 222 | + b := semver.Version{Pre: other} |
| 223 | + return a.Compare(b) |
| 224 | +} |
| 225 | + |
| 226 | +func NewRelease(relStr string) (Release, error) { |
| 227 | + // empty input is not an error, but results in an empty release slice |
| 228 | + if relStr == "" { |
| 229 | + return nil, nil |
227 | 230 | } |
228 | | - return cv.Release.Compare(other.Release) |
| 231 | + |
| 232 | + var ( |
| 233 | + segments = strings.Split(relStr, ".") |
| 234 | + r = make(Release, 0, len(segments)) |
| 235 | + errs []error |
| 236 | + ) |
| 237 | + for i, segment := range segments { |
| 238 | + prVer, err := semver.NewPRVersion(segment) |
| 239 | + if err != nil { |
| 240 | + errs = append(errs, fmt.Errorf("segment %d: %v", i, err)) |
| 241 | + continue |
| 242 | + } |
| 243 | + r = append(r, prVer) |
| 244 | + } |
| 245 | + if err := errors.Join(errs...); err != nil { |
| 246 | + return nil, fmt.Errorf("invalid release %q: %v", relStr, err) |
| 247 | + } |
| 248 | + return r, nil |
| 249 | +} |
| 250 | + |
| 251 | +type CompositeVersion struct { |
| 252 | + version semver.Version |
| 253 | + release Release |
| 254 | +} |
| 255 | + |
| 256 | +func (cv *CompositeVersion) Compare(other *CompositeVersion) int { |
| 257 | + if cmp := cv.version.Compare(other.version); cmp != 0 { |
| 258 | + return cmp |
| 259 | + } |
| 260 | + return cv.release.Compare(other.release) |
229 | 261 | } |
230 | 262 |
|
231 | 263 | // order by version, then |
@@ -258,20 +290,16 @@ func (b *Bundle) CompositeVersion() (*CompositeVersion, error) { |
258 | 290 | return nil, fmt.Errorf("bundle %q has invalid version %q: %v", b.Name, props.Packages[0].Version, err) |
259 | 291 | } |
260 | 292 |
|
261 | | - var r semver.Version |
| 293 | + var r Release |
262 | 294 | if props.Packages[0].Release != "" { |
263 | | - r, err = semver.Parse(fmt.Sprintf("0.0.0-%s", props.Packages[0].Release)) |
| 295 | + r, err = NewRelease(props.Packages[0].Release) |
264 | 296 | if err != nil { |
265 | 297 | return nil, fmt.Errorf("error parsing bundle %q release version %q: %v", b.Name, props.Packages[0].Release, err) |
266 | 298 | } |
267 | | - // only need to check for build metadata since we are using explicit zero major, minor, and patch versions above |
268 | | - if len(r.Build) != 0 { |
269 | | - return nil, fmt.Errorf("bundle %q release version %q cannot contain build metadata", b.Name, props.Packages[0].Release) |
270 | | - } |
271 | 299 | } |
272 | 300 |
|
273 | 301 | return &CompositeVersion{ |
274 | | - Version: v, |
275 | | - Release: r, |
| 302 | + version: v, |
| 303 | + release: r, |
276 | 304 | }, nil |
277 | 305 | } |
0 commit comments