mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-12 06:56:24 +00:00
feat: cargo datasource (#2993)
This commit is contained in:
parent
8054ee58b3
commit
71ee394aba
6 changed files with 382 additions and 2 deletions
56
lib/datasource/cargo/index.js
Normal file
56
lib/datasource/cargo/index.js
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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';
|
||||
|
|
1
test/_fixtures/cargo/amethyst.json
Normal file
1
test/_fixtures/cargo/amethyst.json
Normal file
File diff suppressed because one or more lines are too long
1
test/_fixtures/cargo/libc.json
Normal file
1
test/_fixtures/cargo/libc.json
Normal file
File diff suppressed because one or more lines are too long
246
test/datasource/__snapshots__/cargo.spec.js.snap
Normal file
246
test/datasource/__snapshots__/cargo.spec.js.snap
Normal 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]`;
|
74
test/datasource/cargo.spec.js
Normal file
74
test/datasource/cargo.spec.js
Normal 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();
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue