Skip to content

Commit

Permalink
refactor(internal): refactor changelogs (#6878)
Browse files Browse the repository at this point in the history
  • Loading branch information
viceice committed Jul 29, 2020
1 parent 7f563b7 commit 2df9285
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 156 deletions.
96 changes: 96 additions & 0 deletions lib/workers/pr/changelog/github/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import changelogFilenameRegex from 'changelog-filename-regex';
import { logger } from '../../../../logger';
import { GithubGitBlob } from '../../../../types/platform/github';
import { GithubHttp } from '../../../../util/http/github';
import { ensureTrailingSlash } from '../../../../util/url';
import { ChangeLogFile, ChangeLogNotes } from '../common';

const http = new GithubHttp();

export async function getTags(
endpoint: string,
repository: string
): Promise<string[]> {
logger.trace('github.getTags()');
const url = `${endpoint}repos/${repository}/tags?per_page=100`;
try {
const res = await http.getJson<{ name: string }[]>(url, {
paginate: true,
});

const tags = res.body;

if (!tags.length) {
logger.debug({ repository }, 'repository has no Github tags');
}

return tags.map((tag) => tag.name).filter(Boolean);
} catch (err) {
logger.debug({ sourceRepo: repository }, 'Failed to fetch Github tags');
logger.debug({ err });
// istanbul ignore if
if (err.message && err.message.includes('Bad credentials')) {
logger.warn('Bad credentials triggering tag fail lookup in changelog');
throw err;
}
return [];
}
}

export async function getReleaseNotesMd(
repository: string,
apiBaseUrl: string
): Promise<ChangeLogFile> | null {
logger.trace('github.getReleaseNotesMd()');
const apiPrefix = `${ensureTrailingSlash(apiBaseUrl)}repos/${repository}`;

const res = await http.getJson<{ name: string }[]>(`${apiPrefix}/contents/`);

const files = res.body.filter((f) => changelogFilenameRegex.test(f.name));

if (!files.length) {
logger.trace('no changelog file found');
return null;
}
const { name: changelogFile } = files.shift();
/* istanbul ignore if */
if (files.length > 1) {
logger.debug(
`Multiple candidates for changelog file, using ${changelogFile}`
);
}

const fileRes = await http.getJson<GithubGitBlob>(
`${apiPrefix}/contents/${changelogFile}`
);

const changelogMd =
Buffer.from(fileRes.body.content, 'base64').toString() + '\n#\n##';
return { changelogFile, changelogMd };
}

export async function getReleaseList(
apiBaseUrl: string,
repository: string
): Promise<ChangeLogNotes[]> {
logger.trace('github.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);
return res.body.map((release) => ({
url: release.html_url,
id: release.id,
tag: release.tag_name,
name: release.name,
body: release.body,
}));
}
102 changes: 102 additions & 0 deletions lib/workers/pr/changelog/gitlab/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import changelogFilenameRegex from 'changelog-filename-regex';
import { logger } from '../../../../logger';
import { GitlabTreeNode } from '../../../../types/platform/gitlab';
import { GitlabHttp } from '../../../../util/http/gitlab';
import { ensureTrailingSlash } from '../../../../util/url';
import { ChangeLogFile, ChangeLogNotes } from '../common';

const http = new GitlabHttp();

function getRepoId(repository: string): string {
return repository.replace(/\//g, '%2f');
}

export async function getTags(
endpoint: string,
repository: string
): Promise<string[]> {
logger.trace('gitlab.getTags()');
const url = `${ensureTrailingSlash(endpoint)}projects/${getRepoId(
repository
)}/repository/tags`;
try {
const res = await http.getJson<{ name: string }[]>(url);

const tags = res.body;

if (!tags.length) {
logger.debug({ sourceRepo: repository }, 'repository has no Gitlab tags');
}

return tags.map((tag) => tag.name).filter(Boolean);
} catch (err) {
logger.info({ sourceRepo: repository }, 'Failed to fetch Gitlab tags');
// istanbul ignore if
if (err.message && err.message.includes('Bad credentials')) {
logger.warn('Bad credentials triggering tag fail lookup in changelog');
throw err;
}
return [];
}
}

export async function getReleaseNotesMd(
repository: string,
apiBaseUrl: string
): Promise<ChangeLogFile> | null {
logger.trace('gitlab.getReleaseNotesMd()');
const apiPrefix = `${ensureTrailingSlash(
apiBaseUrl
)}projects/${repository}/repository/`;

// https://docs.gitlab.com/13.2/ee/api/repositories.html#list-repository-tree
let files = (await http.getJson<GitlabTreeNode[]>(`${apiPrefix}tree/`)).body;

files = files.filter((f) => changelogFilenameRegex.test(f.name));
if (!files.length) {
logger.trace('no changelog file found');
return null;
}
const { name: changelogFile } = files.shift();
/* istanbul ignore if */
if (files.length > 1) {
logger.debug(
`Multiple candidates for changelog file, using ${changelogFile}`
);
}

const fileRes = await http.getJson<{ content: string }>(
`${apiPrefix}files/${changelogFile}?ref=master`
);
const changelogMd =
Buffer.from(fileRes.body.content, 'base64').toString() + '\n#\n##';
return { changelogFile, changelogMd };
}

export async function getReleaseList(
apiBaseUrl: string,
repository: string
): Promise<ChangeLogNotes[]> {
logger.trace('gitlab.getReleaseNotesMd()');

const repoId = getRepoId(repository);
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`, {
paginate: true,
});
return res.body.map((release) => ({
url: `${apiUrl}/${release.tag_name}`,
name: release.name,
body: release.description,
tag: release.tag_name,
}));
}
94 changes: 8 additions & 86 deletions lib/workers/pr/changelog/release-notes.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import * as URL from 'url';
import changelogFilenameRegex from 'changelog-filename-regex';
import { linkify } from 'linkify-markdown';
import MarkdownIt from 'markdown-it';

import { logger } from '../../../logger';
import * as memCache from '../../../util/cache/memory';
import * as packageCache from '../../../util/cache/package';
import { GithubHttp } from '../../../util/http/github';
import { GitlabHttp } from '../../../util/http/gitlab';
import { ChangeLogFile, ChangeLogNotes, ChangeLogResult } from './common';
import * as github from './github';
import * as gitlab from './gitlab';

const markdown = new MarkdownIt('zero');
markdown.enable(['heading', 'lheading']);

const githubHttp = new GithubHttp();
const gitlabHttp = new GitlabHttp();

export async function getReleaseList(
apiBaseUrl: string,
repository: string
Expand All @@ -27,47 +23,10 @@ export async function getReleaseList(
return [];
}
try {
let url = apiBaseUrl.replace(/\/?$/, '/');
if (apiBaseUrl.includes('gitlab')) {
url += `projects/${repository.replace(
/\//g,
'%2f'
)}/releases?per_page=100`;
const res = await gitlabHttp.getJson<
{
name: string;
release: string;
description: string;
tag_name: string;
}[]
>(url);
return res.body.map((release) => ({
url: `${apiBaseUrl}projects/${repository.replace(
/\//g,
'%2f'
)}/releases/${release.tag_name}`,
name: release.name,
body: release.description,
tag: release.tag_name,
}));
return await gitlab.getReleaseList(apiBaseUrl, repository);
}
url += `repos/${repository}/releases?per_page=100`;
const res = await githubHttp.getJson<
{
html_url: string;
id: number;
tag_name: string;
name: string;
body: string;
}[]
>(url);
return res.body.map((release) => ({
url: release.html_url,
id: release.id,
tag: release.tag_name,
name: release.name,
body: release.body,
}));
return await github.getReleaseList(apiBaseUrl, repository);
} catch (err) /* istanbul ignore next */ {
if (err.statusCode === 404) {
logger.debug({ repository }, 'getReleaseList 404');
Expand Down Expand Up @@ -196,54 +155,16 @@ export async function getReleaseNotesMdFileInner(
repository: string,
apiBaseUrl: string
): Promise<ChangeLogFile> | null {
let changelogFile: string;
let apiTree: string;
let apiFiles: string;
let filesRes: { body: { name: string }[] };
try {
const apiPrefix = apiBaseUrl.replace(/\/?$/, '/');
if (apiBaseUrl.includes('gitlab')) {
apiTree = apiPrefix + `projects/${repository}/repository/tree/`;
apiFiles = apiPrefix + `projects/${repository}/repository/files/`;
filesRes = await gitlabHttp.getJson<{ name: string }[]>(apiTree);
} else {
apiTree = apiPrefix + `repos/${repository}/contents/`;
apiFiles = apiTree;
filesRes = await githubHttp.getJson<{ name: string }[]>(apiTree);
}
const files = filesRes.body
.map((f) => f.name)
.filter((f) => changelogFilenameRegex.test(f));
if (!files.length) {
logger.trace('no changelog file found');
return null;
return await gitlab.getReleaseNotesMd(repository, apiBaseUrl);
}
[changelogFile] = files;
/* istanbul ignore if */
if (files.length > 1) {
logger.debug(
`Multiple candidates for changelog file, using ${changelogFile}`
);
}
let fileRes: { body: { content: string } };
if (apiBaseUrl.includes('gitlab')) {
fileRes = await gitlabHttp.getJson<{ content: string }>(
`${apiFiles}${changelogFile}?ref=master`
);
} else {
fileRes = await githubHttp.getJson<{ content: string }>(
`${apiFiles}${changelogFile}`
);
}

const changelogMd =
Buffer.from(fileRes.body.content, 'base64').toString() + '\n#\n##';
return { changelogFile, changelogMd };
return await github.getReleaseNotesMd(repository, apiBaseUrl);
} catch (err) /* istanbul ignore next */ {
if (err.statusCode === 404) {
logger.debug('Error 404 getting changelog md');
} else {
logger.debug({ err }, 'Error getting changelog md');
logger.debug({ err, repository }, 'Error getting changelog md');
}
return null;
}
Expand Down Expand Up @@ -301,6 +222,7 @@ export async function getReleaseNotesMd(
for (const word of title) {
if (word.includes(version) && !isUrl(word)) {
logger.trace({ body }, 'Found release notes for v' + version);
// TODO: fix url
let url = `${baseUrl}${repository}/blob/master/${changelogFile}#`;
url += title.join('-').replace(/[^A-Za-z0-9-]/g, '');
body = massageBody(body, baseUrl);
Expand Down

0 comments on commit 2df9285

Please sign in to comment.