forked from concourse/github-release-resource
-
Notifications
You must be signed in to change notification settings - Fork 0
/
check_command.go
199 lines (166 loc) · 5.19 KB
/
check_command.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package resource
import (
"sort"
"github.com/Masterminds/semver"
"github.com/cppforlife/go-semi-semantic/version"
"github.com/google/go-github/v39/github"
)
type CheckCommand struct {
github GitHub
}
func NewCheckCommand(github GitHub) *CheckCommand {
return &CheckCommand{
github: github,
}
}
func SortByVersion(releases []*github.RepositoryRelease, versionParser *versionParser) {
sort.Slice(releases, func(i, j int) bool {
first, err := version.NewVersionFromString(versionParser.parse(*releases[i].TagName))
if err != nil {
return true
}
second, err := version.NewVersionFromString(versionParser.parse(*releases[j].TagName))
if err != nil {
return false
}
return first.IsLt(second)
})
}
func SortByTimestamp(releases []*github.RepositoryRelease) {
sort.Slice(releases, func(i, j int) bool {
a := releases[i]
b := releases[j]
return getTimestamp(a).Before(getTimestamp(b))
})
}
func (c *CheckCommand) Run(request CheckRequest) ([]Version, error) {
releases, err := c.github.ListReleases()
if err != nil {
return []Version{}, err
}
if len(releases) == 0 {
return []Version{}, nil
}
orderByTime := false
if request.Source.OrderBy == "time" {
orderByTime = true
}
var filteredReleases []*github.RepositoryRelease
versionParser, err := newVersionParser(request.Source.TagFilter)
if err != nil {
return []Version{}, err
}
var constraint *semver.Constraints
if request.Source.SemverConstraint != "" {
constraint, err = semver.NewConstraint(request.Source.SemverConstraint)
if err != nil {
return []Version{}, err
}
}
for _, release := range releases {
if request.Source.Drafts != *release.Draft {
continue
}
// Should we skip this release
// a- prerelease condition dont match our source config
// b- release condition match prerealse in github since github has true/false to describe release/prerelase
if request.Source.PreRelease != *release.Prerelease && request.Source.Release == *release.Prerelease {
continue
}
if constraint != nil {
if release.TagName == nil {
// Release has no tag, so certainly isn't a valid semver
continue
}
version, err := semver.NewVersion(versionParser.parse(*release.TagName))
if err != nil {
// Release is not tagged with a valid semver
continue
}
if !constraint.Check(version) {
// Valid semver, but does not satisfy constraint
continue
}
}
if orderByTime {
// We won't do anything with the tags, so just make sure the filter matches the tag.
var tag string
if release.TagName != nil {
tag = *release.TagName
}
if !versionParser.re.MatchString(tag) {
continue
}
// We don't expect any releases with a missing (zero) timestamp,
// but we skip those just in case, since the data type includes them
if getTimestamp(release).IsZero() {
continue
}
} else {
// We will sort by versions parsed out of tags, so make sure we parse successfully.
if release.TagName == nil {
continue
}
if _, err := version.NewVersionFromString(versionParser.parse(*release.TagName)); err != nil {
continue
}
}
filteredReleases = append(filteredReleases, release)
}
// If there are no valid releases, output an empty list.
if len(filteredReleases) == 0 {
return []Version{}, nil
}
// Sort releases by time or by version
if orderByTime {
SortByTimestamp(filteredReleases)
} else {
SortByVersion(filteredReleases, &versionParser)
}
// If request has no version, output the latest release
latestRelease := filteredReleases[len(filteredReleases)-1]
if (request.Version == Version{}) {
return []Version{
versionFromRelease(latestRelease),
}, nil
}
// Find first release equal or later than the current version
var firstIncludedReleaseIndex int = -1
if orderByTime {
// Only search if request has a timestamp
if !request.Version.Timestamp.IsZero() {
firstIncludedReleaseIndex = sort.Search(len(filteredReleases), func(i int) bool {
release := filteredReleases[i]
return !getTimestamp(release).Before(request.Version.Timestamp)
})
}
} else {
requestVersion, err := version.NewVersionFromString(versionParser.parse(request.Version.Tag))
if err == nil {
firstIncludedReleaseIndex = sort.Search(len(filteredReleases), func(i int) bool {
release := filteredReleases[i]
releaseVersion, err := version.NewVersionFromString(versionParser.parse(*release.TagName))
if err != nil {
return false
}
return !releaseVersion.IsLt(requestVersion)
})
}
}
// Output all releases equal or later than the current version,
// or just the latest release if there are no such releases.
outputVersions := []Version{}
if firstIncludedReleaseIndex >= 0 && firstIncludedReleaseIndex < len(filteredReleases) {
// Found first release >= current version, so output this and all the following release versions
for i := firstIncludedReleaseIndex; i < len(filteredReleases); i++ {
outputVersions = append(outputVersions, versionFromRelease(filteredReleases[i]))
}
} else {
// No release >= current version, so output the latest release version
outputVersions = append(
outputVersions,
versionFromRelease(filteredReleases[len(filteredReleases)-1]),
)
}
return outputVersions, nil
}