@@ -15,36 +15,42 @@ import (
1515 "golang.org/x/mod/semver"
1616)
1717
18- // Confirm that all specified versions of a package exist in crates.io.
19- func versionsExistInCrates (pkg string , versions []string ) error {
20- packageInstanceURL := fmt .Sprintf ("%s/%s" , EcosystemBaseURLs ["crates.io" ], pkg )
21-
18+ func fetchPackageData (packageInstanceURL string ) ([]byte , error ) {
2219 resp , err := faulttolerant .Get (packageInstanceURL )
2320 if err != nil {
24- return fmt .Errorf ("unable to validate package: %v" , err )
21+ return nil , fmt .Errorf ("unable to validate package: %v" , err )
2522 }
2623 defer resp .Body .Close ()
2724 if resp .StatusCode != http .StatusOK {
28- return fmt .Errorf ("unable to validate package: %q for %s" , resp .Status , packageInstanceURL )
25+ return nil , fmt .Errorf ("unable to validate package: %q for %s" , resp .Status , packageInstanceURL )
2926 }
3027
31- // Parse the known versions from the JSON.
32- respJSON , err := io .ReadAll (resp .Body )
28+ return io .ReadAll (resp .Body )
29+ }
30+
31+ // Confirm that all specified versions of a package exist in a registry
32+ func versionsExistInGeneric (
33+ pkg string ,
34+ versions []string ,
35+ eco string ,
36+ packageInstanceURL string ,
37+ versionsPath string ,
38+ ) error {
39+ respJSON , err := fetchPackageData (packageInstanceURL )
3340 if err != nil {
3441 return fmt .Errorf ("unable to retrieve JSON for %q: %v" , pkg , err )
3542 }
43+
3644 // Fetch all known versions of package.
3745 versionsInRepository := []string {}
38- releases := gjson .GetBytes (respJSON , "versions" )
39- releases .ForEach (func (key , value gjson.Result ) bool {
40- versionsInRepository = append (versionsInRepository , value .Get ("num" ).String ())
41- return true // keep iterating.
42- })
46+ for _ , result := range gjson .GetBytes (respJSON , versionsPath ).Array () {
47+ versionsInRepository = append (versionsInRepository , result .String ())
48+ }
4349 // Determine which referenced versions are missing.
4450 versionsMissing := []string {}
4551 for _ , versionToCheckFor := range versions {
4652 versionFound := false
47- vc , err := semantic .Parse (versionToCheckFor , "crates.io" )
53+ vc , err := semantic .Parse (versionToCheckFor , eco )
4854 if err != nil {
4955 versionsMissing = append (versionsMissing , versionToCheckFor )
5056 continue
@@ -61,12 +67,24 @@ func versionsExistInCrates(pkg string, versions []string) error {
6167 versionsMissing = append (versionsMissing , versionToCheckFor )
6268 }
6369 if len (versionsMissing ) > 0 {
64- return & MissingVersionsError {Package : pkg , Ecosystem : "crates.io" , Missing : versionsMissing , Known : versionsInRepository }
70+ return & MissingVersionsError {Package : pkg , Ecosystem : eco , Missing : versionsMissing , Known : versionsInRepository }
6571 }
6672
6773 return nil
6874}
6975
76+ // Confirm that all specified versions of a package exist in crates.io.
77+ func versionsExistInCrates (pkg string , versions []string ) error {
78+ packageInstanceURL := fmt .Sprintf ("%s/%s" , EcosystemBaseURLs ["crates.io" ], pkg )
79+
80+ return versionsExistInGeneric (
81+ pkg , versions ,
82+ "crates.io" ,
83+ packageInstanceURL ,
84+ "versions.#.num" ,
85+ )
86+ }
87+
7088// Confirm that all specified versions of a package exist in Go.
7189func versionsExistInGo (pkg string , versions []string ) error {
7290 if pkg == "stdlib" || pkg == "toolchain" {
@@ -81,18 +99,7 @@ func versionsExistInGo(pkg string, versions []string) error {
8199
82100 packageInstanceURL := fmt .Sprintf ("%s/%s/@v/list" , EcosystemBaseURLs ["Go" ], pkg )
83101
84- // This 404's for non-existent packages.
85- resp , err := faulttolerant .Get (packageInstanceURL )
86- if err != nil {
87- return fmt .Errorf ("unable to validate package: %v" , err )
88- }
89- defer resp .Body .Close ()
90- if resp .StatusCode != http .StatusOK {
91- return fmt .Errorf ("unable to validate package: %q for %s" , resp .Status , packageInstanceURL )
92- }
93-
94- // Load the known versions from the list provided.
95- respBytes , err := io .ReadAll (resp .Body )
102+ respBytes , err := fetchPackageData (packageInstanceURL )
96103 if err != nil {
97104 return fmt .Errorf ("unable to retrieve versions for for %q: %v" , pkg , err )
98105 }
@@ -185,104 +192,24 @@ func goVersionsExist(versions []string) error {
185192func versionsExistInNpm (pkg string , versions []string ) error {
186193 packageInstanceURL := fmt .Sprintf ("%s/%s" , EcosystemBaseURLs ["npm" ], pkg )
187194
188- resp , err := faulttolerant .Get (packageInstanceURL )
189- if err != nil {
190- return fmt .Errorf ("unable to validate package: %v" , err )
191- }
192- defer resp .Body .Close ()
193- if resp .StatusCode != http .StatusOK {
194- return fmt .Errorf ("unable to validate package: %q for %s" , resp .Status , packageInstanceURL )
195- }
196-
197- // Parse the known versions from the JSON.
198- respJSON , err := io .ReadAll (resp .Body )
199- if err != nil {
200- return fmt .Errorf ("unable to retrieve JSON for %q: %v" , pkg , err )
201- }
202- // Fetch all known versions of package.
203- versionsInRepository := []string {}
204- releases := gjson .GetBytes (respJSON , "versions.@keys" )
205- releases .ForEach (func (key , value gjson.Result ) bool {
206- versionsInRepository = append (versionsInRepository , value .String ())
207- return true // keep iterating.
208- })
209- // Determine which referenced versions are missing.
210- versionsMissing := []string {}
211- for _ , versionToCheckFor := range versions {
212- versionFound := false
213- vc , err := semantic .Parse (versionToCheckFor , "npm" )
214- if err != nil {
215- versionsMissing = append (versionsMissing , versionToCheckFor )
216- continue
217- }
218- for _ , pkgversion := range versionsInRepository {
219- if r , err := vc .CompareStr (pkgversion ); r == 0 && err == nil {
220- versionFound = true
221- break
222- }
223- }
224- if versionFound {
225- continue
226- }
227- versionsMissing = append (versionsMissing , versionToCheckFor )
228- }
229- if len (versionsMissing ) > 0 {
230- return & MissingVersionsError {Package : pkg , Ecosystem : "npm" , Missing : versionsMissing , Known : versionsInRepository }
231- }
232-
233- return nil
195+ return versionsExistInGeneric (
196+ pkg , versions ,
197+ "npm" ,
198+ packageInstanceURL ,
199+ "versions.@keys" ,
200+ )
234201}
235202
236203// Confirm that all specified versions of a package exist in Packagist.
237204func versionsExistInPackagist (pkg string , versions []string ) error {
238205 packageInstanceURL := fmt .Sprintf ("%s/%s.json" , EcosystemBaseURLs ["Packagist" ], pkg )
239206
240- resp , err := faulttolerant .Get (packageInstanceURL )
241- if err != nil {
242- return fmt .Errorf ("unable to validate package: %v" , err )
243- }
244- defer resp .Body .Close ()
245- if resp .StatusCode != http .StatusOK {
246- return fmt .Errorf ("unable to validate package: %q for %s" , resp .Status , packageInstanceURL )
247- }
248-
249- // Parse the known versions from the JSON.
250- respJSON , err := io .ReadAll (resp .Body )
251- if err != nil {
252- return fmt .Errorf ("unable to retrieve JSON for %q: %v" , pkg , err )
253- }
254- // Fetch all known versions of package.
255- versionsInRepository := []string {}
256- releases := gjson .GetBytes (respJSON , fmt .Sprintf ("packages.%s" , pkg ))
257- releases .ForEach (func (key , value gjson.Result ) bool {
258- versionsInRepository = append (versionsInRepository , value .Get ("version" ).String ())
259- return true // keep iterating.
260- })
261- // Determine which referenced versions are missing.
262- versionsMissing := []string {}
263- for _ , versionToCheckFor := range versions {
264- versionFound := false
265- vc , err := semantic .Parse (versionToCheckFor , "Packagist" )
266- if err != nil {
267- versionsMissing = append (versionsMissing , versionToCheckFor )
268- continue
269- }
270- for _ , pkgversion := range versionsInRepository {
271- if r , err := vc .CompareStr (pkgversion ); r == 0 && err == nil {
272- versionFound = true
273- break
274- }
275- }
276- if versionFound {
277- continue
278- }
279- versionsMissing = append (versionsMissing , versionToCheckFor )
280- }
281- if len (versionsMissing ) > 0 {
282- return & MissingVersionsError {Package : pkg , Ecosystem : "Packagist" , Missing : versionsMissing , Known : versionsInRepository }
283- }
284-
285- return nil
207+ return versionsExistInGeneric (
208+ pkg , versions ,
209+ "Packagist" ,
210+ packageInstanceURL ,
211+ fmt .Sprintf ("packages.%s.#.version" , pkg ),
212+ )
286213}
287214
288215// Confirm that all specified versions of a package exist in PyPI.
@@ -292,103 +219,22 @@ func versionsExistInPyPI(pkg string, versions []string) error {
292219 pkgNormalized := strings .ToLower (pythonNormalizationRegex .ReplaceAllString (pkg , "-" ))
293220 packageInstanceURL := fmt .Sprintf ("%s/%s/json" , EcosystemBaseURLs ["PyPI" ], pkgNormalized )
294221
295- // This 404's for non-existent packages.
296- resp , err := faulttolerant .Get (packageInstanceURL )
297- if err != nil {
298- return fmt .Errorf ("unable to validate package: %v" , err )
299- }
300- defer resp .Body .Close ()
301- if resp .StatusCode != http .StatusOK {
302- return fmt .Errorf ("unable to validate package: %q for %s" , resp .Status , packageInstanceURL )
303- }
304-
305- // Parse the known versions from the JSON.
306- respJSON , err := io .ReadAll (resp .Body )
307- if err != nil {
308- return fmt .Errorf ("unable to retrieve JSON for %q: %v" , pkg , err )
309- }
310- // Fetch all known versions of package.
311- versionsInPyPy := []string {}
312- releases := gjson .GetBytes (respJSON , "releases.@keys" )
313- releases .ForEach (func (key , value gjson.Result ) bool {
314- versionsInPyPy = append (versionsInPyPy , value .String ())
315- return true // keep iterating.
316- })
317- // Determine which referenced versions are missing.
318- versionsMissing := []string {}
319- for _ , versionToCheckFor := range versions {
320- versionFound := false
321- vc , err := semantic .Parse (versionToCheckFor , "PyPI" )
322- if err != nil {
323- versionsMissing = append (versionsMissing , versionToCheckFor )
324- continue
325- }
326- for _ , pkgversion := range versionsInPyPy {
327- if r , err := vc .CompareStr (pkgversion ); r == 0 && err == nil {
328- versionFound = true
329- break
330- }
331- }
332- if versionFound {
333- continue
334- }
335- versionsMissing = append (versionsMissing , versionToCheckFor )
336- }
337- if len (versionsMissing ) > 0 {
338- return & MissingVersionsError {Package : pkg , Ecosystem : "PyPI" , Missing : versionsMissing , Known : versionsInPyPy }
339- }
340-
341- return nil
222+ return versionsExistInGeneric (
223+ pkg , versions ,
224+ "PyPI" ,
225+ packageInstanceURL ,
226+ "releases.@keys" ,
227+ )
342228}
343229
344230// Confirm that all specified versions of a package exist in RubyGems.
345231func versionsExistInRubyGems (pkg string , versions []string ) error {
346232 packageInstanceURL := fmt .Sprintf ("%s/versions/%s.json" , EcosystemBaseURLs ["RubyGems" ], pkg )
347233
348- resp , err := faulttolerant .Get (packageInstanceURL )
349- if err != nil {
350- return fmt .Errorf ("unable to validate package: %v" , err )
351- }
352- defer resp .Body .Close ()
353- if resp .StatusCode != http .StatusOK {
354- return fmt .Errorf ("unable to validate package: %q for %s" , resp .Status , packageInstanceURL )
355- }
356-
357- // Parse the known versions from the JSON.
358- respJSON , err := io .ReadAll (resp .Body )
359- if err != nil {
360- return fmt .Errorf ("unable to retrieve JSON for %q: %v" , pkg , err )
361- }
362- // Fetch all known versions of package.
363- versionsInRepository := []string {}
364- releases := gjson .GetBytes (respJSON , "@this" )
365- releases .ForEach (func (key , value gjson.Result ) bool {
366- versionsInRepository = append (versionsInRepository , value .Get ("number" ).String ())
367- return true // keep iterating.
368- })
369- // Determine which referenced versions are missing.
370- versionsMissing := []string {}
371- for _ , versionToCheckFor := range versions {
372- versionFound := false
373- vc , err := semantic .Parse (versionToCheckFor , "RubyGems" )
374- if err != nil {
375- versionsMissing = append (versionsMissing , versionToCheckFor )
376- continue
377- }
378- for _ , pkgversion := range versionsInRepository {
379- if r , err := vc .CompareStr (pkgversion ); r == 0 && err == nil {
380- versionFound = true
381- break
382- }
383- }
384- if versionFound {
385- continue
386- }
387- versionsMissing = append (versionsMissing , versionToCheckFor )
388- }
389- if len (versionsMissing ) > 0 {
390- return & MissingVersionsError {Package : pkg , Ecosystem : "RubyGems" , Missing : versionsMissing , Known : versionsInRepository }
391- }
392-
393- return nil
234+ return versionsExistInGeneric (
235+ pkg , versions ,
236+ "RubyGems" ,
237+ packageInstanceURL ,
238+ "@this.#.number" ,
239+ )
394240}
0 commit comments