Skip to content

Commit 4e38d03

Browse files
committed
refactor: deduplicate "versions exist" functions
Signed-off-by: Gareth Jones <[email protected]>
1 parent c463400 commit 4e38d03

File tree

1 file changed

+75
-139
lines changed

1 file changed

+75
-139
lines changed

tools/osv-linter/internal/pkgchecker/version_check.go

Lines changed: 75 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,63 @@ import (
1515
"golang.org/x/mod/semver"
1616
)
1717

18+
// Confirm that all specified versions of a package exist in a registry
19+
func versionsExistInGeneric(
20+
pkg string,
21+
versions []string,
22+
eco string,
23+
packageInstanceURL string,
24+
releasesPath string,
25+
versionsPath string,
26+
) error {
27+
resp, err := faulttolerant.Get(packageInstanceURL)
28+
if err != nil {
29+
return fmt.Errorf("unable to validate package: %v", err)
30+
}
31+
defer resp.Body.Close()
32+
if resp.StatusCode != http.StatusOK {
33+
return fmt.Errorf("unable to validate package: %q for %s", resp.Status, packageInstanceURL)
34+
}
35+
36+
// Parse the known versions from the JSON.
37+
respJSON, err := io.ReadAll(resp.Body)
38+
if err != nil {
39+
return fmt.Errorf("unable to retrieve JSON for %q: %v", pkg, err)
40+
}
41+
// Fetch all known versions of package.
42+
versionsInRepository := []string{}
43+
releases := gjson.GetBytes(respJSON, releasesPath)
44+
releases.ForEach(func(key, value gjson.Result) bool {
45+
versionsInRepository = append(versionsInRepository, value.Get(versionsPath).String())
46+
return true // keep iterating.
47+
})
48+
// Determine which referenced versions are missing.
49+
versionsMissing := []string{}
50+
for _, versionToCheckFor := range versions {
51+
versionFound := false
52+
vc, err := semantic.Parse(versionToCheckFor, "npm")
53+
if err != nil {
54+
versionsMissing = append(versionsMissing, versionToCheckFor)
55+
continue
56+
}
57+
for _, pkgversion := range versionsInRepository {
58+
if r, err := vc.CompareStr(pkgversion); r == 0 && err == nil {
59+
versionFound = true
60+
break
61+
}
62+
}
63+
if versionFound {
64+
continue
65+
}
66+
versionsMissing = append(versionsMissing, versionToCheckFor)
67+
}
68+
if len(versionsMissing) > 0 {
69+
return &MissingVersionsError{Package: pkg, Ecosystem: eco, Missing: versionsMissing, Known: versionsInRepository}
70+
}
71+
72+
return nil
73+
}
74+
1875
// Confirm that all specified versions of a package exist in Go.
1976
func versionsExistInGo(pkg string, versions []string) error {
2077
if pkg == "stdlib" || pkg == "toolchain" {
@@ -133,52 +190,12 @@ func goVersionsExist(versions []string) error {
133190
func versionsExistInPackagist(pkg string, versions []string) error {
134191
packageInstanceURL := fmt.Sprintf("%s/%s.json", EcosystemBaseURLs["Packagist"], pkg)
135192

136-
resp, err := faulttolerant.Get(packageInstanceURL)
137-
if err != nil {
138-
return fmt.Errorf("unable to validate package: %v", err)
139-
}
140-
defer resp.Body.Close()
141-
if resp.StatusCode != http.StatusOK {
142-
return fmt.Errorf("unable to validate package: %q for %s", resp.Status, packageInstanceURL)
143-
}
144-
145-
// Parse the known versions from the JSON.
146-
respJSON, err := io.ReadAll(resp.Body)
147-
if err != nil {
148-
return fmt.Errorf("unable to retrieve JSON for %q: %v", pkg, err)
149-
}
150-
// Fetch all known versions of package.
151-
versionsInRepository := []string{}
152-
releases := gjson.GetBytes(respJSON, fmt.Sprintf("packages.%s", pkg))
153-
releases.ForEach(func(key, value gjson.Result) bool {
154-
versionsInRepository = append(versionsInRepository, value.Get("version").String())
155-
return true // keep iterating.
156-
})
157-
// Determine which referenced versions are missing.
158-
versionsMissing := []string{}
159-
for _, versionToCheckFor := range versions {
160-
versionFound := false
161-
vc, err := semantic.Parse(versionToCheckFor, "Packagist")
162-
if err != nil {
163-
versionsMissing = append(versionsMissing, versionToCheckFor)
164-
continue
165-
}
166-
for _, pkgversion := range versionsInRepository {
167-
if r, err := vc.CompareStr(pkgversion); r == 0 && err == nil {
168-
versionFound = true
169-
break
170-
}
171-
}
172-
if versionFound {
173-
continue
174-
}
175-
versionsMissing = append(versionsMissing, versionToCheckFor)
176-
}
177-
if len(versionsMissing) > 0 {
178-
return &MissingVersionsError{Package: pkg, Ecosystem: "Packagist", Missing: versionsMissing, Known: versionsInRepository}
179-
}
180-
181-
return nil
193+
return versionsExistInGeneric(
194+
pkg, versions,
195+
"Packagist",
196+
packageInstanceURL,
197+
fmt.Sprintf("packages.%s", pkg), "version",
198+
)
182199
}
183200

184201
// Confirm that all specified versions of a package exist in PyPI.
@@ -188,103 +205,22 @@ func versionsExistInPyPI(pkg string, versions []string) error {
188205
pkgNormalized := strings.ToLower(pythonNormalizationRegex.ReplaceAllString(pkg, "-"))
189206
packageInstanceURL := fmt.Sprintf("%s/%s/json", EcosystemBaseURLs["PyPI"], pkgNormalized)
190207

191-
// This 404's for non-existent packages.
192-
resp, err := faulttolerant.Get(packageInstanceURL)
193-
if err != nil {
194-
return fmt.Errorf("unable to validate package: %v", err)
195-
}
196-
defer resp.Body.Close()
197-
if resp.StatusCode != http.StatusOK {
198-
return fmt.Errorf("unable to validate package: %q for %s", resp.Status, packageInstanceURL)
199-
}
200-
201-
// Parse the known versions from the JSON.
202-
respJSON, err := io.ReadAll(resp.Body)
203-
if err != nil {
204-
return fmt.Errorf("unable to retrieve JSON for %q: %v", pkg, err)
205-
}
206-
// Fetch all known versions of package.
207-
versionsInPyPy := []string{}
208-
releases := gjson.GetBytes(respJSON, "releases.@keys")
209-
releases.ForEach(func(key, value gjson.Result) bool {
210-
versionsInPyPy = append(versionsInPyPy, value.String())
211-
return true // keep iterating.
212-
})
213-
// Determine which referenced versions are missing.
214-
versionsMissing := []string{}
215-
for _, versionToCheckFor := range versions {
216-
versionFound := false
217-
vc, err := semantic.Parse(versionToCheckFor, "PyPI")
218-
if err != nil {
219-
versionsMissing = append(versionsMissing, versionToCheckFor)
220-
continue
221-
}
222-
for _, pkgversion := range versionsInPyPy {
223-
if r, err := vc.CompareStr(pkgversion); r == 0 && err == nil {
224-
versionFound = true
225-
break
226-
}
227-
}
228-
if versionFound {
229-
continue
230-
}
231-
versionsMissing = append(versionsMissing, versionToCheckFor)
232-
}
233-
if len(versionsMissing) > 0 {
234-
return &MissingVersionsError{Package: pkg, Ecosystem: "PyPI", Missing: versionsMissing, Known: versionsInPyPy}
235-
}
236-
237-
return nil
208+
return versionsExistInGeneric(
209+
pkg, versions,
210+
"PyPI",
211+
packageInstanceURL,
212+
"releases.@keys", "@this",
213+
)
238214
}
239215

240216
// Confirm that all specified versions of a package exist in RubyGems.
241217
func versionsExistInRubyGems(pkg string, versions []string) error {
242218
packageInstanceURL := fmt.Sprintf("%s/versions/%s.json", EcosystemBaseURLs["RubyGems"], pkg)
243219

244-
resp, err := faulttolerant.Get(packageInstanceURL)
245-
if err != nil {
246-
return fmt.Errorf("unable to validate package: %v", err)
247-
}
248-
defer resp.Body.Close()
249-
if resp.StatusCode != http.StatusOK {
250-
return fmt.Errorf("unable to validate package: %q for %s", resp.Status, packageInstanceURL)
251-
}
252-
253-
// Parse the known versions from the JSON.
254-
respJSON, err := io.ReadAll(resp.Body)
255-
if err != nil {
256-
return fmt.Errorf("unable to retrieve JSON for %q: %v", pkg, err)
257-
}
258-
// Fetch all known versions of package.
259-
versionsInRepository := []string{}
260-
releases := gjson.GetBytes(respJSON, "@this")
261-
releases.ForEach(func(key, value gjson.Result) bool {
262-
versionsInRepository = append(versionsInRepository, value.Get("number").String())
263-
return true // keep iterating.
264-
})
265-
// Determine which referenced versions are missing.
266-
versionsMissing := []string{}
267-
for _, versionToCheckFor := range versions {
268-
versionFound := false
269-
vc, err := semantic.Parse(versionToCheckFor, "RubyGems")
270-
if err != nil {
271-
versionsMissing = append(versionsMissing, versionToCheckFor)
272-
continue
273-
}
274-
for _, pkgversion := range versionsInRepository {
275-
if r, err := vc.CompareStr(pkgversion); r == 0 && err == nil {
276-
versionFound = true
277-
break
278-
}
279-
}
280-
if versionFound {
281-
continue
282-
}
283-
versionsMissing = append(versionsMissing, versionToCheckFor)
284-
}
285-
if len(versionsMissing) > 0 {
286-
return &MissingVersionsError{Package: pkg, Ecosystem: "RubyGems", Missing: versionsMissing, Known: versionsInRepository}
287-
}
288-
289-
return nil
220+
return versionsExistInGeneric(
221+
pkg, versions,
222+
"RubyGems",
223+
packageInstanceURL,
224+
"@this", "number",
225+
)
290226
}

0 commit comments

Comments
 (0)