From c49c884baed063b48b954f920474f255459fcd34 Mon Sep 17 00:00:00 2001 From: Michael Kriese <michael.kriese@visualon.de> Date: Wed, 4 Dec 2019 04:29:27 +0100 Subject: [PATCH] fix(typescript): convert workers/pr/changelog to ts (#4888) --- lib/workers/pr/changelog/common.ts | 49 ++++++++++ .../{hbs-template.js => hbs-template.ts} | 2 +- .../pr/changelog/{index.js => index.ts} | 17 ++-- .../{release-notes.js => release-notes.ts} | 85 ++++++++++-------- .../pr/changelog/{releases.js => releases.ts} | 31 ++++--- .../{source-github.js => source-github.ts} | 39 ++++---- lib/workers/pr/pr-body.js | 2 +- package.json | 1 + test/util.ts | 7 ++ ...{index.spec.js.snap => index.spec.ts.snap} | 0 ...{index.spec.js.snap => index.spec.ts.snap} | 22 ++--- ...pec.js.snap => release-notes.spec.ts.snap} | 0 ...ses.spec.js.snap => releases.spec.ts.snap} | 0 .../{index.spec.js => index.spec.ts} | 40 ++++----- ...se-notes.spec.js => release-notes.spec.ts} | 35 ++++---- .../{releases.spec.js => releases.spec.ts} | 11 ++- .../pr/{index.spec.js => index.spec.ts} | 90 ++++++++++--------- yarn.lock | 12 +++ 18 files changed, 269 insertions(+), 174 deletions(-) create mode 100644 lib/workers/pr/changelog/common.ts rename lib/workers/pr/changelog/{hbs-template.js => hbs-template.ts} (92%) rename lib/workers/pr/changelog/{index.js => index.ts} (58%) rename lib/workers/pr/changelog/{release-notes.js => release-notes.ts} (82%) rename lib/workers/pr/changelog/{releases.js => releases.ts} (68%) rename lib/workers/pr/changelog/{source-github.js => source-github.ts} (82%) create mode 100644 test/util.ts rename test/workers/pr/__snapshots__/{index.spec.js.snap => index.spec.ts.snap} (100%) rename test/workers/pr/changelog/__snapshots__/{index.spec.js.snap => index.spec.ts.snap} (95%) rename test/workers/pr/changelog/__snapshots__/{release-notes.spec.js.snap => release-notes.spec.ts.snap} (100%) rename test/workers/pr/changelog/__snapshots__/{releases.spec.js.snap => releases.spec.ts.snap} (100%) rename test/workers/pr/changelog/{index.spec.js => index.spec.ts} (87%) rename test/workers/pr/changelog/{release-notes.spec.js => release-notes.spec.ts} (84%) rename test/workers/pr/changelog/{releases.spec.js => releases.spec.ts} (89%) rename test/workers/pr/{index.spec.js => index.spec.ts} (85%) diff --git a/lib/workers/pr/changelog/common.ts b/lib/workers/pr/changelog/common.ts new file mode 100644 index 0000000000..36a7a76c18 --- /dev/null +++ b/lib/workers/pr/changelog/common.ts @@ -0,0 +1,49 @@ +import { Release } from '../../../datasource'; + +export interface ChangeLogNotes { + body?: string; + id?: number; + name?: string; + tag?: string; + url: string; +} + +export interface ChangeLogChange { + date: Date; + message: string; + sha: string; +} + +export interface ChangeLogRelease { + changes: ChangeLogChange[]; + compare: { url?: string }; + date: string | Date; + releaseNotes?: ChangeLogNotes; + version: string; +} + +export interface ChangeLogProject { + depName?: string; + github: string; + githubApiBaseURL?: string; + githubBaseURL: string; + repository: string; +} + +export interface ChangeLogResult { + hasReleaseNotes?: boolean; + project: ChangeLogProject; + versions: ChangeLogRelease[]; +} + +export interface ChangeLogConfig { + depName: string; + depType?: string; + endpoint: string; + fromVersion: string; + manager?: string; + releases: Release[]; + sourceUrl?: string; + toVersion: string; + versionScheme: string; +} diff --git a/lib/workers/pr/changelog/hbs-template.js b/lib/workers/pr/changelog/hbs-template.ts similarity index 92% rename from lib/workers/pr/changelog/hbs-template.js rename to lib/workers/pr/changelog/hbs-template.ts index 6f2aba58a3..f646ea2f9e 100644 --- a/lib/workers/pr/changelog/hbs-template.js +++ b/lib/workers/pr/changelog/hbs-template.ts @@ -1,4 +1,4 @@ -module.exports = `### Release Notes +export default `### Release Notes {{#each upgrades as |upgrade|}} diff --git a/lib/workers/pr/changelog/index.js b/lib/workers/pr/changelog/index.ts similarity index 58% rename from lib/workers/pr/changelog/index.js rename to lib/workers/pr/changelog/index.ts index 70ddcea4d5..40a69f31cc 100644 --- a/lib/workers/pr/changelog/index.js +++ b/lib/workers/pr/changelog/index.ts @@ -1,13 +1,14 @@ -const { logger } = require('../../../logger'); -const versioning = require('../../../versioning'); -const sourceGithub = require('./source-github'); -const { getReleases } = require('./releases'); +import { logger } from '../../../logger'; +import * as versioning from '../../../versioning'; +import * as sourceGithub from './source-github'; +import { getReleases } from './releases'; +import { ChangeLogConfig, ChangeLogResult } from './common'; -module.exports = { - getChangeLogJSON, -}; +export * from './common'; -async function getChangeLogJSON(args) { +export async function getChangeLogJSON( + args: ChangeLogConfig +): Promise<ChangeLogResult | null> { const { sourceUrl, versionScheme, fromVersion, toVersion } = args; if (!sourceUrl) { return null; diff --git a/lib/workers/pr/changelog/release-notes.js b/lib/workers/pr/changelog/release-notes.ts similarity index 82% rename from lib/workers/pr/changelog/release-notes.js rename to lib/workers/pr/changelog/release-notes.ts index f7f3f8bf4a..17b599085a 100644 --- a/lib/workers/pr/changelog/release-notes.js +++ b/lib/workers/pr/changelog/release-notes.ts @@ -4,21 +4,17 @@ import MarkdownIt from 'markdown-it'; import { api } from '../../../platform/github/gh-got-wrapper'; import { logger } from '../../../logger'; +import { ChangeLogResult, ChangeLogNotes } from './common'; const ghGot = api.get; const markdown = new MarkdownIt('zero'); markdown.enable(['heading', 'lheading']); -export { - getReleaseList, - massageBody, - getReleaseNotesMd, - getReleaseNotes, - addReleaseNotes, -}; - -async function getReleaseList(githubApiBaseURL, repository) { +export async function getReleaseList( + githubApiBaseURL: string, + repository: string +): Promise<ChangeLogNotes[]> { logger.trace('getReleaseList()'); // istanbul ignore if if (!githubApiBaseURL) { @@ -27,7 +23,15 @@ async function getReleaseList(githubApiBaseURL, repository) { try { let url = githubApiBaseURL.replace(/\/?$/, '/'); url += `repos/${repository}/releases?per_page=100`; - const res = await ghGot(url); + const res = await ghGot< + { + 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, @@ -41,7 +45,10 @@ async function getReleaseList(githubApiBaseURL, repository) { } } -function massageBody(input, githubBaseURL) { +export function massageBody( + input: string | undefined | null, + githubBaseURL: string +): string { let body = input || ''; // Convert line returns body = body.replace(/\r\n/g, '\n'); @@ -67,16 +74,16 @@ function massageBody(input, githubBaseURL) { return body.trim(); } -async function getReleaseNotes( - repository, - version, - depName, - githubBaseURL, - githubApiBaseURL -) { +export async function getReleaseNotes( + repository: string, + version: string, + depName: string, + githubBaseURL: string, + githubApiBaseURL: string +): Promise<ChangeLogNotes | null> { logger.trace(`getReleaseNotes(${repository}, ${version}, ${depName})`); const releaseList = await getReleaseList(githubApiBaseURL, repository); - let releaseNotes; + let releaseNotes: ChangeLogNotes | null = null; releaseList.forEach(release => { if ( release.tag === version || @@ -87,7 +94,7 @@ async function getReleaseNotes( releaseNotes.url = `${githubBaseURL}${repository}/releases/${release.tag}`; releaseNotes.body = massageBody(releaseNotes.body, githubBaseURL); if (!releaseNotes.body.length) { - releaseNotes = undefined; + releaseNotes = null; } else { releaseNotes.body = linkify(releaseNotes.body, { repository: `https://github.com/${repository}`, @@ -99,10 +106,10 @@ async function getReleaseNotes( return releaseNotes; } -function sectionize(text, level) { - const sections = []; +function sectionize(text: string, level: number): string[] { + const sections: [number, number][] = []; const lines = text.split('\n'); - const tokens = markdown.parse(text); + const tokens = markdown.parse(text, undefined); tokens.forEach(token => { if (token.type === 'heading_open') { const lev = +token.tag.substr(1); @@ -112,7 +119,7 @@ function sectionize(text, level) { } }); sections.push([-1, lines.length]); - const result = []; + const result: string[] = []; for (let i = 1; i < sections.length; i += 1) { const [lev, start] = sections[i - 1]; const [, end] = sections[i]; @@ -123,25 +130,25 @@ function sectionize(text, level) { return result; } -async function getReleaseNotesMd( - repository, - version, - githubBaseURL, - githubApiBaseUrl -) { +export async function getReleaseNotesMd( + repository: string, + version: string, + githubBaseURL: string, + githubApiBaseUrl: string +): Promise<ChangeLogNotes | null> { logger.trace(`getReleaseNotesMd(${repository}, ${version})`); const skippedRepos = ['facebook/react-native']; // istanbul ignore if if (skippedRepos.includes(repository)) { return null; } - let changelogFile; + let changelogFile: string; let changelogMd = ''; try { let apiPrefix = githubApiBaseUrl.replace(/\/?$/, '/'); apiPrefix += `repos/${repository}/contents/`; - const filesRes = await ghGot(apiPrefix); + const filesRes = await ghGot<{ name: string }[]>(apiPrefix); const files = filesRes.body .map(f => f.name) .filter(f => changelogFilenameRegex.test(f)); @@ -156,7 +163,9 @@ async function getReleaseNotesMd( `Multiple candidates for changelog file, using ${changelogFile}` ); } - const fileRes = await ghGot(`${apiPrefix}/${changelogFile}`); + const fileRes = await ghGot<{ content: string }>( + `${apiPrefix}/${changelogFile}` + ); changelogMd = Buffer.from(fileRes.body.content, 'base64').toString() + '\n#\n##'; } catch (err) { @@ -208,19 +217,21 @@ async function getReleaseNotesMd( return null; } -async function addReleaseNotes(input) { +export async function addReleaseNotes( + input: ChangeLogResult +): Promise<ChangeLogResult> { if (!(input && input.project && input.project.github && input.versions)) { logger.debug('Missing project or versions'); return input; } - const output = { ...input, versions: [] }; + const output: ChangeLogResult = { ...input, versions: [] }; const repository = input.project.github.replace(/\.git$/, ''); const cacheNamespace = 'changelog-github-notes'; - function getCacheKey(version) { + function getCacheKey(version: string): string { return `${repository}:${version}`; } for (const v of input.versions) { - let releaseNotes; + let releaseNotes: ChangeLogNotes; const cacheKey = getCacheKey(v.version); releaseNotes = await renovateCache.get(cacheNamespace, cacheKey); if (!releaseNotes) { diff --git a/lib/workers/pr/changelog/releases.js b/lib/workers/pr/changelog/releases.ts similarity index 68% rename from lib/workers/pr/changelog/releases.js rename to lib/workers/pr/changelog/releases.ts index 5357922b4f..941b6573c0 100644 --- a/lib/workers/pr/changelog/releases.js +++ b/lib/workers/pr/changelog/releases.ts @@ -1,12 +1,8 @@ -const { getPkgReleases } = require('../../../datasource'); -const { logger } = require('../../../logger'); -const versioning = require('../../../versioning'); +import { getPkgReleases, Release, PkgReleaseConfig } from '../../../datasource'; +import { logger } from '../../../logger'; +import { get, VersioningApi } from '../../../versioning'; -module.exports = { - getReleases, -}; - -function matchesMMP(version, v1, v2) { +function matchesMMP(version: VersioningApi, v1: string, v2: string): boolean { return ( version.getMajor(v1) === version.getMajor(v2) && version.getMinor(v1) === version.getMinor(v2) && @@ -14,15 +10,28 @@ function matchesMMP(version, v1, v2) { ); } -function matchesUnstable(version, v1, v2) { +function matchesUnstable( + version: VersioningApi, + v1: string, + v2: string +): boolean { return !version.isStable(v1) && matchesMMP(version, v1, v2); } -async function getReleases(config) { +export type ReleaseConfig = PkgReleaseConfig & { + fromVersion: string; + releases?: Release[]; + sourceUrl?: string; + toVersion: string; +}; + +export async function getReleases( + config: ReleaseConfig +): Promise<Release[] | null> { const { versionScheme, fromVersion, toVersion, depName, datasource } = config; try { const pkgReleases = (await getPkgReleases(config)).releases; - const version = versioning.get(versionScheme); + const version = get(versionScheme); const releases = pkgReleases .filter(release => version.isCompatible(release.version, fromVersion)) diff --git a/lib/workers/pr/changelog/source-github.js b/lib/workers/pr/changelog/source-github.ts similarity index 82% rename from lib/workers/pr/changelog/source-github.js rename to lib/workers/pr/changelog/source-github.ts index e1b49523f1..b805085ccb 100644 --- a/lib/workers/pr/changelog/source-github.js +++ b/lib/workers/pr/changelog/source-github.ts @@ -1,22 +1,25 @@ +import URL from 'url'; import { api } from '../../../platform/github/gh-got-wrapper'; - -const URL = require('url'); -const { logger } = require('../../../logger'); -const hostRules = require('../../../util/host-rules'); -const versioning = require('../../../versioning'); -const { addReleaseNotes } = require('./release-notes'); +import { logger } from '../../../logger'; +import * as hostRules from '../../../util/host-rules'; +import * as versioning from '../../../versioning'; +import { addReleaseNotes } from './release-notes'; +import { ChangeLogResult, ChangeLogRelease, ChangeLogConfig } from './common'; +import { Release } from '../../../datasource'; const ghGot = api.get; -export { getChangeLogJSON }; - -async function getTags(endpoint, versionScheme, repository) { +async function getTags( + endpoint: string, + versionScheme: string, + repository: string +): Promise<string[]> { let url = endpoint ? endpoint.replace(/\/?$/, '/') : /* istanbul ignore next: not possible to test, maybe never possible? */ 'https://api.github.com/'; url += `repos/${repository}/tags?per_page=100`; try { - const res = await ghGot(url, { + const res = await ghGot<{ name: string }[]>(url, { paginate: true, }); @@ -39,7 +42,7 @@ async function getTags(endpoint, versionScheme, repository) { } } -async function getChangeLogJSON({ +export async function getChangeLogJSON({ endpoint, versionScheme, fromVersion, @@ -48,7 +51,7 @@ async function getChangeLogJSON({ releases, depName, manager, -}) { +}: ChangeLogConfig): Promise<ChangeLogResult | null> { if (sourceUrl === 'https://github.com/DefinitelyTyped/DefinitelyTyped') { logger.debug('No release notes for @types'); return null; @@ -89,9 +92,9 @@ async function getChangeLogJSON({ return null; } - let tags; + let tags: string[]; - async function getRef(release) { + async function getRef(release: Release): Promise<string | null> { if (!tags) { tags = await getTags(endpoint, versionScheme, repository); } @@ -109,13 +112,13 @@ async function getChangeLogJSON({ } const cacheNamespace = 'changelog-github-release'; - function getCacheKey(prev, next) { + function getCacheKey(prev: string, next: string): string { return `${manager}:${depName}:${prev}:${next}`; } - const changelogReleases = []; + const changelogReleases: ChangeLogRelease[] = []; // compare versions - const include = v => + const include = (v: string): boolean => version.isGreaterThan(v, fromVersion) && !version.isGreaterThan(v, toVersion); for (let i = 1; i < validReleases.length; i += 1) { @@ -151,7 +154,7 @@ async function getChangeLogJSON({ } } - let res = { + let res: ChangeLogResult = { project: { githubApiBaseURL, githubBaseURL, diff --git a/lib/workers/pr/pr-body.js b/lib/workers/pr/pr-body.js index f922010a14..bf11567937 100644 --- a/lib/workers/pr/pr-body.js +++ b/lib/workers/pr/pr-body.js @@ -1,9 +1,9 @@ import is from '@sindresorhus/is'; import { platform } from '../../platform'; +import releaseNotesHbs from './changelog/hbs-template'; const handlebars = require('handlebars'); const { logger } = require('../../logger'); -const releaseNotesHbs = require('./changelog/hbs-template'); const { getPrConfigDescription } = require('./pr-body-config'); const versioning = require('../../versioning'); diff --git a/package.json b/package.json index e889b687bd..3385bd8029 100644 --- a/package.json +++ b/package.json @@ -182,6 +182,7 @@ "@types/later": "1.2.5", "@types/lodash": "4.14.149", "@types/luxon": "1.21.0", + "@types/markdown-it": "0.0.9", "@types/moment-timezone": "0.5.12", "@types/nock": "10.0.3", "@types/node": "11.15.3", diff --git a/test/util.ts b/test/util.ts new file mode 100644 index 0000000000..1c6d9624e8 --- /dev/null +++ b/test/util.ts @@ -0,0 +1,7 @@ +/** + * Simple wrapper for getting mocked version of a module + * @param module module which is mocked by `jest.mock` + */ +export function mocked<T>(module: T): jest.Mocked<T> { + return module as never; +} diff --git a/test/workers/pr/__snapshots__/index.spec.js.snap b/test/workers/pr/__snapshots__/index.spec.ts.snap similarity index 100% rename from test/workers/pr/__snapshots__/index.spec.js.snap rename to test/workers/pr/__snapshots__/index.spec.ts.snap diff --git a/test/workers/pr/changelog/__snapshots__/index.spec.js.snap b/test/workers/pr/changelog/__snapshots__/index.spec.ts.snap similarity index 95% rename from test/workers/pr/changelog/__snapshots__/index.spec.js.snap rename to test/workers/pr/changelog/__snapshots__/index.spec.ts.snap index 23396fe33b..54e0ad951a 100644 --- a/test/workers/pr/changelog/__snapshots__/index.spec.js.snap +++ b/test/workers/pr/changelog/__snapshots__/index.spec.ts.snap @@ -15,14 +15,14 @@ Object { "changes": Array [], "compare": Object {}, "date": undefined, - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.5.2", }, Object { "changes": Array [], "compare": Object {}, "date": "2017-12-24T03:20:46.238Z", - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.4.2", }, Object { @@ -66,14 +66,14 @@ Object { "changes": Array [], "compare": Object {}, "date": undefined, - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.5.2", }, Object { "changes": Array [], "compare": Object {}, "date": "2017-12-24T03:20:46.238Z", - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.4.2", }, Object { @@ -117,14 +117,14 @@ Object { "changes": Array [], "compare": Object {}, "date": undefined, - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.5.2", }, Object { "changes": Array [], "compare": Object {}, "date": "2017-12-24T03:20:46.238Z", - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.4.2", }, Object { @@ -168,14 +168,14 @@ Object { "changes": Array [], "compare": Object {}, "date": undefined, - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.5.2", }, Object { "changes": Array [], "compare": Object {}, "date": "2017-12-24T03:20:46.238Z", - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.4.2", }, Object { @@ -219,7 +219,7 @@ Object { "changes": Array [], "compare": Object {}, "date": undefined, - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.5.2", }, Object { @@ -274,14 +274,14 @@ Object { "changes": Array [], "compare": Object {}, "date": undefined, - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.5.2", }, Object { "changes": Array [], "compare": Object {}, "date": "2017-12-24T03:20:46.238Z", - "releaseNotes": undefined, + "releaseNotes": null, "version": "2.4.2", }, Object { diff --git a/test/workers/pr/changelog/__snapshots__/release-notes.spec.js.snap b/test/workers/pr/changelog/__snapshots__/release-notes.spec.ts.snap similarity index 100% rename from test/workers/pr/changelog/__snapshots__/release-notes.spec.js.snap rename to test/workers/pr/changelog/__snapshots__/release-notes.spec.ts.snap diff --git a/test/workers/pr/changelog/__snapshots__/releases.spec.js.snap b/test/workers/pr/changelog/__snapshots__/releases.spec.ts.snap similarity index 100% rename from test/workers/pr/changelog/__snapshots__/releases.spec.js.snap rename to test/workers/pr/changelog/__snapshots__/releases.spec.ts.snap diff --git a/test/workers/pr/changelog/index.spec.js b/test/workers/pr/changelog/index.spec.ts similarity index 87% rename from test/workers/pr/changelog/index.spec.js rename to test/workers/pr/changelog/index.spec.ts index 1bc3c6d435..8a44a6fc39 100644 --- a/test/workers/pr/changelog/index.spec.js +++ b/test/workers/pr/changelog/index.spec.ts @@ -1,19 +1,17 @@ import { api } from '../../../../lib/platform/github/gh-got-wrapper'; +import * as hostRules from '../../../../lib/util/host-rules'; +import { + getChangeLogJSON, + ChangeLogConfig, +} from '../../../../lib/workers/pr/changelog'; +import { mocked } from '../../../util'; jest.mock('../../../../lib/platform/github/gh-got-wrapper'); jest.mock('../../../../lib/datasource/npm'); -/** @type any */ -const ghGot = api.get; +const ghGot = mocked(api).get; -const hostRules = require('../../../../lib/util/host-rules'); - -const { getChangeLogJSON } = require('../../../../lib/workers/pr/changelog'); -const releaseNotes = require('../../../../lib/workers/pr/changelog/release-notes'); - -releaseNotes.addReleaseNotes = jest.fn(input => input); - -const upgrade = { +const upgrade: ChangeLogConfig = { endpoint: 'https://api.github.com/', depName: 'renovate', versionScheme: 'semver', @@ -90,18 +88,16 @@ describe('workers/pr/changelog', () => { ).toMatchSnapshot(); }); it('uses GitHub tags', async () => { - ghGot.mockReturnValueOnce( - Promise.resolve({ - body: [ - { name: '0.9.0' }, - { name: '1.0.0' }, - { name: '1.4.0' }, - { name: 'v2.3.0' }, - { name: '2.2.2' }, - { name: 'v2.4.2' }, - ], - }) - ); + ghGot.mockResolvedValueOnce({ + body: [ + { name: '0.9.0' }, + { name: '1.0.0' }, + { name: '1.4.0' }, + { name: 'v2.3.0' }, + { name: '2.2.2' }, + { name: 'v2.4.2' }, + ], + } as never); expect( await getChangeLogJSON({ ...upgrade, diff --git a/test/workers/pr/changelog/release-notes.spec.js b/test/workers/pr/changelog/release-notes.spec.ts similarity index 84% rename from test/workers/pr/changelog/release-notes.spec.js rename to test/workers/pr/changelog/release-notes.spec.ts index b8cce3c2ff..6a0771551f 100644 --- a/test/workers/pr/changelog/release-notes.spec.js +++ b/test/workers/pr/changelog/release-notes.spec.ts @@ -6,8 +6,7 @@ import { getReleaseNotesMd, } from '../../../../lib/workers/pr/changelog/release-notes'; -/** @type any */ -const ghGot = got; +const ghGot: jest.Mock<Promise<{ body: unknown }>> = got as never; const angularJsChangelogMd = fs.readFileSync( 'test/workers/pr/_fixtures/angular.js.md', @@ -35,12 +34,12 @@ describe('workers/pr/release-notes', () => { describe('addReleaseNotes()', () => { it('returns input if invalid', async () => { const input = { a: 1 }; - expect(await addReleaseNotes(input)).toEqual(input); + expect(await addReleaseNotes(input as never)).toEqual(input); }); }); describe('getReleaseNotes()', () => { - it('should return undefined for release notes without body', async () => { - ghGot.mockReturnValueOnce({ + it('should return null for release notes without body', async () => { + ghGot.mockResolvedValueOnce({ body: [{ tag_name: 'v1.0.0' }, { tag_name: 'v1.0.1' }], }); const res = await getReleaseNotes( @@ -50,12 +49,12 @@ describe('workers/pr/release-notes', () => { 'https://github.com/', 'https://api.github.com/' ); - expect(res).toBeUndefined(); + expect(res).toBeNull(); }); it.each([[''], ['v'], ['other-']])( 'gets release notes with body', async prefix => { - ghGot.mockReturnValueOnce({ + ghGot.mockResolvedValueOnce({ body: [ { tag_name: `${prefix}1.0.0` }, { @@ -87,7 +86,7 @@ describe('workers/pr/release-notes', () => { expect(res).toBeNull(); }); it('handles files mismatch', async () => { - ghGot.mockReturnValueOnce({ + ghGot.mockResolvedValueOnce({ body: [{ name: 'lib' }, { name: 'README.md' }], }); const res = await getReleaseNotesMd( @@ -100,8 +99,8 @@ describe('workers/pr/release-notes', () => { }); it('handles wrong format', async () => { ghGot - .mockReturnValueOnce({ body: contentsResponse }) - .mockReturnValueOnce({ + .mockResolvedValueOnce({ body: contentsResponse }) + .mockResolvedValueOnce({ body: { content: Buffer.from('not really markdown').toString('base64'), }, @@ -116,8 +115,8 @@ describe('workers/pr/release-notes', () => { }); it('handles bad markdown', async () => { ghGot - .mockReturnValueOnce({ body: contentsResponse }) - .mockReturnValueOnce({ + .mockResolvedValueOnce({ body: contentsResponse }) + .mockResolvedValueOnce({ body: { content: Buffer.from(`#\nha\nha\n#\nha\nha`).toString('base64'), }, @@ -132,8 +131,8 @@ describe('workers/pr/release-notes', () => { }); it('parses angular.js', async () => { ghGot - .mockReturnValueOnce({ body: contentsResponse }) - .mockReturnValueOnce({ + .mockResolvedValueOnce({ body: contentsResponse }) + .mockResolvedValueOnce({ body: { content: Buffer.from(angularJsChangelogMd).toString('base64'), }, @@ -149,8 +148,8 @@ describe('workers/pr/release-notes', () => { }); it('parses jest', async () => { ghGot - .mockReturnValueOnce({ body: contentsResponse }) - .mockReturnValueOnce({ + .mockResolvedValueOnce({ body: contentsResponse }) + .mockResolvedValueOnce({ body: { content: Buffer.from(jestChangelogMd).toString('base64'), }, @@ -166,8 +165,8 @@ describe('workers/pr/release-notes', () => { }); it('parses js-yaml', async () => { ghGot - .mockReturnValueOnce({ body: contentsResponse }) - .mockReturnValueOnce({ + .mockResolvedValueOnce({ body: contentsResponse }) + .mockResolvedValueOnce({ body: { content: Buffer.from(jsYamlChangelogMd).toString('base64'), }, diff --git a/test/workers/pr/changelog/releases.spec.js b/test/workers/pr/changelog/releases.spec.ts similarity index 89% rename from test/workers/pr/changelog/releases.spec.js rename to test/workers/pr/changelog/releases.spec.ts index f79aa195e0..bd0bafb498 100644 --- a/test/workers/pr/changelog/releases.spec.js +++ b/test/workers/pr/changelog/releases.spec.ts @@ -1,16 +1,15 @@ -import releases from '../../../../lib/workers/pr/changelog/releases'; - -const datasource = require('../../../../lib/datasource'); +import * as releases from '../../../../lib/workers/pr/changelog/releases'; +import * as datasource from '../../../../lib/datasource'; +import { mocked } from '../../../util'; jest.mock('../../../../lib/datasource'); -/** @type any */ -const ds = datasource; +const ds = mocked(datasource); describe('workers/pr/changelog/releases', () => { describe('getReleaseNotes()', () => { beforeEach(() => { - ds.getPkgReleases.mockReturnValueOnce({ + ds.getPkgReleases.mockResolvedValueOnce({ releases: [ { version: '1.0.0', diff --git a/test/workers/pr/index.spec.js b/test/workers/pr/index.spec.ts similarity index 85% rename from test/workers/pr/index.spec.js rename to test/workers/pr/index.spec.ts index 61208bc832..912ee3f025 100644 --- a/test/workers/pr/index.spec.js +++ b/test/workers/pr/index.spec.ts @@ -1,14 +1,17 @@ -const prWorker = require('../../../lib/workers/pr'); -/** @type any */ -const changelogHelper = require('../../../lib/workers/pr/changelog'); -const defaultConfig = require('../../../lib/config/defaults').getConfig(); -/** @type any */ -const { platform } = require('../../../lib/platform'); +import * as prWorker from '../../../lib/workers/pr'; +import * as _changelogHelper from '../../../lib/workers/pr/changelog'; +import { getConfig } from '../../../lib/config/defaults'; +import { platform as _platform, Pr } from '../../../lib/platform'; +import { mocked } from '../../util'; + +const changelogHelper = mocked(_changelogHelper); +const platform = mocked(_platform); +const defaultConfig = getConfig(); jest.mock('../../../lib/workers/pr/changelog'); changelogHelper.getChangeLogJSON = jest.fn(); -changelogHelper.getChangeLogJSON.mockReturnValue({ +changelogHelper.getChangeLogJSON.mockResolvedValue({ project: { githubBaseURL: 'https://github.com/', github: 'renovateapp/dummy', @@ -61,8 +64,8 @@ describe('workers/pr', () => { it('should automerge if enabled and pr is mergeable', async () => { config.automerge = true; pr.isModified = false; - platform.getBranchStatus.mockReturnValueOnce('success'); - platform.mergePr.mockReturnValueOnce(true); + platform.getBranchStatus.mockResolvedValueOnce('success'); + platform.mergePr.mockResolvedValueOnce(true); await prWorker.checkAutoMerge(pr, config); expect(platform.mergePr).toHaveBeenCalledTimes(1); }); @@ -71,20 +74,20 @@ describe('workers/pr', () => { config.automergeType = 'pr-comment'; config.automergeComment = '!merge'; pr.isModified = false; - platform.getBranchStatus.mockReturnValueOnce('success'); + platform.getBranchStatus.mockResolvedValueOnce('success'); await prWorker.checkAutoMerge(pr, config); expect(platform.ensureComment).toHaveBeenCalledTimes(1); }); it('should not automerge if enabled and pr is mergeable but cannot rebase', async () => { config.automerge = true; pr.isModified = true; - platform.getBranchStatus.mockReturnValueOnce('success'); + platform.getBranchStatus.mockResolvedValueOnce('success'); await prWorker.checkAutoMerge(pr, config); expect(platform.mergePr).toHaveBeenCalledTimes(0); }); it('should not automerge if enabled and pr is mergeable but branch status is not success', async () => { config.automerge = true; - platform.getBranchStatus.mockReturnValueOnce('pending'); + platform.getBranchStatus.mockResolvedValueOnce('pending'); await prWorker.checkAutoMerge(pr, config); expect(platform.mergePr).toHaveBeenCalledTimes(0); }); @@ -102,15 +105,15 @@ describe('workers/pr', () => { }); }); describe('ensurePr', () => { - /** @type any */ let config; - const existingPr = { + // TODO fix type + const existingPr: Pr = { displayNumber: 'Existing PR', title: 'Update dependency dummy to v1.1.0', body: 'Some body<!-- Reviewable:start -->something<!-- Reviewable:end -->\n\n', isModified: false, - }; + } as never; beforeEach(() => { config = { ...defaultConfig, @@ -127,7 +130,10 @@ describe('workers/pr', () => { config.sourceUrl = 'https://github.com/renovateapp/dummy'; config.sourceDirectory = 'packages/a'; config.changelogUrl = 'https://github.com/renovateapp/dummy/changelog.md'; - platform.createPr.mockReturnValue({ displayNumber: 'New Pull Request' }); + // TODO fix type + platform.createPr.mockResolvedValue({ + displayNumber: 'New Pull Request', + } as never); config.upgrades = [config]; platform.getPrBody = jest.fn(input => input); platform.getBranchPr = jest.fn(); @@ -141,24 +147,24 @@ describe('workers/pr', () => { throw new Error('oops'); }); config.newValue = '1.2.0'; - platform.getBranchPr.mockReturnValueOnce(existingPr); + platform.getBranchPr.mockResolvedValueOnce(existingPr); const pr = await prWorker.ensurePr(config); expect(pr).toBeNull(); }); it('should return null if waiting for success', async () => { - platform.getBranchStatus.mockReturnValueOnce('failed'); + platform.getBranchStatus.mockResolvedValueOnce('failed'); config.prCreation = 'status-success'; const pr = await prWorker.ensurePr(config); expect(pr).toBeNull(); }); it('should return needs-approval if prCreation set to approval', async () => { - platform.getBranchStatus.mockReturnValueOnce('success'); + platform.getBranchStatus.mockResolvedValueOnce('success'); config.prCreation = 'approval'; const pr = await prWorker.ensurePr(config); expect(pr).toBe('needs-pr-approval'); }); it('should create PR if success', async () => { - platform.getBranchStatus.mockReturnValueOnce('success'); + platform.getBranchStatus.mockResolvedValueOnce('success'); config.prCreation = 'status-success'; config.automerge = true; config.schedule = 'before 5am'; @@ -199,7 +205,7 @@ describe('workers/pr', () => { expect(platform.createPr.mock.calls[0]).toMatchSnapshot(); }); it('should add note about Pin', async () => { - platform.getBranchStatus.mockReturnValueOnce('success'); + platform.getBranchStatus.mockResolvedValueOnce('success'); config.prCreation = 'status-success'; config.isPin = true; config.updateType = 'pin'; @@ -214,7 +220,7 @@ describe('workers/pr', () => { ); }); it('should return null if creating PR fails', async () => { - platform.getBranchStatus.mockReturnValueOnce('success'); + platform.getBranchStatus.mockResolvedValueOnce('success'); platform.createPr = jest.fn(); platform.createPr.mockImplementationOnce(() => { throw new Error('Validation Failed (422)'); @@ -224,23 +230,25 @@ describe('workers/pr', () => { expect(pr).toBeNull(); }); it('should return null if waiting for not pending', async () => { - platform.getBranchStatus.mockReturnValueOnce('pending'); - platform.getBranchLastCommitTime.mockImplementationOnce(() => new Date()); + platform.getBranchStatus.mockResolvedValueOnce('pending'); + platform.getBranchLastCommitTime.mockImplementationOnce(() => + Promise.resolve(new Date()) + ); config.prCreation = 'not-pending'; const pr = await prWorker.ensurePr(config); expect(pr).toBeNull(); }); it('should create PR if pending timeout hit', async () => { - platform.getBranchStatus.mockReturnValueOnce('pending'); - platform.getBranchLastCommitTime.mockImplementationOnce( - () => new Date('2017-01-01') + platform.getBranchStatus.mockResolvedValueOnce('pending'); + platform.getBranchLastCommitTime.mockImplementationOnce(() => + Promise.resolve(new Date('2017-01-01')) ); config.prCreation = 'not-pending'; const pr = await prWorker.ensurePr(config); expect(pr).toMatchObject({ displayNumber: 'New Pull Request' }); }); it('should create PR if no longer pending', async () => { - platform.getBranchStatus.mockReturnValueOnce('failed'); + platform.getBranchStatus.mockResolvedValueOnce('failed'); config.prCreation = 'not-pending'; const pr = await prWorker.ensurePr(config); expect(pr).toMatchObject({ displayNumber: 'New Pull Request' }); @@ -318,7 +326,7 @@ describe('workers/pr', () => { expect(config.reviewers).toEqual(expect.arrayContaining(reviewers)); }); it('should return unmodified existing PR', async () => { - platform.getBranchPr.mockReturnValueOnce(existingPr); + platform.getBranchPr.mockResolvedValueOnce(existingPr); config.semanticCommitScope = null; config.automerge = true; config.schedule = 'before 5am'; @@ -333,7 +341,7 @@ describe('workers/pr', () => { .replace(' ', ' ') .replace('\n', '\r\n') ); - platform.getBranchPr.mockReturnValueOnce(modifiedPr); + platform.getBranchPr.mockResolvedValueOnce(modifiedPr); config.semanticCommitScope = null; config.automerge = true; config.schedule = 'before 5am'; @@ -345,13 +353,13 @@ describe('workers/pr', () => { config.newValue = '1.2.0'; config.automerge = true; config.schedule = 'before 5am'; - platform.getBranchPr.mockReturnValueOnce(existingPr); + platform.getBranchPr.mockResolvedValueOnce(existingPr); const pr = await prWorker.ensurePr(config); expect(pr).toMatchSnapshot(); }); it('should return modified existing PR title', async () => { config.newValue = '1.2.0'; - platform.getBranchPr.mockReturnValueOnce({ + platform.getBranchPr.mockResolvedValueOnce({ ...existingPr, title: 'wrong', }); @@ -362,14 +370,14 @@ describe('workers/pr', () => { config.automerge = true; config.automergeType = 'branch'; config.branchAutomergeFailureMessage = 'branch status error'; - platform.getBranchStatus.mockReturnValueOnce('failure'); + platform.getBranchStatus.mockResolvedValueOnce('failed'); const pr = await prWorker.ensurePr(config); expect(pr).toMatchObject({ displayNumber: 'New Pull Request' }); }); it('should create PR if branch automerging failed', async () => { config.automerge = true; config.automergeType = 'branch'; - platform.getBranchStatus.mockReturnValueOnce('success'); + platform.getBranchStatus.mockResolvedValueOnce('success'); config.forcePr = true; const pr = await prWorker.ensurePr(config); expect(pr).toMatchObject({ displayNumber: 'New Pull Request' }); @@ -377,16 +385,16 @@ describe('workers/pr', () => { it('should return null if branch automerging not failed', async () => { config.automerge = true; config.automergeType = 'branch'; - platform.getBranchStatus.mockReturnValueOnce('pending'); - platform.getBranchLastCommitTime.mockReturnValueOnce(new Date()); + platform.getBranchStatus.mockResolvedValueOnce('pending'); + platform.getBranchLastCommitTime.mockResolvedValueOnce(new Date()); const pr = await prWorker.ensurePr(config); expect(pr).toBeNull(); }); it('should not return null if branch automerging taking too long', async () => { config.automerge = true; config.automergeType = 'branch'; - platform.getBranchStatus.mockReturnValueOnce('pending'); - platform.getBranchLastCommitTime.mockReturnValueOnce( + platform.getBranchStatus.mockResolvedValueOnce('pending'); + platform.getBranchLastCommitTime.mockResolvedValueOnce( new Date('2018-01-01') ); const pr = await prWorker.ensurePr(config); @@ -398,7 +406,7 @@ describe('workers/pr', () => { expect(pr).toMatchObject({ displayNumber: 'New Pull Request' }); }); it('should create privateRepo PR if success', async () => { - platform.getBranchStatus.mockReturnValueOnce('success'); + platform.getBranchStatus.mockResolvedValueOnce('success'); config.prCreation = 'status-success'; config.privateRepo = false; const pr = await prWorker.ensurePr(config); @@ -407,8 +415,8 @@ describe('workers/pr', () => { existingPr.body = platform.createPr.mock.calls[0][2]; }); it('should create PR if waiting for not pending but artifactErrors', async () => { - platform.getBranchStatus.mockReturnValueOnce('pending'); - platform.getBranchLastCommitTime.mockImplementationOnce(() => new Date()); + platform.getBranchStatus.mockResolvedValueOnce('pending'); + platform.getBranchLastCommitTime.mockResolvedValueOnce(new Date()); config.prCreation = 'not-pending'; config.artifactErrors = [{}]; config.platform = 'gitlab'; diff --git a/yarn.lock b/yarn.lock index 9a410ef2f2..f0a1cc4f95 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1252,6 +1252,11 @@ resolved "https://registry.yarnpkg.com/@types/later/-/later-1.2.5.tgz#56297f82ea0002549159219d75844a9380ad18bd" integrity sha512-oROpXZfXR+6uQyz4wBs2gZYxvZJ5Zp+iSEJWrIWgvipSnzLcHCpR9br4XUqRBPFS1EP971JlnWfXhr5so5E1sg== +"@types/linkify-it@*": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-2.1.0.tgz#ea3dd64c4805597311790b61e872cbd1ed2cd806" + integrity sha512-Q7DYAOi9O/+cLLhdaSvKdaumWyHbm7HAk/bFwwyTuU0arR5yyCeW5GOoqt4tJTpDRxhpx9Q8kQL6vMpuw9hDSw== + "@types/lodash@4.14.149": version "4.14.149" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" @@ -1262,6 +1267,13 @@ resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-1.21.0.tgz#db792d29f535d49522cb6d94dd9da053efc950a1" integrity sha512-Zhrf65tpjOlVIYrUhX9eu1VzRo8iixQDLFPbfqFxPpG4pBTNNPZ2BFhYE0IAsDfW9GWg+RcrUqiLwrGJH4rq4w== +"@types/markdown-it@0.0.9": + version "0.0.9" + resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.9.tgz#a5d552f95216c478e0a27a5acc1b28dcffd989ce" + integrity sha512-IFSepyZXbF4dgSvsk8EsgaQ/8Msv1I5eTL0BZ0X3iGO9jw6tCVtPG8HchIPm3wrkmGdqZOD42kE0zplVi1gYDA== + dependencies: + "@types/linkify-it" "*" + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" -- GitLab