mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-11 14:36:25 +00:00
feat: autodetect changelog file name (#1770)
Improves changelog detection algorithm to look for different upper/lower case options as well as alternative filenames like `History.md`. Resolves #1754
This commit is contained in:
parent
1ba12ef59c
commit
57ffec14cb
4 changed files with 72 additions and 33 deletions
|
@ -1,4 +1,5 @@
|
||||||
const ghGot = require('../../platform/github/gh-got-wrapper');
|
const ghGot = require('../../platform/github/gh-got-wrapper');
|
||||||
|
const changelogFilenameRegex = require('changelog-filename-regex');
|
||||||
const MarkdownIt = require('markdown-it');
|
const MarkdownIt = require('markdown-it');
|
||||||
|
|
||||||
const markdown = new MarkdownIt('zero');
|
const markdown = new MarkdownIt('zero');
|
||||||
|
@ -101,20 +102,30 @@ function sectionize(text, level) {
|
||||||
|
|
||||||
async function getReleaseNotesMd(repository, version) {
|
async function getReleaseNotesMd(repository, version) {
|
||||||
logger.debug(`getReleaseNotes(${repository}, ${version})`);
|
logger.debug(`getReleaseNotes(${repository}, ${version})`);
|
||||||
let changelogMd;
|
let changelogMd = '';
|
||||||
try {
|
try {
|
||||||
const res = await ghGot(
|
const apiPrefix = `https://api.github.com/repos/${repository}/contents/`;
|
||||||
`https://api.github.com/repos/${repository}/contents/CHANGELOG.md`
|
const filesRes = await ghGot(apiPrefix);
|
||||||
);
|
const files = filesRes.body
|
||||||
changelogMd =
|
.map(f => f.name)
|
||||||
Buffer.from(res.body.content, 'base64').toString() + '\n#\n##';
|
.filter(f => changelogFilenameRegex.test(f));
|
||||||
} catch (err) {
|
if (!files.length) {
|
||||||
// Probably a 404
|
logger.debug('no changelog file found');
|
||||||
}
|
|
||||||
if (!changelogMd) {
|
|
||||||
logger.debug('CHANGELOG.md not found');
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const file = files[0];
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (files.length > 1) {
|
||||||
|
logger.info(`Multiple candidates for changelog file, using ${file}`);
|
||||||
|
}
|
||||||
|
const fileRes = await ghGot(`${apiPrefix}/${file}`);
|
||||||
|
changelogMd =
|
||||||
|
Buffer.from(fileRes.body.content, 'base64').toString() + '\n#\n##';
|
||||||
|
} catch (err) {
|
||||||
|
// Probably a 404?
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
changelogMd = changelogMd.replace(/\n\s*<a name="[^"]*">.*?<\/a>\n/g, '\n');
|
changelogMd = changelogMd.replace(/\n\s*<a name="[^"]*">.*?<\/a>\n/g, '\n');
|
||||||
for (const level of [1, 2, 3, 4, 5, 6, 7]) {
|
for (const level of [1, 2, 3, 4, 5, 6, 7]) {
|
||||||
const changelogParsed = sectionize(changelogMd, level);
|
const changelogParsed = sectionize(changelogMd, level);
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
"cacache": "10.0.4",
|
"cacache": "10.0.4",
|
||||||
"chalk": "2.3.2",
|
"chalk": "2.3.2",
|
||||||
"changelog": "1.4.2",
|
"changelog": "1.4.2",
|
||||||
|
"changelog-filename-regex": "1.1.1",
|
||||||
"child-process-promise": "2.2.1",
|
"child-process-promise": "2.2.1",
|
||||||
"clean-git-ref": "1.0.3",
|
"clean-git-ref": "1.0.3",
|
||||||
"commander": "2.15.1",
|
"commander": "2.15.1",
|
||||||
|
|
|
@ -19,6 +19,12 @@ const jsYamlChangelogMd = fs.readFileSync(
|
||||||
'utf8'
|
'utf8'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const contentsResponse = [
|
||||||
|
{ name: 'lib' },
|
||||||
|
{ name: 'CHANGELOG.md' },
|
||||||
|
{ name: 'README.md' },
|
||||||
|
];
|
||||||
|
|
||||||
jest.mock('gh-got');
|
jest.mock('gh-got');
|
||||||
|
|
||||||
describe('workers/pr/release-notes', () => {
|
describe('workers/pr/release-notes', () => {
|
||||||
|
@ -36,8 +42,17 @@ describe('workers/pr/release-notes', () => {
|
||||||
const res = await getReleaseNotesMd('chalk', '2.0.0');
|
const res = await getReleaseNotesMd('chalk', '2.0.0');
|
||||||
expect(res).toBe(null);
|
expect(res).toBe(null);
|
||||||
});
|
});
|
||||||
it('handles wrong format', async () => {
|
it('handles files mismatch', async () => {
|
||||||
ghGot.mockReturnValueOnce({
|
ghGot.mockReturnValueOnce({
|
||||||
|
body: [{ name: 'lib' }, { name: 'README.md' }],
|
||||||
|
});
|
||||||
|
const res = await getReleaseNotesMd('chalk', '2.0.0');
|
||||||
|
expect(res).toBe(null);
|
||||||
|
});
|
||||||
|
it('handles wrong format', async () => {
|
||||||
|
ghGot
|
||||||
|
.mockReturnValueOnce({ body: contentsResponse })
|
||||||
|
.mockReturnValueOnce({
|
||||||
body: {
|
body: {
|
||||||
content: Buffer.from('not really markdown').toString('base64'),
|
content: Buffer.from('not really markdown').toString('base64'),
|
||||||
},
|
},
|
||||||
|
@ -46,7 +61,9 @@ describe('workers/pr/release-notes', () => {
|
||||||
expect(res).toBe(null);
|
expect(res).toBe(null);
|
||||||
});
|
});
|
||||||
it('handles bad markdown', async () => {
|
it('handles bad markdown', async () => {
|
||||||
ghGot.mockReturnValueOnce({
|
ghGot
|
||||||
|
.mockReturnValueOnce({ body: contentsResponse })
|
||||||
|
.mockReturnValueOnce({
|
||||||
body: {
|
body: {
|
||||||
content: Buffer.from(`#\nha\nha\n#\nha\nha`).toString('base64'),
|
content: Buffer.from(`#\nha\nha\n#\nha\nha`).toString('base64'),
|
||||||
},
|
},
|
||||||
|
@ -55,7 +72,9 @@ describe('workers/pr/release-notes', () => {
|
||||||
expect(res).toBe(null);
|
expect(res).toBe(null);
|
||||||
});
|
});
|
||||||
it('parses angular.js', async () => {
|
it('parses angular.js', async () => {
|
||||||
ghGot.mockReturnValueOnce({
|
ghGot
|
||||||
|
.mockReturnValueOnce({ body: contentsResponse })
|
||||||
|
.mockReturnValueOnce({
|
||||||
body: {
|
body: {
|
||||||
content: Buffer.from(angularJsChangelogMd).toString('base64'),
|
content: Buffer.from(angularJsChangelogMd).toString('base64'),
|
||||||
},
|
},
|
||||||
|
@ -65,7 +84,9 @@ describe('workers/pr/release-notes', () => {
|
||||||
expect(res).toMatchSnapshot();
|
expect(res).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
it('parses jest', async () => {
|
it('parses jest', async () => {
|
||||||
ghGot.mockReturnValueOnce({
|
ghGot
|
||||||
|
.mockReturnValueOnce({ body: contentsResponse })
|
||||||
|
.mockReturnValueOnce({
|
||||||
body: {
|
body: {
|
||||||
content: Buffer.from(jestChangelogMd).toString('base64'),
|
content: Buffer.from(jestChangelogMd).toString('base64'),
|
||||||
},
|
},
|
||||||
|
@ -75,7 +96,9 @@ describe('workers/pr/release-notes', () => {
|
||||||
expect(res).toMatchSnapshot();
|
expect(res).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
it('parses js-yaml', async () => {
|
it('parses js-yaml', async () => {
|
||||||
ghGot.mockReturnValueOnce({
|
ghGot
|
||||||
|
.mockReturnValueOnce({ body: contentsResponse })
|
||||||
|
.mockReturnValueOnce({
|
||||||
body: {
|
body: {
|
||||||
content: Buffer.from(jsYamlChangelogMd).toString('base64'),
|
content: Buffer.from(jsYamlChangelogMd).toString('base64'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -895,6 +895,10 @@ chalk@^1.1.3:
|
||||||
strip-ansi "^3.0.0"
|
strip-ansi "^3.0.0"
|
||||||
supports-color "^2.0.0"
|
supports-color "^2.0.0"
|
||||||
|
|
||||||
|
changelog-filename-regex@1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/changelog-filename-regex/-/changelog-filename-regex-1.1.1.tgz#8a2eb3049a652e3c03c8b601e3cbb032ee9f4e6d"
|
||||||
|
|
||||||
changelog@1.4.2:
|
changelog@1.4.2:
|
||||||
version "1.4.2"
|
version "1.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/changelog/-/changelog-1.4.2.tgz#618abaecfaff42cf2452d52c195ff83b5589d2fe"
|
resolved "https://registry.yarnpkg.com/changelog/-/changelog-1.4.2.tgz#618abaecfaff42cf2452d52c195ff83b5589d2fe"
|
||||||
|
|
Loading…
Reference in a new issue