mirror of https://github.com/renovatebot/renovate
729 lines
18 KiB
TypeScript
729 lines
18 KiB
TypeScript
import { codeBlock, html } from 'common-tags';
|
|
import { getPkgReleases } from '..';
|
|
import { Fixtures } from '../../../../test/fixtures';
|
|
import * as httpMock from '../../../../test/http-mock';
|
|
import { fs } from '../../../../test/util';
|
|
import { CustomDatasource } from './index';
|
|
|
|
jest.mock('../../../util/fs');
|
|
|
|
describe('modules/datasource/custom/index', () => {
|
|
describe('getReleases', () => {
|
|
it('return null if only the prefix is supplied', async () => {
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.`,
|
|
packageName: '*',
|
|
customDatasources: {},
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('return null if no registryUrl is provided as well no defaultRegistryTemplate is defined', async () => {
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {},
|
|
},
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('return null if no custom datasource could be found', async () => {
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: '*',
|
|
customDatasources: {},
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('return null on http error', async () => {
|
|
httpMock.scope('https://example.com').get('/v1').reply(404);
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'aPackageName',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
},
|
|
},
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('return null if schema validation fails', async () => {
|
|
httpMock.scope('https://example.com').get('/v1').reply(200, {
|
|
version: 'v1.0.0',
|
|
});
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
},
|
|
},
|
|
});
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('return releases for api directly exposing in renovate format', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'v1.0.0',
|
|
},
|
|
],
|
|
};
|
|
httpMock.scope('https://example.com').get('/v1').reply(200, expected);
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
},
|
|
},
|
|
});
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases with digests for api directly exposing in renovate format', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'v1.0.0',
|
|
newDigest: '0123456789abcdef',
|
|
},
|
|
],
|
|
};
|
|
const content = {
|
|
releases: [
|
|
{
|
|
version: 'v1.0.0',
|
|
digest: '0123456789abcdef',
|
|
},
|
|
],
|
|
};
|
|
httpMock.scope('https://example.com').get('/v1').reply(200, content);
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
},
|
|
},
|
|
});
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases with tags and other optional fields for api directly exposing in renovate format', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'v1.0.0',
|
|
},
|
|
],
|
|
tags: {
|
|
latest: 'v1.0.0',
|
|
},
|
|
sourceUrl: 'https://example.com/foo.git',
|
|
sourceDirectory: '/',
|
|
changelogUrl: 'https://example.com/foo/blob/main/CHANGELOG.md',
|
|
homepage: 'https://example.com/foo',
|
|
};
|
|
const content = {
|
|
releases: [
|
|
{
|
|
version: 'v1.0.0',
|
|
},
|
|
],
|
|
tags: {
|
|
latest: 'v1.0.0',
|
|
},
|
|
sourceUrl: 'https://example.com/foo.git',
|
|
sourceDirectory: '/',
|
|
changelogUrl: 'https://example.com/foo/blob/main/CHANGELOG.md',
|
|
homepage: 'https://example.com/foo',
|
|
unknown: {},
|
|
};
|
|
httpMock.scope('https://example.com').get('/v1').reply(200, content);
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
},
|
|
},
|
|
});
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases for plain text API directly exposing in Renovate format', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: '1.0.0',
|
|
},
|
|
{
|
|
version: '2.0.0',
|
|
},
|
|
{
|
|
version: '3.0.0',
|
|
},
|
|
],
|
|
};
|
|
httpMock
|
|
.scope('https://example.com')
|
|
.get('/v1')
|
|
.reply(200, '1.0.0\n2.0.0\n3.0.0', {
|
|
'Content-Type': 'text/plain',
|
|
});
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
format: 'plain',
|
|
},
|
|
},
|
|
});
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases for plain text API and trim the content', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: '1.0.0',
|
|
},
|
|
{
|
|
version: '2.0.0',
|
|
},
|
|
{
|
|
version: '3.0.0',
|
|
},
|
|
],
|
|
};
|
|
httpMock
|
|
.scope('https://example.com')
|
|
.get('/v1')
|
|
.reply(200, '1.0.0 \n2.0.0 \n 3.0.0 ', {
|
|
'Content-Type': 'text/plain',
|
|
});
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
format: 'plain',
|
|
},
|
|
},
|
|
});
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases for plain text API when only returns a single version', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: '1.0.0',
|
|
},
|
|
],
|
|
};
|
|
httpMock.scope('https://example.com').get('/v1').reply(200, '1.0.0', {
|
|
'Content-Type': 'text/plain',
|
|
});
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
format: 'plain',
|
|
},
|
|
},
|
|
});
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases for yaml API directly exposing in Renovate format', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: '1.0.0',
|
|
},
|
|
{
|
|
version: '2.0.0',
|
|
},
|
|
{
|
|
version: '3.0.0',
|
|
},
|
|
],
|
|
};
|
|
|
|
const yaml = codeBlock`
|
|
releases:
|
|
- version: 1.0.0
|
|
- version: 2.0.0
|
|
- version: 3.0.0
|
|
`;
|
|
|
|
httpMock.scope('https://example.com').get('/v1').reply(200, yaml, {
|
|
'Content-Type': 'text/yaml',
|
|
});
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
format: 'yaml',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases for yaml file directly exposing in Renovate format', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: '1.0.0',
|
|
},
|
|
{
|
|
version: '2.0.0',
|
|
},
|
|
{
|
|
version: '3.0.0',
|
|
},
|
|
],
|
|
};
|
|
|
|
fs.readLocalFile.mockResolvedValueOnce(codeBlock`
|
|
releases:
|
|
- version: 1.0.0
|
|
- version: 2.0.0
|
|
- version: 3.0.0
|
|
`);
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'file://test.yaml',
|
|
format: 'yaml',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases for json file directly exposing in Renovate format', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: '1.0.0',
|
|
},
|
|
{
|
|
version: '2.0.0',
|
|
},
|
|
{
|
|
version: '3.0.0',
|
|
},
|
|
],
|
|
};
|
|
|
|
fs.readLocalFile.mockResolvedValueOnce(codeBlock`{
|
|
"releases": [
|
|
{ "version": "1.0.0" },
|
|
{ "version": "2.0.0" },
|
|
{ "version": "3.0.0" }
|
|
]
|
|
}`);
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'file://test.json',
|
|
format: 'json',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return null for plain text file if the body is not what is expected', async () => {
|
|
fs.readLocalFile.mockResolvedValueOnce(null);
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'file://test.version',
|
|
format: 'plain',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('return releases for plain text file directly exposing in Renovate format', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: '1.0.0',
|
|
},
|
|
{
|
|
version: '2.0.0',
|
|
},
|
|
{
|
|
version: '3.0.0',
|
|
},
|
|
],
|
|
};
|
|
|
|
fs.readLocalFile.mockResolvedValueOnce(codeBlock`{
|
|
1.0.0
|
|
2.0.0
|
|
3.0.0
|
|
}`);
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'file://test.version',
|
|
format: 'plain',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return release when templating registryUrl', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'v1.0.0',
|
|
},
|
|
],
|
|
};
|
|
httpMock
|
|
.scope('https://example.com')
|
|
.get('/v1/myPackage')
|
|
.reply(200, expected);
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate:
|
|
'https://example.com/v1/{{packageName}}',
|
|
},
|
|
},
|
|
});
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return release with templated path', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'v1.0.0',
|
|
},
|
|
],
|
|
};
|
|
|
|
httpMock
|
|
.scope('https://example.com')
|
|
.get('/v1')
|
|
.reply(200, {
|
|
myPackage: expected,
|
|
otherPackage: {
|
|
releases: [
|
|
{
|
|
version: 'v2.0.0',
|
|
},
|
|
],
|
|
},
|
|
});
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
transformTemplates: ['{{packageName}}'],
|
|
},
|
|
},
|
|
});
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return release with templated path with multiple layers', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'v1.0.0',
|
|
},
|
|
],
|
|
};
|
|
|
|
httpMock
|
|
.scope('https://example.com')
|
|
.get('/v1')
|
|
.reply(200, {
|
|
groupName: {
|
|
myPackage: expected,
|
|
otherPackage: {
|
|
releases: [
|
|
{
|
|
version: 'v2.0.0',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
});
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/v1',
|
|
transformTemplates: ['groupName.{{packageName}}'],
|
|
},
|
|
},
|
|
});
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases from HTML links', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'package-1.0.tar.gz',
|
|
},
|
|
],
|
|
};
|
|
|
|
const content = html`
|
|
<html>
|
|
<body>
|
|
<a href="package-1.0.tar.gz">package-1.0.tar.gz</a>
|
|
</body>
|
|
</html>
|
|
`;
|
|
|
|
httpMock
|
|
.scope('https://example.com')
|
|
.get('/index.html')
|
|
.reply(200, content, {
|
|
'Content-Type': 'text/html',
|
|
});
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/index.html',
|
|
format: 'html',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases from HTML links - local file', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'package-1.0.tar.gz',
|
|
},
|
|
],
|
|
};
|
|
|
|
const content = html`
|
|
<html>
|
|
<body>
|
|
<a href="package-1.0.tar.gz">package-1.0.tar.gz</a>
|
|
</body>
|
|
</html>
|
|
`;
|
|
|
|
fs.readLocalFile.mockResolvedValueOnce(content);
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'file://test.html',
|
|
format: 'html',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return null for local file read error - HTML format', async () => {
|
|
fs.readLocalFile.mockResolvedValueOnce(null);
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'file://test.html',
|
|
format: 'html',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('return releases from nginx directory listing', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'nginx-0.1.0.tar.gz',
|
|
},
|
|
{
|
|
version: 'nginx-0.1.1.tar.gz',
|
|
},
|
|
{
|
|
version: 'nginx-0.1.11.tar.gz',
|
|
},
|
|
],
|
|
};
|
|
|
|
httpMock
|
|
.scope('http://nginx.org')
|
|
.get('/download/')
|
|
.reply(200, Fixtures.get('nginx-downloads.html'), {
|
|
'Content-Type': 'text/html',
|
|
})
|
|
.get('/download')
|
|
.reply(301, undefined, {
|
|
Location: 'http://nginx.org/download/',
|
|
});
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'http://nginx.org/download',
|
|
format: 'html',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases for malformed HTML', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'package-1.0.tar.gz',
|
|
},
|
|
],
|
|
};
|
|
|
|
const content = html`
|
|
<html>
|
|
<body>
|
|
<h1></pre><hr></body><a href="package-1.0.tar.gz">package-1.0.tar.gz</a>
|
|
</html>
|
|
`;
|
|
|
|
httpMock
|
|
.scope('https://example.com')
|
|
.get('/malformed.html')
|
|
.reply(200, content, {
|
|
'Content-Type': 'text/html',
|
|
});
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/malformed.html',
|
|
format: 'html',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it('return releases for incomplete HTML', async () => {
|
|
const expected = {
|
|
releases: [
|
|
{
|
|
version: 'package-1.0.tar.gz',
|
|
},
|
|
],
|
|
};
|
|
|
|
const content = html`
|
|
<html>
|
|
<body>
|
|
<a href="package-1.0.tar.gz">package-1.0.tar.gz</a>
|
|
<a href="package-2.0.tar.gz
|
|
`;
|
|
|
|
httpMock
|
|
.scope('https://example.com')
|
|
.get('/incomplete.html')
|
|
.reply(200, content, {
|
|
'Content-Type': 'text/html',
|
|
});
|
|
|
|
const result = await getPkgReleases({
|
|
datasource: `${CustomDatasource.id}.foo`,
|
|
packageName: 'myPackage',
|
|
customDatasources: {
|
|
foo: {
|
|
defaultRegistryUrlTemplate: 'https://example.com/incomplete.html',
|
|
format: 'html',
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(result).toEqual(expected);
|
|
});
|
|
});
|
|
|
|
describe('getDigest', () => {
|
|
it('returns null as digest should be provided in releases', async () => {
|
|
const digest = await new CustomDatasource().getDigest({
|
|
packageName: 'my-package',
|
|
});
|
|
expect(digest).toBeNull();
|
|
});
|
|
});
|
|
});
|