59 lines
1.5 KiB
Go
59 lines
1.5 KiB
Go
package semver
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
//nolint:lll // regex is as it is
|
|
var (
|
|
ErrNotASemver = errors.New("the given version does not match the semantic versioning scheme")
|
|
semVerRegex = regexp.MustCompile(`^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`)
|
|
)
|
|
|
|
func IsValid(version string) bool {
|
|
return semVerRegex.MatchString(strings.TrimPrefix(version, "v"))
|
|
}
|
|
|
|
func ParseVersion(version string) (v Version, err error) {
|
|
if !IsValid(version) {
|
|
return Version{}, fmt.Errorf("%w: %s", ErrNotASemver, version)
|
|
}
|
|
|
|
submatches := semVerRegex.FindStringSubmatch(strings.TrimPrefix(version, "v"))
|
|
|
|
for i, name := range semVerRegex.SubexpNames() {
|
|
switch name {
|
|
case "major":
|
|
if v.Major, err = strconv.Atoi(submatches[i]); err != nil {
|
|
return Version{}, err
|
|
}
|
|
case "minor":
|
|
if v.Minor, err = strconv.Atoi(submatches[i]); err != nil {
|
|
return Version{}, err
|
|
}
|
|
case "patch":
|
|
if v.Patch, err = strconv.Atoi(submatches[i]); err != nil {
|
|
return Version{}, err
|
|
}
|
|
case "prerelease":
|
|
v.Prerelease = submatches[i]
|
|
case "buildmetadata":
|
|
v.BuildMetadata = submatches[i]
|
|
}
|
|
}
|
|
|
|
return v, nil
|
|
}
|
|
|
|
type Version struct {
|
|
Prerelease string `cty:"prerelease"`
|
|
BuildMetadata string `cty:"build_metadata"`
|
|
Major int `cty:"major"`
|
|
Minor int `cty:"minor"`
|
|
Patch int `cty:"patch"`
|
|
}
|