-
Notifications
You must be signed in to change notification settings - Fork 39
/
semver.go
123 lines (109 loc) · 2.87 KB
/
semver.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package semver
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"regexp"
"strconv"
"strings"
)
const pattern = `^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$`
var ParseError = errors.New("provided string cannot be parsed into semver")
type Comparsion int
const (
CompareEqual Comparsion = iota
CompareOldMajor
CompareNewMajor
CompareOldMinor
CompareNewMinor
CompareOldPatch
CompareNewPatch
)
type Version struct {
major, minor, patch int
}
// Parse parses the the provided string into a semver representation.
func Parse(s string) (Version, error) {
re, err := regexp.Compile(pattern)
if err != nil {
return Version{}, fmt.Errorf("compiling regex: %w", err)
}
if !re.MatchString(s) {
return Version{}, ParseError
}
split := strings.Split(s[1:], ".")
ver := Version{}
ver.major, err = strconv.Atoi(split[0])
if err != nil {
return Version{}, fmt.Errorf("parsing Major to int: %w", err)
}
ver.minor, err = strconv.Atoi(split[1])
if err != nil {
return Version{}, fmt.Errorf("parsing Minor to int: %w", err)
}
ver.patch, err = strconv.Atoi(split[2])
if err != nil {
return Version{}, fmt.Errorf("parsing Patch to int: %w", err)
}
return ver, nil
}
// String returns a string representation of the semver.
func (sv Version) String() string {
return fmt.Sprintf("v%d.%d.%d", sv.major, sv.minor, sv.patch)
}
// Compare compares the semver against the provided oracle statement.
// Return -1 if the semver is less than the oracle statement, 1 if
// the oracle statement is larger than the semver and 0 if they are equal.
func (sv Version) Compare(oracle Version) Comparsion {
switch {
case sv.major < oracle.major:
return CompareOldMajor
case sv.major > oracle.major:
return CompareNewMajor
case sv.minor < oracle.minor:
return CompareOldMinor
case sv.minor > oracle.minor:
return CompareNewMinor
case sv.patch < oracle.patch:
return CompareOldPatch
case sv.patch > oracle.patch:
return CompareNewPatch
default:
return CompareEqual
}
}
func (sv Version) Major() int {
return sv.major
}
func (sv Version) Minor() int {
return sv.minor
}
func (sv Version) Patch() int {
return sv.patch
}
func GetPortalLatest() (Version, error) {
r, err := http.Get("https://api.github.com/repos/SpatiumPortae/portal/releases?per_page=1")
if err != nil {
return Version{}, fmt.Errorf("fetching the latest tag from github: %w", err)
}
type tag struct {
Name string `json:"tag_name"`
}
var tags []tag
if err := json.NewDecoder(r.Body).Decode(&tags); err != nil {
return Version{}, fmt.Errorf("decoding response from github: %w", err)
}
if len(tags) < 1 {
return Version{}, fmt.Errorf("no tags returned from github: %w", err)
}
vers := make([]Version, len(tags))
for i := range tags {
v, err := Parse(tags[i].Name)
if err != nil {
return Version{}, fmt.Errorf("unable to parse tag to semver: %w", err)
}
vers[i] = v
}
return vers[0], nil
}