feat: cargo datasource (#2993)

This commit is contained in:
Nikita Chashchinskii 2018-12-26 07:39:38 +03:00 committed by Rhys Arkins
parent 8054ee58b3
commit 71ee394aba
6 changed files with 382 additions and 2 deletions

View file

@ -0,0 +1,56 @@
const got = require('got');
module.exports = {
getPkgReleases,
};
async function getPkgReleases(purl) {
const { fullname: name } = purl;
const crateUrl = `https://crates.io/api/v1/crates/${name}`;
try {
const res = (await got(crateUrl, {
json: true,
})).body;
if (!(res && res.crate && res.crate.name)) {
logger.warn({ dependency: name }, `Received invalid crate data`);
return null;
}
const result = {
releases: [],
};
if (res.versions) {
result.releases = res.versions.map(version => ({
version: version.num,
}));
}
result.sourceUrl = res.crate.repository;
result.homepage = res.crate.homepage;
return result;
} catch (err) {
if (err.statusCode === 404 || err.code === 'ENOTFOUND') {
logger.info({ dependency: name }, `Dependency lookup failure: not found`);
logger.debug(
{
err,
},
'Crate lookup error'
);
return null;
}
if (
err.statusCode === 429 ||
(err.statusCode > 500 && err.statusCode < 600)
) {
logger.warn(
{ dependency: name, err },
`cargo crates.io registry failure`
);
throw new Error('registry-failure');
}
logger.warn(
{ err, dependency: name },
'cargo crates.io lookup failure: Unknown error'
);
return null;
}
}

View file

@ -10,20 +10,22 @@ const packagist = require('./packagist');
const pypi = require('./pypi');
const terraform = require('./terraform');
const gitlab = require('./gitlab');
const cargo = require('./cargo');
const { addMetaData } = require('./metadata');
const datasources = {
orb,
cargo,
docker,
github,
gitlab,
go,
npm,
nuget,
orb,
packagist,
pypi,
terraform,
gitlab,
};
const cacheNamespace = 'datasource-releases';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,246 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`datasource/cargo getPkgReleases processes real data 1`] = `
Object {
"homepage": "https://github.com/rust-lang/libc",
"releases": Array [
Object {
"version": "0.2.44",
},
Object {
"version": "0.2.43",
},
Object {
"version": "0.2.42",
},
Object {
"version": "0.2.41",
},
Object {
"version": "0.2.40",
},
Object {
"version": "0.2.39",
},
Object {
"version": "0.2.38",
},
Object {
"version": "0.2.37",
},
Object {
"version": "0.2.36",
},
Object {
"version": "0.2.35",
},
Object {
"version": "0.2.34",
},
Object {
"version": "0.2.33",
},
Object {
"version": "0.2.32",
},
Object {
"version": "0.2.31",
},
Object {
"version": "0.2.30",
},
Object {
"version": "0.2.29",
},
Object {
"version": "0.2.28",
},
Object {
"version": "0.2.27",
},
Object {
"version": "0.2.26",
},
Object {
"version": "0.2.25",
},
Object {
"version": "0.2.24",
},
Object {
"version": "0.2.23",
},
Object {
"version": "0.2.22",
},
Object {
"version": "0.2.21",
},
Object {
"version": "0.2.20",
},
Object {
"version": "0.2.19",
},
Object {
"version": "0.2.18",
},
Object {
"version": "0.2.17",
},
Object {
"version": "0.2.16",
},
Object {
"version": "0.2.15",
},
Object {
"version": "0.2.14",
},
Object {
"version": "0.2.13",
},
Object {
"version": "0.2.12",
},
Object {
"version": "0.2.11",
},
Object {
"version": "0.2.10",
},
Object {
"version": "0.2.9",
},
Object {
"version": "0.2.8",
},
Object {
"version": "0.2.7",
},
Object {
"version": "0.2.6",
},
Object {
"version": "0.2.5",
},
Object {
"version": "0.2.4",
},
Object {
"version": "0.2.3",
},
Object {
"version": "0.2.2",
},
Object {
"version": "0.2.1",
},
Object {
"version": "0.2.0",
},
Object {
"version": "0.1.12",
},
Object {
"version": "0.1.11",
},
Object {
"version": "0.1.10",
},
Object {
"version": "0.1.9",
},
Object {
"version": "0.1.8",
},
Object {
"version": "0.1.7",
},
Object {
"version": "0.1.6",
},
Object {
"version": "0.1.5",
},
Object {
"version": "0.1.4",
},
Object {
"version": "0.1.3",
},
Object {
"version": "0.1.2",
},
Object {
"version": "0.1.1",
},
Object {
"version": "0.1.0",
},
],
"sourceUrl": "https://github.com/rust-lang/libc",
}
`;
exports[`datasource/cargo getPkgReleases processes real data 2`] = `
Object {
"homepage": "https://www.amethyst.rs/",
"releases": Array [
Object {
"version": "0.9.0",
},
Object {
"version": "0.8.0",
},
Object {
"version": "0.7.0",
},
Object {
"version": "0.6.0",
},
Object {
"version": "0.5.1",
},
Object {
"version": "0.5.0",
},
Object {
"version": "0.4.3",
},
Object {
"version": "0.4.2",
},
Object {
"version": "0.4.1",
},
Object {
"version": "0.4.0",
},
Object {
"version": "0.3.1",
},
Object {
"version": "0.3.0",
},
Object {
"version": "0.2.1",
},
Object {
"version": "0.1.4",
},
Object {
"version": "0.1.3",
},
Object {
"version": "0.1.1",
},
Object {
"version": "0.1.0",
},
],
"sourceUrl": "https://github.com/amethyst/amethyst",
}
`;
exports[`datasource/cargo getPkgReleases throws for 5xx 1`] = `[Error: registry-failure]`;

View file

@ -0,0 +1,74 @@
const got = require('got');
const fs = require('fs');
const { getPkgReleases } = require('../../lib/datasource/cargo');
let res1 = fs.readFileSync('test/_fixtures/cargo/libc.json', 'utf8');
res1 = JSON.parse(res1);
let res2 = fs.readFileSync('test/_fixtures/cargo/amethyst.json', 'utf8');
res2 = JSON.parse(res2);
jest.mock('got');
describe('datasource/cargo', () => {
describe('getPkgReleases', () => {
it('returns null for empty result', async () => {
got.mockReturnValueOnce(null);
expect(
await getPkgReleases({ fullname: 'non_existent_crate' })
).toBeNull();
});
it('returns null for missing fields', async () => {
got.mockReturnValueOnce({ crate: {} });
expect(
await getPkgReleases({ fullname: 'non_existent_crate' })
).toBeNull();
});
it('returns null for 404', async () => {
got.mockImplementationOnce(() =>
Promise.reject({
statusCode: 404,
})
);
expect(await getPkgReleases({ fullname: 'some_crate' })).toBeNull();
});
it('throws for 5xx', async () => {
got.mockImplementationOnce(() =>
Promise.reject({
statusCode: 502,
})
);
let e;
try {
await getPkgReleases({ fullname: 'some_crate' });
} catch (err) {
e = err;
}
expect(e).toBeDefined();
expect(e).toMatchSnapshot();
});
it('returns null for unknown error', async () => {
got.mockImplementationOnce(() => {
throw new Error();
});
expect(await getPkgReleases('some_crate')).toBeNull();
});
it('processes real data', async () => {
got.mockReturnValueOnce({
body: res1,
});
const res = await getPkgReleases({ fullname: 'libc' });
expect(res).toMatchSnapshot();
expect(res).not.toBeNull();
expect(res).toBeDefined();
});
it('processes real data', async () => {
got.mockReturnValueOnce({
body: res2,
});
const res = await getPkgReleases({ fullname: 'amethyst' });
expect(res).toMatchSnapshot();
expect(res).not.toBeNull();
expect(res).toBeDefined();
});
});
});