fix(core/changelogs): pass though known project info (#11515)

This commit is contained in:
Michael Kriese 2021-09-01 13:07:55 +02:00 committed by GitHub
parent 28793a3900
commit 0eb5c6d2cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 510 additions and 418 deletions

View file

@ -20,7 +20,7 @@ export class GitHubReleaseMocker {
published_at: '2020-03-09T11:00:00Z',
prerelease: false,
assets: [],
};
} as GithubRelease;
for (const assetFn of Object.keys(assets)) {
const assetPath = `/repos/${this.lookupName}/releases/download/${version}/${assetFn}`;
const assetData = assets[assetFn];

View file

@ -1,8 +1,13 @@
export type GithubRelease = {
id: number;
tag_name: string;
published_at: string;
prerelease: boolean;
assets: GithubReleaseAsset[];
html_url: string;
name: string;
body: string;
};
export interface GithubReleaseAsset {

View file

@ -4,7 +4,7 @@ import { GithubHttp } from '../../util/http/github';
import { ensureTrailingSlash } from '../../util/url';
import * as githubReleases from '../github-releases';
import type { DigestConfig, GetReleasesConfig, ReleaseResult } from '../types';
import type { TagResponse } from './types';
import type { GitHubTag, TagResponse } from './types';
export const id = 'github-tags';
export const customRegistrySupport = true;
@ -148,12 +148,9 @@ async function getTags({
: `${sourceUrlBase}api/v3/`;
// tag
const url = `${apiBaseUrl}repos/${repo}/tags?per_page=100`;
type GitHubTag = {
name: string;
}[];
const versions = (
await http.getJson<GitHubTag>(url, {
await http.getJson<GitHubTag[]>(url, {
paginate: true,
})
).body.map((o) => o.name);

View file

@ -5,3 +5,7 @@ export interface TagResponse {
sha: string;
};
}
export interface GitHubTag {
name: string;
}

View file

@ -1,4 +1,5 @@
export interface GitlabRelease {
description: string;
name: string;
tag_name: string;
released_at: string;

View file

@ -60,6 +60,7 @@ Object {
"accept-encoding": "gzip, deflate, br",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"hostType": "any",
"http2": false,
"method": "POST",
"password": "***********",

View file

@ -66,6 +66,7 @@ export default function prepareError(err: Error): Record<string, unknown> {
const options: Record<string, unknown> = {
headers: clone(err.options.headers),
url: err.options.url?.toString(),
hostType: err.options.context.hostType,
};
response.options = options;

View file

@ -105,7 +105,11 @@ async function gotRoutine<T>(
}
export class Http<GetOptions = HttpOptions, PostOptions = HttpPostOptions> {
constructor(private hostType: string, private options?: HttpOptions) {}
private options?: GotOptions;
constructor(private hostType: string, options?: HttpOptions) {
this.options = merge<GotOptions>(options, { context: { hostType } });
}
protected async request<T>(
requestUrl: string | URL,

View file

@ -7,9 +7,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "@renovate/no",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -59,9 +60,10 @@ Object {
"apiBaseUrl": "https://github-enterprise.example.com/api/v3/",
"baseUrl": "https://github-enterprise.example.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github-enterprise.example.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github-enterprise.example.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -111,9 +113,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -163,9 +166,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -215,9 +219,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -267,9 +272,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {

View file

@ -7,8 +7,9 @@ Object {
"apiBaseUrl": "https://gitlab.com/api/v4/",
"baseUrl": "https://gitlab.com/",
"depName": "renovate",
"gitlab": "meno/dropzone",
"repository": "https://gitlab.com/meno/dropzone/",
"repository": "meno/dropzone",
"sourceUrl": "https://gitlab.com/meno/dropzone/",
"type": "gitlab",
},
"versions": Array [
Object {
@ -154,8 +155,9 @@ Object {
"apiBaseUrl": "https://gitlab-enterprise.example.com/api/v4/",
"baseUrl": "https://gitlab-enterprise.example.com/",
"depName": "renovate",
"gitlab": "meno/dropzone",
"repository": "https://gitlab-enterprise.example.com/meno/dropzone/",
"repository": "meno/dropzone",
"sourceUrl": "https://gitlab-enterprise.example.com/meno/dropzone/",
"type": "gitlab",
},
"versions": Array [
Object {
@ -197,8 +199,9 @@ Object {
"apiBaseUrl": "https://git.test.com/api/v4/",
"baseUrl": "https://git.test.com/",
"depName": "renovate",
"gitlab": "meno/dropzone",
"repository": "https://git.test.com/meno/dropzone/",
"repository": "meno/dropzone",
"sourceUrl": "https://git.test.com/meno/dropzone/",
"type": "gitlab",
},
"versions": Array [
Object {
@ -240,8 +243,9 @@ Object {
"apiBaseUrl": "https://gitlab.com/api/v4/",
"baseUrl": "https://gitlab.com/",
"depName": "renovate",
"gitlab": "meno/dropzone",
"repository": "https://gitlab.com/meno/dropzone/",
"repository": "meno/dropzone",
"sourceUrl": "https://gitlab.com/meno/dropzone/",
"type": "gitlab",
},
"versions": Array [
Object {
@ -403,8 +407,9 @@ Object {
"apiBaseUrl": "https://gitlab.com/api/v4/",
"baseUrl": "https://gitlab.com/",
"depName": "renovate",
"gitlab": "meno/dropzone",
"repository": "https://gitlab.com/meno/dropzone/",
"repository": "meno/dropzone",
"sourceUrl": "https://gitlab.com/meno/dropzone/",
"type": "gitlab",
},
"versions": Array [
Object {
@ -550,8 +555,9 @@ Object {
"apiBaseUrl": "https://gitlab.com/api/v4/",
"baseUrl": "https://gitlab.com/",
"depName": "renovate",
"gitlab": "meno/dropzone",
"repository": "https://gitlab.com/meno/dropzone/",
"repository": "meno/dropzone",
"sourceUrl": "https://gitlab.com/meno/dropzone/",
"type": "gitlab",
},
"versions": Array [
Object {

View file

@ -7,9 +7,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "@renovate/no",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -163,9 +164,10 @@ Object {
"apiBaseUrl": "https://github-enterprise.example.com/api/v3/",
"baseUrl": "https://github-enterprise.example.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github-enterprise.example.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github-enterprise.example.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -363,9 +365,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -563,9 +566,10 @@ Object {
"apiBaseUrl": "https://github-enterprise.example.com/api/v3/",
"baseUrl": "https://github-enterprise.example.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github-enterprise.example.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github-enterprise.example.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -763,9 +767,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -815,9 +820,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {
@ -1019,9 +1025,10 @@ Object {
"apiBaseUrl": "https://api.github.com/",
"baseUrl": "https://github.com/",
"depName": "renovate",
"github": "chalk/chalk",
"repository": "https://github.com/chalk/chalk",
"repository": "chalk/chalk",
"sourceDirectory": undefined,
"sourceUrl": "https://github.com/chalk/chalk",
"type": "github",
},
"versions": Array [
Object {

View file

@ -5,7 +5,8 @@ Object {
"a": 1,
"hasReleaseNotes": false,
"project": Object {
"github": "https://github.com/nodeca/js-yaml",
"repository": "https://github.com/nodeca/js-yaml",
"type": "github",
},
"versions": Array [
Object {
@ -24,7 +25,8 @@ Object {
"a": 1,
"hasReleaseNotes": false,
"project": Object {
"gitlab": "https://gitlab.com/gitlab-org/gitter/webapp/",
"repository": "https://gitlab.com/gitlab-org/gitter/webapp/",
"type": "gitlab",
},
"versions": Array [
Object {
@ -137,7 +139,7 @@ Array [
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 1`] = `
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "" 1`] = `
Object {
"body": "some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)
",
@ -148,7 +150,7 @@ Object {
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 2`] = `
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "" 2`] = `
Array [
Object {
"headers": Object {
@ -163,85 +165,7 @@ Array [
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 3`] = `
Object {
"body": "some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)
",
"id": undefined,
"name": undefined,
"tag": "v1.0.1",
"url": "https://github.com/some/other-repository/releases/v1.0.1",
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 4`] = `
Array [
Object {
"headers": Object {
"accept": "application/vnd.github.v3+json",
"accept-encoding": "gzip, deflate, br",
"host": "api.github.com",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.github.com/repos/some/other-repository/releases?per_page=100",
},
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 5`] = `
Object {
"body": "some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)
",
"id": undefined,
"name": undefined,
"tag": "other-1.0.1",
"url": "https://github.com/some/other-repository/releases/other-1.0.1",
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 6`] = `
Array [
Object {
"headers": Object {
"accept": "application/vnd.github.v3+json",
"accept-encoding": "gzip, deflate, br",
"host": "api.github.com",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.github.com/repos/some/other-repository/releases?per_page=100",
},
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 7`] = `
Object {
"body": "some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)
",
"id": undefined,
"name": undefined,
"tag": "other_v1.0.1",
"url": "https://github.com/some/other-repository/releases/other_v1.0.1",
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 8`] = `
Array [
Object {
"headers": Object {
"accept": "application/vnd.github.v3+json",
"accept-encoding": "gzip, deflate, br",
"host": "api.github.com",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.github.com/repos/some/other-repository/releases?per_page=100",
},
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 9`] = `
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "other@" 1`] = `
Object {
"body": "some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)
",
@ -252,7 +176,7 @@ Object {
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body 10`] = `
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "other@" 2`] = `
Array [
Object {
"headers": Object {
@ -267,9 +191,94 @@ Array [
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo 1`] = `null`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "other_v" 1`] = `
Object {
"body": "some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)
",
"id": undefined,
"name": undefined,
"tag": "other_v1.0.1",
"url": "https://github.com/some/other-repository/releases/other_v1.0.1",
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo 2`] = `
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "other_v" 2`] = `
Array [
Object {
"headers": Object {
"accept": "application/vnd.github.v3+json",
"accept-encoding": "gzip, deflate, br",
"host": "api.github.com",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.github.com/repos/some/other-repository/releases?per_page=100",
},
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "other-" 1`] = `
Object {
"body": "some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)
",
"id": undefined,
"name": undefined,
"tag": "other-1.0.1",
"url": "https://github.com/some/other-repository/releases/other-1.0.1",
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "other-" 2`] = `
Array [
Object {
"headers": Object {
"accept": "application/vnd.github.v3+json",
"accept-encoding": "gzip, deflate, br",
"host": "api.github.com",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.github.com/repos/some/other-repository/releases?per_page=100",
},
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "v" 1`] = `
Object {
"body": "some body [#123](https://github.com/some/other-repository/issues/123), [#124](https://github.com/some/yet-other-repository/issues/124)
",
"id": undefined,
"name": undefined,
"tag": "v1.0.1",
"url": "https://github.com/some/other-repository/releases/v1.0.1",
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body "v" 2`] = `
Array [
Object {
"headers": Object {
"accept": "application/vnd.github.v3+json",
"accept-encoding": "gzip, deflate, br",
"host": "api.github.com",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.github.com/repos/some/other-repository/releases?per_page=100",
},
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo "" 1`] = `
Object {
"body": "some body #123, [#124](https://gitlab.com/some/yet-other-repository/issues/124)",
"name": undefined,
"tag": "1.0.1",
"url": "https://gitlab.com/some/other-repository/tags/1.0.1",
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo "" 2`] = `
Array [
Object {
"headers": Object {
@ -284,9 +293,16 @@ Array [
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo other- 1`] = `null`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo "other-" 1`] = `
Object {
"body": "some body #123, [#124](https://gitlab.com/some/yet-other-repository/issues/124)",
"name": undefined,
"tag": "other-1.0.1",
"url": "https://gitlab.com/some/other-repository/tags/other-1.0.1",
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo other- 2`] = `
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo "other-" 2`] = `
Array [
Object {
"headers": Object {
@ -301,9 +317,16 @@ Array [
]
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo v 1`] = `null`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo "v" 1`] = `
Object {
"body": "some body #123, [#124](https://gitlab.com/some/yet-other-repository/issues/124)",
"name": undefined,
"tag": "v1.0.1",
"url": "https://gitlab.com/some/other-repository/tags/v1.0.1",
}
`;
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo v 2`] = `
exports[`workers/pr/changelog/release-notes getReleaseNotes() gets release notes with body from gitlab repo "v" 2`] = `
Array [
Object {
"headers": Object {

View file

@ -1,4 +1,6 @@
import changelogFilenameRegex from 'changelog-filename-regex';
import type { GithubRelease } from '../../../../datasource/github-releases/types';
import type { GitHubTag } from '../../../../datasource/github-tags/types';
import { logger } from '../../../../logger';
import type {
GithubGitBlob,
@ -18,7 +20,7 @@ export async function getTags(
logger.trace('github.getTags()');
const url = `${endpoint}repos/${repository}/tags?per_page=100`;
try {
const res = await http.getJson<{ name: string }[]>(url, {
const res = await http.getJson<GitHubTag[]>(url, {
paginate: true,
});
@ -30,8 +32,10 @@ export async function getTags(
return tags.map((tag) => tag.name).filter(Boolean);
} catch (err) {
logger.debug({ sourceRepo: repository }, 'Failed to fetch Github tags');
logger.debug({ err });
logger.debug(
{ sourceRepo: repository, err },
'Failed to fetch Github tags'
);
// istanbul ignore if
if (err.message?.includes('Bad credentials')) {
logger.warn('Bad credentials triggering tag fail lookup in changelog');
@ -108,15 +112,7 @@ export async function getReleaseList(
const url = `${ensureTrailingSlash(
apiBaseUrl
)}repos/${repository}/releases?per_page=100`;
const res = await http.getJson<
{
html_url: string;
id: number;
tag_name: string;
name: string;
body: string;
}[]
>(url, { paginate: true });
const res = await http.getJson<GithubRelease[]>(url, { paginate: true });
return res.body.map((release) => ({
url: release.html_url,
id: release.id,

View file

@ -1,4 +1,6 @@
import changelogFilenameRegex from 'changelog-filename-regex';
import type { GitlabRelease } from '../../../../datasource/gitlab-releases/types';
import type { GitlabTag } from '../../../../datasource/gitlab-tags/types';
import { logger } from '../../../../logger';
import type { GitlabTreeNode } from '../../../../types/platform/gitlab';
import { GitlabHttp } from '../../../../util/http/gitlab';
@ -20,7 +22,7 @@ export async function getTags(
repository
)}/repository/tags?per_page=100`;
try {
const res = await http.getJson<{ name: string }[]>(url, {
const res = await http.getJson<GitlabTag[]>(url, {
paginate: true,
});
@ -32,7 +34,10 @@ export async function getTags(
return tags.map((tag) => tag.name).filter(Boolean);
} catch (err) {
logger.info({ sourceRepo: repository }, 'Failed to fetch Gitlab tags');
logger.debug(
{ sourceRepo: repository, err },
'Failed to fetch Gitlab tags'
);
// istanbul ignore if
if (err.message?.includes('Bad credentials')) {
logger.warn('Bad credentials triggering tag fail lookup in changelog');
@ -101,14 +106,8 @@ export async function getReleaseList(
const apiUrl = `${ensureTrailingSlash(
apiBaseUrl
)}projects/${repoId}/releases`;
const res = await http.getJson<
{
name: string;
release: string;
description: string;
tag_name: string;
}[]
>(`${apiUrl}?per_page=100`, {
const res = await http.getJson<GitlabRelease[]>(`${apiUrl}?per_page=100`, {
paginate: true,
});
return res.body.map((release) => ({

View file

@ -10,7 +10,12 @@ import {
getReleaseNotesMd,
releaseNotesCacheMinutes,
} from './release-notes';
import type { ChangeLogNotes } from './types';
import type {
ChangeLogNotes,
ChangeLogProject,
ChangeLogRelease,
ChangeLogResult,
} from './types';
jest.mock('../../../util/host-rules');
@ -37,6 +42,18 @@ const gitlabTreeResponse = [
{ path: 'README.md', type: 'blob' },
];
const githubProject = {
type: 'github',
apiBaseUrl: 'https://api.github.com/',
baseUrl: 'https://github.com/',
} as ChangeLogProject;
const gitlabProject = {
type: 'gitlab',
apiBaseUrl: 'https://gitlab.com/api/v4/',
baseUrl: 'https://gitlab.com/',
} as ChangeLogProject;
describe('workers/pr/changelog/release-notes', () => {
beforeEach(() => {
hostRules.find.mockReturnValue({});
@ -60,6 +77,7 @@ describe('workers/pr/changelog/release-notes', () => {
it('handles date object', () => {
expect(releaseNotesCacheMinutes(new Date())).toEqual(55);
});
it.each([null, undefined, 'fake', 123])('handles invalid: %s', (date) => {
expect(releaseNotesCacheMinutes(date as never)).toEqual(55);
});
@ -69,31 +87,47 @@ describe('workers/pr/changelog/release-notes', () => {
it('returns input if invalid', async () => {
const input = { a: 1 };
expect(await addReleaseNotes(input as never)).toEqual(input);
expect(await addReleaseNotes(null)).toBeNull();
expect(await addReleaseNotes({ versions: [] } as never)).toStrictEqual({
versions: [],
});
});
it('returns ChangeLogResult', async () => {
const input = {
a: 1,
project: { github: 'https://github.com/nodeca/js-yaml' },
project: {
type: 'github',
repository: 'https://github.com/nodeca/js-yaml',
},
versions: [{ version: '3.10.0', compare: { url: '' } }],
};
// FIXME: explicit assert condition
expect(await addReleaseNotes(input as never)).toMatchSnapshot();
});
it('returns ChangeLogResult without release notes', async () => {
const input = {
a: 1,
project: { gitlab: 'https://gitlab.com/gitlab-org/gitter/webapp/' },
versions: [{ version: '20.26.0', compare: { url: '' } }],
};
project: {
type: 'gitlab',
repository: 'https://gitlab.com/gitlab-org/gitter/webapp/',
} as ChangeLogProject,
versions: [
{ version: '20.26.0', compare: { url: '' } } as ChangeLogRelease,
],
} as ChangeLogResult;
// FIXME: explicit assert condition
expect(await addReleaseNotes(input as never)).toMatchSnapshot();
expect(await addReleaseNotes(input)).toMatchSnapshot();
});
});
describe('getReleaseList()', () => {
it('should return empty array if no apiBaseUrl', async () => {
const res = await getReleaseList('', 'some/yet-other-repository');
const res = await getReleaseList({} as ChangeLogProject);
expect(res).toEqual([]);
});
it('should return release list for github repo', async () => {
httpMock
.scope('https://api.github.com/')
@ -106,14 +140,15 @@ describe('workers/pr/changelog/release-notes', () => {
},
]);
const res = await getReleaseList(
'https://api.github.com/',
'some/yet-other-repository'
);
const res = await getReleaseList({
...githubProject,
repository: 'some/yet-other-repository',
});
// FIXME: explicit assert condition
expect(res).toMatchSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('should return release list for gitlab.com project', async () => {
httpMock
.scope('https://gitlab.com/')
@ -127,14 +162,15 @@ describe('workers/pr/changelog/release-notes', () => {
body: 'some body #123, [#124](https://gitlab.com/some/yet-other-repository/issues/124)',
},
]);
const res = await getReleaseList(
'https://gitlab.com/api/v4/',
'some/yet-other-repository'
);
const res = await getReleaseList({
...gitlabProject,
repository: 'some/yet-other-repository',
});
// FIXME: explicit assert condition
expect(res).toMatchSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('should return release list for self hosted gitlab project', async () => {
hostRules.find.mockReturnValue({ token: 'some-token' });
httpMock
@ -149,15 +185,18 @@ describe('workers/pr/changelog/release-notes', () => {
body: 'some body #123, [#124](https://my.custom.domain/some/yet-other-repository/issues/124)',
},
]);
const res = await getReleaseList(
'https://my.custom.domain/api/v4/',
'some/yet-other-repository'
);
const res = await getReleaseList({
...gitlabProject,
repository: 'some/yet-other-repository',
apiBaseUrl: 'https://my.custom.domain/api/v4/',
baseUrl: 'https://my.custom.domain/',
});
// FIXME: explicit assert condition
expect(res).toMatchSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
});
});
describe('getReleaseNotes()', () => {
it('should return null for release notes without body', async () => {
httpMock
@ -165,17 +204,19 @@ describe('workers/pr/changelog/release-notes', () => {
.get('/repos/some/repository/releases?per_page=100')
.reply(200, [{ tag_name: 'v1.0.0' }, { tag_name: 'v1.0.1' }]);
const res = await getReleaseNotes(
'some/repository',
'1.0.0',
'some',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'some/repository',
depName: 'some',
},
'1.0.0'
);
expect(res).toBeNull();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it.each([[''], ['v'], ['other-'], ['other_v'], ['other@']])(
'gets release notes with body',
'gets release notes with body "%s"',
async (prefix) => {
httpMock
.scope('https://api.github.com/')
@ -188,19 +229,21 @@ describe('workers/pr/changelog/release-notes', () => {
},
]);
const res = await getReleaseNotes(
'some/other-repository',
'1.0.1',
'other',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'some/other-repository',
depName: 'other',
},
'1.0.1'
);
// FIXME: explicit assert condition
expect(res).toMatchSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
}
);
it.each([[''], ['v'], ['other-']])(
'gets release notes with body from gitlab repo %s',
'gets release notes with body from gitlab repo "%s"',
async (prefix) => {
httpMock
.scope('https://api.gitlab.com/')
@ -209,52 +252,53 @@ describe('workers/pr/changelog/release-notes', () => {
{ tag_name: `${prefix}1.0.0` },
{
tag_name: `${prefix}1.0.1`,
body: 'some body #123, [#124](https://gitlab.com/some/yet-other-repository/issues/124)',
description:
'some body #123, [#124](https://gitlab.com/some/yet-other-repository/issues/124)',
},
]);
const res = await getReleaseNotes(
'some/other-repository',
'1.0.1',
'other',
'https://gitlab.com/',
'https://api.gitlab.com/'
{
...gitlabProject,
repository: 'some/other-repository',
depName: 'other',
apiBaseUrl: 'https://api.gitlab.com/',
},
'1.0.1'
);
// FIXME: explicit assert condition
expect(res).toMatchSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
}
);
it.each([[''], ['v'], ['other-']])(
'gets null from repository without gitlab/github in domain %s',
async (prefix) => {
// FIXME: Should not call `api.lol.lol` ?
httpMock
.scope('https://api.lol.lol')
.get('/repos/some/other-repository/releases?per_page=100')
.reply(404);
it('gets null from repository without gitlab/github in domain', async () => {
const res = await getReleaseNotes(
'some/other-repository',
'1.0.1',
'other',
'https://lol.lol/',
'https://api.lol.lol/'
{
repository: 'some/repository',
depName: 'other',
apiBaseUrl: 'https://api.lol.lol/',
baseUrl: 'https://lol.lol/',
} as ChangeLogProject,
'1.0.1'
);
expect(res).toBeNull();
}
);
});
});
describe('getReleaseNotesMd()', () => {
it('handles not found', async () => {
httpMock.scope('https://api.github.com').get('/repos/chalk').reply(404);
const res = await getReleaseNotesMd(
'chalk',
'2.0.0',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'chalk',
},
'2.0.0'
);
expect(res).toBeNull();
});
it('handles files mismatch', async () => {
httpMock
.scope('https://api.github.com')
@ -268,14 +312,16 @@ describe('workers/pr/changelog/release-notes', () => {
],
});
const res = await getReleaseNotesMd(
'chalk',
'2.0.0',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'chalk',
},
'2.0.0'
);
expect(res).toBeNull();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('handles wrong format', async () => {
httpMock
.scope('https://api.github.com')
@ -288,14 +334,16 @@ describe('workers/pr/changelog/release-notes', () => {
content: Buffer.from('not really markdown').toString('base64'),
});
const res = await getReleaseNotesMd(
'some/repository1',
'1.0.0',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'some/repository1',
},
'1.0.0'
);
expect(res).toBeNull();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('handles bad markdown', async () => {
httpMock
.scope('https://api.github.com')
@ -308,14 +356,16 @@ describe('workers/pr/changelog/release-notes', () => {
content: Buffer.from(`#\nha\nha\n#\nha\nha`).toString('base64'),
});
const res = await getReleaseNotesMd(
'some/repository2',
'1.0.0',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'some/repository2',
},
'1.0.0'
);
expect(res).toBeNull();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('parses angular.js', async () => {
httpMock
.scope('https://api.github.com')
@ -328,16 +378,18 @@ describe('workers/pr/changelog/release-notes', () => {
content: Buffer.from(angularJsChangelogMd).toString('base64'),
});
const res = await getReleaseNotesMd(
'angular/angular.js',
'1.6.9',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'angular/angular.js',
},
'1.6.9'
);
// FIXME: explicit assert condition
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('parses gitlab.com/gitlab-org/gitter/webapp', async () => {
jest.setTimeout(0);
httpMock
@ -349,16 +401,19 @@ describe('workers/pr/changelog/release-notes', () => {
.get('/projects/gitlab-org%2fgitter%2fwebapp/repository/blobs/abcd/raw')
.reply(200, gitterWebappChangelogMd);
const res = await getReleaseNotesMd(
'gitlab-org/gitter/webapp',
'20.26.0',
'https://gitlab.com/',
'https://api.gitlab.com/'
{
...gitlabProject,
repository: 'gitlab-org/gitter/webapp',
apiBaseUrl: 'https://api.gitlab.com/',
},
'20.26.0'
);
expect(httpMock.getTrace()).toMatchSnapshot();
// FIXME: explicit assert condition
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
});
it('parses self hosted gitlab', async () => {
hostRules.find.mockReturnValue({ token: 'some-token' });
jest.setTimeout(0);
@ -371,16 +426,20 @@ describe('workers/pr/changelog/release-notes', () => {
.get('/projects/gitlab-org%2fgitter%2fwebapp/repository/blobs/abcd/raw')
.reply(200, gitterWebappChangelogMd);
const res = await getReleaseNotesMd(
'gitlab-org/gitter/webapp',
'20.26.0',
'https://my.custom.domain/',
'https://my.custom.domain/'
{
...gitlabProject,
repository: 'gitlab-org/gitter/webapp',
apiBaseUrl: 'https://my.custom.domain/',
baseUrl: 'https://my.custom.domain/',
},
'20.26.0'
);
expect(httpMock.getTrace()).toMatchSnapshot();
// FIXME: explicit assert condition
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
});
it('parses jest', async () => {
httpMock
.scope('https://api.github.com')
@ -393,16 +452,18 @@ describe('workers/pr/changelog/release-notes', () => {
content: Buffer.from(jestChangelogMd).toString('base64'),
});
const res = await getReleaseNotesMd(
'facebook/jest',
'22.0.0',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'facebook/jest',
},
'22.0.0'
);
expect(httpMock.getTrace()).toMatchSnapshot();
// FIXME: explicit assert condition
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
});
it('handles github sourceDirectory', async () => {
const sourceDirectory = 'packages/foo';
const subdirTree = clone(githubTreeResponse);
@ -420,17 +481,19 @@ describe('workers/pr/changelog/release-notes', () => {
content: Buffer.from(jsYamlChangelogMd).toString('base64'),
});
const res = await getReleaseNotesMd(
'nodeca/js-yaml',
'3.10.0',
'https://github.com/',
'https://api.github.com/',
sourceDirectory
{
...githubProject,
repository: 'nodeca/js-yaml',
sourceDirectory,
},
'3.10.0'
);
expect(httpMock.getTrace()).toMatchSnapshot();
// FIXME: explicit assert condition
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
});
it('parses js-yaml', async () => {
httpMock
.scope('https://api.github.com')
@ -443,16 +506,28 @@ describe('workers/pr/changelog/release-notes', () => {
content: Buffer.from(jsYamlChangelogMd).toString('base64'),
});
const res = await getReleaseNotesMd(
'nodeca/js-yaml',
'3.10.0',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'nodeca/js-yaml',
},
'3.10.0'
);
expect(httpMock.getTrace()).toMatchSnapshot();
// FIXME: explicit assert condition
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
});
it('ignores invalid', async () => {
const res = await getReleaseNotesMd(
{
repository: 'nodeca/js-yaml',
} as ChangeLogProject,
'3.10.0'
);
expect(res).toBeNull();
});
describe('ReleaseNotes Correctness', () => {
let versionOneNotes: ChangeLogNotes;
let versionTwoNotes: ChangeLogNotes;
@ -468,10 +543,11 @@ describe('workers/pr/changelog/release-notes', () => {
content: Buffer.from(yargsChangelogMd).toString('base64'),
});
const res = await getReleaseNotesMd(
'yargs/yargs',
'15.3.0',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'yargs/yargs',
},
'15.3.0'
);
versionOneNotes = res;
expect(httpMock.getTrace()).toMatchSnapshot();
@ -479,6 +555,7 @@ describe('workers/pr/changelog/release-notes', () => {
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
});
it('parses yargs 15.2.0', async () => {
httpMock
.scope('https://api.github.com')
@ -491,10 +568,11 @@ describe('workers/pr/changelog/release-notes', () => {
content: Buffer.from(yargsChangelogMd).toString('base64'),
});
const res = await getReleaseNotesMd(
'yargs/yargs',
'15.2.0',
'https://github.com/',
'https://api.github.com/'
{
...githubProject,
repository: 'yargs/yargs',
},
'15.2.0'
);
versionTwoNotes = res;
expect(httpMock.getTrace()).toMatchSnapshot();
@ -502,6 +580,7 @@ describe('workers/pr/changelog/release-notes', () => {
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
});
it('parses adapter-utils 4.33.0', async () => {
httpMock
.scope('https://gitlab.com/')
@ -514,10 +593,11 @@ describe('workers/pr/changelog/release-notes', () => {
)
.reply(200, adapterutilsChangelogMd);
const res = await getReleaseNotesMd(
'itentialopensource/adapter-utils',
'4.33.0',
'https://gitlab.com/',
'https://gitlab.com/api/v4/'
{
...gitlabProject,
repository: 'itentialopensource/adapter-utils',
},
'4.33.0'
);
versionTwoNotes = res;
expect(httpMock.getTrace()).toMatchSnapshot();
@ -525,6 +605,7 @@ describe('workers/pr/changelog/release-notes', () => {
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
});
it('handles gitlab sourceDirectory', async () => {
const sourceDirectory = 'packages/foo';
const response = clone(gitlabTreeResponse).map((file) => ({
@ -542,11 +623,12 @@ describe('workers/pr/changelog/release-notes', () => {
)
.reply(200, adapterutilsChangelogMd);
const res = await getReleaseNotesMd(
'itentialopensource/adapter-utils',
'4.33.0',
'https://gitlab.com/',
'https://gitlab.com/api/v4/',
sourceDirectory
{
...gitlabProject,
repository: 'itentialopensource/adapter-utils',
sourceDirectory,
},
'4.33.0'
);
versionTwoNotes = res;
expect(httpMock.getTrace()).toMatchSnapshot();
@ -554,9 +636,11 @@ describe('workers/pr/changelog/release-notes', () => {
expect(res).not.toBeNull();
expect(res).toMatchSnapshot();
});
it('isUrl', () => {
expect(versionOneNotes).not.toMatchObject(versionTwoNotes);
});
it('15.3.0 is not equal to 15.2.0', () => {
expect(versionOneNotes).not.toMatchObject(versionTwoNotes);
});

View file

@ -2,64 +2,61 @@ import * as URL from 'url';
import is from '@sindresorhus/is';
import { DateTime } from 'luxon';
import MarkdownIt from 'markdown-it';
import { PLATFORM_TYPE_GITLAB } from '../../../constants/platforms';
import { logger } from '../../../logger';
import * as memCache from '../../../util/cache/memory';
import * as packageCache from '../../../util/cache/package';
import * as hostRules from '../../../util/host-rules';
import { linkify } from '../../../util/markdown';
import * as github from './github';
import * as gitlab from './gitlab';
import type { ChangeLogFile, ChangeLogNotes, ChangeLogResult } from './types';
import type {
ChangeLogFile,
ChangeLogNotes,
ChangeLogProject,
ChangeLogResult,
} from './types';
const markdown = new MarkdownIt('zero');
markdown.enable(['heading', 'lheading']);
export async function getReleaseList(
apiBaseUrl: string,
repository: string
project: ChangeLogProject
): Promise<ChangeLogNotes[]> {
logger.trace('getReleaseList()');
// istanbul ignore if
if (!apiBaseUrl) {
logger.debug('No apiBaseUrl');
const { apiBaseUrl, repository, type } = project;
try {
switch (type) {
case 'gitlab':
return await gitlab.getReleaseList(apiBaseUrl, repository);
case 'github':
return await github.getReleaseList(apiBaseUrl, repository);
default:
logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type');
return [];
}
try {
if (apiBaseUrl.includes('gitlab')) {
return await gitlab.getReleaseList(apiBaseUrl, repository);
}
const opts = hostRules.find({
hostType: PLATFORM_TYPE_GITLAB,
url: apiBaseUrl,
});
if (opts.token) {
return await gitlab.getReleaseList(apiBaseUrl, repository);
}
return await github.getReleaseList(apiBaseUrl, repository);
} catch (err) /* istanbul ignore next */ {
if (err.statusCode === 404) {
logger.debug({ repository }, 'getReleaseList 404');
logger.debug({ repository, type, apiBaseUrl }, 'getReleaseList 404');
} else {
logger.info({ repository, err }, 'getReleaseList error');
logger.debug(
{ repository, type, apiBaseUrl, err },
'getReleaseList error'
);
}
}
return [];
}
}
export function getCachedReleaseList(
apiBaseUrl: string,
repository: string
project: ChangeLogProject
): Promise<ChangeLogNotes[]> {
const cacheKey = `getReleaseList-${apiBaseUrl}-${repository}`;
const cacheKey = `getReleaseList-${project.apiBaseUrl}-${project.repository}`;
const cachedResult = memCache.get<Promise<ChangeLogNotes[]>>(cacheKey);
// istanbul ignore if
if (cachedResult !== undefined) {
return cachedResult;
}
const promisedRes = getReleaseList(apiBaseUrl, repository);
const promisedRes = getReleaseList(project);
memCache.set(cacheKey, promisedRes);
return promisedRes;
}
@ -94,14 +91,12 @@ export function massageBody(
}
export async function getReleaseNotes(
repository: string,
version: string,
depName: string,
baseUrl: string,
apiBaseUrl: string
project: ChangeLogProject,
version: string
): Promise<ChangeLogNotes | null> {
const { baseUrl, depName, repository } = project;
logger.trace(`getReleaseNotes(${repository}, ${version}, ${depName})`);
const releaseList = await getCachedReleaseList(apiBaseUrl, repository);
const releaseList = await getCachedReleaseList(project);
logger.trace({ releaseList }, 'Release list from getReleaseList');
let releaseNotes: ChangeLogNotes | null = null;
for (const release of releaseList) {
@ -172,84 +167,70 @@ function isUrl(url: string): boolean {
}
export async function getReleaseNotesMdFileInner(
repository: string,
apiBaseUrl: string,
sourceDirectory?: string
project: ChangeLogProject
): Promise<ChangeLogFile> | null {
const { apiBaseUrl, repository, sourceDirectory, type } = project;
try {
if (apiBaseUrl.includes('gitlab')) {
switch (type) {
case 'gitlab':
return await gitlab.getReleaseNotesMd(
repository,
apiBaseUrl,
sourceDirectory
);
}
const opts = hostRules.find({
hostType: PLATFORM_TYPE_GITLAB,
url: apiBaseUrl,
});
if (opts.token) {
return await gitlab.getReleaseNotesMd(
repository,
apiBaseUrl,
sourceDirectory
);
}
case 'github':
return await github.getReleaseNotesMd(
repository,
apiBaseUrl,
sourceDirectory
);
} catch (err) /* istanbul ignore next */ {
if (err.statusCode === 404) {
logger.debug('Error 404 getting changelog md');
} else {
logger.debug({ err, repository }, 'Error getting changelog md');
}
default:
logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type');
return null;
}
} catch (err) /* istanbul ignore next */ {
if (err.statusCode === 404) {
logger.debug(
{ repository, type, apiBaseUrl },
'Error 404 getting changelog md'
);
} else {
logger.debug(
{ err, repository, type, apiBaseUrl },
'Error getting changelog md'
);
}
}
return null;
}
export function getReleaseNotesMdFile(
repository: string,
apiBaseUrl: string,
sourceDirectory?: string
project: ChangeLogProject
): Promise<ChangeLogFile | null> {
const cacheKey = `getReleaseNotesMdFile-${repository}-${apiBaseUrl}`;
const cacheKey = `getReleaseNotesMdFile-${project.repository}-${project.apiBaseUrl}`;
const cachedResult = memCache.get<Promise<ChangeLogFile | null>>(cacheKey);
// istanbul ignore if
if (cachedResult !== undefined) {
return cachedResult;
}
const promisedRes = getReleaseNotesMdFileInner(
repository,
apiBaseUrl,
sourceDirectory
);
const promisedRes = getReleaseNotesMdFileInner(project);
memCache.set(cacheKey, promisedRes);
return promisedRes;
}
export async function getReleaseNotesMd(
repository: string,
version: string,
baseUrl: string,
apiBaseUrl: string,
sourceDirectory?: string
project: ChangeLogProject,
version: string
): Promise<ChangeLogNotes | null> {
const { baseUrl, repository } = project;
logger.trace(`getReleaseNotesMd(${repository}, ${version})`);
const skippedRepos = ['facebook/react-native'];
// istanbul ignore if
if (skippedRepos.includes(repository)) {
return null;
}
const changelog = await getReleaseNotesMdFile(
repository,
apiBaseUrl,
sourceDirectory
);
const changelog = await getReleaseNotesMdFile(project);
if (!changelog) {
return null;
}
@ -332,20 +313,13 @@ export function releaseNotesCacheMinutes(releaseDate?: string | Date): number {
export async function addReleaseNotes(
input: ChangeLogResult
): Promise<ChangeLogResult> {
if (
!input?.versions ||
(!input?.project?.github && !input?.project?.gitlab)
) {
if (!input?.versions || !input.project?.type) {
logger.debug('Missing project or versions');
return input;
}
const output: ChangeLogResult = { ...input, versions: [] };
const repository = input.project.github
? input.project.github.replace(/\.git$/, '')
: input.project.gitlab;
const cacheNamespace = input.project.github
? 'changelog-github-notes'
: 'changelog-gitlab-notes';
const repository = input.project.repository;
const cacheNamespace = `changelog-${input.project.type}-notes`;
function getCacheKey(version: string): string {
return `${repository}:${version}`;
}
@ -355,23 +329,10 @@ export async function addReleaseNotes(
releaseNotes = await packageCache.get(cacheNamespace, cacheKey);
// istanbul ignore else: no cache tests
if (!releaseNotes) {
const { sourceDirectory } = input.project;
releaseNotes = await getReleaseNotesMd(
repository,
v.version,
input.project.baseUrl,
input.project.apiBaseUrl,
sourceDirectory
);
releaseNotes = await getReleaseNotesMd(input.project, v.version);
// istanbul ignore else: should be tested
if (!releaseNotes) {
releaseNotes = await getReleaseNotes(
repository,
v.version,
input.project.depName,
input.project.baseUrl,
input.project.apiBaseUrl
);
releaseNotes = await getReleaseNotes(input.project, v.version);
}
// Small hack to force display of release notes when there is a compare url
if (!releaseNotes && v.compare.url) {

View file

@ -68,7 +68,10 @@ export async function getChangeLogJSON({
const apiBaseUrl = sourceUrl.startsWith('https://github.com/')
? 'https://api.github.com/'
: baseUrl + 'api/v3/';
const repository = pathname.slice(1).replace(/\/$/, '');
const repository = pathname
.slice(1)
.replace(/\/$/, '')
.replace(/\.git$/, '');
if (repository.split('/').length !== 2) {
logger.debug({ sourceUrl }, 'Invalid github URL found');
return null;
@ -154,8 +157,9 @@ export async function getChangeLogJSON({
project: {
apiBaseUrl,
baseUrl,
github: repository,
repository: sourceUrl,
type: 'github',
repository,
sourceUrl,
sourceDirectory,
depName,
},

View file

@ -130,8 +130,9 @@ export async function getChangeLogJSON({
project: {
apiBaseUrl,
baseUrl,
gitlab: repository,
repository: sourceUrl,
type: 'gitlab',
repository,
sourceUrl,
depName,
},
versions: changelogReleases,

View file

@ -22,11 +22,11 @@ export interface ChangeLogRelease {
export interface ChangeLogProject {
depName?: string;
github?: string;
gitlab?: string;
type: 'github' | 'gitlab';
apiBaseUrl?: string;
baseUrl: string;
repository: string;
sourceUrl: string;
sourceDirectory?: string;
}

View file

@ -1,21 +1,18 @@
import { git, mocked, partial } from '../../../test/util';
import { getConfig } from '../../config/defaults';
import { getConfig, git, mocked, partial, platform } from '../../../test/util';
import { PLATFORM_TYPE_GITLAB } from '../../constants/platforms';
import { Pr, platform as _platform } from '../../platform';
import type { Pr } from '../../platform/types';
import { BranchStatus } from '../../types';
import * as _limits from '../global/limits';
import type { BranchConfig } from '../types';
import * as prAutomerge from './automerge';
import * as _changelogHelper from './changelog';
import { getChangeLogJSON } from './changelog';
import type { ChangeLogResult } from './changelog';
import * as codeOwners from './code-owners';
import * as prWorker from '.';
const codeOwnersMock = mocked(codeOwners);
const changelogHelper = mocked(_changelogHelper);
const gitlabChangelogHelper = mocked(_changelogHelper);
const platform = mocked(_platform);
const defaultConfig = getConfig();
const limits = mocked(_limits);
jest.mock('../../util/git');
@ -24,12 +21,12 @@ jest.mock('./code-owners');
jest.mock('../global/limits');
function setupChangelogMock() {
changelogHelper.getChangeLogJSON = jest.fn();
const resultValue = {
project: {
type: 'github',
baseUrl: 'https://github.com/',
github: 'renovateapp/dummy',
repository: 'https://github.com/renovateapp/dummy',
repository: 'renovateapp/dummy',
sourceUrl: 'https://github.com/renovateapp/dummy',
},
hasReleaseNotes: true,
versions: [
@ -51,7 +48,7 @@ function setupChangelogMock() {
},
},
],
};
} as ChangeLogResult;
const errorValue = {
error: _changelogHelper.ChangeLogError.MissingGithubToken,
};
@ -61,12 +58,12 @@ function setupChangelogMock() {
}
function setupGitlabChangelogMock() {
gitlabChangelogHelper.getChangeLogJSON = jest.fn();
const resultValue = {
project: {
type: 'gitlab',
baseUrl: 'https://gitlab.com/',
gitlab: 'renovateapp/gitlabdummy',
repository: 'https://gitlab.com/renovateapp/gitlabdummy',
repository: 'renovateapp/gitlabdummy',
sourceUrl: 'https://gitlab.com/renovateapp/gitlabdummy',
},
hasReleaseNotes: true,
versions: [
@ -88,7 +85,7 @@ function setupGitlabChangelogMock() {
},
},
],
};
} as ChangeLogResult;
const errorValue = {
error: _changelogHelper.ChangeLogError.MissingGithubToken,
};
@ -103,7 +100,7 @@ describe('workers/pr/index', () => {
let pr: Pr;
beforeEach(() => {
config = partial<BranchConfig>({
...defaultConfig,
...getConfig(),
});
pr = partial<Pr>({
canMerge: true,
@ -180,7 +177,7 @@ describe('workers/pr/index', () => {
jest.resetAllMocks();
setupChangelogMock();
config = partial<BranchConfig>({
...defaultConfig,
...getConfig(),
});
config.branchName = 'renovate/dummy-1.x';
config.prTitle = 'Update dependency dummy to v1.1.0';
@ -199,9 +196,7 @@ describe('workers/pr/index', () => {
displayNumber: 'New Pull Request',
} as never);
config.upgrades = [config];
platform.massageMarkdown = jest.fn((input) => input);
platform.getBranchPr = jest.fn();
platform.getBranchStatus = jest.fn();
platform.massageMarkdown.mockImplementation((input) => input);
});
afterEach(() => {
jest.clearAllMocks();
@ -252,7 +247,7 @@ describe('workers/pr/index', () => {
});
it('should create PR if success', async () => {
platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.green);
config.logJSON = await getChangeLogJSON(config);
config.logJSON = await changelogHelper.getChangeLogJSON(config);
config.prCreation = 'status-success';
config.automerge = true;
config.schedule = ['before 5am'];
@ -264,7 +259,7 @@ describe('workers/pr/index', () => {
});
it('should not create PR if limit is reached', async () => {
platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.green);
config.logJSON = await getChangeLogJSON(config);
config.logJSON = await changelogHelper.getChangeLogJSON(config);
config.prCreation = 'status-success';
config.automerge = true;
config.schedule = ['before 5am'];
@ -275,7 +270,7 @@ describe('workers/pr/index', () => {
});
it('should create PR if limit is reached but dashboard checked', async () => {
platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.green);
config.logJSON = await getChangeLogJSON(config);
config.logJSON = await changelogHelper.getChangeLogJSON(config);
config.prCreation = 'status-success';
config.automerge = true;
config.schedule = ['before 5am'];
@ -315,7 +310,7 @@ describe('workers/pr/index', () => {
config.recreateClosed = true;
config.rebaseWhen = 'never';
for (const upgrade of config.upgrades) {
upgrade.logJSON = await getChangeLogJSON(upgrade);
upgrade.logJSON = await changelogHelper.getChangeLogJSON(upgrade);
}
const { pr } = await prWorker.ensurePr(config);
expect(pr).toMatchObject({ displayNumber: 'New Pull Request' });
@ -330,7 +325,7 @@ describe('workers/pr/index', () => {
config.schedule = ['before 5am'];
config.timezone = 'some timezone';
config.rebaseWhen = 'behind-base-branch';
config.logJSON = await getChangeLogJSON(config);
config.logJSON = await changelogHelper.getChangeLogJSON(config);
const { pr } = await prWorker.ensurePr(config);
expect(pr).toMatchObject({ displayNumber: 'New Pull Request' });
// FIXME: explicit assert condition
@ -341,7 +336,6 @@ describe('workers/pr/index', () => {
});
it('should return null if creating PR fails', async () => {
platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.green);
platform.createPr = jest.fn();
platform.createPr.mockImplementationOnce(() => {
throw new Error('Validation Failed (422)');
});
@ -405,6 +399,7 @@ describe('workers/pr/index', () => {
config.assignees = ['@foo', 'bar'];
config.reviewers = ['foo', '@bar', 'foo@bar.com'];
config.filterUnavailableUsers = true;
// optional function is undefined by jest
platform.filterUnavailableUsers = jest.fn();
platform.filterUnavailableUsers.mockResolvedValue(['foo']);
await prWorker.ensurePr(config);
@ -523,7 +518,7 @@ describe('workers/pr/index', () => {
config.semanticCommitScope = null;
config.automerge = true;
config.schedule = ['before 5am'];
config.logJSON = await getChangeLogJSON(config);
config.logJSON = await changelogHelper.getChangeLogJSON(config);
const { pr } = await prWorker.ensurePr(config);
expect(platform.updatePr.mock.calls).toMatchSnapshot();
expect(platform.updatePr).toHaveBeenCalledTimes(0);
@ -537,7 +532,7 @@ describe('workers/pr/index', () => {
config.semanticCommitScope = null;
config.automerge = true;
config.schedule = ['before 5am'];
config.logJSON = await getChangeLogJSON(config);
config.logJSON = await changelogHelper.getChangeLogJSON(config);
const { pr } = await prWorker.ensurePr(config);
expect(platform.updatePr).toHaveBeenCalledTimes(0);
expect(pr).toMatchObject(modifiedPr);
@ -546,7 +541,7 @@ describe('workers/pr/index', () => {
config.newValue = '1.2.0';
config.automerge = true;
config.schedule = ['before 5am'];
config.logJSON = await getChangeLogJSON(config);
config.logJSON = await changelogHelper.getChangeLogJSON(config);
platform.getBranchPr.mockResolvedValueOnce(existingPr);
const { pr } = await prWorker.ensurePr(config);
// FIXME: explicit assert condition
@ -614,9 +609,8 @@ describe('workers/pr/index', () => {
platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.green);
config.prCreation = 'status-success';
config.privateRepo = false;
config.logJSON = await getChangeLogJSON(config);
config.logJSON.project.gitlab = 'someproject';
delete config.logJSON.project.github;
config.logJSON = await changelogHelper.getChangeLogJSON(config);
config.logJSON.project.repository = 'someproject';
const { pr } = await prWorker.ensurePr(config);
expect(pr).toMatchObject({ displayNumber: 'New Pull Request' });
expect(platform.createPr.mock.calls[0]).toMatchSnapshot();

View file

@ -278,9 +278,7 @@ export async function ensurePr(
if (logJSON) {
if (typeof logJSON.error === 'undefined') {
if (logJSON.project) {
upgrade.repoName = logJSON.project.github
? logJSON.project.github
: logJSON.project.gitlab;
upgrade.repoName = logJSON.project.repository;
}
upgrade.hasReleaseNotes = logJSON.hasReleaseNotes;
upgrade.releases = [];