Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use correct latest crates.io version #9454

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion services/crates/crates-base.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Joi from 'joi'
import { nonNegativeInteger } from '../validators.js'
import { BaseJsonService } from '../index.js'
import { BaseJsonService, InvalidParameter } from '../index.js'

const keywords = ['Rust']

Expand Down Expand Up @@ -47,6 +47,45 @@ class BaseCratesService extends BaseJsonService {
: `https://crates.io/api/v1/crates/${crate}?include=versions,downloads`
return this._requestJson({ schema, url })
}

/** get the default version for a crate using the same logic as crates.io
* this should be kept in sync with the crates.io implementation in
* https://github.com/rust-lang/crates.io/blob/20bbac9f5521cb4888ef63f8464fddb28fd973f5/app/models/crate.js#L34-L41
*
* @param {object} crate the `json.crate` response from crates.io
* @returns {string} the default version string, or throws an error
*/
static defaultVersion(crate) {
if (crate) {
if (crate.max_stable_version) {
return crate.max_stable_version
}
if (crate.max_version && crate.max_version !== '0.0.0') {
return crate.max_version
}
}
throw new InvalidParameter({
prettyMessage:
'default version not found, possibly all versions were yanked',
})
}

/** get the default version object from the `json.versions` array.
*
* @param {object} crate the `json.crate` response from crates.io
* @param {object[]} versions the `json.versions` response from crates.io
* @returns {object} the default version object, or throws an error if not found
*/
static defaultVersionObject(crate, versions) {
const lastVerNum = BaseCratesService.defaultVersion(crate)
const version = versions.find(ver => ver.num === lastVerNum)
if (!version) {
throw new InvalidParameter({
prettyMessage: 'version object not found in the versions array',
})
}
return version
}
}

export { BaseCratesService, keywords }
9 changes: 8 additions & 1 deletion services/crates/crates-downloads.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,14 @@ export default class CratesDownloads extends BaseCratesService {
transform({ variant, json }) {
switch (variant) {
case 'dv':
return json.crate ? json.versions[0].downloads : json.version.downloads
if (json.crate) {
return BaseCratesService.defaultVersionObject(
json.crate,
json.versions,
).downloads
} else {
return json.version.downloads
}
case 'dr':
return json.crate.recent_downloads || 0
default:
Expand Down
7 changes: 5 additions & 2 deletions services/crates/crates-license.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,17 @@ export default class CratesLicense extends BaseCratesService {
return { message }
}

static transform({ errors, version, versions }) {
static transform({ errors, version, crate, versions }) {
// crates.io returns a 200 response with an errors object in
// error scenarios, e.g. https://crates.io/api/v1/crates/libc/0.1
if (errors) {
throw new InvalidResponse({ prettyMessage: errors[0].detail })
}

const license = version ? version.license : versions[0].license
const license = version
? version.license
: BaseCratesService.defaultVersionObject(crate, versions).license

if (!license) {
throw new InvalidResponse({ prettyMessage: 'invalid null license' })
}
Expand Down
13 changes: 10 additions & 3 deletions services/crates/crates-license.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import CratesLicense from './crates-license.service.js'
describe('CratesLicense', function () {
test(CratesLicense.transform, () => {
given({
crate: { max_stable_version: '1.0.0', max_version: '1.0.0' },
version: { num: '1.0.0', license: 'MIT' },
versions: [{ license: 'MIT/Apache 2.0' }],
versions: [{ num: '1.0.0', license: 'MIT/Apache 2.0' }],
}).expect({ license: 'MIT' })
given({
versions: [{ license: 'MIT/Apache 2.0' }],
crate: { max_stable_version: '1.0.0', max_version: '1.0.0' },
versions: [{ num: '1.0.0', license: 'MIT/Apache 2.0' }],
}).expect({ license: 'MIT/Apache 2.0' })
})

Expand All @@ -31,7 +33,12 @@ describe('CratesLicense', function () {
})

it('throws InvalidResponse on null license with latest version', function () {
expect(() => CratesLicense.transform({ versions: [{ license: null }] }))
expect(() =>
CratesLicense.transform({
crate: { max_stable_version: '1.0.0', max_version: '1.0.0' },
versions: [{ num: '1.0.0', license: null }],
}),
)
.to.throw(InvalidResponse)
.with.property('prettyMessage', 'invalid null license')
})
Expand Down
4 changes: 1 addition & 3 deletions services/crates/crates-version.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ export default class CratesVersion extends BaseCratesService {
if (json.errors) {
throw new InvalidResponse({ prettyMessage: json.errors[0].detail })
}
return json.crate.max_stable_version
? json.crate.max_stable_version
: json.crate.max_version
return BaseCratesService.defaultVersion(json.crate)
}

async handle({ crate }) {
Expand Down
Loading