From d7a649302bcfa2a75ebec688b8e3ae40dddd8287 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Thu, 11 May 2023 09:26:48 -0400 Subject: [PATCH 01/71] feat: bitbucket changelogs --- lib/modules/platform/bitbucket/index.ts | 100 +++++++++++ lib/modules/platform/bitbucket/types.ts | 22 +++ lib/util/common.ts | 16 +- .../repository/update/pr/changelog/index.ts | 11 +- .../update/pr/changelog/release-notes.ts | 28 ++- .../update/pr/changelog/source-bitbucket.ts | 159 ++++++++++++++++++ .../repository/update/pr/changelog/types.ts | 7 +- 7 files changed, 327 insertions(+), 16 deletions(-) create mode 100644 lib/workers/repository/update/pr/changelog/source-bitbucket.ts diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index b76e66576851c6..60ea222018c252 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -1,5 +1,6 @@ import URL from 'node:url'; import is from '@sindresorhus/is'; +import changelogFilenameRegex from 'changelog-filename-regex'; import JSON5 from 'json5'; import { REPOSITORY_NOT_FOUND } from '../../../constants/error-messages'; import { logger } from '../../../logger'; @@ -10,6 +11,8 @@ import { BitbucketHttp, setBaseUrl } from '../../../util/http/bitbucket'; import type { HttpOptions } from '../../../util/http/types'; import { isUUID, regEx } from '../../../util/regex'; import { sanitize } from '../../../util/sanitize'; +import { joinUrlParts } from '../../../util/url'; +import type { ChangeLogFile } from '../../../workers/repository/update/pr/changelog/types'; import type { BranchStatusConfig, CreatePRConfig, @@ -33,7 +36,9 @@ import { readOnlyIssueBody } from '../utils/read-only-issue-body'; import * as comments from './comments'; import type { Account, + BitbucketSourceResults, BitbucketStatus, + BitbucketTag, BranchResponse, Config, EffectiveReviewer, @@ -949,3 +954,98 @@ export async function mergePr({ } return true; } + +export async function getReleaseNotesMd( + repository: string, + sourceDirectory?: string +): Promise { + logger.trace('bitbucket.getReleaseNotesMd()'); + + const repositorySourceURl = joinUrlParts( + '/2.0/repositories', + repository, + 'src' + ); + + const rootFiles = ( + await bitbucketHttp.getJson>( + repositorySourceURl + ) + ).body.values; + + const allFiles = rootFiles.filter((f) => f.type === 'commit_file'); + + let files: BitbucketSourceResults[] = []; + + if (!files.length) { + files = allFiles.filter((f) => changelogFilenameRegex.test(f.path)); + } + if (!files.length) { + logger.trace('no changelog file found'); + return null; + } + + const changelogFile = files.shift()!; + + if (files.length !== 0) { + logger.debug( + `Multiple candidates for changelog file, using ${changelogFile.path}` + ); + } + + const fileRes = await bitbucketHttp.get( + joinUrlParts( + repositorySourceURl, + changelogFile.commit.hash, + changelogFile.path + ) + ); + + const changelogMd = fileRes.body + '\n#\n##'; + return { changelogFile: changelogFile.path, changelogMd }; +} + +export async function getTags(repository: string): Promise { + logger.trace('bitbucket.getTags()'); + try { + const baseRepositoryTagURL = joinUrlParts( + '/2.0/repositories', + repository, + 'refs/tags?pagelen=100' + ); + + const tags: BitbucketTag[] = []; + let hasNextPage = true; + let repositoryTagURL = baseRepositoryTagURL; + + while (hasNextPage) { + const tagsResponse = ( + await bitbucketHttp.getJson>(repositoryTagURL) + ).body; + + tags.push(...tagsResponse.values); + hasNextPage = is.nonEmptyString(tagsResponse.next); + repositoryTagURL = tagsResponse.next ?? ''; + } + + for (const tag of tags) { + logger.debug(`Found tag ${tag.name}`); + } + + // Bitbucket Tags endpoint is paginated differently to all other endpoints + + // istanbul ignore if + if (!tags.length) { + logger.debug(`No Bitbucket tags found for repository:${repository}`); + } + + return tags.map(({ name }) => name); + } catch (err) { + logger.debug( + { sourceRepo: repository, err }, + 'Failed to fetch Bitbucket tags' + ); + + return []; + } +} diff --git a/lib/modules/platform/bitbucket/types.ts b/lib/modules/platform/bitbucket/types.ts index 0ffb4b9623cb77..81a6a46e36ba6b 100644 --- a/lib/modules/platform/bitbucket/types.ts +++ b/lib/modules/platform/bitbucket/types.ts @@ -100,3 +100,25 @@ export interface EffectiveReviewer { reviewer_type: string; user: Account; } + +export interface BitbucketSourceResults { + path: string; + type: BitbucketSourceType; + commit: { + hash: string; + }; +} + +export type BitbucketSourceType = 'commit_directory' | 'commit_file'; + +export interface BitbucketTag { + name: string; + message: string; + date: string; + target: { + hash: string; + date: string; + message: string; + }; + next?: string; +} diff --git a/lib/util/common.ts b/lib/util/common.ts index 5133bfc2b1720b..79e239d11a53f8 100644 --- a/lib/util/common.ts +++ b/lib/util/common.ts @@ -1,4 +1,5 @@ import { + BITBUCKET_API_USING_HOST_TYPES, GITHUB_API_USING_HOST_TYPES, GITLAB_API_USING_HOST_TYPES, } from '../constants'; @@ -11,8 +12,14 @@ import { parseUrl } from './url'; * @param url the url to detect `platform` from * @returns matched `platform` if found, otherwise `null` */ -export function detectPlatform(url: string): 'gitlab' | 'github' | null { +export function detectPlatform( + url: string +): 'bitbucket' | 'github' | 'gitlab' | null { const { hostname } = parseUrl(url) ?? {}; + + if (hostname === 'bitbucket.org' || hostname?.includes('bitbucket')) { + return 'bitbucket'; + } if (hostname === 'github.com' || hostname?.includes('github')) { return 'github'; } @@ -26,12 +33,15 @@ export function detectPlatform(url: string): 'gitlab' | 'github' | null { return null; } - if (GITLAB_API_USING_HOST_TYPES.includes(hostType)) { - return 'gitlab'; + if (BITBUCKET_API_USING_HOST_TYPES.includes(hostType)) { + return 'bitbucket'; } if (GITHUB_API_USING_HOST_TYPES.includes(hostType)) { return 'github'; } + if (GITLAB_API_USING_HOST_TYPES.includes(hostType)) { + return 'gitlab'; + } return null; } diff --git a/lib/workers/repository/update/pr/changelog/index.ts b/lib/workers/repository/update/pr/changelog/index.ts index 7af3284a056312..874d70dc858f43 100644 --- a/lib/workers/repository/update/pr/changelog/index.ts +++ b/lib/workers/repository/update/pr/changelog/index.ts @@ -1,7 +1,11 @@ import { logger } from '../../../../../logger'; +import * as bitbucket from '../../../../../modules/platform/bitbucket'; +import * as github from '../../../../../modules/platform/github'; +import * as gitlab from '../../../../../modules/platform/gitlab'; import * as allVersioning from '../../../../../modules/versioning'; import { detectPlatform } from '../../../../../util/common'; import type { BranchUpgradeConfig } from '../../../../types'; +import * as sourceBitbucket from './source-bitbucket'; import * as sourceGithub from './source-github'; import * as sourceGitlab from './source-gitlab'; import type { ChangeLogResult } from './types'; @@ -31,12 +35,15 @@ export async function getChangeLogJSON( const platform = detectPlatform(sourceUrl); switch (platform) { - case 'gitlab': + case gitlab.id: res = await sourceGitlab.getChangeLogJSON(config); break; - case 'github': + case github.id: res = await sourceGithub.getChangeLogJSON(config); break; + case bitbucket.id: + res = await sourceBitbucket.getChangeLogJSON(config); + break; default: logger.info( diff --git a/lib/workers/repository/update/pr/changelog/release-notes.ts b/lib/workers/repository/update/pr/changelog/release-notes.ts index cae6f67d65655f..8d2ba5de28565f 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.ts @@ -4,6 +4,7 @@ import is from '@sindresorhus/is'; import { DateTime } from 'luxon'; import MarkdownIt from 'markdown-it'; import { logger } from '../../../../../logger'; +import * as bitbucketPlatform from '../../../../../modules/platform/bitbucket'; import * as memCache from '../../../../../util/cache/memory'; import * as packageCache from '../../../../../util/cache/package'; import { detectPlatform } from '../../../../../util/common'; @@ -35,7 +36,6 @@ export async function getReleaseList( return await gitlab.getReleaseList(project, release); case 'github': return await github.getReleaseList(project, release); - default: logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type'); return []; @@ -179,13 +179,17 @@ async function releaseNotesResult( } const { baseUrl, repository } = project; const releaseNotes: ChangeLogNotes = releaseMatch; - if (detectPlatform(baseUrl) === 'gitlab') { - releaseNotes.url = `${baseUrl}${repository}/tags/${releaseMatch.tag!}`; - } else { - releaseNotes.url = releaseMatch.url - ? releaseMatch.url - : /* istanbul ignore next */ - `${baseUrl}${repository}/releases/${releaseMatch.tag!}`; + const platform = detectPlatform(baseUrl); + switch (platform) { + case 'gitlab': + releaseNotes.url = `${baseUrl}${repository}/tags/${releaseMatch.tag!}`; + break; + case 'github': + releaseNotes.url = releaseMatch.url + ? releaseMatch.url + : /* istanbul ignore next */ + `${baseUrl}${repository}/releases/${releaseMatch.tag!}`; + break; } // set body for release notes releaseNotes.body = massageBody(releaseNotes.body, baseUrl); @@ -248,6 +252,7 @@ export async function getReleaseNotesMdFileInner( const { repository, type } = project; const apiBaseUrl = project.apiBaseUrl!; const sourceDirectory = project.sourceDirectory!; + try { switch (type) { case 'gitlab': @@ -262,7 +267,11 @@ export async function getReleaseNotesMdFileInner( apiBaseUrl, sourceDirectory ); - + case 'bitbucket': + return await bitbucketPlatform.getReleaseNotesMd( + repository, + sourceDirectory + ); default: logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type'); return null; @@ -313,6 +322,7 @@ export async function getReleaseNotesMd( return null; } const changelog = await getReleaseNotesMdFile(project); + if (!changelog) { return null; } diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts new file mode 100644 index 00000000000000..1db615ec31b704 --- /dev/null +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -0,0 +1,159 @@ +import URL from 'node:url'; +import { logger } from '../../../../../logger'; +import type { Release } from '../../../../../modules/datasource/types'; +import * as bitbucketHttp from '../../../../../modules/platform/bitbucket'; +import * as allVersioning from '../../../../../modules/versioning'; +import * as memCache from '../../../../../util/cache/memory'; +import * as packageCache from '../../../../../util/cache/package'; +import { regEx } from '../../../../../util/regex'; +import type { BranchUpgradeConfig } from '../../../../types'; +import { slugifyUrl } from './common'; +import { addReleaseNotes } from './release-notes'; +import { getInRangeReleases } from './releases'; +import type { ChangeLogRelease, ChangeLogResult } from './types'; + +const cacheNamespace = 'changelog-bitbucket-release'; + +function getCachedTags( + endpoint: string, + versionScheme: string, + repository: string +): Promise { + const cacheKey = `getTags-${endpoint}-${versionScheme}-${repository}`; + const cachedResult = memCache.get>(cacheKey); + // istanbul ignore if + if (cachedResult !== undefined) { + return cachedResult; + } + const promisedRes = bitbucketHttp.getTags(repository); + memCache.set(cacheKey, promisedRes); + return promisedRes; +} + +export async function getChangeLogJSON( + config: BranchUpgradeConfig +): Promise { + const versioning = config.versioning!; + const currentVersion = config.currentVersion!; + const newVersion = config.newVersion!; + const sourceUrl = config.sourceUrl!; + const packageName = config.packageName!; + const sourceDirectory = config.sourceDirectory!; + + logger.trace('getChangeLogJSON for bitbucket'); + const version = allVersioning.get(versioning); + + const parsedUrl = URL.parse(sourceUrl); + const protocol = parsedUrl.protocol!; + const host = parsedUrl.host!; + const pathname = parsedUrl.pathname!; + + logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); + const baseUrl = protocol.concat('//', host, '/'); + const apiBaseUrl = protocol.concat('//', '.api', host, '/2.0/repositories/'); + const repository = pathname + .slice(1) + .replace(regEx(/\/$/), '') + .replace(regEx(/\.git$/), ''); + + if (repository.split('/').length < 2) { + logger.info({ sourceUrl }, 'Invalid bitbucket URL found'); + return null; + } + + const releases = config.releases ?? (await getInRangeReleases(config)); + if (!releases?.length) { + logger.debug('No releases'); + return null; + } + + // This extra filter/sort should not be necessary, but better safe than sorry + const validReleases = [...releases] + .filter((release) => version.isVersion(release.version)) + .sort((a, b) => version.sortVersions(a.version, b.version)); + + if (validReleases.length < 2) { + logger.debug('Not enough valid releases'); + return null; + } + + let tags: string[]; + + async function getRef(release: Release): Promise { + if (!tags) { + tags = await getCachedTags(apiBaseUrl, versioning, repository); + } + const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); + const tagName = tags + .filter((tag) => version.isVersion(tag.replace(regex, ''))) + .find((tag) => version.equals(tag.replace(regex, ''), release.version)); + if (tagName) { + return tagName; + } + if (release.gitRef) { + return release.gitRef; + } + return null; + } + + function getCacheKey(prev: string, next: string): string { + return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; + } + + const changelogReleases: ChangeLogRelease[] = []; + // compare versions + const include = (v: string): boolean => + version.isGreaterThan(v, currentVersion) && + !version.isGreaterThan(v, newVersion); + + for (let i = 1; i < validReleases.length; i += 1) { + const prev = validReleases[i - 1]; + const next = validReleases[i]; + if (include(next.version)) { + let release = await packageCache.get( + cacheNamespace, + getCacheKey(prev.version, next.version) + ); + if (!release) { + release = { + version: next.version, + date: next.releaseTimestamp, + gitRef: next.gitRef, + // put empty changes so that existing templates won't break + changes: [], + compare: {}, + }; + const prevHead = await getRef(prev); + const nextHead = await getRef(next); + if (prevHead && nextHead) { + release.compare.url = `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; + } + const cacheMinutes = 55; + await packageCache.set( + cacheNamespace, + getCacheKey(prev.version, next.version), + release, + cacheMinutes + ); + } + changelogReleases.unshift(release); + } + } + + let res: ChangeLogResult | null = { + project: { + apiBaseUrl, + baseUrl, + type: 'bitbucket', + repository, + sourceUrl, + packageName, + sourceDirectory, + }, + versions: changelogReleases, + }; + + res = await addReleaseNotes(res, config); + + return res; +} diff --git a/lib/workers/repository/update/pr/changelog/types.ts b/lib/workers/repository/update/pr/changelog/types.ts index 23c4747a057e13..34f4d359394257 100644 --- a/lib/workers/repository/update/pr/changelog/types.ts +++ b/lib/workers/repository/update/pr/changelog/types.ts @@ -25,7 +25,7 @@ export interface ChangeLogRelease { export interface ChangeLogProject { packageName?: string; - type: 'github' | 'gitlab'; + type: 'bitbucket' | 'github' | 'gitlab'; apiBaseUrl?: string; baseUrl: string; repository: string; @@ -33,7 +33,10 @@ export interface ChangeLogProject { sourceDirectory?: string; } -export type ChangeLogError = 'MissingGithubToken' | 'MissingGitlabToken'; +export type ChangeLogError = + | 'MissingBitbucketToken' + | 'MissingGithubToken' + | 'MissingGitlabToken'; export interface ChangeLogResult { hasReleaseNotes?: boolean; From 291a8d8fa530496a9851574f6cff5f6ac00644d5 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Thu, 11 May 2023 09:52:16 -0400 Subject: [PATCH 02/71] feat: bitbucket changelogs --- lib/modules/platform/bitbucket/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index 60ea222018c252..80ca3602a1b43d 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -964,7 +964,7 @@ export async function getReleaseNotesMd( const repositorySourceURl = joinUrlParts( '/2.0/repositories', repository, - 'src' + 'src?pagelen=100' ); const rootFiles = ( From a9069213dd0544cbf948e0bc81fed20449f4f049 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Thu, 11 May 2023 10:40:29 -0400 Subject: [PATCH 03/71] fix: update api base url --- lib/workers/repository/update/pr/changelog/source-bitbucket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 1db615ec31b704..192e281e6e3313 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -50,7 +50,7 @@ export async function getChangeLogJSON( logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); const baseUrl = protocol.concat('//', host, '/'); - const apiBaseUrl = protocol.concat('//', '.api', host, '/2.0/repositories/'); + const apiBaseUrl = protocol.concat('//', 'api.', host, '/2.0/repositories/'); const repository = pathname .slice(1) .replace(regEx(/\/$/), '') From 453c613e17e31575b908c5050ee85e4867f83997 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Thu, 11 May 2023 10:43:09 -0400 Subject: [PATCH 04/71] bitbucket doesnt have the concept of releases --- lib/workers/repository/update/pr/changelog/release-notes.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/workers/repository/update/pr/changelog/release-notes.ts b/lib/workers/repository/update/pr/changelog/release-notes.ts index 8d2ba5de28565f..1b00c94d4f63fd 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.ts @@ -36,6 +36,8 @@ export async function getReleaseList( return await gitlab.getReleaseList(project, release); case 'github': return await github.getReleaseList(project, release); + case 'bitbucket': + return []; default: logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type'); return []; From fdc2a0311dd5a73eb19d11511494aa865b77675c Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Thu, 11 May 2023 11:08:51 -0400 Subject: [PATCH 05/71] refactor: make unpaginated function reusable --- lib/modules/platform/bitbucket/index.ts | 33 ++++++------------------- lib/util/http/bitbucket.ts | 33 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index 80ca3602a1b43d..7a6f5c478fa072 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -964,14 +964,13 @@ export async function getReleaseNotesMd( const repositorySourceURl = joinUrlParts( '/2.0/repositories', repository, - 'src?pagelen=100' + 'src' ); - const rootFiles = ( - await bitbucketHttp.getJson>( + const rootFiles = + await bitbucketHttp.getUnpaginatedJson( repositorySourceURl - ) - ).body.values; + ); const allFiles = rootFiles.filter((f) => f.type === 'commit_file'); @@ -1011,28 +1010,12 @@ export async function getTags(repository: string): Promise { const baseRepositoryTagURL = joinUrlParts( '/2.0/repositories', repository, - 'refs/tags?pagelen=100' + 'refs/tags' ); - const tags: BitbucketTag[] = []; - let hasNextPage = true; - let repositoryTagURL = baseRepositoryTagURL; - - while (hasNextPage) { - const tagsResponse = ( - await bitbucketHttp.getJson>(repositoryTagURL) - ).body; - - tags.push(...tagsResponse.values); - hasNextPage = is.nonEmptyString(tagsResponse.next); - repositoryTagURL = tagsResponse.next ?? ''; - } - - for (const tag of tags) { - logger.debug(`Found tag ${tag.name}`); - } - - // Bitbucket Tags endpoint is paginated differently to all other endpoints + const tags = await bitbucketHttp.getUnpaginatedJson( + baseRepositoryTagURL + ); // istanbul ignore if if (!tags.length) { diff --git a/lib/util/http/bitbucket.ts b/lib/util/http/bitbucket.ts index 628ef154cba1fe..a82a97ef15be98 100644 --- a/lib/util/http/bitbucket.ts +++ b/lib/util/http/bitbucket.ts @@ -1,3 +1,6 @@ +import is from '@sindresorhus/is'; +import type { PagedResult } from '../../modules/platform/bitbucket/types'; +import { regEx } from '../regex'; import type { HttpOptions, HttpResponse, InternalHttpOptions } from './types'; import { Http } from '.'; @@ -19,4 +22,34 @@ export class BitbucketHttp extends Http { const opts = { baseUrl, ...options }; return super.request(url, opts); } + + async getUnpaginatedJson( + url: string, + options?: HttpOptions + ): Promise { + let apiUrl = url; + const values: T[] = []; + let isIterating = true; + + while (isIterating) { + const response = (await this.getJson>(apiUrl, options)) + .body; + + values.push(...response.values); + + if (is.nullOrUndefined(response.next)) { + isIterating = false; + continue; + } + + const nextPage = + regEx(/page=\w*/) + .exec(response.next) + ?.shift() ?? ''; + + apiUrl = url.concat(`?${nextPage}`); + } + + return values; + } } From d2e3e47799786b8db2005b73442dac4fa7f52ecc Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Thu, 11 May 2023 14:09:33 -0400 Subject: [PATCH 06/71] revert: remove id usage --- lib/workers/repository/update/pr/changelog/index.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/index.ts b/lib/workers/repository/update/pr/changelog/index.ts index 874d70dc858f43..ca001ebd24aeea 100644 --- a/lib/workers/repository/update/pr/changelog/index.ts +++ b/lib/workers/repository/update/pr/changelog/index.ts @@ -1,7 +1,4 @@ import { logger } from '../../../../../logger'; -import * as bitbucket from '../../../../../modules/platform/bitbucket'; -import * as github from '../../../../../modules/platform/github'; -import * as gitlab from '../../../../../modules/platform/gitlab'; import * as allVersioning from '../../../../../modules/versioning'; import { detectPlatform } from '../../../../../util/common'; import type { BranchUpgradeConfig } from '../../../../types'; @@ -35,13 +32,13 @@ export async function getChangeLogJSON( const platform = detectPlatform(sourceUrl); switch (platform) { - case gitlab.id: + case 'gitlab': res = await sourceGitlab.getChangeLogJSON(config); break; - case github.id: + case 'github': res = await sourceGithub.getChangeLogJSON(config); break; - case bitbucket.id: + case 'bitbucket': res = await sourceBitbucket.getChangeLogJSON(config); break; From aa12bf3e742d1037311bc4969838fcaac1edc846 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Thu, 11 May 2023 16:48:59 -0400 Subject: [PATCH 07/71] revert: refactor not required --- .../update/pr/changelog/release-notes.ts | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/release-notes.ts b/lib/workers/repository/update/pr/changelog/release-notes.ts index 1b00c94d4f63fd..eb4b32e46a25fa 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.ts @@ -181,17 +181,13 @@ async function releaseNotesResult( } const { baseUrl, repository } = project; const releaseNotes: ChangeLogNotes = releaseMatch; - const platform = detectPlatform(baseUrl); - switch (platform) { - case 'gitlab': - releaseNotes.url = `${baseUrl}${repository}/tags/${releaseMatch.tag!}`; - break; - case 'github': - releaseNotes.url = releaseMatch.url - ? releaseMatch.url - : /* istanbul ignore next */ - `${baseUrl}${repository}/releases/${releaseMatch.tag!}`; - break; + if (detectPlatform(baseUrl) === 'gitlab') { + releaseNotes.url = `${baseUrl}${repository}/tags/${releaseMatch.tag!}`; + } else { + releaseNotes.url = releaseMatch.url + ? releaseMatch.url + : /* istanbul ignore next */ + `${baseUrl}${repository}/releases/${releaseMatch.tag!}`; } // set body for release notes releaseNotes.body = massageBody(releaseNotes.body, baseUrl); From 3e7c20ce4b1bc7b4f9d0344ba2741170bfc0d0c6 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Fri, 12 May 2023 07:20:34 -0400 Subject: [PATCH 08/71] types: add page to paginated bitbucket response --- lib/modules/platform/bitbucket/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/modules/platform/bitbucket/types.ts b/lib/modules/platform/bitbucket/types.ts index 81a6a46e36ba6b..82b8ead4f1bd83 100644 --- a/lib/modules/platform/bitbucket/types.ts +++ b/lib/modules/platform/bitbucket/types.ts @@ -19,6 +19,7 @@ export interface Config { } export interface PagedResult { + page?: number; pagelen: number; size?: number; next?: string; From 36b9eb88386509b4612523b69cc6f980dbfe9b7b Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Fri, 12 May 2023 11:19:19 -0400 Subject: [PATCH 09/71] add paginate query --- lib/modules/platform/bitbucket/index.ts | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index 7a6f5c478fa072..84bd5a3b1566c6 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -967,10 +967,14 @@ export async function getReleaseNotesMd( 'src' ); - const rootFiles = - await bitbucketHttp.getUnpaginatedJson( - repositorySourceURl - ); + const rootFiles = ( + await bitbucketHttp.getJson>( + repositorySourceURl, + { + paginate: true, + } + ) + ).body.values; const allFiles = rootFiles.filter((f) => f.type === 'commit_file'); @@ -1013,9 +1017,14 @@ export async function getTags(repository: string): Promise { 'refs/tags' ); - const tags = await bitbucketHttp.getUnpaginatedJson( - baseRepositoryTagURL - ); + const tags = ( + await bitbucketHttp.getJson>( + baseRepositoryTagURL, + { + paginate: true, + } + ) + ).body.values; // istanbul ignore if if (!tags.length) { From 1375e34f8198d22c90c0f671a9bead37a32d3932 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 13 May 2023 07:46:24 -0400 Subject: [PATCH 10/71] revert http/bitbucket --- lib/util/http/bitbucket.ts | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/lib/util/http/bitbucket.ts b/lib/util/http/bitbucket.ts index a82a97ef15be98..628ef154cba1fe 100644 --- a/lib/util/http/bitbucket.ts +++ b/lib/util/http/bitbucket.ts @@ -1,6 +1,3 @@ -import is from '@sindresorhus/is'; -import type { PagedResult } from '../../modules/platform/bitbucket/types'; -import { regEx } from '../regex'; import type { HttpOptions, HttpResponse, InternalHttpOptions } from './types'; import { Http } from '.'; @@ -22,34 +19,4 @@ export class BitbucketHttp extends Http { const opts = { baseUrl, ...options }; return super.request(url, opts); } - - async getUnpaginatedJson( - url: string, - options?: HttpOptions - ): Promise { - let apiUrl = url; - const values: T[] = []; - let isIterating = true; - - while (isIterating) { - const response = (await this.getJson>(apiUrl, options)) - .body; - - values.push(...response.values); - - if (is.nullOrUndefined(response.next)) { - isIterating = false; - continue; - } - - const nextPage = - regEx(/page=\w*/) - .exec(response.next) - ?.shift() ?? ''; - - apiUrl = url.concat(`?${nextPage}`); - } - - return values; - } } From 1273cb485348ff76f106f39748b0694ac87fad1e Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 07:00:51 -0400 Subject: [PATCH 11/71] refactor to match other changelog impls --- lib/modules/platform/bitbucket/index.ts | 92 --------------- .../update/pr/changelog/bitbucket/index.ts | 107 ++++++++++++++++++ .../update/pr/changelog/release-notes.ts | 9 +- .../update/pr/changelog/source-bitbucket.ts | 4 +- 4 files changed, 112 insertions(+), 100 deletions(-) create mode 100644 lib/workers/repository/update/pr/changelog/bitbucket/index.ts diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index d62949e3ddd26c..979384249c6666 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -1,6 +1,5 @@ import URL from 'node:url'; import is from '@sindresorhus/is'; -import changelogFilenameRegex from 'changelog-filename-regex'; import JSON5 from 'json5'; import { REPOSITORY_NOT_FOUND } from '../../../constants/error-messages'; import { logger } from '../../../logger'; @@ -11,8 +10,6 @@ import { BitbucketHttp, setBaseUrl } from '../../../util/http/bitbucket'; import type { HttpOptions } from '../../../util/http/types'; import { isUUID, regEx } from '../../../util/regex'; import { sanitize } from '../../../util/sanitize'; -import { joinUrlParts } from '../../../util/url'; -import type { ChangeLogFile } from '../../../workers/repository/update/pr/changelog/types'; import type { BranchStatusConfig, CreatePRConfig, @@ -36,9 +33,7 @@ import { readOnlyIssueBody } from '../utils/read-only-issue-body'; import * as comments from './comments'; import type { Account, - BitbucketSourceResults, BitbucketStatus, - BitbucketTag, BranchResponse, Config, EffectiveReviewer, @@ -958,90 +953,3 @@ export async function mergePr({ } return true; } - -export async function getReleaseNotesMd( - repository: string, - sourceDirectory?: string -): Promise { - logger.trace('bitbucket.getReleaseNotesMd()'); - - const repositorySourceURl = joinUrlParts( - '/2.0/repositories', - repository, - 'src' - ); - - const rootFiles = ( - await bitbucketHttp.getJson>( - repositorySourceURl, - { - paginate: true, - } - ) - ).body.values; - - const allFiles = rootFiles.filter((f) => f.type === 'commit_file'); - - let files: BitbucketSourceResults[] = []; - - if (!files.length) { - files = allFiles.filter((f) => changelogFilenameRegex.test(f.path)); - } - if (!files.length) { - logger.trace('no changelog file found'); - return null; - } - - const changelogFile = files.shift()!; - - if (files.length !== 0) { - logger.debug( - `Multiple candidates for changelog file, using ${changelogFile.path}` - ); - } - - const fileRes = await bitbucketHttp.get( - joinUrlParts( - repositorySourceURl, - changelogFile.commit.hash, - changelogFile.path - ) - ); - - const changelogMd = fileRes.body + '\n#\n##'; - return { changelogFile: changelogFile.path, changelogMd }; -} - -export async function getTags(repository: string): Promise { - logger.trace('bitbucket.getTags()'); - try { - const baseRepositoryTagURL = joinUrlParts( - '/2.0/repositories', - repository, - 'refs/tags' - ); - - const tags = ( - await bitbucketHttp.getJson>( - baseRepositoryTagURL, - { - paginate: true, - } - ) - ).body.values; - - // istanbul ignore if - if (!tags.length) { - logger.debug(`No Bitbucket tags found for repository:${repository}`); - } - - return tags.map(({ name }) => name); - } catch (err) { - logger.debug( - { sourceRepo: repository, err }, - 'Failed to fetch Bitbucket tags' - ); - - return []; - } -} diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts new file mode 100644 index 00000000000000..e962305cd50255 --- /dev/null +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -0,0 +1,107 @@ +import is from '@sindresorhus/is'; +import changelogFilenameRegex from 'changelog-filename-regex'; +import { logger } from '../../../../../../logger'; +import { BitbucketTagsDatasource } from '../../../../../../modules/datasource/bitbucket-tags'; +import type { + BitbucketSourceResults, + PagedResult, +} from '../../../../../../modules/platform/bitbucket/types'; +import { BitbucketHttp } from '../../../../../../util/http/bitbucket'; +import { joinUrlParts } from '../../../../../../util/url'; +import type { + ChangeLogFile, + ChangeLogNotes, + ChangeLogProject, + ChangeLogRelease, +} from '../types'; + +export const id = 'bitbucket-changelog'; +const bitbucketHttp = new BitbucketHttp(id); +const bitbucketTags = new BitbucketTagsDatasource(); + +export async function getReleaseNotesMd( + repository: string, + sourceDirectory?: string +): Promise { + logger.trace('bitbucket.getReleaseNotesMd()'); + + const repositorySourceURl = joinUrlParts( + '/2.0/repositories', + repository, + 'src' + ); + + const response = await bitbucketHttp.getJson< + PagedResult + >(repositorySourceURl, { + paginate: true, + }); + + const rootFiles = response.body.values; + const allFiles = rootFiles.filter((f) => f.type === 'commit_file'); + + let files: BitbucketSourceResults[] = []; + + if (!files.length) { + files = allFiles.filter((f) => changelogFilenameRegex.test(f.path)); + } + if (!files.length) { + logger.trace('no changelog file found'); + return null; + } + + const changelogFile = files.shift()!; + + if (files.length !== 0) { + logger.debug( + `Multiple candidates for changelog file, using ${changelogFile.path}` + ); + } + + const fileRes = await bitbucketHttp.get( + joinUrlParts( + repositorySourceURl, + changelogFile.commit.hash, + changelogFile.path + ) + ); + + const changelogMd = fileRes.body + '\n#\n##'; + return { changelogFile: changelogFile.path, changelogMd }; +} + +export async function getTags(repository: string): Promise { + logger.trace('bitbucket.getTags()'); + try { + const tags = ( + await bitbucketTags.getReleases({ + packageName: repository, + }) + )?.releases; + + // istanbul ignore if + if (is.nullOrUndefined(tags) || is.emptyArray(tags)) { + logger.debug(`No Bitbucket tags found for repository:${repository}`); + + return []; + } + + return []; + } catch (err) { + logger.debug( + { sourceRepo: repository, err }, + 'Failed to fetch Bitbucket tags' + ); + + return []; + } +} + +export function getReleaseList( + project: ChangeLogProject, + _release: ChangeLogRelease +): ChangeLogNotes[] { + logger.trace('github.getReleaseList()'); + logger.warn('TODO: implement getReleaseList() for Bitbucket'); + return []; +} diff --git a/lib/workers/repository/update/pr/changelog/release-notes.ts b/lib/workers/repository/update/pr/changelog/release-notes.ts index eb4b32e46a25fa..e35a765d95a80b 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.ts @@ -4,13 +4,13 @@ import is from '@sindresorhus/is'; import { DateTime } from 'luxon'; import MarkdownIt from 'markdown-it'; import { logger } from '../../../../../logger'; -import * as bitbucketPlatform from '../../../../../modules/platform/bitbucket'; import * as memCache from '../../../../../util/cache/memory'; import * as packageCache from '../../../../../util/cache/package'; import { detectPlatform } from '../../../../../util/common'; import { linkify } from '../../../../../util/markdown'; import { newlineRegex, regEx } from '../../../../../util/regex'; import type { BranchUpgradeConfig } from '../../../../types'; +import * as bitbucket from './bitbucket'; import * as github from './github'; import * as gitlab from './gitlab'; import type { @@ -37,7 +37,7 @@ export async function getReleaseList( case 'github': return await github.getReleaseList(project, release); case 'bitbucket': - return []; + return bitbucket.getReleaseList(project, release); default: logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type'); return []; @@ -266,10 +266,7 @@ export async function getReleaseNotesMdFileInner( sourceDirectory ); case 'bitbucket': - return await bitbucketPlatform.getReleaseNotesMd( - repository, - sourceDirectory - ); + return await bitbucket.getReleaseNotesMd(repository, sourceDirectory); default: logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type'); return null; diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 192e281e6e3313..519bcac639570c 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -1,12 +1,12 @@ import URL from 'node:url'; import { logger } from '../../../../../logger'; import type { Release } from '../../../../../modules/datasource/types'; -import * as bitbucketHttp from '../../../../../modules/platform/bitbucket'; import * as allVersioning from '../../../../../modules/versioning'; import * as memCache from '../../../../../util/cache/memory'; import * as packageCache from '../../../../../util/cache/package'; import { regEx } from '../../../../../util/regex'; import type { BranchUpgradeConfig } from '../../../../types'; +import { getTags } from './bitbucket'; import { slugifyUrl } from './common'; import { addReleaseNotes } from './release-notes'; import { getInRangeReleases } from './releases'; @@ -25,7 +25,7 @@ function getCachedTags( if (cachedResult !== undefined) { return cachedResult; } - const promisedRes = bitbucketHttp.getTags(repository); + const promisedRes = getTags(repository); memCache.set(cacheKey, promisedRes); return promisedRes; } From d13dc6d3c53c8d97838becdc389b672a20a04b56 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 07:39:33 -0400 Subject: [PATCH 12/71] refactor to match other changelog impls --- .../update/pr/changelog/bitbucket/index.ts | 24 +++++++++---------- .../update/pr/changelog/release-notes.ts | 6 ++++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index e962305cd50255..6f83541309d57e 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -15,29 +15,27 @@ import type { ChangeLogRelease, } from '../types'; -export const id = 'bitbucket-changelog'; -const bitbucketHttp = new BitbucketHttp(id); +const bitbucketHttp = new BitbucketHttp(); const bitbucketTags = new BitbucketTagsDatasource(); export async function getReleaseNotesMd( repository: string, + apiBaseUrl: string, sourceDirectory?: string ): Promise { logger.trace('bitbucket.getReleaseNotesMd()'); - const repositorySourceURl = joinUrlParts( - '/2.0/repositories', - repository, - 'src' - ); + const repositorySourceURl = joinUrlParts(apiBaseUrl, repository, 'src'); - const response = await bitbucketHttp.getJson< - PagedResult - >(repositorySourceURl, { - paginate: true, - }); + const rootFiles = ( + await bitbucketHttp.getJson>( + repositorySourceURl, + { + paginate: true, + } + ) + ).body.values; - const rootFiles = response.body.values; const allFiles = rootFiles.filter((f) => f.type === 'commit_file'); let files: BitbucketSourceResults[] = []; diff --git a/lib/workers/repository/update/pr/changelog/release-notes.ts b/lib/workers/repository/update/pr/changelog/release-notes.ts index e35a765d95a80b..11c081f7d08378 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.ts @@ -266,7 +266,11 @@ export async function getReleaseNotesMdFileInner( sourceDirectory ); case 'bitbucket': - return await bitbucket.getReleaseNotesMd(repository, sourceDirectory); + return await bitbucket.getReleaseNotesMd( + repository, + apiBaseUrl, + sourceDirectory + ); default: logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type'); return null; From 3af6724e4458caeff7718af9008d06f38db252ea Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 07:51:01 -0400 Subject: [PATCH 13/71] update bitbucket host types --- lib/constants/platforms.ts | 6 +++++- .../repository/update/pr/changelog/bitbucket/index.ts | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/constants/platforms.ts b/lib/constants/platforms.ts index 049155bd3ba43c..79814fb137e421 100644 --- a/lib/constants/platforms.ts +++ b/lib/constants/platforms.ts @@ -26,4 +26,8 @@ export const GITLAB_API_USING_HOST_TYPES = [ 'gitlab-changelog', ]; -export const BITBUCKET_API_USING_HOST_TYPES = ['bitbucket', 'bitbucket-tags']; +export const BITBUCKET_API_USING_HOST_TYPES = [ + 'bitbucket', + 'bitbucket-tags', + 'bitbucket-changelog', +]; diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index 6f83541309d57e..a3ca0fbbbb6e13 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -15,7 +15,8 @@ import type { ChangeLogRelease, } from '../types'; -const bitbucketHttp = new BitbucketHttp(); +export const id = 'bitbucket-changelog'; +const bitbucketHttp = new BitbucketHttp(id); const bitbucketTags = new BitbucketTagsDatasource(); export async function getReleaseNotesMd( From 700d819da32a888757a69c6b0f9525a314198a2e Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 08:01:16 -0400 Subject: [PATCH 14/71] remove unused type --- lib/modules/platform/bitbucket/types.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/modules/platform/bitbucket/types.ts b/lib/modules/platform/bitbucket/types.ts index 82b8ead4f1bd83..3bbbe546963e03 100644 --- a/lib/modules/platform/bitbucket/types.ts +++ b/lib/modules/platform/bitbucket/types.ts @@ -111,15 +111,3 @@ export interface BitbucketSourceResults { } export type BitbucketSourceType = 'commit_directory' | 'commit_file'; - -export interface BitbucketTag { - name: string; - message: string; - date: string; - target: { - hash: string; - date: string; - message: string; - }; - next?: string; -} From df5d87dc5aa8e7e664c3c18b5d0b55e9330445d5 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 15:36:40 -0400 Subject: [PATCH 15/71] tests --- .../update/pr/changelog/bitbucket.spec.ts | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 lib/workers/repository/update/pr/changelog/bitbucket.spec.ts diff --git a/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts new file mode 100644 index 00000000000000..d004199907d402 --- /dev/null +++ b/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts @@ -0,0 +1,251 @@ +import * as httpMock from '../../../../../../test/http-mock'; +import { partial } from '../../../../../../test/util'; +import * as semverVersioning from '../../../../../modules/versioning/semver'; +import * as hostRules from '../../../../../util/host-rules'; +import type { BranchUpgradeConfig } from '../../../../types'; +import { getChangeLogJSON } from '.'; + +jest.mock('../../../../../modules/datasource/npm'); + +const upgrade = partial({ + manager: 'some-manager', + branchName: '', + endpoint: 'https://api.bitbucket.org/', + packageName: 'renovate', + versioning: semverVersioning.id, + currentVersion: '5.2.0', + newVersion: '5.7.0', + sourceUrl: 'https://bitbucket.org/meno/dropzone/', + releases: [ + // TODO: test gitRef + { version: '5.2.0' }, + { + version: '5.4.0', + releaseTimestamp: '2018-08-24T14:23:00.000Z', + }, + { version: '5.5.0', gitRef: 'eba303e91c930292198b2fc57040145682162a1b' }, + { version: '5.6.0', releaseTimestamp: '2020-02-13T15:37:00.000Z' }, + { version: '5.6.1' }, + ], +}); + +const matchHost = 'https://bitbucket.org/'; + +describe('workers/repository/update/pr/changelog/bitbucket', () => { + afterEach(() => { + // FIXME: add missing http mocks + httpMock.clear(false); + }); + + describe('getChangeLogJSON', () => { + beforeEach(() => { + hostRules.clear(); + hostRules.add({ + hostType: 'bitbucket', + matchHost, + token: 'abc', + }); + }); + + it('returns null if @types', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + currentVersion: undefined, + }) + ).toBeNull(); + }); + + it('returns null if currentVersion equals newVersion', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + currentVersion: '1.0.0', + newVersion: '1.0.0', + }) + ).toBeNull(); + }); + + it('skips invalid repos', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + sourceUrl: 'https://bitbucket.org/help', + }) + ).toBeNull(); + }); + + it('works with Bitbucket', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + }) + ).toEqual({ + hasReleaseNotes: false, + project: { + apiBaseUrl: 'https://api.bitbucket.org/2.0/repositories/', + baseUrl: 'https://bitbucket.org/', + packageName: 'renovate', + repository: 'meno/dropzone', + sourceDirectory: undefined, + sourceUrl: 'https://bitbucket.org/meno/dropzone/', + type: 'bitbucket', + }, + versions: [ + expect.objectContaining({ version: '5.6.1' }), + expect.objectContaining({ version: '5.6.0' }), + expect.objectContaining({ version: '5.5.0' }), + expect.objectContaining({ version: '5.4.0' }), + ], + }); + }); + + it('uses Bitbucket tags', async () => { + httpMock + .scope(matchHost) + .get('/2.0/repositories//meno%2Fdropzone/refs/tags') + .reply(200, [ + { name: 'v5.2.0' }, + { name: 'v5.4.0' }, + { name: 'v5.5.0' }, + { name: 'v5.6.0' }, + { name: 'v5.6.1' }, + { name: 'v5.7.0' }, + ]) + .persist() + .get('/2.0/repositories//meno%2Fdropzone/refs/tags') + .reply(200, []) + .persist() + .get('/2.0/repositories//meno%2Fdropzone/refs/tags') + .reply(200, []); + expect( + await getChangeLogJSON({ + ...upgrade, + }) + ).toEqual({ + hasReleaseNotes: false, + project: { + apiBaseUrl: 'https://api.bitbucket.org/2.0/repositories/', + baseUrl: 'https://bitbucket.org/', + packageName: 'renovate', + repository: 'meno/dropzone', + sourceDirectory: undefined, + sourceUrl: 'https://bitbucket.org/meno/dropzone/', + type: 'bitbucket', + }, + versions: [ + expect.objectContaining({ version: '5.6.1' }), + expect.objectContaining({ version: '5.6.0' }), + expect.objectContaining({ version: '5.5.0' }), + expect.objectContaining({ version: '5.4.0' }), + ], + }); + }); + + it('handles empty Bitbucket tags response', async () => { + httpMock + .scope(matchHost) + .get('/2.0/repositories//meno%2Fdropzone/refs/tags') + .reply(200, []) + .persist() + .get('/2.0/repositories//meno%2Fdropzone/refs/tags') + .reply(200, []) + .persist() + .get('/2.0/repositories//meno%2Fdropzone/refs/tags') + .reply(200, []); + expect( + await getChangeLogJSON({ + ...upgrade, + }) + ).toEqual({ + hasReleaseNotes: false, + project: { + apiBaseUrl: 'https://api.bitbucket.org/2.0/repositories/', + baseUrl: 'https://bitbucket.org/', + packageName: 'renovate', + repository: 'meno/dropzone', + sourceDirectory: undefined, + sourceUrl: 'https://bitbucket.org/meno/dropzone/', + type: 'bitbucket', + }, + versions: [ + expect.objectContaining({ version: '5.6.1' }), + expect.objectContaining({ version: '5.6.0' }), + expect.objectContaining({ version: '5.5.0' }), + expect.objectContaining({ version: '5.4.0' }), + ], + }); + }); + + it('uses Bitbucket tags with error', async () => { + httpMock + .scope(matchHost) + .get('/2.0/repositories//meno%2Fdropzone/refs/tags') + .replyWithError('Unknown Bitbucket Repo') + .persist() + .get('/2.0/repositories//meno%2Fdropzone/refs/tags') + .reply(200, []) + .persist() + .get('/2.0/repositories//meno%2Fdropzone/refs/tags') + .reply(200, []); + expect( + await getChangeLogJSON({ + ...upgrade, + }) + ).toEqual({ + hasReleaseNotes: false, + project: { + apiBaseUrl: 'https://api.bitbucket.org/2.0/repositories/', + baseUrl: 'https://bitbucket.org/', + packageName: 'renovate', + repository: 'meno/dropzone', + sourceDirectory: undefined, + sourceUrl: 'https://bitbucket.org/meno/dropzone/', + type: 'bitbucket', + }, + versions: [ + expect.objectContaining({ version: '5.6.1' }), + expect.objectContaining({ version: '5.6.0' }), + expect.objectContaining({ version: '5.5.0' }), + expect.objectContaining({ version: '5.4.0' }), + ], + }); + }); + + it('handles no sourceUrl', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + sourceUrl: undefined, + }) + ).toBeNull(); + }); + + it('handles invalid sourceUrl', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + sourceUrl: 'http://example.com', + }) + ).toBeNull(); + }); + + it('handles no releases', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + releases: [], + }) + ).toBeNull(); + }); + + it('handles not enough releases', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + releases: [{ version: '0.9.0' }], + }) + ).toBeNull(); + }); + }); +}); From 73b5cf05ae9e7bdd9cd3e68dab69e51e4b58c216 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 15:47:37 -0400 Subject: [PATCH 16/71] update apiBaseUrl --- .../repository/update/pr/changelog/bitbucket.spec.ts | 8 ++++---- .../repository/update/pr/changelog/bitbucket/index.ts | 7 ++++++- .../repository/update/pr/changelog/source-bitbucket.ts | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts index d004199907d402..f31a271a30c24b 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts @@ -83,7 +83,7 @@ describe('workers/repository/update/pr/changelog/bitbucket', () => { ).toEqual({ hasReleaseNotes: false, project: { - apiBaseUrl: 'https://api.bitbucket.org/2.0/repositories/', + apiBaseUrl: 'https://api.bitbucket.org/', baseUrl: 'https://bitbucket.org/', packageName: 'renovate', repository: 'meno/dropzone', @@ -125,7 +125,7 @@ describe('workers/repository/update/pr/changelog/bitbucket', () => { ).toEqual({ hasReleaseNotes: false, project: { - apiBaseUrl: 'https://api.bitbucket.org/2.0/repositories/', + apiBaseUrl: 'https://api.bitbucket.org/', baseUrl: 'https://bitbucket.org/', packageName: 'renovate', repository: 'meno/dropzone', @@ -160,7 +160,7 @@ describe('workers/repository/update/pr/changelog/bitbucket', () => { ).toEqual({ hasReleaseNotes: false, project: { - apiBaseUrl: 'https://api.bitbucket.org/2.0/repositories/', + apiBaseUrl: 'https://api.bitbucket.org/', baseUrl: 'https://bitbucket.org/', packageName: 'renovate', repository: 'meno/dropzone', @@ -195,7 +195,7 @@ describe('workers/repository/update/pr/changelog/bitbucket', () => { ).toEqual({ hasReleaseNotes: false, project: { - apiBaseUrl: 'https://api.bitbucket.org/2.0/repositories/', + apiBaseUrl: 'https://api.bitbucket.org/', baseUrl: 'https://bitbucket.org/', packageName: 'renovate', repository: 'meno/dropzone', diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index a3ca0fbbbb6e13..c286bbcb12bcd2 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -26,7 +26,12 @@ export async function getReleaseNotesMd( ): Promise { logger.trace('bitbucket.getReleaseNotesMd()'); - const repositorySourceURl = joinUrlParts(apiBaseUrl, repository, 'src'); + const repositorySourceURl = joinUrlParts( + apiBaseUrl, + `/2.0/repositories`, + repository, + 'src' + ); const rootFiles = ( await bitbucketHttp.getJson>( diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 519bcac639570c..dc58fbcef60417 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -50,7 +50,7 @@ export async function getChangeLogJSON( logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); const baseUrl = protocol.concat('//', host, '/'); - const apiBaseUrl = protocol.concat('//', 'api.', host, '/2.0/repositories/'); + const apiBaseUrl = protocol.concat('//', 'api.', host, '/'); const repository = pathname .slice(1) .replace(regEx(/\/$/), '') From de6713465b25cdfb6d7f090663f7bc47f2d6daea Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:22:34 -0400 Subject: [PATCH 17/71] Update lib/workers/repository/update/pr/changelog/bitbucket/index.ts Co-authored-by: Sebastian Poxhofer --- lib/workers/repository/update/pr/changelog/bitbucket/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index c286bbcb12bcd2..061d54bdf049b0 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -28,7 +28,7 @@ export async function getReleaseNotesMd( const repositorySourceURl = joinUrlParts( apiBaseUrl, - `/2.0/repositories`, + `2.0/repositories`, repository, 'src' ); From f4800a7f39415370335ba2c45938cbbbd34062e4 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:26:58 -0400 Subject: [PATCH 18/71] simplify --- .../repository/update/pr/changelog/bitbucket/index.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index c286bbcb12bcd2..75f2421cb11680 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -44,11 +44,8 @@ export async function getReleaseNotesMd( const allFiles = rootFiles.filter((f) => f.type === 'commit_file'); - let files: BitbucketSourceResults[] = []; + const files = allFiles.filter((f) => changelogFilenameRegex.test(f.path)); - if (!files.length) { - files = allFiles.filter((f) => changelogFilenameRegex.test(f.path)); - } if (!files.length) { logger.trace('no changelog file found'); return null; From 18a7151b1a3d71b6a6f2cacad3b7488263275d02 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:28:23 -0400 Subject: [PATCH 19/71] Update lib/workers/repository/update/pr/changelog/bitbucket/index.ts Co-authored-by: Sebastian Poxhofer --- lib/workers/repository/update/pr/changelog/bitbucket/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index e685f57d91d1f3..8415e6a4398fc2 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -46,12 +46,12 @@ export async function getReleaseNotesMd( const files = allFiles.filter((f) => changelogFilenameRegex.test(f.path)); - if (!files.length) { + const changelogFile = files.shift(); + if (is.nullOrUndefined(changelogFile)) { logger.trace('no changelog file found'); return null; } - const changelogFile = files.shift()!; if (files.length !== 0) { logger.debug( From 788229d566a1263084b534d120b2a1fd4b8520b2 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:28:55 -0400 Subject: [PATCH 20/71] Update lib/workers/repository/update/pr/changelog/bitbucket/index.ts Co-authored-by: Sebastian Poxhofer --- lib/workers/repository/update/pr/changelog/bitbucket/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index 8415e6a4398fc2..c4d4354dbec4ce 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -80,7 +80,6 @@ export async function getTags(repository: string): Promise { }) )?.releases; - // istanbul ignore if if (is.nullOrUndefined(tags) || is.emptyArray(tags)) { logger.debug(`No Bitbucket tags found for repository:${repository}`); From 15c46dd484a904f828d2fffc2abe5cc08be5c984 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:29:09 -0400 Subject: [PATCH 21/71] Update lib/workers/repository/update/pr/changelog/bitbucket/index.ts Co-authored-by: Sebastian Poxhofer --- lib/workers/repository/update/pr/changelog/bitbucket/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index c4d4354dbec4ce..334a3f34b36337 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -67,7 +67,7 @@ export async function getReleaseNotesMd( ) ); - const changelogMd = fileRes.body + '\n#\n##'; + const changelogMd = `${fileRes.body}\n#\n##`; return { changelogFile: changelogFile.path, changelogMd }; } From 9bf934af1781f234884fd37e82b3746cf3ea041d Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:31:23 -0400 Subject: [PATCH 22/71] update to return versions --- lib/workers/repository/update/pr/changelog/bitbucket/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index e685f57d91d1f3..e6791120d7a24b 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -87,7 +87,7 @@ export async function getTags(repository: string): Promise { return []; } - return []; + return tags.map(({ version }) => version); } catch (err) { logger.debug( { sourceRepo: repository, err }, From fb8e3d634f2a2e50b9529adb5200ac4cf1d32765 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:32:17 -0400 Subject: [PATCH 23/71] Update lib/workers/repository/update/pr/changelog/source-bitbucket.ts Co-authored-by: Sebastian Poxhofer --- .../repository/update/pr/changelog/source-bitbucket.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index dc58fbcef60417..7a32a014e6364e 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -49,11 +49,9 @@ export async function getChangeLogJSON( const pathname = parsedUrl.pathname!; logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); - const baseUrl = protocol.concat('//', host, '/'); - const apiBaseUrl = protocol.concat('//', 'api.', host, '/'); - const repository = pathname - .slice(1) - .replace(regEx(/\/$/), '') + const baseUrl = `${protocol}//${host}/`; + const apiBaseUrl = `${protocol}//api.${host}/`; + const repository = trimSlashes(pathname) .replace(regEx(/\.git$/), ''); if (repository.split('/').length < 2) { From 383240195e6bf4031835a424c53f386e34293a24 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:33:01 -0400 Subject: [PATCH 24/71] Update lib/workers/repository/update/pr/changelog/source-bitbucket.ts Co-authored-by: Sebastian Poxhofer --- lib/workers/repository/update/pr/changelog/source-bitbucket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 7a32a014e6364e..692a89a8e91b75 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -85,7 +85,7 @@ export async function getChangeLogJSON( const tagName = tags .filter((tag) => version.isVersion(tag.replace(regex, ''))) .find((tag) => version.equals(tag.replace(regex, ''), release.version)); - if (tagName) { + if (is.nonEmptyString(tagName)) { return tagName; } if (release.gitRef) { From 4fc6bb53724a33b65de31322feeffb6c1591306f Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:33:11 -0400 Subject: [PATCH 25/71] Update lib/workers/repository/update/pr/changelog/source-bitbucket.ts Co-authored-by: Sebastian Poxhofer --- lib/workers/repository/update/pr/changelog/source-bitbucket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 692a89a8e91b75..71bacc33a8c76e 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -88,7 +88,7 @@ export async function getChangeLogJSON( if (is.nonEmptyString(tagName)) { return tagName; } - if (release.gitRef) { + if (is.nonEmptyString(release.gitRef)) { return release.gitRef; } return null; From 99fc1fce6815b108af41bf971aeaac94f4f5f664 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 14 May 2023 17:33:23 -0400 Subject: [PATCH 26/71] Update lib/workers/repository/update/pr/changelog/source-bitbucket.ts Co-authored-by: Sebastian Poxhofer --- lib/workers/repository/update/pr/changelog/source-bitbucket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 71bacc33a8c76e..0b78d4ee102e4d 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -123,7 +123,7 @@ export async function getChangeLogJSON( }; const prevHead = await getRef(prev); const nextHead = await getRef(next); - if (prevHead && nextHead) { + if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { release.compare.url = `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; } const cacheMinutes = 55; From 3dcf9634216489b8abe8c6a24f03d18bc48c63d1 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Mon, 15 May 2023 07:20:46 -0400 Subject: [PATCH 27/71] add imports --- .../repository/update/pr/changelog/source-bitbucket.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 0b78d4ee102e4d..141dbea56b5158 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -1,10 +1,12 @@ import URL from 'node:url'; +import is from '@sindresorhus/is'; import { logger } from '../../../../../logger'; import type { Release } from '../../../../../modules/datasource/types'; import * as allVersioning from '../../../../../modules/versioning'; import * as memCache from '../../../../../util/cache/memory'; import * as packageCache from '../../../../../util/cache/package'; import { regEx } from '../../../../../util/regex'; +import { trimSlashes } from '../../../../../util/url'; import type { BranchUpgradeConfig } from '../../../../types'; import { getTags } from './bitbucket'; import { slugifyUrl } from './common'; @@ -51,8 +53,7 @@ export async function getChangeLogJSON( logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); const baseUrl = `${protocol}//${host}/`; const apiBaseUrl = `${protocol}//api.${host}/`; - const repository = trimSlashes(pathname) - .replace(regEx(/\.git$/), ''); + const repository = trimSlashes(pathname).replace(regEx(/\.git$/), ''); if (repository.split('/').length < 2) { logger.info({ sourceUrl }, 'Invalid bitbucket URL found'); From 610a28654cb8f0f63d7ccf5b14f0cb38da2c4fd1 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Mon, 15 May 2023 07:33:06 -0400 Subject: [PATCH 28/71] per feedback, use early return --- .../update/pr/changelog/source-bitbucket.ts | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 141dbea56b5158..fecf5b1f78ee82 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -66,7 +66,6 @@ export async function getChangeLogJSON( return null; } - // This extra filter/sort should not be necessary, but better safe than sorry const validReleases = [...releases] .filter((release) => version.isVersion(release.version)) .sort((a, b) => version.sortVersions(a.version, b.version)); @@ -108,35 +107,36 @@ export async function getChangeLogJSON( for (let i = 1; i < validReleases.length; i += 1) { const prev = validReleases[i - 1]; const next = validReleases[i]; - if (include(next.version)) { - let release = await packageCache.get( + if (!include(next.version)) { + continue; + } + let release = await packageCache.get( + cacheNamespace, + getCacheKey(prev.version, next.version) + ); + if (!release) { + release = { + version: next.version, + date: next.releaseTimestamp, + gitRef: next.gitRef, + // put empty changes so that existing templates won't break + changes: [], + compare: {}, + }; + const prevHead = await getRef(prev); + const nextHead = await getRef(next); + if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { + release.compare.url = `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; + } + const cacheMinutes = 55; + await packageCache.set( cacheNamespace, - getCacheKey(prev.version, next.version) + getCacheKey(prev.version, next.version), + release, + cacheMinutes ); - if (!release) { - release = { - version: next.version, - date: next.releaseTimestamp, - gitRef: next.gitRef, - // put empty changes so that existing templates won't break - changes: [], - compare: {}, - }; - const prevHead = await getRef(prev); - const nextHead = await getRef(next); - if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { - release.compare.url = `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; - } - const cacheMinutes = 55; - await packageCache.set( - cacheNamespace, - getCacheKey(prev.version, next.version), - release, - cacheMinutes - ); - } - changelogReleases.unshift(release); } + changelogReleases.unshift(release); } let res: ChangeLogResult | null = { From 2ec9d490635a1834bf1ad2c5cc39dda15046c0a5 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Mon, 15 May 2023 08:30:44 -0400 Subject: [PATCH 29/71] fix linting --- lib/workers/repository/update/pr/changelog/bitbucket/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index 8e19cbdda58027..082c5061a30550 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -52,7 +52,6 @@ export async function getReleaseNotesMd( return null; } - if (files.length !== 0) { logger.debug( `Multiple candidates for changelog file, using ${changelogFile.path}` From 230f2602d889ad8b9ad7678d8b9deb830b676689 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Wed, 24 May 2023 08:12:20 -0400 Subject: [PATCH 30/71] export function --- lib/modules/datasource/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/modules/datasource/index.ts b/lib/modules/datasource/index.ts index 34e3b652743a38..33e7c7d17ebed2 100644 --- a/lib/modules/datasource/index.ts +++ b/lib/modules/datasource/index.ts @@ -30,7 +30,7 @@ export const getDatasourceList = (): string[] => Array.from(datasources.keys()); const cacheNamespace = 'datasource-releases'; -function getDatasourceFor(datasource: string): DatasourceApi | null { +export function getDatasourceFor(datasource: string): DatasourceApi | null { return datasources.get(datasource) ?? null; } From 46ef4eabadbc61a0d0bca43ad51fea71da77f794 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Mon, 19 Jun 2023 05:49:57 -0400 Subject: [PATCH 31/71] Merge branch 'main' into feature/14964-bitbucket-release-notes --- lib/util/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/common.ts b/lib/util/common.ts index 95a990435b8ff5..3bfb48e826c770 100644 --- a/lib/util/common.ts +++ b/lib/util/common.ts @@ -14,7 +14,7 @@ import { parseUrl } from './url'; */ export function detectPlatform( url: string -): 'azure' | 'bitbucket' | 'github' | 'gitlab' | null { +): 'bitbucket' | 'github' | 'gitlab' | 'azure' | null { const { hostname } = parseUrl(url) ?? {}; if (hostname === 'bitbucket.org' || hostname?.includes('bitbucket')) { From 250c7e4dd71157b5abb681c7ec1d787bf671f4f3 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Mon, 19 Jun 2023 06:12:22 -0400 Subject: [PATCH 32/71] rename type --- lib/modules/platform/bitbucket/types.ts | 2 +- lib/workers/repository/update/pr/changelog/bitbucket/index.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/modules/platform/bitbucket/types.ts b/lib/modules/platform/bitbucket/types.ts index 42783f6af27336..eb1582ba9c9246 100644 --- a/lib/modules/platform/bitbucket/types.ts +++ b/lib/modules/platform/bitbucket/types.ts @@ -103,7 +103,7 @@ export interface EffectiveReviewer { user: Account; } -export interface BitbucketSourceResults { +export interface SourceResults { path: string; type: BitbucketSourceType; commit: { diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index 082c5061a30550..ee6f56206b26dc 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -3,8 +3,8 @@ import changelogFilenameRegex from 'changelog-filename-regex'; import { logger } from '../../../../../../logger'; import { BitbucketTagsDatasource } from '../../../../../../modules/datasource/bitbucket-tags'; import type { - BitbucketSourceResults, PagedResult, + SourceResults, } from '../../../../../../modules/platform/bitbucket/types'; import { BitbucketHttp } from '../../../../../../util/http/bitbucket'; import { joinUrlParts } from '../../../../../../util/url'; @@ -34,7 +34,7 @@ export async function getReleaseNotesMd( ); const rootFiles = ( - await bitbucketHttp.getJson>( + await bitbucketHttp.getJson>( repositorySourceURl, { paginate: true, From f8acb5746f443b86cd375758d212d8d217c9794b Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Mon, 19 Jun 2023 08:11:37 -0400 Subject: [PATCH 33/71] refactor: make source-* more aligned --- .../update/pr/changelog/bitbucket/index.ts | 5 +- .../update/pr/changelog/source-bitbucket.ts | 53 ++++++--- .../update/pr/changelog/source-github.ts | 95 +++++++++------ .../update/pr/changelog/source-gitlab.ts | 110 +++++++++++------- 4 files changed, 174 insertions(+), 89 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index ee6f56206b26dc..e85bfdce90c03e 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -70,7 +70,10 @@ export async function getReleaseNotesMd( return { changelogFile: changelogFile.path, changelogMd }; } -export async function getTags(repository: string): Promise { +export async function getTags( + endpoint: string, + repository: string +): Promise { logger.trace('bitbucket.getTags()'); try { const tags = ( diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index fecf5b1f78ee82..26709e443e4d32 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -18,16 +18,15 @@ const cacheNamespace = 'changelog-bitbucket-release'; function getCachedTags( endpoint: string, - versionScheme: string, repository: string ): Promise { - const cacheKey = `getTags-${endpoint}-${versionScheme}-${repository}`; + const cacheKey = `getTags-${endpoint}-${repository}`; const cachedResult = memCache.get>(cacheKey); // istanbul ignore if if (cachedResult !== undefined) { return cachedResult; } - const promisedRes = getTags(repository); + const promisedRes = getTags(endpoint, repository); memCache.set(cacheKey, promisedRes); return promisedRes; } @@ -49,7 +48,6 @@ export async function getChangeLogJSON( const protocol = parsedUrl.protocol!; const host = parsedUrl.host!; const pathname = parsedUrl.pathname!; - logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); const baseUrl = `${protocol}//${host}/`; const apiBaseUrl = `${protocol}//api.${host}/`; @@ -65,13 +63,13 @@ export async function getChangeLogJSON( logger.debug('No releases'); return null; } - + // This extra filter/sort should not be necessary, but better safe than sorry const validReleases = [...releases] .filter((release) => version.isVersion(release.version)) .sort((a, b) => version.sortVersions(a.version, b.version)); if (validReleases.length < 2) { - logger.debug('Not enough valid releases'); + logger.debug(`Not enough valid releases for dep ${packageName}`); return null; } @@ -79,12 +77,14 @@ export async function getChangeLogJSON( async function getRef(release: Release): Promise { if (!tags) { - tags = await getCachedTags(apiBaseUrl, versioning, repository); + tags = await getCachedTags(apiBaseUrl, repository); } - const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); - const tagName = tags - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), release.version)); + const tagName = findTagOfRelease( + version, + packageName, + release.version, + tags + ); if (is.nonEmptyString(tagName)) { return tagName; } @@ -126,7 +126,12 @@ export async function getChangeLogJSON( const prevHead = await getRef(prev); const nextHead = await getRef(next); if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { - release.compare.url = `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; + release.compare.url = getCompareURL( + baseUrl, + repository, + prevHead, + nextHead + ); } const cacheMinutes = 55; await packageCache.set( @@ -146,8 +151,8 @@ export async function getChangeLogJSON( type: 'bitbucket', repository, sourceUrl, - packageName, sourceDirectory, + packageName, }, versions: changelogReleases, }; @@ -156,3 +161,25 @@ export async function getChangeLogJSON( return res; } + +function getCompareURL( + baseUrl: string, + repository: string, + prevHead: string, + nextHead: string +): string { + return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; +} + +function findTagOfRelease( + version: allVersioning.VersioningApi, + packageName: string, + depNewVersion: string, + tags: string[] +): string | undefined { + const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); + const tagName = tags + .filter((tag) => version.isVersion(tag.replace(regex, ''))) + .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); + return tagName; +} diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index 2430d6f5b80c9b..011b323e590ea4 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -1,5 +1,6 @@ // TODO #7154 import URL from 'node:url'; +import is from '@sindresorhus/is'; import { GlobalConfig } from '../../../../../config/global'; import { logger } from '../../../../../logger'; import type { Release } from '../../../../../modules/datasource/types'; @@ -15,6 +16,8 @@ import { addReleaseNotes } from './release-notes'; import { getInRangeReleases } from './releases'; import type { ChangeLogRelease, ChangeLogResult } from './types'; +const cacheNamespace = 'changelog-github-release'; + function getCachedTags( endpoint: string, repository: string @@ -37,17 +40,23 @@ export async function getChangeLogJSON( const currentVersion = config.currentVersion!; const newVersion = config.newVersion!; const sourceUrl = config.sourceUrl!; - const sourceDirectory = config.sourceDirectory!; const packageName = config.packageName!; + const sourceDirectory = config.sourceDirectory!; const manager = config.manager; if (sourceUrl === 'https://github.com/DefinitelyTyped/DefinitelyTyped') { logger.trace('No release notes for @types'); return null; } const version = allVersioning.get(versioning); - const { protocol, host, pathname } = URL.parse(sourceUrl); + + const parsedUrl = URL.parse(sourceUrl); + const protocol = parsedUrl.protocol!; + const host = parsedUrl.host!; + const pathname = parsedUrl.pathname!; + logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); + // TODO: types (#7154) - const baseUrl = `${protocol!}//${host!}/`; + const baseUrl = `${protocol}//${host}/`; const url = sourceUrl.startsWith('https://github.com/') ? 'https://api.github.com/' : sourceUrl; @@ -57,7 +66,7 @@ export async function getChangeLogJSON( }); // istanbul ignore if if (!token) { - if (host!.endsWith('.github.com') || host === 'github.com') { + if (host.endsWith('.github.com') || host === 'github.com') { if (!GlobalConfig.get('githubTokenWarn')) { logger.debug( { manager, packageName, sourceUrl }, @@ -80,7 +89,7 @@ export async function getChangeLogJSON( const apiBaseUrl = sourceUrl.startsWith('https://github.com/') ? 'https://api.github.com/' : baseUrl + 'api/v3/'; - const repository = pathname! + const repository = pathname .slice(1) .replace(regEx(/\/$/), '') .replace(regEx(/\.git$/), ''); @@ -88,6 +97,7 @@ export async function getChangeLogJSON( logger.debug(`Invalid github URL found: ${sourceUrl}`); return null; } + const releases = config.releases ?? (await getInRangeReleases(config)); if (!releases?.length) { logger.debug('No releases'); @@ -115,17 +125,15 @@ export async function getChangeLogJSON( release.version, tags ); - if (tagName) { + if (is.nonEmptyString(tagName)) { return tagName; } - if (release.gitRef) { + if (is.nonEmptyString(release.gitRef)) { return release.gitRef; } return null; } - const cacheNamespace = 'changelog-github-release'; - function getCacheKey(prev: string, next: string): string { return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; } @@ -135,39 +143,45 @@ export async function getChangeLogJSON( const include = (v: string): boolean => version.isGreaterThan(v, currentVersion) && !version.isGreaterThan(v, newVersion); + for (let i = 1; i < validReleases.length; i += 1) { const prev = validReleases[i - 1]; const next = validReleases[i]; - if (include(next.version)) { - let release = await packageCache.get( - cacheNamespace, - getCacheKey(prev.version, next.version) - ); - // istanbul ignore else - if (!release) { - release = { - version: next.version, - gitRef: next.gitRef, - date: next.releaseTimestamp, - // put empty changes so that existing templates won't break - changes: [], - compare: {}, - }; - const prevHead = await getRef(prev); - const nextHead = await getRef(next); - if (prevHead && nextHead) { - release.compare.url = `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; - } - const cacheMinutes = 55; - await packageCache.set( - cacheNamespace, - getCacheKey(prev.version, next.version), - release, - cacheMinutes + if (!include(next.version)) { + continue; + } + let release = await packageCache.get( + cacheNamespace, + getCacheKey(prev.version, next.version) + ); + if (!release) { + release = { + version: next.version, + date: next.releaseTimestamp, + gitRef: next.gitRef, + // put empty changes so that existing templates won't break + changes: [], + compare: {}, + }; + const prevHead = await getRef(prev); + const nextHead = await getRef(next); + if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { + release.compare.url = getCompareURL( + baseUrl, + repository, + prevHead, + nextHead ); } - changelogReleases.unshift(release); + const cacheMinutes = 55; + await packageCache.set( + cacheNamespace, + getCacheKey(prev.version, next.version), + release, + cacheMinutes + ); } + changelogReleases.unshift(release); } let res: ChangeLogResult | null = { @@ -188,6 +202,15 @@ export async function getChangeLogJSON( return res; } +function getCompareURL( + baseUrl: string, + repository: string, + prevHead: string, + nextHead: string +): string { + return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; +} + function findTagOfRelease( version: allVersioning.VersioningApi, packageName: string, diff --git a/lib/workers/repository/update/pr/changelog/source-gitlab.ts b/lib/workers/repository/update/pr/changelog/source-gitlab.ts index d6cd87601cb6f4..42d6f24bd9b6fd 100644 --- a/lib/workers/repository/update/pr/changelog/source-gitlab.ts +++ b/lib/workers/repository/update/pr/changelog/source-gitlab.ts @@ -1,5 +1,6 @@ // TODO #7154 import URL from 'node:url'; +import is from '@sindresorhus/is'; import { logger } from '../../../../../logger'; import type { Release } from '../../../../../modules/datasource/types'; import * as allVersioning from '../../../../../modules/versioning'; @@ -17,10 +18,9 @@ const cacheNamespace = 'changelog-gitlab-release'; function getCachedTags( endpoint: string, - versionScheme: string, repository: string ): Promise { - const cacheKey = `getTags-${endpoint}-${versionScheme}-${repository}`; + const cacheKey = `getTags-${endpoint}-${repository}`; const cachedResult = memCache.get>(cacheKey); // istanbul ignore if if (cachedResult !== undefined) { @@ -50,8 +50,8 @@ export async function getChangeLogJSON( const pathname = parsedUrl.pathname!; logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); - const baseUrl = protocol.concat('//', host, '/'); - const apiBaseUrl = baseUrl.concat('api/v4/'); + const baseUrl = `${protocol}//${host}/`; + const apiBaseUrl = `${baseUrl}api/v4/`; const repository = pathname .slice(1) .replace(regEx(/\/$/), '') @@ -60,6 +60,7 @@ export async function getChangeLogJSON( logger.info({ sourceUrl }, 'Invalid gitlab URL found'); return null; } + const releases = config.releases ?? (await getInRangeReleases(config)); if (!releases?.length) { logger.debug('No releases'); @@ -71,7 +72,7 @@ export async function getChangeLogJSON( .sort((a, b) => version.sortVersions(a.version, b.version)); if (validReleases.length < 2) { - logger.debug('Not enough valid releases'); + logger.debug(`Not enough valid releases for dep ${packageName}`); return null; } @@ -79,16 +80,18 @@ export async function getChangeLogJSON( async function getRef(release: Release): Promise { if (!tags) { - tags = await getCachedTags(apiBaseUrl, versioning, repository); + tags = await getCachedTags(apiBaseUrl, repository); } - const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); - const tagName = tags - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), release.version)); - if (tagName) { + const tagName = findTagOfRelease( + version, + packageName, + release.version, + tags + ); + if (is.nonEmptyString(tagName)) { return tagName; } - if (release.gitRef) { + if (is.nonEmptyString(release.gitRef)) { return release.gitRef; } return null; @@ -103,38 +106,45 @@ export async function getChangeLogJSON( const include = (v: string): boolean => version.isGreaterThan(v, currentVersion) && !version.isGreaterThan(v, newVersion); + for (let i = 1; i < validReleases.length; i += 1) { const prev = validReleases[i - 1]; const next = validReleases[i]; - if (include(next.version)) { - let release = await packageCache.get( - cacheNamespace, - getCacheKey(prev.version, next.version) - ); - if (!release) { - release = { - version: next.version, - date: next.releaseTimestamp, - gitRef: next.gitRef, - // put empty changes so that existing templates won't break - changes: [], - compare: {}, - }; - const prevHead = await getRef(prev); - const nextHead = await getRef(next); - if (prevHead && nextHead) { - release.compare.url = `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; - } - const cacheMinutes = 55; - await packageCache.set( - cacheNamespace, - getCacheKey(prev.version, next.version), - release, - cacheMinutes + if (!include(next.version)) { + continue; + } + let release = await packageCache.get( + cacheNamespace, + getCacheKey(prev.version, next.version) + ); + if (!release) { + release = { + version: next.version, + date: next.releaseTimestamp, + gitRef: next.gitRef, + // put empty changes so that existing templates won't break + changes: [], + compare: {}, + }; + const prevHead = await getRef(prev); + const nextHead = await getRef(next); + if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { + release.compare.url = getCompareURL( + baseUrl, + repository, + prevHead, + nextHead ); } - changelogReleases.unshift(release); + const cacheMinutes = 55; + await packageCache.set( + cacheNamespace, + getCacheKey(prev.version, next.version), + release, + cacheMinutes + ); } + changelogReleases.unshift(release); } let res: ChangeLogResult | null = { @@ -144,8 +154,8 @@ export async function getChangeLogJSON( type: 'gitlab', repository, sourceUrl, - packageName, sourceDirectory, + packageName, }, versions: changelogReleases, }; @@ -154,3 +164,25 @@ export async function getChangeLogJSON( return res; } + +function getCompareURL( + baseUrl: string, + repository: string, + prevHead: string, + nextHead: string +): string { + return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; +} + +function findTagOfRelease( + version: allVersioning.VersioningApi, + packageName: string, + depNewVersion: string, + tags: string[] +): string | undefined { + const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); + const tagName = tags + .filter((tag) => version.isVersion(tag.replace(regex, ''))) + .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); + return tagName; +} From 5555cf89a8c8e21957bfd12ab85729b7e8cc7978 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Mon, 19 Jun 2023 08:42:59 -0400 Subject: [PATCH 34/71] refactor: make source-* more aligned --- .../update/pr/changelog/source-bitbucket.ts | 5 +++-- .../repository/update/pr/changelog/source-github.ts | 7 +++---- .../repository/update/pr/changelog/source-gitlab.ts | 11 +++++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 26709e443e4d32..3fe02221f1a5fa 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -48,13 +48,14 @@ export async function getChangeLogJSON( const protocol = parsedUrl.protocol!; const host = parsedUrl.host!; const pathname = parsedUrl.pathname!; + logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); const baseUrl = `${protocol}//${host}/`; const apiBaseUrl = `${protocol}//api.${host}/`; const repository = trimSlashes(pathname).replace(regEx(/\.git$/), ''); - if (repository.split('/').length < 2) { - logger.info({ sourceUrl }, 'Invalid bitbucket URL found'); + if (repository.split('/').length !== 2) { + logger.debug(`Invalid bitbucket URL found: ${sourceUrl}`); return null; } diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index 011b323e590ea4..2fc0e7360a006b 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -9,6 +9,7 @@ import * as memCache from '../../../../../util/cache/memory'; import * as packageCache from '../../../../../util/cache/package'; import * as hostRules from '../../../../../util/host-rules'; import { regEx } from '../../../../../util/regex'; +import { trimSlashes } from '../../../../../util/url'; import type { BranchUpgradeConfig } from '../../../../types'; import { slugifyUrl } from './common'; import { getTags } from './github'; @@ -89,10 +90,8 @@ export async function getChangeLogJSON( const apiBaseUrl = sourceUrl.startsWith('https://github.com/') ? 'https://api.github.com/' : baseUrl + 'api/v3/'; - const repository = pathname - .slice(1) - .replace(regEx(/\/$/), '') - .replace(regEx(/\.git$/), ''); + const repository = trimSlashes(pathname).replace(regEx(/\.git$/), ''); + if (repository.split('/').length !== 2) { logger.debug(`Invalid github URL found: ${sourceUrl}`); return null; diff --git a/lib/workers/repository/update/pr/changelog/source-gitlab.ts b/lib/workers/repository/update/pr/changelog/source-gitlab.ts index 42d6f24bd9b6fd..6735a9d86373e2 100644 --- a/lib/workers/repository/update/pr/changelog/source-gitlab.ts +++ b/lib/workers/repository/update/pr/changelog/source-gitlab.ts @@ -7,6 +7,7 @@ import * as allVersioning from '../../../../../modules/versioning'; import * as memCache from '../../../../../util/cache/memory'; import * as packageCache from '../../../../../util/cache/package'; import { regEx } from '../../../../../util/regex'; +import { trimSlashes } from '../../../../../util/url'; import type { BranchUpgradeConfig } from '../../../../types'; import { slugifyUrl } from './common'; import { getTags } from './gitlab'; @@ -52,12 +53,10 @@ export async function getChangeLogJSON( logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); const baseUrl = `${protocol}//${host}/`; const apiBaseUrl = `${baseUrl}api/v4/`; - const repository = pathname - .slice(1) - .replace(regEx(/\/$/), '') - .replace(regEx(/\.git$/), ''); - if (repository.split('/').length < 2) { - logger.info({ sourceUrl }, 'Invalid gitlab URL found'); + const repository = trimSlashes(pathname).replace(regEx(/\.git$/), ''); + + if (repository.split('/').length !== 2) { + logger.debug(`Invalid gitlab URL found: ${sourceUrl}`); return null; } From 25b210da0a9c00cc8c2c32fa4636b83a4655200a Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 06:25:07 -0400 Subject: [PATCH 35/71] refactor: remove inner functions --- .../update/pr/changelog/source-bitbucket.ts | 73 +++++++++++-------- .../update/pr/changelog/source-github.ts | 73 +++++++++++-------- .../update/pr/changelog/source-gitlab.ts | 73 +++++++++++-------- 3 files changed, 132 insertions(+), 87 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 3fe02221f1a5fa..b0f62a938351e7 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -74,31 +74,6 @@ export async function getChangeLogJSON( return null; } - let tags: string[]; - - async function getRef(release: Release): Promise { - if (!tags) { - tags = await getCachedTags(apiBaseUrl, repository); - } - const tagName = findTagOfRelease( - version, - packageName, - release.version, - tags - ); - if (is.nonEmptyString(tagName)) { - return tagName; - } - if (is.nonEmptyString(release.gitRef)) { - return release.gitRef; - } - return null; - } - - function getCacheKey(prev: string, next: string): string { - return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; - } - const changelogReleases: ChangeLogRelease[] = []; // compare versions const include = (v: string): boolean => @@ -113,7 +88,7 @@ export async function getChangeLogJSON( } let release = await packageCache.get( cacheNamespace, - getCacheKey(prev.version, next.version) + getCacheKey(sourceUrl, packageName, prev.version, next.version) ); if (!release) { release = { @@ -124,8 +99,20 @@ export async function getChangeLogJSON( changes: [], compare: {}, }; - const prevHead = await getRef(prev); - const nextHead = await getRef(next); + const prevHead = await getRef( + version, + packageName, + prev, + apiBaseUrl, + repository + ); + const nextHead = await getRef( + version, + packageName, + next, + apiBaseUrl, + repository + ); if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { release.compare.url = getCompareURL( baseUrl, @@ -137,7 +124,7 @@ export async function getChangeLogJSON( const cacheMinutes = 55; await packageCache.set( cacheNamespace, - getCacheKey(prev.version, next.version), + getCacheKey(sourceUrl, packageName, prev.version, next.version), release, cacheMinutes ); @@ -184,3 +171,31 @@ function findTagOfRelease( .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); return tagName; } + +async function getRef( + version: allVersioning.VersioningApi, + packageName: string, + release: Release, + apiBaseUrl: string, + repository: string +): Promise { + const tags = await getCachedTags(apiBaseUrl, repository); + + const tagName = findTagOfRelease(version, packageName, release.version, tags); + if (is.nonEmptyString(tagName)) { + return tagName; + } + if (is.nonEmptyString(release.gitRef)) { + return release.gitRef; + } + return null; +} + +function getCacheKey( + sourceUrl: string, + packageName: string, + prev: string, + next: string +): string { + return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; +} diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index 2fc0e7360a006b..bc3e72cd85d225 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -112,31 +112,6 @@ export async function getChangeLogJSON( return null; } - let tags: string[]; - - async function getRef(release: Release): Promise { - if (!tags) { - tags = await getCachedTags(apiBaseUrl, repository); - } - const tagName = findTagOfRelease( - version, - packageName, - release.version, - tags - ); - if (is.nonEmptyString(tagName)) { - return tagName; - } - if (is.nonEmptyString(release.gitRef)) { - return release.gitRef; - } - return null; - } - - function getCacheKey(prev: string, next: string): string { - return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; - } - const changelogReleases: ChangeLogRelease[] = []; // compare versions const include = (v: string): boolean => @@ -151,7 +126,7 @@ export async function getChangeLogJSON( } let release = await packageCache.get( cacheNamespace, - getCacheKey(prev.version, next.version) + getCacheKey(sourceUrl, packageName, prev.version, next.version) ); if (!release) { release = { @@ -162,8 +137,20 @@ export async function getChangeLogJSON( changes: [], compare: {}, }; - const prevHead = await getRef(prev); - const nextHead = await getRef(next); + const prevHead = await getRef( + version, + packageName, + prev, + apiBaseUrl, + repository + ); + const nextHead = await getRef( + version, + packageName, + next, + apiBaseUrl, + repository + ); if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { release.compare.url = getCompareURL( baseUrl, @@ -175,7 +162,7 @@ export async function getChangeLogJSON( const cacheMinutes = 55; await packageCache.set( cacheNamespace, - getCacheKey(prev.version, next.version), + getCacheKey(sourceUrl, packageName, prev.version, next.version), release, cacheMinutes ); @@ -233,3 +220,31 @@ function findTagOfRelease( } return tagName; } + +async function getRef( + version: allVersioning.VersioningApi, + packageName: string, + release: Release, + apiBaseUrl: string, + repository: string +): Promise { + const tags = await getCachedTags(apiBaseUrl, repository); + + const tagName = findTagOfRelease(version, packageName, release.version, tags); + if (is.nonEmptyString(tagName)) { + return tagName; + } + if (is.nonEmptyString(release.gitRef)) { + return release.gitRef; + } + return null; +} + +function getCacheKey( + sourceUrl: string, + packageName: string, + prev: string, + next: string +): string { + return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; +} diff --git a/lib/workers/repository/update/pr/changelog/source-gitlab.ts b/lib/workers/repository/update/pr/changelog/source-gitlab.ts index 6735a9d86373e2..7b8d9b07c09f71 100644 --- a/lib/workers/repository/update/pr/changelog/source-gitlab.ts +++ b/lib/workers/repository/update/pr/changelog/source-gitlab.ts @@ -75,31 +75,6 @@ export async function getChangeLogJSON( return null; } - let tags: string[]; - - async function getRef(release: Release): Promise { - if (!tags) { - tags = await getCachedTags(apiBaseUrl, repository); - } - const tagName = findTagOfRelease( - version, - packageName, - release.version, - tags - ); - if (is.nonEmptyString(tagName)) { - return tagName; - } - if (is.nonEmptyString(release.gitRef)) { - return release.gitRef; - } - return null; - } - - function getCacheKey(prev: string, next: string): string { - return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; - } - const changelogReleases: ChangeLogRelease[] = []; // compare versions const include = (v: string): boolean => @@ -114,7 +89,7 @@ export async function getChangeLogJSON( } let release = await packageCache.get( cacheNamespace, - getCacheKey(prev.version, next.version) + getCacheKey(sourceUrl, packageName, prev.version, next.version) ); if (!release) { release = { @@ -125,8 +100,20 @@ export async function getChangeLogJSON( changes: [], compare: {}, }; - const prevHead = await getRef(prev); - const nextHead = await getRef(next); + const prevHead = await getRef( + version, + packageName, + prev, + apiBaseUrl, + repository + ); + const nextHead = await getRef( + version, + packageName, + next, + apiBaseUrl, + repository + ); if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { release.compare.url = getCompareURL( baseUrl, @@ -138,7 +125,7 @@ export async function getChangeLogJSON( const cacheMinutes = 55; await packageCache.set( cacheNamespace, - getCacheKey(prev.version, next.version), + getCacheKey(sourceUrl, packageName, prev.version, next.version), release, cacheMinutes ); @@ -185,3 +172,31 @@ function findTagOfRelease( .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); return tagName; } + +async function getRef( + version: allVersioning.VersioningApi, + packageName: string, + release: Release, + apiBaseUrl: string, + repository: string +): Promise { + const tags = await getCachedTags(apiBaseUrl, repository); + + const tagName = findTagOfRelease(version, packageName, release.version, tags); + if (is.nonEmptyString(tagName)) { + return tagName; + } + if (is.nonEmptyString(release.gitRef)) { + return release.gitRef; + } + return null; +} + +function getCacheKey( + sourceUrl: string, + packageName: string, + prev: string, + next: string +): string { + return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; +} From cd8383550973591aed386f3b1b9e40b9cb6aeccc Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 06:55:25 -0400 Subject: [PATCH 36/71] refactor: add base class --- .../repository/update/pr/changelog/index.ts | 6 +- .../update/pr/changelog/source-bitbucket.ts | 207 +---------------- .../repository/update/pr/changelog/source.ts | 214 ++++++++++++++++++ 3 files changed, 229 insertions(+), 198 deletions(-) create mode 100644 lib/workers/repository/update/pr/changelog/source.ts diff --git a/lib/workers/repository/update/pr/changelog/index.ts b/lib/workers/repository/update/pr/changelog/index.ts index ca001ebd24aeea..e3556c47a5f9c4 100644 --- a/lib/workers/repository/update/pr/changelog/index.ts +++ b/lib/workers/repository/update/pr/changelog/index.ts @@ -2,7 +2,7 @@ import { logger } from '../../../../../logger'; import * as allVersioning from '../../../../../modules/versioning'; import { detectPlatform } from '../../../../../util/common'; import type { BranchUpgradeConfig } from '../../../../types'; -import * as sourceBitbucket from './source-bitbucket'; +import { BitbucketChangeLogSource } from './source-bitbucket'; import * as sourceGithub from './source-github'; import * as sourceGitlab from './source-gitlab'; import type { ChangeLogResult } from './types'; @@ -31,6 +31,8 @@ export async function getChangeLogJSON( const platform = detectPlatform(sourceUrl); + const source = new BitbucketChangeLogSource(); + switch (platform) { case 'gitlab': res = await sourceGitlab.getChangeLogJSON(config); @@ -39,7 +41,7 @@ export async function getChangeLogJSON( res = await sourceGithub.getChangeLogJSON(config); break; case 'bitbucket': - res = await sourceBitbucket.getChangeLogJSON(config); + res = await source.getChangeLogJSON(config); break; default: diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index b0f62a938351e7..8b4b0d1e44fa23 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -1,201 +1,16 @@ -import URL from 'node:url'; -import is from '@sindresorhus/is'; -import { logger } from '../../../../../logger'; -import type { Release } from '../../../../../modules/datasource/types'; -import * as allVersioning from '../../../../../modules/versioning'; -import * as memCache from '../../../../../util/cache/memory'; -import * as packageCache from '../../../../../util/cache/package'; -import { regEx } from '../../../../../util/regex'; -import { trimSlashes } from '../../../../../util/url'; -import type { BranchUpgradeConfig } from '../../../../types'; -import { getTags } from './bitbucket'; -import { slugifyUrl } from './common'; -import { addReleaseNotes } from './release-notes'; -import { getInRangeReleases } from './releases'; -import type { ChangeLogRelease, ChangeLogResult } from './types'; +import { ChangeLogSource } from './source'; -const cacheNamespace = 'changelog-bitbucket-release'; - -function getCachedTags( - endpoint: string, - repository: string -): Promise { - const cacheKey = `getTags-${endpoint}-${repository}`; - const cachedResult = memCache.get>(cacheKey); - // istanbul ignore if - if (cachedResult !== undefined) { - return cachedResult; - } - const promisedRes = getTags(endpoint, repository); - memCache.set(cacheKey, promisedRes); - return promisedRes; -} - -export async function getChangeLogJSON( - config: BranchUpgradeConfig -): Promise { - const versioning = config.versioning!; - const currentVersion = config.currentVersion!; - const newVersion = config.newVersion!; - const sourceUrl = config.sourceUrl!; - const packageName = config.packageName!; - const sourceDirectory = config.sourceDirectory!; - - logger.trace('getChangeLogJSON for bitbucket'); - const version = allVersioning.get(versioning); - - const parsedUrl = URL.parse(sourceUrl); - const protocol = parsedUrl.protocol!; - const host = parsedUrl.host!; - const pathname = parsedUrl.pathname!; - - logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); - const baseUrl = `${protocol}//${host}/`; - const apiBaseUrl = `${protocol}//api.${host}/`; - const repository = trimSlashes(pathname).replace(regEx(/\.git$/), ''); - - if (repository.split('/').length !== 2) { - logger.debug(`Invalid bitbucket URL found: ${sourceUrl}`); - return null; - } - - const releases = config.releases ?? (await getInRangeReleases(config)); - if (!releases?.length) { - logger.debug('No releases'); - return null; +export class BitbucketChangeLogSource extends ChangeLogSource { + constructor() { + super('bitbucket'); } - // This extra filter/sort should not be necessary, but better safe than sorry - const validReleases = [...releases] - .filter((release) => version.isVersion(release.version)) - .sort((a, b) => version.sortVersions(a.version, b.version)); - if (validReleases.length < 2) { - logger.debug(`Not enough valid releases for dep ${packageName}`); - return null; + protected override getCompareURL( + baseUrl: string, + repository: string, + prevHead: string, + nextHead: string + ): string { + return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; } - - const changelogReleases: ChangeLogRelease[] = []; - // compare versions - const include = (v: string): boolean => - version.isGreaterThan(v, currentVersion) && - !version.isGreaterThan(v, newVersion); - - for (let i = 1; i < validReleases.length; i += 1) { - const prev = validReleases[i - 1]; - const next = validReleases[i]; - if (!include(next.version)) { - continue; - } - let release = await packageCache.get( - cacheNamespace, - getCacheKey(sourceUrl, packageName, prev.version, next.version) - ); - if (!release) { - release = { - version: next.version, - date: next.releaseTimestamp, - gitRef: next.gitRef, - // put empty changes so that existing templates won't break - changes: [], - compare: {}, - }; - const prevHead = await getRef( - version, - packageName, - prev, - apiBaseUrl, - repository - ); - const nextHead = await getRef( - version, - packageName, - next, - apiBaseUrl, - repository - ); - if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { - release.compare.url = getCompareURL( - baseUrl, - repository, - prevHead, - nextHead - ); - } - const cacheMinutes = 55; - await packageCache.set( - cacheNamespace, - getCacheKey(sourceUrl, packageName, prev.version, next.version), - release, - cacheMinutes - ); - } - changelogReleases.unshift(release); - } - - let res: ChangeLogResult | null = { - project: { - apiBaseUrl, - baseUrl, - type: 'bitbucket', - repository, - sourceUrl, - sourceDirectory, - packageName, - }, - versions: changelogReleases, - }; - - res = await addReleaseNotes(res, config); - - return res; -} - -function getCompareURL( - baseUrl: string, - repository: string, - prevHead: string, - nextHead: string -): string { - return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; -} - -function findTagOfRelease( - version: allVersioning.VersioningApi, - packageName: string, - depNewVersion: string, - tags: string[] -): string | undefined { - const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); - const tagName = tags - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); - return tagName; -} - -async function getRef( - version: allVersioning.VersioningApi, - packageName: string, - release: Release, - apiBaseUrl: string, - repository: string -): Promise { - const tags = await getCachedTags(apiBaseUrl, repository); - - const tagName = findTagOfRelease(version, packageName, release.version, tags); - if (is.nonEmptyString(tagName)) { - return tagName; - } - if (is.nonEmptyString(release.gitRef)) { - return release.gitRef; - } - return null; -} - -function getCacheKey( - sourceUrl: string, - packageName: string, - prev: string, - next: string -): string { - return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; } diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts new file mode 100644 index 00000000000000..eed319aa764006 --- /dev/null +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -0,0 +1,214 @@ +import URL from 'node:url'; +import is from '@sindresorhus/is'; +import { logger } from '../../../../../logger'; +import type { Release } from '../../../../../modules/datasource/types'; +import * as allVersioning from '../../../../../modules/versioning'; +import * as memCache from '../../../../../util/cache/memory'; +import * as packageCache from '../../../../../util/cache/package'; +import { regEx } from '../../../../../util/regex'; +import { trimSlashes } from '../../../../../util/url'; +import type { BranchUpgradeConfig } from '../../../../types'; +import { getTags } from './bitbucket'; +import { slugifyUrl } from './common'; +import { addReleaseNotes } from './release-notes'; +import { getInRangeReleases } from './releases'; +import type { ChangeLogRelease, ChangeLogResult } from './types'; + +export class ChangeLogSource { + private source: 'bitbucket' | 'github' | 'gitlab'; + private cacheNamespace: string; + + constructor(source: 'bitbucket' | 'github' | 'gitlab') { + this.source = source; + this.cacheNamespace = `changelog-${source}-release`; + } + + private getCachedTags( + endpoint: string, + repository: string + ): Promise { + const cacheKey = `getTags-${endpoint}-${repository}`; + const cachedResult = memCache.get>(cacheKey); + // istanbul ignore if + if (cachedResult !== undefined) { + return cachedResult; + } + const promisedRes = getTags(endpoint, repository); + memCache.set(cacheKey, promisedRes); + return promisedRes; + } + + public async getChangeLogJSON( + config: BranchUpgradeConfig + ): Promise { + const versioning = config.versioning!; + const currentVersion = config.currentVersion!; + const newVersion = config.newVersion!; + const sourceUrl = config.sourceUrl!; + const packageName = config.packageName!; + const sourceDirectory = config.sourceDirectory!; + + logger.trace(`getChangeLogJSON for ${this.source}`); + const version = allVersioning.get(versioning); + + const parsedUrl = URL.parse(sourceUrl); + const protocol = parsedUrl.protocol!; + const host = parsedUrl.host!; + const pathname = parsedUrl.pathname!; + + logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); + const baseUrl = `${protocol}//${host}/`; + const apiBaseUrl = `${protocol}//api.${host}/`; + const repository = trimSlashes(pathname).replace(regEx(/\.git$/), ''); + + if (repository.split('/').length !== 2) { + logger.debug(`Invalid ${this.source} URL found: ${sourceUrl}`); + return null; + } + + const releases = config.releases ?? (await getInRangeReleases(config)); + if (!releases?.length) { + logger.debug('No releases'); + return null; + } + // This extra filter/sort should not be necessary, but better safe than sorry + const validReleases = [...releases] + .filter((release) => version.isVersion(release.version)) + .sort((a, b) => version.sortVersions(a.version, b.version)); + + if (validReleases.length < 2) { + logger.debug(`Not enough valid releases for dep ${packageName}`); + return null; + } + + const changelogReleases: ChangeLogRelease[] = []; + // compare versions + const include = (v: string): boolean => + version.isGreaterThan(v, currentVersion) && + !version.isGreaterThan(v, newVersion); + + for (let i = 1; i < validReleases.length; i += 1) { + const prev = validReleases[i - 1]; + const next = validReleases[i]; + if (!include(next.version)) { + continue; + } + let release = await packageCache.get( + this.cacheNamespace, + this.getCacheKey(sourceUrl, packageName, prev.version, next.version) + ); + if (!release) { + release = { + version: next.version, + date: next.releaseTimestamp, + gitRef: next.gitRef, + // put empty changes so that existing templates won't break + changes: [], + compare: {}, + }; + const prevHead = await this.getRef( + version, + packageName, + prev, + apiBaseUrl, + repository + ); + const nextHead = await this.getRef( + version, + packageName, + next, + apiBaseUrl, + repository + ); + if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { + release.compare.url = this.getCompareURL( + baseUrl, + repository, + prevHead, + nextHead + ); + } + const cacheMinutes = 55; + await packageCache.set( + this.cacheNamespace, + this.getCacheKey(sourceUrl, packageName, prev.version, next.version), + release, + cacheMinutes + ); + } + changelogReleases.unshift(release); + } + + let res: ChangeLogResult | null = { + project: { + apiBaseUrl, + baseUrl, + type: this.source, + repository, + sourceUrl, + sourceDirectory, + packageName, + }, + versions: changelogReleases, + }; + + res = await addReleaseNotes(res, config); + + return res; + } + + protected getCompareURL( + baseUrl: string, + repository: string, + prevHead: string, + nextHead: string + ): string { + return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; + } + + private findTagOfRelease( + version: allVersioning.VersioningApi, + packageName: string, + depNewVersion: string, + tags: string[] + ): string | undefined { + const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); + const tagName = tags + .filter((tag) => version.isVersion(tag.replace(regex, ''))) + .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); + return tagName; + } + + private async getRef( + version: allVersioning.VersioningApi, + packageName: string, + release: Release, + apiBaseUrl: string, + repository: string + ): Promise { + const tags = await this.getCachedTags(apiBaseUrl, repository); + + const tagName = this.findTagOfRelease( + version, + packageName, + release.version, + tags + ); + if (is.nonEmptyString(tagName)) { + return tagName; + } + if (is.nonEmptyString(release.gitRef)) { + return release.gitRef; + } + return null; + } + + private getCacheKey( + sourceUrl: string, + packageName: string, + prev: string, + next: string + ): string { + return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; + } +} From 7ed34f40fb9a85404ed89f26cb6d3cdcaf624164 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 07:42:10 -0400 Subject: [PATCH 37/71] refactor: add base class --- .../repository/update/pr/changelog/index.ts | 56 ++-- .../update/pr/changelog/source-bitbucket.ts | 10 +- .../update/pr/changelog/source-github.ts | 301 +++++------------- .../update/pr/changelog/source-gitlab.ts | 208 +----------- .../repository/update/pr/changelog/source.ts | 49 ++- 5 files changed, 161 insertions(+), 463 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/index.ts b/lib/workers/repository/update/pr/changelog/index.ts index e3556c47a5f9c4..2916643b20e557 100644 --- a/lib/workers/repository/update/pr/changelog/index.ts +++ b/lib/workers/repository/update/pr/changelog/index.ts @@ -1,10 +1,12 @@ +import is from '@sindresorhus/is'; import { logger } from '../../../../../logger'; import * as allVersioning from '../../../../../modules/versioning'; import { detectPlatform } from '../../../../../util/common'; import type { BranchUpgradeConfig } from '../../../../types'; +import type { ChangeLogSource } from './source'; import { BitbucketChangeLogSource } from './source-bitbucket'; -import * as sourceGithub from './source-github'; -import * as sourceGitlab from './source-gitlab'; +import { GitHubChangeLogSource } from './source-github'; +import { GitLabChangeLogSource } from './source-gitlab'; import type { ChangeLogResult } from './types'; export * from './types'; @@ -27,34 +29,40 @@ export async function getChangeLogJSON( `Fetching changelog: ${sourceUrl} (${currentVersion} -> ${newVersion})` ); - let res: ChangeLogResult | null = null; - const platform = detectPlatform(sourceUrl); - const source = new BitbucketChangeLogSource(); - - switch (platform) { - case 'gitlab': - res = await sourceGitlab.getChangeLogJSON(config); - break; - case 'github': - res = await sourceGithub.getChangeLogJSON(config); - break; - case 'bitbucket': - res = await source.getChangeLogJSON(config); - break; - - default: - logger.info( - { sourceUrl, hostType: platform }, - 'Unknown platform, skipping changelog fetching.' - ); - break; + if (is.nullOrUndefined(platform)) { + logger.info( + { sourceUrl, hostType: platform }, + 'Unknown platform, skipping changelog fetching.' + ); + return null; } - return res; + const changeLogSource = getChangeLogSourceFor(platform); + + if (is.nullOrUndefined(changeLogSource)) { + logger.info( + { sourceUrl, hostType: platform }, + 'Unknown changelog source, skipping changelog fetching.' + ); + return null; + } + + return await changeLogSource.getChangeLogJSON(config); } catch (err) /* istanbul ignore next */ { logger.error({ config, err }, 'getChangeLogJSON error'); return null; } } + +const changeLogSources = new Map(); +changeLogSources.set('gitlab', new GitLabChangeLogSource()); +changeLogSources.set('github', new GitHubChangeLogSource()); +changeLogSources.set('bitbucket', new BitbucketChangeLogSource()); + +export function getChangeLogSourceFor( + platform: string +): ChangeLogSource | null { + return changeLogSources.get(platform) ?? null; +} diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 8b4b0d1e44fa23..81018362fd4068 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -1,3 +1,4 @@ +import URL from 'node:url'; import { ChangeLogSource } from './source'; export class BitbucketChangeLogSource extends ChangeLogSource { @@ -5,7 +6,7 @@ export class BitbucketChangeLogSource extends ChangeLogSource { super('bitbucket'); } - protected override getCompareURL( + getCompareURL( baseUrl: string, repository: string, prevHead: string, @@ -13,4 +14,11 @@ export class BitbucketChangeLogSource extends ChangeLogSource { ): string { return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; } + + getAPIBaseUrl(sourceUrl: string): string { + const parsedUrl = URL.parse(sourceUrl); + const protocol = parsedUrl.protocol!; + const host = parsedUrl.host!; + return `${protocol}//api.${host}/`; + } } diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index bc3e72cd85d225..d08a015e876e0d 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -1,250 +1,97 @@ -// TODO #7154 import URL from 'node:url'; -import is from '@sindresorhus/is'; import { GlobalConfig } from '../../../../../config/global'; import { logger } from '../../../../../logger'; -import type { Release } from '../../../../../modules/datasource/types'; -import * as allVersioning from '../../../../../modules/versioning'; -import * as memCache from '../../../../../util/cache/memory'; -import * as packageCache from '../../../../../util/cache/package'; +import type * as allVersioning from '../../../../../modules/versioning'; import * as hostRules from '../../../../../util/host-rules'; import { regEx } from '../../../../../util/regex'; -import { trimSlashes } from '../../../../../util/url'; import type { BranchUpgradeConfig } from '../../../../types'; -import { slugifyUrl } from './common'; -import { getTags } from './github'; -import { addReleaseNotes } from './release-notes'; -import { getInRangeReleases } from './releases'; -import type { ChangeLogRelease, ChangeLogResult } from './types'; +import { ChangeLogSource } from './source'; +import type { ChangeLogResult } from './types'; -const cacheNamespace = 'changelog-github-release'; +export class GitHubChangeLogSource extends ChangeLogSource { + constructor() { + super('github'); + } -function getCachedTags( - endpoint: string, - repository: string -): Promise { - const cacheKey = `getTags-${endpoint}-${repository}`; - const cachedResult = memCache.get>(cacheKey); - // istanbul ignore if - if (cachedResult !== undefined) { - return cachedResult; + getAPIBaseUrl(sourceUrl: string): string { + return sourceUrl.startsWith('https://github.com/') + ? 'https://api.github.com/' + : this.getBaseUrl(sourceUrl) + 'api/v3/'; } - const promisedRes = getTags(endpoint, repository); - memCache.set(cacheKey, promisedRes); - return promisedRes; -} -export async function getChangeLogJSON( - config: BranchUpgradeConfig -): Promise { - const versioning = config.versioning!; - const currentVersion = config.currentVersion!; - const newVersion = config.newVersion!; - const sourceUrl = config.sourceUrl!; - const packageName = config.packageName!; - const sourceDirectory = config.sourceDirectory!; - const manager = config.manager; - if (sourceUrl === 'https://github.com/DefinitelyTyped/DefinitelyTyped') { - logger.trace('No release notes for @types'); - return null; + getCompareURL( + baseUrl: string, + repository: string, + prevHead: string, + nextHead: string + ): string { + return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; } - const version = allVersioning.get(versioning); - const parsedUrl = URL.parse(sourceUrl); - const protocol = parsedUrl.protocol!; - const host = parsedUrl.host!; - const pathname = parsedUrl.pathname!; - logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); + // TODO - Should this be the common logic? + protected override findTagOfRelease( + version: allVersioning.VersioningApi, + packageName: string, + depNewVersion: string, + tags: string[] + ): string | undefined { + const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); + const exactReleaseRegex = regEx(`${packageName}[@\\-_]v?${depNewVersion}`); + const exactTagsList = tags.filter((tag) => { + return exactReleaseRegex.test(tag); + }); + let tagName: string | undefined; + if (exactTagsList.length) { + tagName = exactTagsList + .filter((tag) => version.isVersion(tag.replace(regex, ''))) + .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); + } else { + tagName = tags + .filter((tag) => version.isVersion(tag.replace(regex, ''))) + .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); + } + return tagName; + } - // TODO: types (#7154) - const baseUrl = `${protocol}//${host}/`; - const url = sourceUrl.startsWith('https://github.com/') - ? 'https://api.github.com/' - : sourceUrl; - const { token } = hostRules.find({ - hostType: 'github', - url, - }); - // istanbul ignore if - if (!token) { - if (host.endsWith('.github.com') || host === 'github.com') { - if (!GlobalConfig.get('githubTokenWarn')) { - logger.debug( + protected override validateToken( + sourceUrl: string, + config: BranchUpgradeConfig + ): ChangeLogResult | null { + const parsedUrl = URL.parse(sourceUrl); + const host = parsedUrl.host!; + const manager = config.manager; + const packageName = config.packageName; + + const url = sourceUrl.startsWith('https://github.com/') + ? 'https://api.github.com/' + : sourceUrl; + const { token } = hostRules.find({ + hostType: 'github', + url, + }); + // istanbul ignore if + if (!token) { + if (host.endsWith('.github.com') || host === 'github.com') { + if (!GlobalConfig.get('githubTokenWarn')) { + logger.debug( + { manager, packageName, sourceUrl }, + 'GitHub token warning has been suppressed. Skipping release notes retrieval' + ); + return null; + } + logger.warn( { manager, packageName, sourceUrl }, - 'GitHub token warning has been suppressed. Skipping release notes retrieval' + 'No github.com token has been configured. Skipping release notes retrieval' ); - return null; + return { error: 'MissingGithubToken' }; } - logger.warn( + logger.debug( { manager, packageName, sourceUrl }, - 'No github.com token has been configured. Skipping release notes retrieval' + 'Repository URL does not match any known github hosts - skipping changelog retrieval' ); - return { error: 'MissingGithubToken' }; + return null; } - logger.debug( - { manager, packageName, sourceUrl }, - 'Repository URL does not match any known github hosts - skipping changelog retrieval' - ); - return null; - } - const apiBaseUrl = sourceUrl.startsWith('https://github.com/') - ? 'https://api.github.com/' - : baseUrl + 'api/v3/'; - const repository = trimSlashes(pathname).replace(regEx(/\.git$/), ''); - - if (repository.split('/').length !== 2) { - logger.debug(`Invalid github URL found: ${sourceUrl}`); - return null; - } - const releases = config.releases ?? (await getInRangeReleases(config)); - if (!releases?.length) { - logger.debug('No releases'); return null; } - // This extra filter/sort should not be necessary, but better safe than sorry - const validReleases = [...releases] - .filter((release) => version.isVersion(release.version)) - .sort((a, b) => version.sortVersions(a.version, b.version)); - - if (validReleases.length < 2) { - logger.debug(`Not enough valid releases for dep ${packageName}`); - return null; - } - - const changelogReleases: ChangeLogRelease[] = []; - // compare versions - const include = (v: string): boolean => - version.isGreaterThan(v, currentVersion) && - !version.isGreaterThan(v, newVersion); - - for (let i = 1; i < validReleases.length; i += 1) { - const prev = validReleases[i - 1]; - const next = validReleases[i]; - if (!include(next.version)) { - continue; - } - let release = await packageCache.get( - cacheNamespace, - getCacheKey(sourceUrl, packageName, prev.version, next.version) - ); - if (!release) { - release = { - version: next.version, - date: next.releaseTimestamp, - gitRef: next.gitRef, - // put empty changes so that existing templates won't break - changes: [], - compare: {}, - }; - const prevHead = await getRef( - version, - packageName, - prev, - apiBaseUrl, - repository - ); - const nextHead = await getRef( - version, - packageName, - next, - apiBaseUrl, - repository - ); - if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { - release.compare.url = getCompareURL( - baseUrl, - repository, - prevHead, - nextHead - ); - } - const cacheMinutes = 55; - await packageCache.set( - cacheNamespace, - getCacheKey(sourceUrl, packageName, prev.version, next.version), - release, - cacheMinutes - ); - } - changelogReleases.unshift(release); - } - - let res: ChangeLogResult | null = { - project: { - apiBaseUrl, - baseUrl, - type: 'github', - repository, - sourceUrl, - sourceDirectory, - packageName, - }, - versions: changelogReleases, - }; - - res = await addReleaseNotes(res, config); - - return res; -} - -function getCompareURL( - baseUrl: string, - repository: string, - prevHead: string, - nextHead: string -): string { - return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; -} - -function findTagOfRelease( - version: allVersioning.VersioningApi, - packageName: string, - depNewVersion: string, - tags: string[] -): string | undefined { - const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); - const exactReleaseRegex = regEx(`${packageName}[@\\-_]v?${depNewVersion}`); - const exactTagsList = tags.filter((tag) => { - return exactReleaseRegex.test(tag); - }); - let tagName: string | undefined; - if (exactTagsList.length) { - tagName = exactTagsList - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); - } else { - tagName = tags - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); - } - return tagName; -} - -async function getRef( - version: allVersioning.VersioningApi, - packageName: string, - release: Release, - apiBaseUrl: string, - repository: string -): Promise { - const tags = await getCachedTags(apiBaseUrl, repository); - - const tagName = findTagOfRelease(version, packageName, release.version, tags); - if (is.nonEmptyString(tagName)) { - return tagName; - } - if (is.nonEmptyString(release.gitRef)) { - return release.gitRef; - } - return null; -} - -function getCacheKey( - sourceUrl: string, - packageName: string, - prev: string, - next: string -): string { - return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; } diff --git a/lib/workers/repository/update/pr/changelog/source-gitlab.ts b/lib/workers/repository/update/pr/changelog/source-gitlab.ts index 7b8d9b07c09f71..235cfd87d116f3 100644 --- a/lib/workers/repository/update/pr/changelog/source-gitlab.ts +++ b/lib/workers/repository/update/pr/changelog/source-gitlab.ts @@ -1,202 +1,20 @@ -// TODO #7154 -import URL from 'node:url'; -import is from '@sindresorhus/is'; -import { logger } from '../../../../../logger'; -import type { Release } from '../../../../../modules/datasource/types'; -import * as allVersioning from '../../../../../modules/versioning'; -import * as memCache from '../../../../../util/cache/memory'; -import * as packageCache from '../../../../../util/cache/package'; -import { regEx } from '../../../../../util/regex'; -import { trimSlashes } from '../../../../../util/url'; -import type { BranchUpgradeConfig } from '../../../../types'; -import { slugifyUrl } from './common'; -import { getTags } from './gitlab'; -import { addReleaseNotes } from './release-notes'; -import { getInRangeReleases } from './releases'; -import type { ChangeLogRelease, ChangeLogResult } from './types'; +import { ChangeLogSource } from './source'; -const cacheNamespace = 'changelog-gitlab-release'; - -function getCachedTags( - endpoint: string, - repository: string -): Promise { - const cacheKey = `getTags-${endpoint}-${repository}`; - const cachedResult = memCache.get>(cacheKey); - // istanbul ignore if - if (cachedResult !== undefined) { - return cachedResult; +export class GitLabChangeLogSource extends ChangeLogSource { + constructor() { + super('gitlab'); } - const promisedRes = getTags(endpoint, repository); - memCache.set(cacheKey, promisedRes); - return promisedRes; -} - -export async function getChangeLogJSON( - config: BranchUpgradeConfig -): Promise { - const versioning = config.versioning!; - const currentVersion = config.currentVersion!; - const newVersion = config.newVersion!; - const sourceUrl = config.sourceUrl!; - const packageName = config.packageName!; - const sourceDirectory = config.sourceDirectory!; - - logger.trace('getChangeLogJSON for gitlab'); - const version = allVersioning.get(versioning); - const parsedUrl = URL.parse(sourceUrl); - const protocol = parsedUrl.protocol!; - const host = parsedUrl.host!; - const pathname = parsedUrl.pathname!; - - logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); - const baseUrl = `${protocol}//${host}/`; - const apiBaseUrl = `${baseUrl}api/v4/`; - const repository = trimSlashes(pathname).replace(regEx(/\.git$/), ''); - - if (repository.split('/').length !== 2) { - logger.debug(`Invalid gitlab URL found: ${sourceUrl}`); - return null; + getAPIBaseUrl(sourceUrl: string): string { + return this.getBaseUrl(sourceUrl) + 'api/v4/'; } - const releases = config.releases ?? (await getInRangeReleases(config)); - if (!releases?.length) { - logger.debug('No releases'); - return null; + getCompareURL( + baseUrl: string, + repository: string, + prevHead: string, + nextHead: string + ): string { + return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; } - // This extra filter/sort should not be necessary, but better safe than sorry - const validReleases = [...releases] - .filter((release) => version.isVersion(release.version)) - .sort((a, b) => version.sortVersions(a.version, b.version)); - - if (validReleases.length < 2) { - logger.debug(`Not enough valid releases for dep ${packageName}`); - return null; - } - - const changelogReleases: ChangeLogRelease[] = []; - // compare versions - const include = (v: string): boolean => - version.isGreaterThan(v, currentVersion) && - !version.isGreaterThan(v, newVersion); - - for (let i = 1; i < validReleases.length; i += 1) { - const prev = validReleases[i - 1]; - const next = validReleases[i]; - if (!include(next.version)) { - continue; - } - let release = await packageCache.get( - cacheNamespace, - getCacheKey(sourceUrl, packageName, prev.version, next.version) - ); - if (!release) { - release = { - version: next.version, - date: next.releaseTimestamp, - gitRef: next.gitRef, - // put empty changes so that existing templates won't break - changes: [], - compare: {}, - }; - const prevHead = await getRef( - version, - packageName, - prev, - apiBaseUrl, - repository - ); - const nextHead = await getRef( - version, - packageName, - next, - apiBaseUrl, - repository - ); - if (is.nonEmptyString(prevHead) && is.nonEmptyString(nextHead)) { - release.compare.url = getCompareURL( - baseUrl, - repository, - prevHead, - nextHead - ); - } - const cacheMinutes = 55; - await packageCache.set( - cacheNamespace, - getCacheKey(sourceUrl, packageName, prev.version, next.version), - release, - cacheMinutes - ); - } - changelogReleases.unshift(release); - } - - let res: ChangeLogResult | null = { - project: { - apiBaseUrl, - baseUrl, - type: 'gitlab', - repository, - sourceUrl, - sourceDirectory, - packageName, - }, - versions: changelogReleases, - }; - - res = await addReleaseNotes(res, config); - - return res; -} - -function getCompareURL( - baseUrl: string, - repository: string, - prevHead: string, - nextHead: string -): string { - return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; -} - -function findTagOfRelease( - version: allVersioning.VersioningApi, - packageName: string, - depNewVersion: string, - tags: string[] -): string | undefined { - const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); - const tagName = tags - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); - return tagName; -} - -async function getRef( - version: allVersioning.VersioningApi, - packageName: string, - release: Release, - apiBaseUrl: string, - repository: string -): Promise { - const tags = await getCachedTags(apiBaseUrl, repository); - - const tagName = findTagOfRelease(version, packageName, release.version, tags); - if (is.nonEmptyString(tagName)) { - return tagName; - } - if (is.nonEmptyString(release.gitRef)) { - return release.gitRef; - } - return null; -} - -function getCacheKey( - sourceUrl: string, - packageName: string, - prev: string, - next: string -): string { - return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; } diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index eed319aa764006..41a2de101d09ae 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -14,7 +14,7 @@ import { addReleaseNotes } from './release-notes'; import { getInRangeReleases } from './releases'; import type { ChangeLogRelease, ChangeLogResult } from './types'; -export class ChangeLogSource { +export abstract class ChangeLogSource { private source: 'bitbucket' | 'github' | 'gitlab'; private cacheNamespace: string; @@ -41,25 +41,21 @@ export class ChangeLogSource { public async getChangeLogJSON( config: BranchUpgradeConfig ): Promise { + logger.trace(`getChangeLogJSON for ${this.source}`); + const versioning = config.versioning!; const currentVersion = config.currentVersion!; const newVersion = config.newVersion!; const sourceUrl = config.sourceUrl!; const packageName = config.packageName!; const sourceDirectory = config.sourceDirectory!; - - logger.trace(`getChangeLogJSON for ${this.source}`); const version = allVersioning.get(versioning); - const parsedUrl = URL.parse(sourceUrl); - const protocol = parsedUrl.protocol!; - const host = parsedUrl.host!; - const pathname = parsedUrl.pathname!; + const baseUrl = this.getBaseUrl(sourceUrl); + const apiBaseUrl = this.getAPIBaseUrl(sourceUrl); + const repository = this.getRepositoryFromUrl(sourceUrl); - logger.trace({ protocol, host, pathname }, 'Protocol, host, pathname'); - const baseUrl = `${protocol}//${host}/`; - const apiBaseUrl = `${protocol}//api.${host}/`; - const repository = trimSlashes(pathname).replace(regEx(/\.git$/), ''); + this.validateToken(sourceUrl, config); if (repository.split('/').length !== 2) { logger.debug(`Invalid ${this.source} URL found: ${sourceUrl}`); @@ -157,16 +153,14 @@ export class ChangeLogSource { return res; } - protected getCompareURL( + abstract getCompareURL( baseUrl: string, repository: string, prevHead: string, nextHead: string - ): string { - return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; - } + ): string; - private findTagOfRelease( + protected findTagOfRelease( version: allVersioning.VersioningApi, packageName: string, depNewVersion: string, @@ -211,4 +205,27 @@ export class ChangeLogSource { ): string { return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; } + + protected getBaseUrl(sourceUrl: string): string { + const parsedUrl = URL.parse(sourceUrl); + const protocol = parsedUrl.protocol!; + const host = parsedUrl.host!; + return `${protocol}//${host}/`; + } + + abstract getAPIBaseUrl(sourceUrl: string): string; + + private getRepositoryFromUrl(sourceUrl: string): string { + const parsedUrl = URL.parse(sourceUrl); + const pathname = parsedUrl.pathname!; + return trimSlashes(pathname).replace(regEx(/\.git$/), ''); + } + + // TODO Fix this + protected validateToken( + sourceUrl: string, + config: BranchUpgradeConfig + ): ChangeLogResult | null { + return null; + } } From 8fecd6d039811980a837f36dba05743635b19eb6 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 07:49:15 -0400 Subject: [PATCH 38/71] refactor: add base class --- .../repository/update/pr/changelog/source.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index 41a2de101d09ae..0e1cbd88d6cf7a 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -15,12 +15,12 @@ import { getInRangeReleases } from './releases'; import type { ChangeLogRelease, ChangeLogResult } from './types'; export abstract class ChangeLogSource { - private source: 'bitbucket' | 'github' | 'gitlab'; + private platform: 'bitbucket' | 'github' | 'gitlab'; private cacheNamespace: string; - constructor(source: 'bitbucket' | 'github' | 'gitlab') { - this.source = source; - this.cacheNamespace = `changelog-${source}-release`; + constructor(platform: 'bitbucket' | 'github' | 'gitlab') { + this.platform = platform; + this.cacheNamespace = `changelog-${platform}-release`; } private getCachedTags( @@ -41,7 +41,7 @@ export abstract class ChangeLogSource { public async getChangeLogJSON( config: BranchUpgradeConfig ): Promise { - logger.trace(`getChangeLogJSON for ${this.source}`); + logger.trace(`getChangeLogJSON for ${this.platform}`); const versioning = config.versioning!; const currentVersion = config.currentVersion!; @@ -58,7 +58,7 @@ export abstract class ChangeLogSource { this.validateToken(sourceUrl, config); if (repository.split('/').length !== 2) { - logger.debug(`Invalid ${this.source} URL found: ${sourceUrl}`); + logger.debug(`Invalid ${this.platform} URL found: ${sourceUrl}`); return null; } @@ -139,7 +139,7 @@ export abstract class ChangeLogSource { project: { apiBaseUrl, baseUrl, - type: this.source, + type: this.platform, repository, sourceUrl, sourceDirectory, From f1ad9c2efc798f418c2186ba1e9e8754324f283f Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 08:22:57 -0400 Subject: [PATCH 39/71] refactor: add base class --- .../update/pr/changelog/source-bitbucket.ts | 5 +++ .../update/pr/changelog/source-github.ts | 17 +++++++-- .../update/pr/changelog/source-gitlab.ts | 7 +++- .../repository/update/pr/changelog/source.ts | 36 ++++++++++++------- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 81018362fd4068..c06ae1328a436c 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -1,4 +1,5 @@ import URL from 'node:url'; +import { getTags } from './bitbucket'; import { ChangeLogSource } from './source'; export class BitbucketChangeLogSource extends ChangeLogSource { @@ -21,4 +22,8 @@ export class BitbucketChangeLogSource extends ChangeLogSource { const host = parsedUrl.host!; return `${protocol}//api.${host}/`; } + + getTags(endpoint: string, repository: string): Promise { + return getTags(endpoint, repository); + } } diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index d08a015e876e0d..17c7fd3b112e1b 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -5,9 +5,9 @@ import type * as allVersioning from '../../../../../modules/versioning'; import * as hostRules from '../../../../../util/host-rules'; import { regEx } from '../../../../../util/regex'; import type { BranchUpgradeConfig } from '../../../../types'; +import { getTags } from './github'; import { ChangeLogSource } from './source'; import type { ChangeLogResult } from './types'; - export class GitHubChangeLogSource extends ChangeLogSource { constructor() { super('github'); @@ -25,7 +25,20 @@ export class GitHubChangeLogSource extends ChangeLogSource { prevHead: string, nextHead: string ): string { - return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; + return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; + } + + getTags(endpoint: string, repository: string): Promise { + return getTags(endpoint, repository); + } + + protected override shouldSkipSource(sourceUrl: string): boolean { + if (sourceUrl === 'https://github.com/DefinitelyTyped/DefinitelyTyped') { + logger.trace('No release notes for @types'); + return true; + } + + return false; } // TODO - Should this be the common logic? diff --git a/lib/workers/repository/update/pr/changelog/source-gitlab.ts b/lib/workers/repository/update/pr/changelog/source-gitlab.ts index 235cfd87d116f3..26a753705f5357 100644 --- a/lib/workers/repository/update/pr/changelog/source-gitlab.ts +++ b/lib/workers/repository/update/pr/changelog/source-gitlab.ts @@ -1,3 +1,4 @@ +import { getTags } from './gitlab'; import { ChangeLogSource } from './source'; export class GitLabChangeLogSource extends ChangeLogSource { @@ -15,6 +16,10 @@ export class GitLabChangeLogSource extends ChangeLogSource { prevHead: string, nextHead: string ): string { - return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; + return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; + } + + getTags(endpoint: string, repository: string): Promise { + return getTags(endpoint, repository); } } diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index 0e1cbd88d6cf7a..0cdd472bc47921 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -8,7 +8,6 @@ import * as packageCache from '../../../../../util/cache/package'; import { regEx } from '../../../../../util/regex'; import { trimSlashes } from '../../../../../util/url'; import type { BranchUpgradeConfig } from '../../../../types'; -import { getTags } from './bitbucket'; import { slugifyUrl } from './common'; import { addReleaseNotes } from './release-notes'; import { getInRangeReleases } from './releases'; @@ -23,6 +22,17 @@ export abstract class ChangeLogSource { this.cacheNamespace = `changelog-${platform}-release`; } + abstract getCompareURL( + baseUrl: string, + repository: string, + prevHead: string, + nextHead: string + ): string; + + abstract getAPIBaseUrl(sourceUrl: string): string; + + abstract getTags(endpoint: string, repository: string): Promise; + private getCachedTags( endpoint: string, repository: string @@ -33,7 +43,7 @@ export abstract class ChangeLogSource { if (cachedResult !== undefined) { return cachedResult; } - const promisedRes = getTags(endpoint, repository); + const promisedRes = this.getTags(endpoint, repository); memCache.set(cacheKey, promisedRes); return promisedRes; } @@ -51,11 +61,18 @@ export abstract class ChangeLogSource { const sourceDirectory = config.sourceDirectory!; const version = allVersioning.get(versioning); + if (this.shouldSkipSource(sourceUrl)) { + return null; + } + const baseUrl = this.getBaseUrl(sourceUrl); const apiBaseUrl = this.getAPIBaseUrl(sourceUrl); const repository = this.getRepositoryFromUrl(sourceUrl); - this.validateToken(sourceUrl, config); + const isValid = this.validateToken(sourceUrl, config); + if (!is.nullOrUndefined(isValid)) { + return isValid; + } if (repository.split('/').length !== 2) { logger.debug(`Invalid ${this.platform} URL found: ${sourceUrl}`); @@ -153,13 +170,6 @@ export abstract class ChangeLogSource { return res; } - abstract getCompareURL( - baseUrl: string, - repository: string, - prevHead: string, - nextHead: string - ): string; - protected findTagOfRelease( version: allVersioning.VersioningApi, packageName: string, @@ -213,8 +223,6 @@ export abstract class ChangeLogSource { return `${protocol}//${host}/`; } - abstract getAPIBaseUrl(sourceUrl: string): string; - private getRepositoryFromUrl(sourceUrl: string): string { const parsedUrl = URL.parse(sourceUrl); const pathname = parsedUrl.pathname!; @@ -228,4 +236,8 @@ export abstract class ChangeLogSource { ): ChangeLogResult | null { return null; } + + protected shouldSkipSource(sourceUrl: string): boolean { + return false; + } } From 5d237af6ea08b091265a8f99260c813fe1ee0888 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 09:39:34 -0400 Subject: [PATCH 40/71] refactor: change how host validation is handled --- .../update/pr/changelog/source-github.ts | 16 ++++++------- .../repository/update/pr/changelog/source.ts | 24 ++++++++++++------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index 17c7fd3b112e1b..1a20b11a87aa18 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -7,7 +7,7 @@ import { regEx } from '../../../../../util/regex'; import type { BranchUpgradeConfig } from '../../../../types'; import { getTags } from './github'; import { ChangeLogSource } from './source'; -import type { ChangeLogResult } from './types'; +import type { ChangeLogError } from './types'; export class GitHubChangeLogSource extends ChangeLogSource { constructor() { super('github'); @@ -41,7 +41,6 @@ export class GitHubChangeLogSource extends ChangeLogSource { return false; } - // TODO - Should this be the common logic? protected override findTagOfRelease( version: allVersioning.VersioningApi, packageName: string, @@ -66,10 +65,10 @@ export class GitHubChangeLogSource extends ChangeLogSource { return tagName; } - protected override validateToken( + protected override hasValidToken( sourceUrl: string, config: BranchUpgradeConfig - ): ChangeLogResult | null { + ): { isValid: boolean; error?: ChangeLogError } { const parsedUrl = URL.parse(sourceUrl); const host = parsedUrl.host!; const manager = config.manager; @@ -90,21 +89,20 @@ export class GitHubChangeLogSource extends ChangeLogSource { { manager, packageName, sourceUrl }, 'GitHub token warning has been suppressed. Skipping release notes retrieval' ); - return null; + return { isValid: false }; } logger.warn( { manager, packageName, sourceUrl }, 'No github.com token has been configured. Skipping release notes retrieval' ); - return { error: 'MissingGithubToken' }; + return { isValid: false, error: 'MissingGithubToken' }; } logger.debug( { manager, packageName, sourceUrl }, 'Repository URL does not match any known github hosts - skipping changelog retrieval' ); - return null; + return { isValid: false }; } - - return null; + return { isValid: true }; } } diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index 0cdd472bc47921..f7c793d6b2703f 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -11,7 +11,11 @@ import type { BranchUpgradeConfig } from '../../../../types'; import { slugifyUrl } from './common'; import { addReleaseNotes } from './release-notes'; import { getInRangeReleases } from './releases'; -import type { ChangeLogRelease, ChangeLogResult } from './types'; +import type { + ChangeLogError, + ChangeLogRelease, + ChangeLogResult, +} from './types'; export abstract class ChangeLogSource { private platform: 'bitbucket' | 'github' | 'gitlab'; @@ -69,9 +73,14 @@ export abstract class ChangeLogSource { const apiBaseUrl = this.getAPIBaseUrl(sourceUrl); const repository = this.getRepositoryFromUrl(sourceUrl); - const isValid = this.validateToken(sourceUrl, config); - if (!is.nullOrUndefined(isValid)) { - return isValid; + const tokenResponse = this.hasValidToken(sourceUrl, config); + if (!tokenResponse.isValid) { + if (tokenResponse.error) { + return { + error: tokenResponse.error, + }; + } + return null; } if (repository.split('/').length !== 2) { @@ -229,12 +238,11 @@ export abstract class ChangeLogSource { return trimSlashes(pathname).replace(regEx(/\.git$/), ''); } - // TODO Fix this - protected validateToken( + protected hasValidToken( sourceUrl: string, config: BranchUpgradeConfig - ): ChangeLogResult | null { - return null; + ): { isValid: boolean; error?: ChangeLogError } { + return { isValid: true }; } protected shouldSkipSource(sourceUrl: string): boolean { From 444ee527d1148b508b9ae172f313b409b54ceff6 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 09:54:43 -0400 Subject: [PATCH 41/71] tests: update mocks --- .../repository/update/pr/changelog/index.spec.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/index.spec.ts b/lib/workers/repository/update/pr/changelog/index.spec.ts index 9fd8a4f3cdb619..17e2f3a8e6cb4f 100644 --- a/lib/workers/repository/update/pr/changelog/index.spec.ts +++ b/lib/workers/repository/update/pr/changelog/index.spec.ts @@ -84,7 +84,7 @@ describe('workers/repository/update/pr/changelog/index', () => { }); it('works without Github', async () => { - githubTagsMock.mockRejectedValueOnce(new Error('Unknown')); + githubTagsMock.mockRejectedValue(new Error('Unknown')); // 4 versions, so 4 calls without cache githubReleasesMock .mockRejectedValueOnce(new Error('Unknown')) @@ -156,7 +156,7 @@ describe('workers/repository/update/pr/changelog/index', () => { }); it('filters unnecessary warns', async () => { - githubTagsMock.mockRejectedValueOnce(new Error('Unknown Github Repo')); + githubTagsMock.mockRejectedValue(new Error('Unknown Github Repo')); githubReleasesMock.mockRejectedValueOnce( new Error('Unknown Github Repo') ); @@ -261,8 +261,8 @@ describe('workers/repository/update/pr/changelog/index', () => { }); it('supports github enterprise and github.com changelog', async () => { - githubTagsMock.mockRejectedValueOnce([]); - githubReleasesMock.mockRejectedValueOnce([]); + githubTagsMock.mockRejectedValue([]); + githubReleasesMock.mockRejectedValue([]); httpMock.scope(githubApiHost).persist().get(/.*/).reply(200, []); hostRules.add({ hostType: 'github', @@ -295,8 +295,8 @@ describe('workers/repository/update/pr/changelog/index', () => { }); it('supports github enterprise and github enterprise changelog', async () => { - githubTagsMock.mockRejectedValueOnce([]); - githubReleasesMock.mockRejectedValueOnce([]); + githubTagsMock.mockRejectedValue([]); + githubReleasesMock.mockRejectedValue([]); httpMock .scope('https://github-enterprise.example.com') .persist() @@ -335,8 +335,8 @@ describe('workers/repository/update/pr/changelog/index', () => { }); it('supports github.com and github enterprise changelog', async () => { - githubTagsMock.mockRejectedValueOnce([]); - githubReleasesMock.mockRejectedValueOnce([]); + githubTagsMock.mockRejectedValue([]); + githubReleasesMock.mockRejectedValue([]); httpMock .scope('https://github-enterprise.example.com') .persist() From 257938443a04c190df0897cf138d7ca0a54eb350 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 10:05:12 -0400 Subject: [PATCH 42/71] refactor: use cache decorator --- .../update/pr/changelog/source-bitbucket.ts | 6 ++++++ .../update/pr/changelog/source-github.ts | 6 ++++++ .../update/pr/changelog/source-gitlab.ts | 6 ++++++ .../repository/update/pr/changelog/source.ts | 18 +----------------- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index c06ae1328a436c..2bbf254448ad32 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -1,4 +1,5 @@ import URL from 'node:url'; +import { cache } from '../../../../../util/cache/package/decorator'; import { getTags } from './bitbucket'; import { ChangeLogSource } from './source'; @@ -23,6 +24,11 @@ export class BitbucketChangeLogSource extends ChangeLogSource { return `${protocol}//api.${host}/`; } + @cache({ + namespace: `changelog-bitbucket-release`, + key: (endpoint: string, repository: string) => + `getTags-${endpoint}-${repository}`, + }) getTags(endpoint: string, repository: string): Promise { return getTags(endpoint, repository); } diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index 1a20b11a87aa18..6ee6ae1a12bf15 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -2,6 +2,7 @@ import URL from 'node:url'; import { GlobalConfig } from '../../../../../config/global'; import { logger } from '../../../../../logger'; import type * as allVersioning from '../../../../../modules/versioning'; +import { cache } from '../../../../../util/cache/package/decorator'; import * as hostRules from '../../../../../util/host-rules'; import { regEx } from '../../../../../util/regex'; import type { BranchUpgradeConfig } from '../../../../types'; @@ -28,6 +29,11 @@ export class GitHubChangeLogSource extends ChangeLogSource { return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; } + @cache({ + namespace: `changelog-github-release`, + key: (endpoint: string, repository: string) => + `getTags-${endpoint}-${repository}`, + }) getTags(endpoint: string, repository: string): Promise { return getTags(endpoint, repository); } diff --git a/lib/workers/repository/update/pr/changelog/source-gitlab.ts b/lib/workers/repository/update/pr/changelog/source-gitlab.ts index 26a753705f5357..804fec17f9319f 100644 --- a/lib/workers/repository/update/pr/changelog/source-gitlab.ts +++ b/lib/workers/repository/update/pr/changelog/source-gitlab.ts @@ -1,3 +1,4 @@ +import { cache } from '../../../../../util/cache/package/decorator'; import { getTags } from './gitlab'; import { ChangeLogSource } from './source'; @@ -19,6 +20,11 @@ export class GitLabChangeLogSource extends ChangeLogSource { return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; } + @cache({ + namespace: `changelog-gitlab-release`, + key: (endpoint: string, repository: string) => + `getTags-${endpoint}-${repository}`, + }) getTags(endpoint: string, repository: string): Promise { return getTags(endpoint, repository); } diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index f7c793d6b2703f..df5e50221462b5 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -3,7 +3,6 @@ import is from '@sindresorhus/is'; import { logger } from '../../../../../logger'; import type { Release } from '../../../../../modules/datasource/types'; import * as allVersioning from '../../../../../modules/versioning'; -import * as memCache from '../../../../../util/cache/memory'; import * as packageCache from '../../../../../util/cache/package'; import { regEx } from '../../../../../util/regex'; import { trimSlashes } from '../../../../../util/url'; @@ -37,21 +36,6 @@ export abstract class ChangeLogSource { abstract getTags(endpoint: string, repository: string): Promise; - private getCachedTags( - endpoint: string, - repository: string - ): Promise { - const cacheKey = `getTags-${endpoint}-${repository}`; - const cachedResult = memCache.get>(cacheKey); - // istanbul ignore if - if (cachedResult !== undefined) { - return cachedResult; - } - const promisedRes = this.getTags(endpoint, repository); - memCache.set(cacheKey, promisedRes); - return promisedRes; - } - public async getChangeLogJSON( config: BranchUpgradeConfig ): Promise { @@ -199,7 +183,7 @@ export abstract class ChangeLogSource { apiBaseUrl: string, repository: string ): Promise { - const tags = await this.getCachedTags(apiBaseUrl, repository); + const tags = await this.getTags(apiBaseUrl, repository); const tagName = this.findTagOfRelease( version, From 805fb180e52756d4cc4dd6f0b260b27e9c2a7115 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 10:36:56 -0400 Subject: [PATCH 43/71] refactor: use getPkgReleases --- .../update/pr/changelog/bitbucket/index.ts | 31 --------------- .../update/pr/changelog/github/index.ts | 39 +------------------ .../update/pr/changelog/gitlab/index.ts | 36 ----------------- .../update/pr/changelog/source-bitbucket.ts | 13 +------ .../update/pr/changelog/source-github.ts | 13 +------ .../update/pr/changelog/source-gitlab.ts | 13 +------ .../repository/update/pr/changelog/source.ts | 29 ++++++++++++-- 7 files changed, 29 insertions(+), 145 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index e85bfdce90c03e..610161f1c48c65 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -1,7 +1,6 @@ import is from '@sindresorhus/is'; import changelogFilenameRegex from 'changelog-filename-regex'; import { logger } from '../../../../../../logger'; -import { BitbucketTagsDatasource } from '../../../../../../modules/datasource/bitbucket-tags'; import type { PagedResult, SourceResults, @@ -17,7 +16,6 @@ import type { export const id = 'bitbucket-changelog'; const bitbucketHttp = new BitbucketHttp(id); -const bitbucketTags = new BitbucketTagsDatasource(); export async function getReleaseNotesMd( repository: string, @@ -70,35 +68,6 @@ export async function getReleaseNotesMd( return { changelogFile: changelogFile.path, changelogMd }; } -export async function getTags( - endpoint: string, - repository: string -): Promise { - logger.trace('bitbucket.getTags()'); - try { - const tags = ( - await bitbucketTags.getReleases({ - packageName: repository, - }) - )?.releases; - - if (is.nullOrUndefined(tags) || is.emptyArray(tags)) { - logger.debug(`No Bitbucket tags found for repository:${repository}`); - - return []; - } - - return tags.map(({ version }) => version); - } catch (err) { - logger.debug( - { sourceRepo: repository, err }, - 'Failed to fetch Bitbucket tags' - ); - - return []; - } -} - export function getReleaseList( project: ChangeLogProject, _release: ChangeLogRelease diff --git a/lib/workers/repository/update/pr/changelog/github/index.ts b/lib/workers/repository/update/pr/changelog/github/index.ts index c989b2fa0b988f..2575c8c12a718e 100644 --- a/lib/workers/repository/update/pr/changelog/github/index.ts +++ b/lib/workers/repository/update/pr/changelog/github/index.ts @@ -5,10 +5,7 @@ import type { GithubGitTree, GithubGitTreeNode, } from '../../../../../../types/platform/github'; -import { - queryReleases, - queryTags, -} from '../../../../../../util/github/graphql'; +import { queryReleases } from '../../../../../../util/github/graphql'; import { GithubHttp } from '../../../../../../util/http/github'; import { fromBase64 } from '../../../../../../util/string'; import { ensureTrailingSlash, joinUrlParts } from '../../../../../../util/url'; @@ -22,40 +19,6 @@ import type { export const id = 'github-changelog'; const http = new GithubHttp(id); -export async function getTags( - endpoint: string, - repository: string -): Promise { - logger.trace('github.getTags()'); - try { - const tags = await queryTags( - { - registryUrl: endpoint, - packageName: repository, - }, - http - ); - - // istanbul ignore if - if (!tags.length) { - logger.debug(`No Github tags found for repository:${repository}`); - } - - return tags.map(({ version }) => version); - } catch (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'); - throw err; - } - return []; - } -} - export async function getReleaseNotesMd( repository: string, apiBaseUrl: string, diff --git a/lib/workers/repository/update/pr/changelog/gitlab/index.ts b/lib/workers/repository/update/pr/changelog/gitlab/index.ts index b192286d472b72..418e12df042f37 100644 --- a/lib/workers/repository/update/pr/changelog/gitlab/index.ts +++ b/lib/workers/repository/update/pr/changelog/gitlab/index.ts @@ -1,7 +1,6 @@ import changelogFilenameRegex from 'changelog-filename-regex'; import { logger } from '../../../../../../logger'; import type { GitlabRelease } from '../../../../../../modules/datasource/gitlab-releases/types'; -import type { GitlabTag } from '../../../../../../modules/datasource/gitlab-tags/types'; import type { GitlabTreeNode } from '../../../../../../types/platform/gitlab'; import { GitlabHttp } from '../../../../../../util/http/gitlab'; import { ensureTrailingSlash } from '../../../../../../util/url'; @@ -15,41 +14,6 @@ import type { export const id = 'gitlab-changelog'; const http = new GitlabHttp(id); -export async function getTags( - endpoint: string, - repository: string -): Promise { - logger.trace('gitlab.getTags()'); - const urlEncodedRepo = encodeURIComponent(repository); - const url = `${ensureTrailingSlash( - endpoint - )}projects/${urlEncodedRepo}/repository/tags?per_page=100`; - try { - const res = await http.getJson(url, { - paginate: true, - }); - - const tags = res.body; - - if (!tags.length) { - logger.debug(`No Gitlab tags found for ${repository}`); - } - - return tags.map((tag) => tag.name).filter(Boolean); - } catch (err) { - 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'); - throw err; - } - return []; - } -} - export async function getReleaseNotesMd( repository: string, apiBaseUrl: string, diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 2bbf254448ad32..d3074a6f949047 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -1,11 +1,9 @@ import URL from 'node:url'; -import { cache } from '../../../../../util/cache/package/decorator'; -import { getTags } from './bitbucket'; import { ChangeLogSource } from './source'; export class BitbucketChangeLogSource extends ChangeLogSource { constructor() { - super('bitbucket'); + super('bitbucket', 'bitbucket-tags'); } getCompareURL( @@ -23,13 +21,4 @@ export class BitbucketChangeLogSource extends ChangeLogSource { const host = parsedUrl.host!; return `${protocol}//api.${host}/`; } - - @cache({ - namespace: `changelog-bitbucket-release`, - key: (endpoint: string, repository: string) => - `getTags-${endpoint}-${repository}`, - }) - getTags(endpoint: string, repository: string): Promise { - return getTags(endpoint, repository); - } } diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index 6ee6ae1a12bf15..cbb794cb9c4d79 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -2,16 +2,14 @@ import URL from 'node:url'; import { GlobalConfig } from '../../../../../config/global'; import { logger } from '../../../../../logger'; import type * as allVersioning from '../../../../../modules/versioning'; -import { cache } from '../../../../../util/cache/package/decorator'; import * as hostRules from '../../../../../util/host-rules'; import { regEx } from '../../../../../util/regex'; import type { BranchUpgradeConfig } from '../../../../types'; -import { getTags } from './github'; import { ChangeLogSource } from './source'; import type { ChangeLogError } from './types'; export class GitHubChangeLogSource extends ChangeLogSource { constructor() { - super('github'); + super('github', 'github-tags'); } getAPIBaseUrl(sourceUrl: string): string { @@ -29,15 +27,6 @@ export class GitHubChangeLogSource extends ChangeLogSource { return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; } - @cache({ - namespace: `changelog-github-release`, - key: (endpoint: string, repository: string) => - `getTags-${endpoint}-${repository}`, - }) - getTags(endpoint: string, repository: string): Promise { - return getTags(endpoint, repository); - } - protected override shouldSkipSource(sourceUrl: string): boolean { if (sourceUrl === 'https://github.com/DefinitelyTyped/DefinitelyTyped') { logger.trace('No release notes for @types'); diff --git a/lib/workers/repository/update/pr/changelog/source-gitlab.ts b/lib/workers/repository/update/pr/changelog/source-gitlab.ts index 804fec17f9319f..3143c1489512ee 100644 --- a/lib/workers/repository/update/pr/changelog/source-gitlab.ts +++ b/lib/workers/repository/update/pr/changelog/source-gitlab.ts @@ -1,10 +1,8 @@ -import { cache } from '../../../../../util/cache/package/decorator'; -import { getTags } from './gitlab'; import { ChangeLogSource } from './source'; export class GitLabChangeLogSource extends ChangeLogSource { constructor() { - super('gitlab'); + super('gitlab', 'gitlab-tags'); } getAPIBaseUrl(sourceUrl: string): string { @@ -19,13 +17,4 @@ export class GitLabChangeLogSource extends ChangeLogSource { ): string { return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; } - - @cache({ - namespace: `changelog-gitlab-release`, - key: (endpoint: string, repository: string) => - `getTags-${endpoint}-${repository}`, - }) - getTags(endpoint: string, repository: string): Promise { - return getTags(endpoint, repository); - } } diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index df5e50221462b5..601b428d67e655 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -1,6 +1,7 @@ import URL from 'node:url'; import is from '@sindresorhus/is'; import { logger } from '../../../../../logger'; +import { getPkgReleases } from '../../../../../modules/datasource'; import type { Release } from '../../../../../modules/datasource/types'; import * as allVersioning from '../../../../../modules/versioning'; import * as packageCache from '../../../../../util/cache/package'; @@ -17,11 +18,16 @@ import type { } from './types'; export abstract class ChangeLogSource { - private platform: 'bitbucket' | 'github' | 'gitlab'; + private platform; + private tagsDatasource; private cacheNamespace: string; - constructor(platform: 'bitbucket' | 'github' | 'gitlab') { + constructor( + platform: 'bitbucket' | 'github' | 'gitlab', + tagsDatasource: 'bitbucket-tags' | 'github-tags' | 'gitlab-tags' + ) { this.platform = platform; + this.tagsDatasource = tagsDatasource; this.cacheNamespace = `changelog-${platform}-release`; } @@ -34,7 +40,22 @@ export abstract class ChangeLogSource { abstract getAPIBaseUrl(sourceUrl: string): string; - abstract getTags(endpoint: string, repository: string): Promise; + async getTags(repository: string): Promise { + const releases = await getPkgReleases({ + datasource: this.tagsDatasource, + packageName: repository, + }); + + const tags = releases?.releases; + + if (is.nullOrUndefined(tags) || is.emptyArray(tags)) { + logger.debug(`No Bitbucket tags found for repository:${repository}`); + + return []; + } + + return tags.map(({ version }) => version); + } public async getChangeLogJSON( config: BranchUpgradeConfig @@ -183,7 +204,7 @@ export abstract class ChangeLogSource { apiBaseUrl: string, repository: string ): Promise { - const tags = await this.getTags(apiBaseUrl, repository); + const tags = await this.getTags(repository); const tagName = this.findTagOfRelease( version, From a239f4ef0dd12cfafcc96af4f802b6949579c7ed Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 10:49:00 -0400 Subject: [PATCH 44/71] revert: github queryTags returns richer data than getPkgReleases --- .../update/pr/changelog/github/index.ts | 39 ++++++++++++++++++- .../update/pr/changelog/source-github.ts | 11 ++++++ .../repository/update/pr/changelog/source.ts | 4 +- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/github/index.ts b/lib/workers/repository/update/pr/changelog/github/index.ts index 2575c8c12a718e..c989b2fa0b988f 100644 --- a/lib/workers/repository/update/pr/changelog/github/index.ts +++ b/lib/workers/repository/update/pr/changelog/github/index.ts @@ -5,7 +5,10 @@ import type { GithubGitTree, GithubGitTreeNode, } from '../../../../../../types/platform/github'; -import { queryReleases } from '../../../../../../util/github/graphql'; +import { + queryReleases, + queryTags, +} from '../../../../../../util/github/graphql'; import { GithubHttp } from '../../../../../../util/http/github'; import { fromBase64 } from '../../../../../../util/string'; import { ensureTrailingSlash, joinUrlParts } from '../../../../../../util/url'; @@ -19,6 +22,40 @@ import type { export const id = 'github-changelog'; const http = new GithubHttp(id); +export async function getTags( + endpoint: string, + repository: string +): Promise { + logger.trace('github.getTags()'); + try { + const tags = await queryTags( + { + registryUrl: endpoint, + packageName: repository, + }, + http + ); + + // istanbul ignore if + if (!tags.length) { + logger.debug(`No Github tags found for repository:${repository}`); + } + + return tags.map(({ version }) => version); + } catch (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'); + throw err; + } + return []; + } +} + export async function getReleaseNotesMd( repository: string, apiBaseUrl: string, diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index cbb794cb9c4d79..8fb0653d038022 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -2,9 +2,11 @@ import URL from 'node:url'; import { GlobalConfig } from '../../../../../config/global'; import { logger } from '../../../../../logger'; import type * as allVersioning from '../../../../../modules/versioning'; +import { cache } from '../../../../../util/cache/package/decorator'; import * as hostRules from '../../../../../util/host-rules'; import { regEx } from '../../../../../util/regex'; import type { BranchUpgradeConfig } from '../../../../types'; +import { getTags } from './github'; import { ChangeLogSource } from './source'; import type { ChangeLogError } from './types'; export class GitHubChangeLogSource extends ChangeLogSource { @@ -27,6 +29,15 @@ export class GitHubChangeLogSource extends ChangeLogSource { return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; } + @cache({ + namespace: `changelog-github-release`, + key: (endpoint: string, repository: string) => + `getTags-${endpoint}-${repository}`, + }) + override getTags(endpoint: string, repository: string): Promise { + return getTags(endpoint, repository); + } + protected override shouldSkipSource(sourceUrl: string): boolean { if (sourceUrl === 'https://github.com/DefinitelyTyped/DefinitelyTyped') { logger.trace('No release notes for @types'); diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index 601b428d67e655..5745787e3c38f6 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -40,7 +40,7 @@ export abstract class ChangeLogSource { abstract getAPIBaseUrl(sourceUrl: string): string; - async getTags(repository: string): Promise { + async getTags(endpoint: string, repository: string): Promise { const releases = await getPkgReleases({ datasource: this.tagsDatasource, packageName: repository, @@ -204,7 +204,7 @@ export abstract class ChangeLogSource { apiBaseUrl: string, repository: string ): Promise { - const tags = await this.getTags(repository); + const tags = await this.getTags(apiBaseUrl, repository); const tagName = this.findTagOfRelease( version, From 25e0a9b5888553308ac1cd84d0880692d15d325c Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 17:50:52 -0400 Subject: [PATCH 45/71] refactor --- .../update/pr/changelog/github.spec.ts | 17 ++++--- .../update/pr/changelog/github/index.ts | 39 +--------------- .../update/pr/changelog/source-bitbucket.ts | 5 +- .../update/pr/changelog/source-github.ts | 32 +++++-------- .../update/pr/changelog/source-gitlab.ts | 5 +- .../repository/update/pr/changelog/source.ts | 46 ++++++++++--------- 6 files changed, 53 insertions(+), 91 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/github.spec.ts b/lib/workers/repository/update/pr/changelog/github.spec.ts index ee6fe19cee6109..1d80109aa2b911 100644 --- a/lib/workers/repository/update/pr/changelog/github.spec.ts +++ b/lib/workers/repository/update/pr/changelog/github.spec.ts @@ -1,9 +1,8 @@ import * as httpMock from '../../../../../../test/http-mock'; import { partial } from '../../../../../../test/util'; import { GlobalConfig } from '../../../../../config/global'; +import { GithubTagsDatasource } from '../../../../../modules/datasource/github-tags'; import * as semverVersioning from '../../../../../modules/versioning/semver'; -import * as githubGraphql from '../../../../../util/github/graphql'; -import type { GithubTagItem } from '../../../../../util/github/graphql/types'; import * as hostRules from '../../../../../util/host-rules'; import type { BranchUpgradeConfig } from '../../../../types'; import { getChangeLogJSON } from '.'; @@ -359,9 +358,13 @@ describe('workers/repository/update/pr/changelog/github', () => { }); it('works with same version releases but different prefix', async () => { - const githubTagsMock = jest.spyOn(githubGraphql, 'queryTags'); - githubTagsMock.mockResolvedValue( - partial([ + const githubGetTags = jest.spyOn( + GithubTagsDatasource.prototype, + 'getReleases' + ); + // const githubTagsMock = jest.spyOn(githubGraphql, 'queryTags'); + githubGetTags.mockResolvedValue({ + releases: [ { version: 'v1.0.1' }, { version: '1.0.1' }, { version: 'correctPrefix/target@1.0.1' }, @@ -370,8 +373,8 @@ describe('workers/repository/update/pr/changelog/github', () => { { version: '1.0.2' }, { version: 'correctPrefix/target-1.0.2' }, { version: 'wrongPrefix/target@1.0.2' }, - ]) - ); + ], + }); const upgradeData = partial({ manager: 'some-manager', diff --git a/lib/workers/repository/update/pr/changelog/github/index.ts b/lib/workers/repository/update/pr/changelog/github/index.ts index c989b2fa0b988f..2575c8c12a718e 100644 --- a/lib/workers/repository/update/pr/changelog/github/index.ts +++ b/lib/workers/repository/update/pr/changelog/github/index.ts @@ -5,10 +5,7 @@ import type { GithubGitTree, GithubGitTreeNode, } from '../../../../../../types/platform/github'; -import { - queryReleases, - queryTags, -} from '../../../../../../util/github/graphql'; +import { queryReleases } from '../../../../../../util/github/graphql'; import { GithubHttp } from '../../../../../../util/http/github'; import { fromBase64 } from '../../../../../../util/string'; import { ensureTrailingSlash, joinUrlParts } from '../../../../../../util/url'; @@ -22,40 +19,6 @@ import type { export const id = 'github-changelog'; const http = new GithubHttp(id); -export async function getTags( - endpoint: string, - repository: string -): Promise { - logger.trace('github.getTags()'); - try { - const tags = await queryTags( - { - registryUrl: endpoint, - packageName: repository, - }, - http - ); - - // istanbul ignore if - if (!tags.length) { - logger.debug(`No Github tags found for repository:${repository}`); - } - - return tags.map(({ version }) => version); - } catch (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'); - throw err; - } - return []; - } -} - export async function getReleaseNotesMd( repository: string, apiBaseUrl: string, diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index d3074a6f949047..58003cce5f47f9 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -1,4 +1,5 @@ import URL from 'node:url'; +import type { BranchUpgradeConfig } from '../../../../types'; import { ChangeLogSource } from './source'; export class BitbucketChangeLogSource extends ChangeLogSource { @@ -15,8 +16,8 @@ export class BitbucketChangeLogSource extends ChangeLogSource { return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; } - getAPIBaseUrl(sourceUrl: string): string { - const parsedUrl = URL.parse(sourceUrl); + getAPIBaseUrl(config: BranchUpgradeConfig): string { + const parsedUrl = URL.parse(config.sourceUrl!); const protocol = parsedUrl.protocol!; const host = parsedUrl.host!; return `${protocol}//api.${host}/`; diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index 8fb0653d038022..12dfca6138d85a 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -2,11 +2,9 @@ import URL from 'node:url'; import { GlobalConfig } from '../../../../../config/global'; import { logger } from '../../../../../logger'; import type * as allVersioning from '../../../../../modules/versioning'; -import { cache } from '../../../../../util/cache/package/decorator'; import * as hostRules from '../../../../../util/host-rules'; import { regEx } from '../../../../../util/regex'; import type { BranchUpgradeConfig } from '../../../../types'; -import { getTags } from './github'; import { ChangeLogSource } from './source'; import type { ChangeLogError } from './types'; export class GitHubChangeLogSource extends ChangeLogSource { @@ -14,10 +12,10 @@ export class GitHubChangeLogSource extends ChangeLogSource { super('github', 'github-tags'); } - getAPIBaseUrl(sourceUrl: string): string { - return sourceUrl.startsWith('https://github.com/') + getAPIBaseUrl(config: BranchUpgradeConfig): string { + return config.sourceUrl!.startsWith('https://github.com/') ? 'https://api.github.com/' - : this.getBaseUrl(sourceUrl) + 'api/v3/'; + : this.getBaseUrl(config) + 'api/v3/'; } getCompareURL( @@ -29,17 +27,10 @@ export class GitHubChangeLogSource extends ChangeLogSource { return `${baseUrl}${repository}/compare/${prevHead}...${nextHead}`; } - @cache({ - namespace: `changelog-github-release`, - key: (endpoint: string, repository: string) => - `getTags-${endpoint}-${repository}`, - }) - override getTags(endpoint: string, repository: string): Promise { - return getTags(endpoint, repository); - } - - protected override shouldSkipSource(sourceUrl: string): boolean { - if (sourceUrl === 'https://github.com/DefinitelyTyped/DefinitelyTyped') { + protected override shouldSkipPackage(config: BranchUpgradeConfig): boolean { + if ( + config.sourceUrl === 'https://github.com/DefinitelyTyped/DefinitelyTyped' + ) { logger.trace('No release notes for @types'); return true; } @@ -71,10 +62,11 @@ export class GitHubChangeLogSource extends ChangeLogSource { return tagName; } - protected override hasValidToken( - sourceUrl: string, - config: BranchUpgradeConfig - ): { isValid: boolean; error?: ChangeLogError } { + protected override hasValidToken(config: BranchUpgradeConfig): { + isValid: boolean; + error?: ChangeLogError; + } { + const sourceUrl = config.sourceUrl!; const parsedUrl = URL.parse(sourceUrl); const host = parsedUrl.host!; const manager = config.manager; diff --git a/lib/workers/repository/update/pr/changelog/source-gitlab.ts b/lib/workers/repository/update/pr/changelog/source-gitlab.ts index 3143c1489512ee..4279dc1dfd6574 100644 --- a/lib/workers/repository/update/pr/changelog/source-gitlab.ts +++ b/lib/workers/repository/update/pr/changelog/source-gitlab.ts @@ -1,3 +1,4 @@ +import type { BranchUpgradeConfig } from '../../../../types'; import { ChangeLogSource } from './source'; export class GitLabChangeLogSource extends ChangeLogSource { @@ -5,8 +6,8 @@ export class GitLabChangeLogSource extends ChangeLogSource { super('gitlab', 'gitlab-tags'); } - getAPIBaseUrl(sourceUrl: string): string { - return this.getBaseUrl(sourceUrl) + 'api/v4/'; + getAPIBaseUrl(config: BranchUpgradeConfig): string { + return this.getBaseUrl(config) + 'api/v4/'; } getCompareURL( diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index 5745787e3c38f6..20444cd7f34f95 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -19,15 +19,15 @@ import type { export abstract class ChangeLogSource { private platform; - private tagsDatasource; + private datasource; private cacheNamespace: string; constructor( platform: 'bitbucket' | 'github' | 'gitlab', - tagsDatasource: 'bitbucket-tags' | 'github-tags' | 'gitlab-tags' + datasource: 'bitbucket-tags' | 'github-tags' | 'gitlab-tags' ) { this.platform = platform; - this.tagsDatasource = tagsDatasource; + this.datasource = datasource; this.cacheNamespace = `changelog-${platform}-release`; } @@ -38,18 +38,20 @@ export abstract class ChangeLogSource { nextHead: string ): string; - abstract getAPIBaseUrl(sourceUrl: string): string; + abstract getAPIBaseUrl(config: BranchUpgradeConfig): string; - async getTags(endpoint: string, repository: string): Promise { + async getTags(repository: string): Promise { const releases = await getPkgReleases({ - datasource: this.tagsDatasource, + datasource: this.datasource, packageName: repository, }); const tags = releases?.releases; if (is.nullOrUndefined(tags) || is.emptyArray(tags)) { - logger.debug(`No Bitbucket tags found for repository:${repository}`); + logger.debug( + `No ${this.datasource} tags found for repository:${repository}` + ); return []; } @@ -70,15 +72,15 @@ export abstract class ChangeLogSource { const sourceDirectory = config.sourceDirectory!; const version = allVersioning.get(versioning); - if (this.shouldSkipSource(sourceUrl)) { + if (this.shouldSkipPackage(config)) { return null; } - const baseUrl = this.getBaseUrl(sourceUrl); - const apiBaseUrl = this.getAPIBaseUrl(sourceUrl); - const repository = this.getRepositoryFromUrl(sourceUrl); + const baseUrl = this.getBaseUrl(config); + const apiBaseUrl = this.getAPIBaseUrl(config); + const repository = this.getRepositoryFromUrl(config); - const tokenResponse = this.hasValidToken(sourceUrl, config); + const tokenResponse = this.hasValidToken(config); if (!tokenResponse.isValid) { if (tokenResponse.error) { return { @@ -204,7 +206,7 @@ export abstract class ChangeLogSource { apiBaseUrl: string, repository: string ): Promise { - const tags = await this.getTags(apiBaseUrl, repository); + const tags = await this.getTags(repository); const tagName = this.findTagOfRelease( version, @@ -230,27 +232,27 @@ export abstract class ChangeLogSource { return `${slugifyUrl(sourceUrl)}:${packageName}:${prev}:${next}`; } - protected getBaseUrl(sourceUrl: string): string { - const parsedUrl = URL.parse(sourceUrl); + protected getBaseUrl(config: BranchUpgradeConfig): string { + const parsedUrl = URL.parse(config.sourceUrl!); const protocol = parsedUrl.protocol!; const host = parsedUrl.host!; return `${protocol}//${host}/`; } - private getRepositoryFromUrl(sourceUrl: string): string { - const parsedUrl = URL.parse(sourceUrl); + private getRepositoryFromUrl(config: BranchUpgradeConfig): string { + const parsedUrl = URL.parse(config.sourceUrl!); const pathname = parsedUrl.pathname!; return trimSlashes(pathname).replace(regEx(/\.git$/), ''); } - protected hasValidToken( - sourceUrl: string, - config: BranchUpgradeConfig - ): { isValid: boolean; error?: ChangeLogError } { + protected hasValidToken(config: BranchUpgradeConfig): { + isValid: boolean; + error?: ChangeLogError; + } { return { isValid: true }; } - protected shouldSkipSource(sourceUrl: string): boolean { + protected shouldSkipPackage(config: BranchUpgradeConfig): boolean { return false; } } From 3de7e5df87ecc45ef3e622eb9dc8d30be709dfe2 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sat, 24 Jun 2023 18:22:06 -0400 Subject: [PATCH 46/71] fix: change order of tags --- lib/workers/repository/update/pr/changelog/source-bitbucket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index 58003cce5f47f9..be928bbb54db66 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -13,7 +13,7 @@ export class BitbucketChangeLogSource extends ChangeLogSource { prevHead: string, nextHead: string ): string { - return `${baseUrl}${repository}/branches/compare/${prevHead}%0D${nextHead}`; + return `${baseUrl}${repository}/branches/compare/${nextHead}%0D${prevHead}`; } getAPIBaseUrl(config: BranchUpgradeConfig): string { From b056d8fbff805b61f55db2ad8fe98a4039b12307 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 25 Jun 2023 06:30:30 -0400 Subject: [PATCH 47/71] fix: use regex versioning to fetch tags which may have package prefix --- .../update/pr/changelog/github.spec.ts | 17 ++++---- .../update/pr/changelog/source-github.ts | 26 ------------- .../repository/update/pr/changelog/source.ts | 39 ++++++++++++------- 3 files changed, 33 insertions(+), 49 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/github.spec.ts b/lib/workers/repository/update/pr/changelog/github.spec.ts index 1d80109aa2b911..ee6fe19cee6109 100644 --- a/lib/workers/repository/update/pr/changelog/github.spec.ts +++ b/lib/workers/repository/update/pr/changelog/github.spec.ts @@ -1,8 +1,9 @@ import * as httpMock from '../../../../../../test/http-mock'; import { partial } from '../../../../../../test/util'; import { GlobalConfig } from '../../../../../config/global'; -import { GithubTagsDatasource } from '../../../../../modules/datasource/github-tags'; import * as semverVersioning from '../../../../../modules/versioning/semver'; +import * as githubGraphql from '../../../../../util/github/graphql'; +import type { GithubTagItem } from '../../../../../util/github/graphql/types'; import * as hostRules from '../../../../../util/host-rules'; import type { BranchUpgradeConfig } from '../../../../types'; import { getChangeLogJSON } from '.'; @@ -358,13 +359,9 @@ describe('workers/repository/update/pr/changelog/github', () => { }); it('works with same version releases but different prefix', async () => { - const githubGetTags = jest.spyOn( - GithubTagsDatasource.prototype, - 'getReleases' - ); - // const githubTagsMock = jest.spyOn(githubGraphql, 'queryTags'); - githubGetTags.mockResolvedValue({ - releases: [ + const githubTagsMock = jest.spyOn(githubGraphql, 'queryTags'); + githubTagsMock.mockResolvedValue( + partial([ { version: 'v1.0.1' }, { version: '1.0.1' }, { version: 'correctPrefix/target@1.0.1' }, @@ -373,8 +370,8 @@ describe('workers/repository/update/pr/changelog/github', () => { { version: '1.0.2' }, { version: 'correctPrefix/target-1.0.2' }, { version: 'wrongPrefix/target@1.0.2' }, - ], - }); + ]) + ); const upgradeData = partial({ manager: 'some-manager', diff --git a/lib/workers/repository/update/pr/changelog/source-github.ts b/lib/workers/repository/update/pr/changelog/source-github.ts index 12dfca6138d85a..0fb7bfc0fe9d9f 100644 --- a/lib/workers/repository/update/pr/changelog/source-github.ts +++ b/lib/workers/repository/update/pr/changelog/source-github.ts @@ -1,9 +1,7 @@ import URL from 'node:url'; import { GlobalConfig } from '../../../../../config/global'; import { logger } from '../../../../../logger'; -import type * as allVersioning from '../../../../../modules/versioning'; import * as hostRules from '../../../../../util/host-rules'; -import { regEx } from '../../../../../util/regex'; import type { BranchUpgradeConfig } from '../../../../types'; import { ChangeLogSource } from './source'; import type { ChangeLogError } from './types'; @@ -38,30 +36,6 @@ export class GitHubChangeLogSource extends ChangeLogSource { return false; } - protected override findTagOfRelease( - version: allVersioning.VersioningApi, - packageName: string, - depNewVersion: string, - tags: string[] - ): string | undefined { - const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); - const exactReleaseRegex = regEx(`${packageName}[@\\-_]v?${depNewVersion}`); - const exactTagsList = tags.filter((tag) => { - return exactReleaseRegex.test(tag); - }); - let tagName: string | undefined; - if (exactTagsList.length) { - tagName = exactTagsList - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); - } else { - tagName = tags - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); - } - return tagName; - } - protected override hasValidToken(config: BranchUpgradeConfig): { isValid: boolean; error?: ChangeLogError; diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index 20444cd7f34f95..bb53970a38dc12 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -40,17 +40,19 @@ export abstract class ChangeLogSource { abstract getAPIBaseUrl(config: BranchUpgradeConfig): string; - async getTags(repository: string): Promise { - const releases = await getPkgReleases({ - datasource: this.datasource, - packageName: repository, - }); - - const tags = releases?.releases; + async getAllTags(endpoint: string, repository: string): Promise { + const tags = ( + await getPkgReleases({ + datasource: this.datasource, + packageName: repository, + versioning: + 'regex:(?\\d+)(\\.(?\\d+))?(\\.(?\\d+))?', + }) + )?.releases; if (is.nullOrUndefined(tags) || is.emptyArray(tags)) { logger.debug( - `No ${this.datasource} tags found for repository:${repository}` + `No ${this.datasource} tags found for repository: ${repository}` ); return []; @@ -186,16 +188,27 @@ export abstract class ChangeLogSource { return res; } - protected findTagOfRelease( + private findTagOfRelease( version: allVersioning.VersioningApi, packageName: string, depNewVersion: string, tags: string[] ): string | undefined { const regex = regEx(`(?:${packageName}|release)[@-]`, undefined, false); - const tagName = tags - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); + const exactReleaseRegex = regEx(`${packageName}[@\\-_]v?${depNewVersion}`); + const exactTagsList = tags.filter((tag) => { + return exactReleaseRegex.test(tag); + }); + let tagName: string | undefined; + if (exactTagsList.length) { + tagName = exactTagsList + .filter((tag) => version.isVersion(tag.replace(regex, ''))) + .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); + } else { + tagName = tags + .filter((tag) => version.isVersion(tag.replace(regex, ''))) + .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); + } return tagName; } @@ -206,7 +219,7 @@ export abstract class ChangeLogSource { apiBaseUrl: string, repository: string ): Promise { - const tags = await this.getTags(repository); + const tags = await this.getAllTags(apiBaseUrl, repository); const tagName = this.findTagOfRelease( version, From 99ef3f9d6b90d4a933e2cb61e87f63a672c89054 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 25 Jun 2023 06:34:28 -0400 Subject: [PATCH 48/71] reorder functions for consistency --- .../update/pr/changelog/source-bitbucket.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts index be928bbb54db66..17ef5457c8d16a 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/source-bitbucket.ts @@ -7,6 +7,13 @@ export class BitbucketChangeLogSource extends ChangeLogSource { super('bitbucket', 'bitbucket-tags'); } + getAPIBaseUrl(config: BranchUpgradeConfig): string { + const parsedUrl = URL.parse(config.sourceUrl!); + const protocol = parsedUrl.protocol!; + const host = parsedUrl.host!; + return `${protocol}//api.${host}/`; + } + getCompareURL( baseUrl: string, repository: string, @@ -15,11 +22,4 @@ export class BitbucketChangeLogSource extends ChangeLogSource { ): string { return `${baseUrl}${repository}/branches/compare/${nextHead}%0D${prevHead}`; } - - getAPIBaseUrl(config: BranchUpgradeConfig): string { - const parsedUrl = URL.parse(config.sourceUrl!); - const protocol = parsedUrl.protocol!; - const host = parsedUrl.host!; - return `${protocol}//api.${host}/`; - } } From 9b414743600515421faa2266eb173971f49293c0 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 25 Jun 2023 07:41:58 -0400 Subject: [PATCH 49/71] tests: coverage --- .../__snapshots__/release-notes.spec.ts.snap | 645 ++++++++++++++++++ .../update/pr/changelog/bitbucket.spec.ts | 248 +------ .../update/pr/changelog/github.spec.ts | 10 + .../update/pr/changelog/index.spec.ts | 9 + .../update/pr/changelog/release-notes.spec.ts | 91 +++ 5 files changed, 786 insertions(+), 217 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap b/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap index 3777869d2b0810..0e78abf6227591 100644 --- a/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap +++ b/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap @@ -1,5 +1,437 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`workers/repository/update/pr/changelog/release-notes ReleaseNotes Correctness handles gitlab sourceDirectory 1`] = ` +{ + "body": "- add new auth, fix accept header and base path in mock + +Closes ADAPT-207 + +See merge request itentialopensource/adapter-utils!177 + +*** +", + "notesSourceUrl": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/packages/foo/CHANGELOG.md", + "url": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/packages/foo/CHANGELOG.md#4330-05-15-2020", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes ReleaseNotes Correctness parses adapter-utils 4.33.0 1`] = ` +{ + "body": "- add new auth, fix accept header and base path in mock + +Closes ADAPT-207 + +See merge request itentialopensource/adapter-utils!177 + +*** +", + "notesSourceUrl": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/CHANGELOG.md", + "url": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/CHANGELOG.md#4330-05-15-2020", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes ReleaseNotes Correctness parses yargs 15.2.0 1`] = ` +{ + "body": "##### âš  BREAKING CHANGES + +- **deps:** yargs-parser@17.0.0 no longer implicitly creates arrays out of boolean + arguments when duplicates are provided + +##### Features + +- **completion:** takes negated flags into account when boolean-negation is set ([#1509](https://www.github.com/yargs/yargs/issues/1509)) ([7293ad5](https://www.github.com/yargs/yargs/commit/7293ad50d20ea0fb7dd1ac9b925e90e1bd95dea8)) +- **deps:** pull in yargs-parser@17.0.0 ([#1553](https://www.github.com/yargs/yargs/issues/1553)) ([b9409da](https://www.github.com/yargs/yargs/commit/b9409da199ebca515a848489c206b807fab2e65d)) +- deprecateOption ([#1559](https://www.github.com/yargs/yargs/issues/1559)) ([8aae333](https://www.github.com/yargs/yargs/commit/8aae3332251d09fa136db17ef4a40d83fa052bc4)) +- display appropriate $0 for electron apps ([#1536](https://www.github.com/yargs/yargs/issues/1536)) ([d0e4379](https://www.github.com/yargs/yargs/commit/d0e437912917d6a66bb5128992fa2f566a5f830b)) +- introduces strictCommands() subset of strict mode ([#1540](https://www.github.com/yargs/yargs/issues/1540)) ([1d4cca3](https://www.github.com/yargs/yargs/commit/1d4cca395a98b395e6318f0505fc73bef8b01350)) +- **deps:** yargs-parser with 'greedy-array' configuration ([#1569](https://www.github.com/yargs/yargs/issues/1569)) ([a03a320](https://www.github.com/yargs/yargs/commit/a03a320dbf5c0ce33d829a857fc04a651c0bb53e)) + +##### Bug Fixes + +- help always displayed for the first command parsed having an async handler ([#1535](https://www.github.com/yargs/yargs/issues/1535)) ([d585b30](https://www.github.com/yargs/yargs/commit/d585b303a43746201b05c9c9fda94a444634df33)) +- **deps:** fix enumeration for normalized path arguments ([#1567](https://www.github.com/yargs/yargs/issues/1567)) ([0b5b1b0](https://www.github.com/yargs/yargs/commit/0b5b1b0e5f4f9baf393c48e9cc2bc85c1b67a47a)) +- **locales:** only translate default option group name ([acc16de](https://www.github.com/yargs/yargs/commit/acc16de6b846ea7332db753646a9cec76b589162)) +- **locales:** remove extra space in French for 'default' ([#1564](https://www.github.com/yargs/yargs/issues/1564)) ([ecfc2c4](https://www.github.com/yargs/yargs/commit/ecfc2c474575c6cdbc6d273c94c13181bd1dbaa6)) +- **translations:** add French translation for unknown command ([#1563](https://www.github.com/yargs/yargs/issues/1563)) ([18b0b75](https://www.github.com/yargs/yargs/commit/18b0b752424bf560271e670ff95a0f90c8386787)) +- **translations:** fix pluralization in error messages. ([#1557](https://www.github.com/yargs/yargs/issues/1557)) ([94fa38c](https://www.github.com/yargs/yargs/commit/94fa38cbab8d86943e87bf41d368ed56dffa6835)) +- **yargs:** correct support of bundled electron apps ([#1554](https://www.github.com/yargs/yargs/issues/1554)) ([a0b61ac](https://www.github.com/yargs/yargs/commit/a0b61ac21e2b554aa73dbf1a66d4a7af94047c2f)) +", + "notesSourceUrl": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md", + "url": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md#1520-httpswwwgithubcomyargsyargscomparev1510v1520-2020-03-01", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes ReleaseNotes Correctness parses yargs 15.3.0 1`] = ` +{ + "body": "##### Features + +- **yargs-parser:** introduce single-digit boolean aliases ([#1576](https://www.github.com/yargs/yargs/issues/1576)) ([3af7f04](https://www.github.com/yargs/yargs/commit/3af7f04cdbfcbd4b3f432aca5144d43f21958c39)) +- add usage for single-digit boolean aliases ([#1580](https://www.github.com/yargs/yargs/issues/1580)) ([6014e39](https://www.github.com/yargs/yargs/commit/6014e39bca3a1e8445aa0fb2a435f6181e344c45)) + +##### Bug Fixes + +- address ambiguity between nargs of 1 and requiresArg ([#1572](https://www.github.com/yargs/yargs/issues/1572)) ([a5edc32](https://www.github.com/yargs/yargs/commit/a5edc328ecb3f90d1ba09cfe70a0040f68adf50a)) +", + "notesSourceUrl": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md", + "url": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md#1530-httpswwwgithubcomyargsyargscomparev1520v1530-2020-03-08", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() ReleaseNotes Correctness handles gitlab sourceDirectory 1`] = ` +{ + "body": "- add new auth, fix accept header and base path in mock + +Closes ADAPT-207 + +See merge request itentialopensource/adapter-utils!177 + +*** +", + "notesSourceUrl": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/packages/foo/CHANGELOG.md", + "url": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/packages/foo/CHANGELOG.md#4330-05-15-2020", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() ReleaseNotes Correctness parses adapter-utils 4.33.0 1`] = ` +{ + "body": "- add new auth, fix accept header and base path in mock + +Closes ADAPT-207 + +See merge request itentialopensource/adapter-utils!177 + +*** +", + "notesSourceUrl": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/CHANGELOG.md", + "url": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/CHANGELOG.md#4330-05-15-2020", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() ReleaseNotes Correctness parses yargs 15.2.0 1`] = ` +{ + "body": "##### âš  BREAKING CHANGES + +- **deps:** yargs-parser@17.0.0 no longer implicitly creates arrays out of boolean + arguments when duplicates are provided + +##### Features + +- **completion:** takes negated flags into account when boolean-negation is set ([#1509](https://www.github.com/yargs/yargs/issues/1509)) ([7293ad5](https://www.github.com/yargs/yargs/commit/7293ad50d20ea0fb7dd1ac9b925e90e1bd95dea8)) +- **deps:** pull in yargs-parser@17.0.0 ([#1553](https://www.github.com/yargs/yargs/issues/1553)) ([b9409da](https://www.github.com/yargs/yargs/commit/b9409da199ebca515a848489c206b807fab2e65d)) +- deprecateOption ([#1559](https://www.github.com/yargs/yargs/issues/1559)) ([8aae333](https://www.github.com/yargs/yargs/commit/8aae3332251d09fa136db17ef4a40d83fa052bc4)) +- display appropriate $0 for electron apps ([#1536](https://www.github.com/yargs/yargs/issues/1536)) ([d0e4379](https://www.github.com/yargs/yargs/commit/d0e437912917d6a66bb5128992fa2f566a5f830b)) +- introduces strictCommands() subset of strict mode ([#1540](https://www.github.com/yargs/yargs/issues/1540)) ([1d4cca3](https://www.github.com/yargs/yargs/commit/1d4cca395a98b395e6318f0505fc73bef8b01350)) +- **deps:** yargs-parser with 'greedy-array' configuration ([#1569](https://www.github.com/yargs/yargs/issues/1569)) ([a03a320](https://www.github.com/yargs/yargs/commit/a03a320dbf5c0ce33d829a857fc04a651c0bb53e)) + +##### Bug Fixes + +- help always displayed for the first command parsed having an async handler ([#1535](https://www.github.com/yargs/yargs/issues/1535)) ([d585b30](https://www.github.com/yargs/yargs/commit/d585b303a43746201b05c9c9fda94a444634df33)) +- **deps:** fix enumeration for normalized path arguments ([#1567](https://www.github.com/yargs/yargs/issues/1567)) ([0b5b1b0](https://www.github.com/yargs/yargs/commit/0b5b1b0e5f4f9baf393c48e9cc2bc85c1b67a47a)) +- **locales:** only translate default option group name ([acc16de](https://www.github.com/yargs/yargs/commit/acc16de6b846ea7332db753646a9cec76b589162)) +- **locales:** remove extra space in French for 'default' ([#1564](https://www.github.com/yargs/yargs/issues/1564)) ([ecfc2c4](https://www.github.com/yargs/yargs/commit/ecfc2c474575c6cdbc6d273c94c13181bd1dbaa6)) +- **translations:** add French translation for unknown command ([#1563](https://www.github.com/yargs/yargs/issues/1563)) ([18b0b75](https://www.github.com/yargs/yargs/commit/18b0b752424bf560271e670ff95a0f90c8386787)) +- **translations:** fix pluralization in error messages. ([#1557](https://www.github.com/yargs/yargs/issues/1557)) ([94fa38c](https://www.github.com/yargs/yargs/commit/94fa38cbab8d86943e87bf41d368ed56dffa6835)) +- **yargs:** correct support of bundled electron apps ([#1554](https://www.github.com/yargs/yargs/issues/1554)) ([a0b61ac](https://www.github.com/yargs/yargs/commit/a0b61ac21e2b554aa73dbf1a66d4a7af94047c2f)) +", + "notesSourceUrl": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md", + "url": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md#1520-httpswwwgithubcomyargsyargscomparev1510v1520-2020-03-01", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() ReleaseNotes Correctness parses yargs 15.3.0 1`] = ` +{ + "body": "##### Features + +- **yargs-parser:** introduce single-digit boolean aliases ([#1576](https://www.github.com/yargs/yargs/issues/1576)) ([3af7f04](https://www.github.com/yargs/yargs/commit/3af7f04cdbfcbd4b3f432aca5144d43f21958c39)) +- add usage for single-digit boolean aliases ([#1580](https://www.github.com/yargs/yargs/issues/1580)) ([6014e39](https://www.github.com/yargs/yargs/commit/6014e39bca3a1e8445aa0fb2a435f6181e344c45)) + +##### Bug Fixes + +- address ambiguity between nargs of 1 and requiresArg ([#1572](https://www.github.com/yargs/yargs/issues/1572)) ([a5edc32](https://www.github.com/yargs/yargs/commit/a5edc328ecb3f90d1ba09cfe70a0040f68adf50a)) +", + "notesSourceUrl": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md", + "url": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md#1530-httpswwwgithubcomyargsyargscomparev1520v1530-2020-03-08", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() handles github sourceDirectory 1`] = ` +{ + "body": "- Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370). +- Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368). +", + "notesSourceUrl": "https://github.com/nodeca/js-yaml/blob/HEAD/packages/foo/CHANGELOG.md", + "url": "https://github.com/nodeca/js-yaml/blob/HEAD/packages/foo/CHANGELOG.md#3100--2017-09-10", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses angular.js 1`] = ` +{ + "body": "#### Bug Fixes + +- **input:** add \`drop\` event support for IE + ([5dc076](https://github.com/angular/angular.js/commit/5dc07667de00c5e85fd69c5b7b7fe4fb5fd65a77)) +- **ngMessages:** prevent memory leak from messages that are never attached + ([9d058d](https://github.com/angular/angular.js/commit/9d058de04bb78694b83179e9b97bc40214eca01a), + [#16389](https://github.com/angular/angular.js/issues/16389), + [#16404](https://github.com/angular/angular.js/issues/16404), + [#16406](https://github.com/angular/angular.js/issues/16406)) +- **ngTransclude:** remove terminal: true + ([1d826e](https://github.com/angular/angular.js/commit/1d826e2f1e941d14c3c56d7a0249f5796ba11f85), + [#16411](https://github.com/angular/angular.js/issues/16411), + [#16412](https://github.com/angular/angular.js/issues/16412)) +- **$sanitize:** sanitize \`xml:base\` attributes + ([b9ef65](https://github.com/angular/angular.js/commit/b9ef6585e10477fbbf912a971fe0b390bca692a6)) + +#### New Features + +- **currencyFilter:** trim whitespace around an empty currency symbol + ([367390](https://github.com/angular/angular.js/commit/3673909896efb6ff47546caf7fc61549f193e043), + [#15018](https://github.com/angular/angular.js/issues/15018), + [#15085](https://github.com/angular/angular.js/issues/15085), + [#15105](https://github.com/angular/angular.js/issues/15105)) +", + "notesSourceUrl": "https://github.com/angular/angular.js/blob/HEAD/CHANGELOG.md", + "url": "https://github.com/angular/angular.js/blob/HEAD/CHANGELOG.md#169-fiery-basilisk-2018-02-02", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses gitlab.com/gitlab-org/gitter/webapp 1`] = ` +{ + "body": "- Removing markup from a part of the French translation, +- Fix typo documentation -> documentation, + - Thanks to [@auua](https://gitlab.com/auua) for the contribution +- Fix \`/channel\` slash command name regex to accept hyphenated names, + - Thanks to [@auua](https://gitlab.com/auua) for the contribution +- Add GitLab branding to the left-menu, +- Fix left-menu search state showing all rooms, +- Update Polish translation, + - Thanks to [@biesiad](https://gitlab.com/biesiad) for the contribution +", + "notesSourceUrl": "https://gitlab.com/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md", + "url": "https://gitlab.com/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md#20260---2020-05-18", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses jest 1`] = ` +{ + "body": "##### Fixes + +- \`[jest-resolve]\` Use \`module.builtinModules\` as \`BUILTIN_MODULES\` when it + exists +- \`[jest-worker]\` Remove \`debug\` and \`inspect\` flags from the arguments sent to + the child ([#5068](https://github.com/facebook/jest/pull/5068)) +- \`[jest-config]\` Use all \`--testPathPattern\` and \`\` args in + \`testPathPattern\` ([#5066](https://github.com/facebook/jest/pull/5066)) +- \`[jest-cli]\` Do not support \`--watch\` inside non-version-controlled + environments ([#5060](https://github.com/facebook/jest/pull/5060)) +- \`[jest-config]\` Escape Windows path separator in testPathPattern CLI arguments + ([#5054](https://github.com/facebook/jest/pull/5054) +- \`[jest-jasmine]\` Register sourcemaps as node environment to improve + performance with jsdom ([#5045](https://github.com/facebook/jest/pull/5045)) +- \`[pretty-format]\` Do not call toJSON recursively + ([#5044](https://github.com/facebook/jest/pull/5044)) +- \`[pretty-format]\` Fix errors when identity-obj-proxy mocks CSS Modules + ([#4935](https://github.com/facebook/jest/pull/4935)) +- \`[babel-jest]\` Fix support for namespaced babel version 7 + ([#4918](https://github.com/facebook/jest/pull/4918)) +- \`[expect]\` fix .toThrow for promises + ([#4884](https://github.com/facebook/jest/pull/4884)) +- \`[jest-docblock]\` pragmas should preserve urls + ([#4837](https://github.com/facebook/jest/pull/4629)) +- \`[jest-cli]\` Check if \`npm_lifecycle_script\` calls Jest directly + ([#4629](https://github.com/facebook/jest/pull/4629)) +- \`[jest-cli]\` Fix --showConfig to show all configs + ([#4494](https://github.com/facebook/jest/pull/4494)) +- \`[jest-cli]\` Throw if \`maxWorkers\` doesn't have a value + ([#4591](https://github.com/facebook/jest/pull/4591)) +- \`[jest-cli]\` Use \`fs.realpathSync.native\` if available + ([#5031](https://github.com/facebook/jest/pull/5031)) +- \`[jest-config]\` Fix \`--passWithNoTests\` + ([#4639](https://github.com/facebook/jest/pull/4639)) +- \`[jest-config]\` Support \`rootDir\` tag in testEnvironment + ([#4579](https://github.com/facebook/jest/pull/4579)) +- \`[jest-editor-support]\` Fix \`--showConfig\` to support jest 20 and jest 21 + ([#4575](https://github.com/facebook/jest/pull/4575)) +- \`[jest-editor-support]\` Fix editor support test for node 4 + ([#4640](https://github.com/facebook/jest/pull/4640)) +- \`[jest-mock]\` Support mocking constructor in \`mockImplementationOnce\` + ([#4599](https://github.com/facebook/jest/pull/4599)) +- \`[jest-runtime]\` Fix manual user mocks not working with custom resolver + ([#4489](https://github.com/facebook/jest/pull/4489)) +- \`[jest-util]\` Fix \`runOnlyPendingTimers\` for \`setTimeout\` inside + \`setImmediate\` ([#4608](https://github.com/facebook/jest/pull/4608)) +- \`[jest-message-util]\` Always remove node internals from stacktraces + ([#4695](https://github.com/facebook/jest/pull/4695)) +- \`[jest-resolve]\` changes method of determining builtin modules to include + missing builtins ([#4740](https://github.com/facebook/jest/pull/4740)) +- \`[pretty-format]\` Prevent error in pretty-format for window in jsdom test env + ([#4750](https://github.com/facebook/jest/pull/4750)) +- \`[jest-resolve]\` Preserve module identity for symlinks + ([#4761](https://github.com/facebook/jest/pull/4761)) +- \`[jest-config]\` Include error message for \`preset\` json + ([#4766](https://github.com/facebook/jest/pull/4766)) +- \`[pretty-format]\` Throw \`PrettyFormatPluginError\` if a plugin halts with an + exception ([#4787](https://github.com/facebook/jest/pull/4787)) +- \`[expect]\` Keep the stack trace unchanged when \`PrettyFormatPluginError\` is + thrown by pretty-format ([#4787](https://github.com/facebook/jest/pull/4787)) +- \`[jest-environment-jsdom]\` Fix asynchronous test will fail due to timeout + issue. ([#4669](https://github.com/facebook/jest/pull/4669)) +- \`[jest-cli]\` Fix \`--onlyChanged\` path case sensitivity on Windows platform + ([#4730](https://github.com/facebook/jest/pull/4730)) +- \`[jest-runtime]\` Use realpath to match transformers + ([#5000](https://github.com/facebook/jest/pull/5000)) +- \`[expect]\` \\[**BREAKING**] Replace identity equality with Object.is in toBe + matcher ([#4917](https://github.com/facebook/jest/pull/4917)) + +##### Features + +- \`[jest-message-util]\` Add codeframe to test assertion failures + ([#5087](https://github.com/facebook/jest/pull/5087)) +- \`[jest-config]\` Add Global Setup/Teardown options + ([#4716](https://github.com/facebook/jest/pull/4716)) +- \`[jest-config]\` Add \`testEnvironmentOptions\` to apply to jsdom options or node + context. ([#5003](https://github.com/facebook/jest/pull/5003)) +- \`[jest-jasmine2]\` Update Timeout error message to \`jest.timeout\` and display + current timeout value ([#4990](https://github.com/facebook/jest/pull/4990)) +- \`[jest-runner]\` Enable experimental detection of leaked contexts + ([#4895](https://github.com/facebook/jest/pull/4895)) +- \`[jest-cli]\` Add combined coverage threshold for directories. + ([#4885](https://github.com/facebook/jest/pull/4885)) +- \`[jest-mock]\` Add \`timestamps\` to mock state. + ([#4866](https://github.com/facebook/jest/pull/4866)) +- \`[eslint-plugin-jest]\` Add \`prefer-to-have-length\` lint rule. + ([#4771](https://github.com/facebook/jest/pull/4771)) +- \`[jest-environment-jsdom]\` \\[**BREAKING**] Upgrade to JSDOM@11 + ([#4770](https://github.com/facebook/jest/pull/4770)) +- \`[jest-environment-*]\` \\[**BREAKING**] Add Async Test Environment APIs, dispose + is now teardown ([#4506](https://github.com/facebook/jest/pull/4506)) +- \`[jest-cli]\` Add an option to clear the cache + ([#4430](https://github.com/facebook/jest/pull/4430)) +- \`[babel-plugin-jest-hoist]\` Improve error message, that the second argument of + \`jest.mock\` must be an inline function + ([#4593](https://github.com/facebook/jest/pull/4593)) +- \`[jest-snapshot]\` \\[**BREAKING**] Concatenate name of test and snapshot + ([#4460](https://github.com/facebook/jest/pull/4460)) +- \`[jest-cli]\` \\[**BREAKING**] Fail if no tests are found + ([#3672](https://github.com/facebook/jest/pull/3672)) +- \`[jest-diff]\` Highlight only last of odd length leading spaces + ([#4558](https://github.com/facebook/jest/pull/4558)) +- \`[jest-docblock]\` Add \`docblock.print()\` + ([#4517](https://github.com/facebook/jest/pull/4517)) +- \`[jest-docblock]\` Add \`strip\` + ([#4571](https://github.com/facebook/jest/pull/4571)) +- \`[jest-docblock]\` Preserve leading whitespace in docblock comments + ([#4576](https://github.com/facebook/jest/pull/4576)) +- \`[jest-docblock]\` remove leading newlines from \`parswWithComments().comments\` + ([#4610](https://github.com/facebook/jest/pull/4610)) +- \`[jest-editor-support]\` Add Snapshots metadata + ([#4570](https://github.com/facebook/jest/pull/4570)) +- \`[jest-editor-support]\` Adds an 'any' to the typedef for + \`updateFileWithJestStatus\` + ([#4636](https://github.com/facebook/jest/pull/4636)) +- \`[jest-editor-support]\` Better monorepo support + ([#4572](https://github.com/facebook/jest/pull/4572)) +- \`[jest-environment-jsdom]\` Add simple rAF polyfill in jsdom environment to + work with React 16 ([#4568](https://github.com/facebook/jest/pull/4568)) +- \`[jest-environment-node]\` Implement node Timer api + ([#4622](https://github.com/facebook/jest/pull/4622)) +- \`[jest-jasmine2]\` Add testPath to reporter callbacks + ([#4594](https://github.com/facebook/jest/pull/4594)) +- \`[jest-mock]\` Added support for naming mocked functions with + \`.mockName(value)\` and \`.mockGetName()\` + ([#4586](https://github.com/facebook/jest/pull/4586)) +- \`[jest-runtime]\` Add \`module.loaded\`, and make \`module.require\` not enumerable + ([#4623](https://github.com/facebook/jest/pull/4623)) +- \`[jest-runtime]\` Add \`module.parent\` + ([#4614](https://github.com/facebook/jest/pull/4614)) +- \`[jest-runtime]\` Support sourcemaps in transformers + ([#3458](https://github.com/facebook/jest/pull/3458)) +- \`[jest-snapshot]\` \\[**BREAKING**] Add a serializer for \`jest.fn\` to allow a + snapshot of a jest mock ([#4668](https://github.com/facebook/jest/pull/4668)) +- \`[jest-worker]\` Initial version of parallel worker abstraction, say hello! + ([#4497](https://github.com/facebook/jest/pull/4497)) +- \`[jest-jasmine2]\` Add \`testLocationInResults\` flag to add location information + per spec to test results ([#4782](https://github.com/facebook/jest/pull/4782)) +- \`[jest-environment-jsdom]\` Update JSOM to 11.4, which includes built-in + support for \`requestAnimationFrame\` + ([#4919](https://github.com/facebook/jest/pull/4919)) +- \`[jest-cli]\` Hide watch usage output when running on non-interactive + environments ([#4958](https://github.com/facebook/jest/pull/4958)) +- \`[jest-snapshot]\` Promises support for \`toThrowErrorMatchingSnapshot\` + ([#4946](https://github.com/facebook/jest/pull/4946)) +- \`[jest-cli]\` Explain which snapshots are obsolete + ([#5005](https://github.com/facebook/jest/pull/5005)) + +##### Chore & Maintenance + +- \`[docs]\` Add guide of using with puppeteer + ([#5093](https://github.com/facebook/jest/pull/5093)) +- \`[jest-util]\` \`jest-util\` should not depend on \`jest-mock\` + ([#4992](https://github.com/facebook/jest/pull/4992)) +- \`[*]\` \\[**BREAKING**] Drop support for Node.js version 4 + ([#4769](https://github.com/facebook/jest/pull/4769)) +- \`[docs]\` Wrap code comments at 80 characters + ([#4781](https://github.com/facebook/jest/pull/4781)) +- \`[eslint-plugin-jest]\` Removed from the Jest core repo, and moved to + + ([#4867](https://github.com/facebook/jest/pull/4867)) +- \`[babel-jest]\` Explicitly bump istanbul to newer versions + ([#4616](https://github.com/facebook/jest/pull/4616)) +- \`[expect]\` Upgrade mocha and rollup for browser testing + ([#4642](https://github.com/facebook/jest/pull/4642)) +- \`[docs]\` Add info about \`coveragePathIgnorePatterns\` + ([#4602](https://github.com/facebook/jest/pull/4602)) +- \`[docs]\` Add Vuejs series of testing with Jest + ([#4648](https://github.com/facebook/jest/pull/4648)) +- \`[docs]\` Mention about optional \`done\` argument in test function + ([#4556](https://github.com/facebook/jest/pull/4556)) +- \`[jest-cli]\` Bump node-notifier version + ([#4609](https://github.com/facebook/jest/pull/4609)) +- \`[jest-diff]\` Simplify highlight for leading and trailing spaces + ([#4553](https://github.com/facebook/jest/pull/4553)) +- \`[jest-get-type]\` Add support for date + ([#4621](https://github.com/facebook/jest/pull/4621)) +- \`[jest-matcher-utils]\` Call \`chalk.inverse\` for trailing spaces + ([#4578](https://github.com/facebook/jest/pull/4578)) +- \`[jest-runtime]\` Add \`.advanceTimersByTime\`; keep \`.runTimersToTime()\` as an + alias. +- \`[docs]\` Include missing dependency in TestEnvironment sample code +- \`[docs]\` Add clarification for hook execution order +- \`[docs]\` Update \`expect.anything()\` sample code + ([#5007](https://github.com/facebook/jest/pull/5007)) +", + "notesSourceUrl": "https://github.com/facebook/jest/blob/HEAD/CHANGELOG.md", + "url": "https://github.com/facebook/jest/blob/HEAD/CHANGELOG.md#jest-2200", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses js-yaml 1`] = ` +{ + "body": "- Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370). +- Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368). +", + "notesSourceUrl": "https://github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md", + "url": "https://github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md#3100--2017-09-10", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses self hosted gitlab 1`] = ` +{ + "body": "- Removing markup from a part of the French translation, +- Fix typo documentation -> documentation, + - Thanks to [@auua](https://gitlab.com/auua) for the contribution +- Fix \`/channel\` slash command name regex to accept hyphenated names, + - Thanks to [@auua](https://gitlab.com/auua) for the contribution +- Add GitLab branding to the left-menu, +- Fix left-menu search state showing all rooms, +- Update Polish translation, + - Thanks to [@biesiad](https://gitlab.com/biesiad) for the contribution +", + "notesSourceUrl": "https://my.custom.domain/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md", + "url": "https://my.custom.domain/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md#20260---2020-05-18", +} +`; + exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() ReleaseNotes Correctness handles gitlab sourceDirectory 1`] = ` { "body": "- add new auth, fix accept header and base path in mock @@ -354,3 +786,216 @@ exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd( "url": "https://my.custom.domain/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md#20260---2020-05-18", } `; + +exports[`workers/repository/update/pr/changelog/release-notes handles github sourceDirectory 1`] = ` +{ + "body": "- Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370). +- Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368). +", + "notesSourceUrl": "https://github.com/nodeca/js-yaml/blob/HEAD/packages/foo/CHANGELOG.md", + "url": "https://github.com/nodeca/js-yaml/blob/HEAD/packages/foo/CHANGELOG.md#3100--2017-09-10", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes parses jest 1`] = ` +{ + "body": "##### Fixes + +- \`[jest-resolve]\` Use \`module.builtinModules\` as \`BUILTIN_MODULES\` when it + exists +- \`[jest-worker]\` Remove \`debug\` and \`inspect\` flags from the arguments sent to + the child ([#5068](https://github.com/facebook/jest/pull/5068)) +- \`[jest-config]\` Use all \`--testPathPattern\` and \`\` args in + \`testPathPattern\` ([#5066](https://github.com/facebook/jest/pull/5066)) +- \`[jest-cli]\` Do not support \`--watch\` inside non-version-controlled + environments ([#5060](https://github.com/facebook/jest/pull/5060)) +- \`[jest-config]\` Escape Windows path separator in testPathPattern CLI arguments + ([#5054](https://github.com/facebook/jest/pull/5054) +- \`[jest-jasmine]\` Register sourcemaps as node environment to improve + performance with jsdom ([#5045](https://github.com/facebook/jest/pull/5045)) +- \`[pretty-format]\` Do not call toJSON recursively + ([#5044](https://github.com/facebook/jest/pull/5044)) +- \`[pretty-format]\` Fix errors when identity-obj-proxy mocks CSS Modules + ([#4935](https://github.com/facebook/jest/pull/4935)) +- \`[babel-jest]\` Fix support for namespaced babel version 7 + ([#4918](https://github.com/facebook/jest/pull/4918)) +- \`[expect]\` fix .toThrow for promises + ([#4884](https://github.com/facebook/jest/pull/4884)) +- \`[jest-docblock]\` pragmas should preserve urls + ([#4837](https://github.com/facebook/jest/pull/4629)) +- \`[jest-cli]\` Check if \`npm_lifecycle_script\` calls Jest directly + ([#4629](https://github.com/facebook/jest/pull/4629)) +- \`[jest-cli]\` Fix --showConfig to show all configs + ([#4494](https://github.com/facebook/jest/pull/4494)) +- \`[jest-cli]\` Throw if \`maxWorkers\` doesn't have a value + ([#4591](https://github.com/facebook/jest/pull/4591)) +- \`[jest-cli]\` Use \`fs.realpathSync.native\` if available + ([#5031](https://github.com/facebook/jest/pull/5031)) +- \`[jest-config]\` Fix \`--passWithNoTests\` + ([#4639](https://github.com/facebook/jest/pull/4639)) +- \`[jest-config]\` Support \`rootDir\` tag in testEnvironment + ([#4579](https://github.com/facebook/jest/pull/4579)) +- \`[jest-editor-support]\` Fix \`--showConfig\` to support jest 20 and jest 21 + ([#4575](https://github.com/facebook/jest/pull/4575)) +- \`[jest-editor-support]\` Fix editor support test for node 4 + ([#4640](https://github.com/facebook/jest/pull/4640)) +- \`[jest-mock]\` Support mocking constructor in \`mockImplementationOnce\` + ([#4599](https://github.com/facebook/jest/pull/4599)) +- \`[jest-runtime]\` Fix manual user mocks not working with custom resolver + ([#4489](https://github.com/facebook/jest/pull/4489)) +- \`[jest-util]\` Fix \`runOnlyPendingTimers\` for \`setTimeout\` inside + \`setImmediate\` ([#4608](https://github.com/facebook/jest/pull/4608)) +- \`[jest-message-util]\` Always remove node internals from stacktraces + ([#4695](https://github.com/facebook/jest/pull/4695)) +- \`[jest-resolve]\` changes method of determining builtin modules to include + missing builtins ([#4740](https://github.com/facebook/jest/pull/4740)) +- \`[pretty-format]\` Prevent error in pretty-format for window in jsdom test env + ([#4750](https://github.com/facebook/jest/pull/4750)) +- \`[jest-resolve]\` Preserve module identity for symlinks + ([#4761](https://github.com/facebook/jest/pull/4761)) +- \`[jest-config]\` Include error message for \`preset\` json + ([#4766](https://github.com/facebook/jest/pull/4766)) +- \`[pretty-format]\` Throw \`PrettyFormatPluginError\` if a plugin halts with an + exception ([#4787](https://github.com/facebook/jest/pull/4787)) +- \`[expect]\` Keep the stack trace unchanged when \`PrettyFormatPluginError\` is + thrown by pretty-format ([#4787](https://github.com/facebook/jest/pull/4787)) +- \`[jest-environment-jsdom]\` Fix asynchronous test will fail due to timeout + issue. ([#4669](https://github.com/facebook/jest/pull/4669)) +- \`[jest-cli]\` Fix \`--onlyChanged\` path case sensitivity on Windows platform + ([#4730](https://github.com/facebook/jest/pull/4730)) +- \`[jest-runtime]\` Use realpath to match transformers + ([#5000](https://github.com/facebook/jest/pull/5000)) +- \`[expect]\` \\[**BREAKING**] Replace identity equality with Object.is in toBe + matcher ([#4917](https://github.com/facebook/jest/pull/4917)) + +##### Features + +- \`[jest-message-util]\` Add codeframe to test assertion failures + ([#5087](https://github.com/facebook/jest/pull/5087)) +- \`[jest-config]\` Add Global Setup/Teardown options + ([#4716](https://github.com/facebook/jest/pull/4716)) +- \`[jest-config]\` Add \`testEnvironmentOptions\` to apply to jsdom options or node + context. ([#5003](https://github.com/facebook/jest/pull/5003)) +- \`[jest-jasmine2]\` Update Timeout error message to \`jest.timeout\` and display + current timeout value ([#4990](https://github.com/facebook/jest/pull/4990)) +- \`[jest-runner]\` Enable experimental detection of leaked contexts + ([#4895](https://github.com/facebook/jest/pull/4895)) +- \`[jest-cli]\` Add combined coverage threshold for directories. + ([#4885](https://github.com/facebook/jest/pull/4885)) +- \`[jest-mock]\` Add \`timestamps\` to mock state. + ([#4866](https://github.com/facebook/jest/pull/4866)) +- \`[eslint-plugin-jest]\` Add \`prefer-to-have-length\` lint rule. + ([#4771](https://github.com/facebook/jest/pull/4771)) +- \`[jest-environment-jsdom]\` \\[**BREAKING**] Upgrade to JSDOM@11 + ([#4770](https://github.com/facebook/jest/pull/4770)) +- \`[jest-environment-*]\` \\[**BREAKING**] Add Async Test Environment APIs, dispose + is now teardown ([#4506](https://github.com/facebook/jest/pull/4506)) +- \`[jest-cli]\` Add an option to clear the cache + ([#4430](https://github.com/facebook/jest/pull/4430)) +- \`[babel-plugin-jest-hoist]\` Improve error message, that the second argument of + \`jest.mock\` must be an inline function + ([#4593](https://github.com/facebook/jest/pull/4593)) +- \`[jest-snapshot]\` \\[**BREAKING**] Concatenate name of test and snapshot + ([#4460](https://github.com/facebook/jest/pull/4460)) +- \`[jest-cli]\` \\[**BREAKING**] Fail if no tests are found + ([#3672](https://github.com/facebook/jest/pull/3672)) +- \`[jest-diff]\` Highlight only last of odd length leading spaces + ([#4558](https://github.com/facebook/jest/pull/4558)) +- \`[jest-docblock]\` Add \`docblock.print()\` + ([#4517](https://github.com/facebook/jest/pull/4517)) +- \`[jest-docblock]\` Add \`strip\` + ([#4571](https://github.com/facebook/jest/pull/4571)) +- \`[jest-docblock]\` Preserve leading whitespace in docblock comments + ([#4576](https://github.com/facebook/jest/pull/4576)) +- \`[jest-docblock]\` remove leading newlines from \`parswWithComments().comments\` + ([#4610](https://github.com/facebook/jest/pull/4610)) +- \`[jest-editor-support]\` Add Snapshots metadata + ([#4570](https://github.com/facebook/jest/pull/4570)) +- \`[jest-editor-support]\` Adds an 'any' to the typedef for + \`updateFileWithJestStatus\` + ([#4636](https://github.com/facebook/jest/pull/4636)) +- \`[jest-editor-support]\` Better monorepo support + ([#4572](https://github.com/facebook/jest/pull/4572)) +- \`[jest-environment-jsdom]\` Add simple rAF polyfill in jsdom environment to + work with React 16 ([#4568](https://github.com/facebook/jest/pull/4568)) +- \`[jest-environment-node]\` Implement node Timer api + ([#4622](https://github.com/facebook/jest/pull/4622)) +- \`[jest-jasmine2]\` Add testPath to reporter callbacks + ([#4594](https://github.com/facebook/jest/pull/4594)) +- \`[jest-mock]\` Added support for naming mocked functions with + \`.mockName(value)\` and \`.mockGetName()\` + ([#4586](https://github.com/facebook/jest/pull/4586)) +- \`[jest-runtime]\` Add \`module.loaded\`, and make \`module.require\` not enumerable + ([#4623](https://github.com/facebook/jest/pull/4623)) +- \`[jest-runtime]\` Add \`module.parent\` + ([#4614](https://github.com/facebook/jest/pull/4614)) +- \`[jest-runtime]\` Support sourcemaps in transformers + ([#3458](https://github.com/facebook/jest/pull/3458)) +- \`[jest-snapshot]\` \\[**BREAKING**] Add a serializer for \`jest.fn\` to allow a + snapshot of a jest mock ([#4668](https://github.com/facebook/jest/pull/4668)) +- \`[jest-worker]\` Initial version of parallel worker abstraction, say hello! + ([#4497](https://github.com/facebook/jest/pull/4497)) +- \`[jest-jasmine2]\` Add \`testLocationInResults\` flag to add location information + per spec to test results ([#4782](https://github.com/facebook/jest/pull/4782)) +- \`[jest-environment-jsdom]\` Update JSOM to 11.4, which includes built-in + support for \`requestAnimationFrame\` + ([#4919](https://github.com/facebook/jest/pull/4919)) +- \`[jest-cli]\` Hide watch usage output when running on non-interactive + environments ([#4958](https://github.com/facebook/jest/pull/4958)) +- \`[jest-snapshot]\` Promises support for \`toThrowErrorMatchingSnapshot\` + ([#4946](https://github.com/facebook/jest/pull/4946)) +- \`[jest-cli]\` Explain which snapshots are obsolete + ([#5005](https://github.com/facebook/jest/pull/5005)) + +##### Chore & Maintenance + +- \`[docs]\` Add guide of using with puppeteer + ([#5093](https://github.com/facebook/jest/pull/5093)) +- \`[jest-util]\` \`jest-util\` should not depend on \`jest-mock\` + ([#4992](https://github.com/facebook/jest/pull/4992)) +- \`[*]\` \\[**BREAKING**] Drop support for Node.js version 4 + ([#4769](https://github.com/facebook/jest/pull/4769)) +- \`[docs]\` Wrap code comments at 80 characters + ([#4781](https://github.com/facebook/jest/pull/4781)) +- \`[eslint-plugin-jest]\` Removed from the Jest core repo, and moved to + + ([#4867](https://github.com/facebook/jest/pull/4867)) +- \`[babel-jest]\` Explicitly bump istanbul to newer versions + ([#4616](https://github.com/facebook/jest/pull/4616)) +- \`[expect]\` Upgrade mocha and rollup for browser testing + ([#4642](https://github.com/facebook/jest/pull/4642)) +- \`[docs]\` Add info about \`coveragePathIgnorePatterns\` + ([#4602](https://github.com/facebook/jest/pull/4602)) +- \`[docs]\` Add Vuejs series of testing with Jest + ([#4648](https://github.com/facebook/jest/pull/4648)) +- \`[docs]\` Mention about optional \`done\` argument in test function + ([#4556](https://github.com/facebook/jest/pull/4556)) +- \`[jest-cli]\` Bump node-notifier version + ([#4609](https://github.com/facebook/jest/pull/4609)) +- \`[jest-diff]\` Simplify highlight for leading and trailing spaces + ([#4553](https://github.com/facebook/jest/pull/4553)) +- \`[jest-get-type]\` Add support for date + ([#4621](https://github.com/facebook/jest/pull/4621)) +- \`[jest-matcher-utils]\` Call \`chalk.inverse\` for trailing spaces + ([#4578](https://github.com/facebook/jest/pull/4578)) +- \`[jest-runtime]\` Add \`.advanceTimersByTime\`; keep \`.runTimersToTime()\` as an + alias. +- \`[docs]\` Include missing dependency in TestEnvironment sample code +- \`[docs]\` Add clarification for hook execution order +- \`[docs]\` Update \`expect.anything()\` sample code + ([#5007](https://github.com/facebook/jest/pull/5007)) +", + "notesSourceUrl": "https://github.com/facebook/jest/blob/HEAD/CHANGELOG.md", + "url": "https://github.com/facebook/jest/blob/HEAD/CHANGELOG.md#jest-2200", +} +`; + +exports[`workers/repository/update/pr/changelog/release-notes parses js-yaml 1`] = ` +{ + "body": "- Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370). +- Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368). +", + "notesSourceUrl": "https://github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md", + "url": "https://github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md#3100--2017-09-10", +} +`; diff --git a/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts index f31a271a30c24b..0afbf2ce48b753 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts @@ -11,241 +11,55 @@ const upgrade = partial({ manager: 'some-manager', branchName: '', endpoint: 'https://api.bitbucket.org/', - packageName: 'renovate', + packageName: 'some-repo', versioning: semverVersioning.id, currentVersion: '5.2.0', newVersion: '5.7.0', - sourceUrl: 'https://bitbucket.org/meno/dropzone/', + sourceUrl: 'https://bitbucket.org/some-org/some-repo', releases: [ - // TODO: test gitRef { version: '5.2.0' }, { version: '5.4.0', releaseTimestamp: '2018-08-24T14:23:00.000Z', }, - { version: '5.5.0', gitRef: 'eba303e91c930292198b2fc57040145682162a1b' }, - { version: '5.6.0', releaseTimestamp: '2020-02-13T15:37:00.000Z' }, - { version: '5.6.1' }, + { version: '5.5.0', gitRef: 'abcd' }, + { + version: '5.6.0', + gitRef: '1234', + releaseTimestamp: '2020-02-13T15:37:00.000Z', + }, + { version: '5.6.1', gitRef: 'asdf' }, ], }); -const matchHost = 'https://bitbucket.org/'; - describe('workers/repository/update/pr/changelog/bitbucket', () => { afterEach(() => { // FIXME: add missing http mocks httpMock.clear(false); }); - describe('getChangeLogJSON', () => { - beforeEach(() => { - hostRules.clear(); - hostRules.add({ - hostType: 'bitbucket', - matchHost, - token: 'abc', - }); - }); - - it('returns null if @types', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - currentVersion: undefined, - }) - ).toBeNull(); - }); - - it('returns null if currentVersion equals newVersion', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - currentVersion: '1.0.0', - newVersion: '1.0.0', - }) - ).toBeNull(); - }); - - it('skips invalid repos', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - sourceUrl: 'https://bitbucket.org/help', - }) - ).toBeNull(); - }); - - it('works with Bitbucket', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - }) - ).toEqual({ - hasReleaseNotes: false, - project: { - apiBaseUrl: 'https://api.bitbucket.org/', - baseUrl: 'https://bitbucket.org/', - packageName: 'renovate', - repository: 'meno/dropzone', - sourceDirectory: undefined, - sourceUrl: 'https://bitbucket.org/meno/dropzone/', - type: 'bitbucket', - }, - versions: [ - expect.objectContaining({ version: '5.6.1' }), - expect.objectContaining({ version: '5.6.0' }), - expect.objectContaining({ version: '5.5.0' }), - expect.objectContaining({ version: '5.4.0' }), - ], - }); - }); - - it('uses Bitbucket tags', async () => { - httpMock - .scope(matchHost) - .get('/2.0/repositories//meno%2Fdropzone/refs/tags') - .reply(200, [ - { name: 'v5.2.0' }, - { name: 'v5.4.0' }, - { name: 'v5.5.0' }, - { name: 'v5.6.0' }, - { name: 'v5.6.1' }, - { name: 'v5.7.0' }, - ]) - .persist() - .get('/2.0/repositories//meno%2Fdropzone/refs/tags') - .reply(200, []) - .persist() - .get('/2.0/repositories//meno%2Fdropzone/refs/tags') - .reply(200, []); - expect( - await getChangeLogJSON({ - ...upgrade, - }) - ).toEqual({ - hasReleaseNotes: false, - project: { - apiBaseUrl: 'https://api.bitbucket.org/', - baseUrl: 'https://bitbucket.org/', - packageName: 'renovate', - repository: 'meno/dropzone', - sourceDirectory: undefined, - sourceUrl: 'https://bitbucket.org/meno/dropzone/', - type: 'bitbucket', - }, - versions: [ - expect.objectContaining({ version: '5.6.1' }), - expect.objectContaining({ version: '5.6.0' }), - expect.objectContaining({ version: '5.5.0' }), - expect.objectContaining({ version: '5.4.0' }), - ], - }); - }); - - it('handles empty Bitbucket tags response', async () => { - httpMock - .scope(matchHost) - .get('/2.0/repositories//meno%2Fdropzone/refs/tags') - .reply(200, []) - .persist() - .get('/2.0/repositories//meno%2Fdropzone/refs/tags') - .reply(200, []) - .persist() - .get('/2.0/repositories//meno%2Fdropzone/refs/tags') - .reply(200, []); - expect( - await getChangeLogJSON({ - ...upgrade, - }) - ).toEqual({ - hasReleaseNotes: false, - project: { - apiBaseUrl: 'https://api.bitbucket.org/', - baseUrl: 'https://bitbucket.org/', - packageName: 'renovate', - repository: 'meno/dropzone', - sourceDirectory: undefined, - sourceUrl: 'https://bitbucket.org/meno/dropzone/', - type: 'bitbucket', - }, - versions: [ - expect.objectContaining({ version: '5.6.1' }), - expect.objectContaining({ version: '5.6.0' }), - expect.objectContaining({ version: '5.5.0' }), - expect.objectContaining({ version: '5.4.0' }), - ], - }); - }); - - it('uses Bitbucket tags with error', async () => { - httpMock - .scope(matchHost) - .get('/2.0/repositories//meno%2Fdropzone/refs/tags') - .replyWithError('Unknown Bitbucket Repo') - .persist() - .get('/2.0/repositories//meno%2Fdropzone/refs/tags') - .reply(200, []) - .persist() - .get('/2.0/repositories//meno%2Fdropzone/refs/tags') - .reply(200, []); - expect( - await getChangeLogJSON({ - ...upgrade, - }) - ).toEqual({ - hasReleaseNotes: false, - project: { - apiBaseUrl: 'https://api.bitbucket.org/', - baseUrl: 'https://bitbucket.org/', - packageName: 'renovate', - repository: 'meno/dropzone', - sourceDirectory: undefined, - sourceUrl: 'https://bitbucket.org/meno/dropzone/', - type: 'bitbucket', - }, - versions: [ - expect.objectContaining({ version: '5.6.1' }), - expect.objectContaining({ version: '5.6.0' }), - expect.objectContaining({ version: '5.5.0' }), - expect.objectContaining({ version: '5.4.0' }), - ], - }); - }); - - it('handles no sourceUrl', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - sourceUrl: undefined, - }) - ).toBeNull(); - }); - - it('handles invalid sourceUrl', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - sourceUrl: 'http://example.com', - }) - ).toBeNull(); - }); - - it('handles no releases', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - releases: [], - }) - ).toBeNull(); - }); - - it('handles not enough releases', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - releases: [{ version: '0.9.0' }], - }) - ).toBeNull(); + it('works with Bitbucket', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + }) + ).toEqual({ + hasReleaseNotes: true, + project: { + apiBaseUrl: 'https://api.bitbucket.org/', + baseUrl: 'https://bitbucket.org/', + packageName: 'some-repo', + repository: 'some-org/some-repo', + sourceDirectory: undefined, + sourceUrl: 'https://bitbucket.org/some-org/some-repo', + type: 'bitbucket', + }, + versions: [ + expect.objectContaining({ version: '5.6.1' }), + expect.objectContaining({ version: '5.6.0' }), + expect.objectContaining({ version: '5.5.0' }), + expect.objectContaining({ version: '5.4.0' }), + ], }); }); }); diff --git a/lib/workers/repository/update/pr/changelog/github.spec.ts b/lib/workers/repository/update/pr/changelog/github.spec.ts index ee6fe19cee6109..c85121ff92213e 100644 --- a/lib/workers/repository/update/pr/changelog/github.spec.ts +++ b/lib/workers/repository/update/pr/changelog/github.spec.ts @@ -217,6 +217,16 @@ describe('workers/repository/update/pr/changelog/github', () => { ).toEqual({ error: 'MissingGithubToken' }); }); + it('handles supressed Github warnings', async () => { + GlobalConfig.set({ githubTokenWarn: false }); + expect( + await getChangeLogJSON({ + ...upgrade, + sourceUrl: 'https://github.com', + }) + ).toBeNull(); + }); + it('handles no releases', async () => { expect( await getChangeLogJSON({ diff --git a/lib/workers/repository/update/pr/changelog/index.spec.ts b/lib/workers/repository/update/pr/changelog/index.spec.ts index 17e2f3a8e6cb4f..6d0c15a7767c85 100644 --- a/lib/workers/repository/update/pr/changelog/index.spec.ts +++ b/lib/workers/repository/update/pr/changelog/index.spec.ts @@ -55,6 +55,15 @@ describe('workers/repository/update/pr/changelog/index', () => { ).toBeNull(); }); + it('handles unsupported changelog source', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + sourceUrl: 'https://dev.azure.com/unknown-repo', + }) + ).toBeNull(); + }); + it('returns null if no currentVersion', async () => { expect( await getChangeLogJSON({ diff --git a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts index 20f4492537e148..682550dddfa3fd 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts @@ -46,6 +46,43 @@ const gitlabTreeResponse = [ { path: 'README.md', name: 'README.md', type: 'blob' }, ]; +const bitbucketTreeResponse = { + values: [ + { + type: 'commit_directory', + path: 'lib', + commit: { + hash: '1234', + }, + }, + { + type: 'commit_file', + path: 'CHANGELOG.md', + commit: { + hash: 'abcd', + }, + }, + { + type: 'commit_file', + path: 'RELEASE_NOTES.md', + commit: { + hash: 'asdf', + }, + }, + ], +}; + +const bitbucketTreeResponseNoChangelogFiles = { + values: [ + { + type: 'commit_directory', + path: 'lib', + commit: { + hash: '1234', + }, + }, + ], +}; const githubProject = partial({ type: 'github', apiBaseUrl: 'https://api.github.com/', @@ -58,6 +95,12 @@ const gitlabProject = partial({ baseUrl: 'https://gitlab.com/', }); +const bitbucketProject = partial({ + type: 'bitbucket', + apiBaseUrl: 'https://api.bitbucket.org', + baseUrl: 'https://bitbucket.org/', +}); + describe('workers/repository/update/pr/changelog/release-notes', () => { const githubReleasesMock = jest.spyOn(githubGraphql, 'queryReleases'); @@ -1103,6 +1146,54 @@ describe('workers/repository/update/pr/changelog/release-notes', () => { }); }); + it('bitbucket: parses changelog', async () => { + hostRules.find.mockReturnValue({ token: 'some-token' }); + jest.setTimeout(0); + httpMock + .scope('https://api.bitbucket.org/') + .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') + .reply(200, bitbucketTreeResponse) + .get('/2.0/repositories/some-org/some-repo/src/abcd/CHANGELOG.md') + .reply(200, gitterWebappChangelogMd); + const res = await getReleaseNotesMd( + { + ...bitbucketProject, + repository: 'some-org/some-repo', + apiBaseUrl: 'https://api.bitbucket.org/', + baseUrl: 'https://bitbucket.org/', + }, + partial({ + version: '20.26.0', + gitRef: '20.26.0', + }) + ); + + expect(res?.notesSourceUrl).toBe( + 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md' + ); + expect(res?.url).toBe( + 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md#20260---2020-05-18' + ); + }); + + it('bitbucket: handles not found', async () => { + httpMock + .scope('https://api.bitbucket.org/') + .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') + .reply(200, bitbucketTreeResponseNoChangelogFiles); + const res = await getReleaseNotesMd( + { + ...bitbucketProject, + repository: 'some-org/some-repo', + }, + partial({ + version: '2.0.0', + gitRef: '2.0.0', + }) + ); + expect(res).toBeNull(); + }); + it('parses jest', async () => { httpMock .scope('https://api.github.com') From b10f88cb96e4b4838c2252e76d5c3f751c3738c4 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 25 Jun 2023 07:46:56 -0400 Subject: [PATCH 50/71] fix linting --- lib/workers/repository/update/pr/changelog/bitbucket.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts index 0afbf2ce48b753..54f1d8838ab8a6 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts @@ -1,7 +1,6 @@ import * as httpMock from '../../../../../../test/http-mock'; import { partial } from '../../../../../../test/util'; import * as semverVersioning from '../../../../../modules/versioning/semver'; -import * as hostRules from '../../../../../util/host-rules'; import type { BranchUpgradeConfig } from '../../../../types'; import { getChangeLogJSON } from '.'; From 8b162656a51f1cee3cb9d1cb2ce9fd67fad77d12 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 25 Jun 2023 07:59:11 -0400 Subject: [PATCH 51/71] tests: update snapshot --- .../__snapshots__/release-notes.spec.ts.snap | 645 ------------------ 1 file changed, 645 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap b/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap index 0e78abf6227591..3777869d2b0810 100644 --- a/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap +++ b/lib/workers/repository/update/pr/changelog/__snapshots__/release-notes.spec.ts.snap @@ -1,437 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`workers/repository/update/pr/changelog/release-notes ReleaseNotes Correctness handles gitlab sourceDirectory 1`] = ` -{ - "body": "- add new auth, fix accept header and base path in mock - -Closes ADAPT-207 - -See merge request itentialopensource/adapter-utils!177 - -*** -", - "notesSourceUrl": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/packages/foo/CHANGELOG.md", - "url": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/packages/foo/CHANGELOG.md#4330-05-15-2020", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes ReleaseNotes Correctness parses adapter-utils 4.33.0 1`] = ` -{ - "body": "- add new auth, fix accept header and base path in mock - -Closes ADAPT-207 - -See merge request itentialopensource/adapter-utils!177 - -*** -", - "notesSourceUrl": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/CHANGELOG.md", - "url": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/CHANGELOG.md#4330-05-15-2020", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes ReleaseNotes Correctness parses yargs 15.2.0 1`] = ` -{ - "body": "##### âš  BREAKING CHANGES - -- **deps:** yargs-parser@17.0.0 no longer implicitly creates arrays out of boolean - arguments when duplicates are provided - -##### Features - -- **completion:** takes negated flags into account when boolean-negation is set ([#1509](https://www.github.com/yargs/yargs/issues/1509)) ([7293ad5](https://www.github.com/yargs/yargs/commit/7293ad50d20ea0fb7dd1ac9b925e90e1bd95dea8)) -- **deps:** pull in yargs-parser@17.0.0 ([#1553](https://www.github.com/yargs/yargs/issues/1553)) ([b9409da](https://www.github.com/yargs/yargs/commit/b9409da199ebca515a848489c206b807fab2e65d)) -- deprecateOption ([#1559](https://www.github.com/yargs/yargs/issues/1559)) ([8aae333](https://www.github.com/yargs/yargs/commit/8aae3332251d09fa136db17ef4a40d83fa052bc4)) -- display appropriate $0 for electron apps ([#1536](https://www.github.com/yargs/yargs/issues/1536)) ([d0e4379](https://www.github.com/yargs/yargs/commit/d0e437912917d6a66bb5128992fa2f566a5f830b)) -- introduces strictCommands() subset of strict mode ([#1540](https://www.github.com/yargs/yargs/issues/1540)) ([1d4cca3](https://www.github.com/yargs/yargs/commit/1d4cca395a98b395e6318f0505fc73bef8b01350)) -- **deps:** yargs-parser with 'greedy-array' configuration ([#1569](https://www.github.com/yargs/yargs/issues/1569)) ([a03a320](https://www.github.com/yargs/yargs/commit/a03a320dbf5c0ce33d829a857fc04a651c0bb53e)) - -##### Bug Fixes - -- help always displayed for the first command parsed having an async handler ([#1535](https://www.github.com/yargs/yargs/issues/1535)) ([d585b30](https://www.github.com/yargs/yargs/commit/d585b303a43746201b05c9c9fda94a444634df33)) -- **deps:** fix enumeration for normalized path arguments ([#1567](https://www.github.com/yargs/yargs/issues/1567)) ([0b5b1b0](https://www.github.com/yargs/yargs/commit/0b5b1b0e5f4f9baf393c48e9cc2bc85c1b67a47a)) -- **locales:** only translate default option group name ([acc16de](https://www.github.com/yargs/yargs/commit/acc16de6b846ea7332db753646a9cec76b589162)) -- **locales:** remove extra space in French for 'default' ([#1564](https://www.github.com/yargs/yargs/issues/1564)) ([ecfc2c4](https://www.github.com/yargs/yargs/commit/ecfc2c474575c6cdbc6d273c94c13181bd1dbaa6)) -- **translations:** add French translation for unknown command ([#1563](https://www.github.com/yargs/yargs/issues/1563)) ([18b0b75](https://www.github.com/yargs/yargs/commit/18b0b752424bf560271e670ff95a0f90c8386787)) -- **translations:** fix pluralization in error messages. ([#1557](https://www.github.com/yargs/yargs/issues/1557)) ([94fa38c](https://www.github.com/yargs/yargs/commit/94fa38cbab8d86943e87bf41d368ed56dffa6835)) -- **yargs:** correct support of bundled electron apps ([#1554](https://www.github.com/yargs/yargs/issues/1554)) ([a0b61ac](https://www.github.com/yargs/yargs/commit/a0b61ac21e2b554aa73dbf1a66d4a7af94047c2f)) -", - "notesSourceUrl": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md", - "url": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md#1520-httpswwwgithubcomyargsyargscomparev1510v1520-2020-03-01", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes ReleaseNotes Correctness parses yargs 15.3.0 1`] = ` -{ - "body": "##### Features - -- **yargs-parser:** introduce single-digit boolean aliases ([#1576](https://www.github.com/yargs/yargs/issues/1576)) ([3af7f04](https://www.github.com/yargs/yargs/commit/3af7f04cdbfcbd4b3f432aca5144d43f21958c39)) -- add usage for single-digit boolean aliases ([#1580](https://www.github.com/yargs/yargs/issues/1580)) ([6014e39](https://www.github.com/yargs/yargs/commit/6014e39bca3a1e8445aa0fb2a435f6181e344c45)) - -##### Bug Fixes - -- address ambiguity between nargs of 1 and requiresArg ([#1572](https://www.github.com/yargs/yargs/issues/1572)) ([a5edc32](https://www.github.com/yargs/yargs/commit/a5edc328ecb3f90d1ba09cfe70a0040f68adf50a)) -", - "notesSourceUrl": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md", - "url": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md#1530-httpswwwgithubcomyargsyargscomparev1520v1530-2020-03-08", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() ReleaseNotes Correctness handles gitlab sourceDirectory 1`] = ` -{ - "body": "- add new auth, fix accept header and base path in mock - -Closes ADAPT-207 - -See merge request itentialopensource/adapter-utils!177 - -*** -", - "notesSourceUrl": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/packages/foo/CHANGELOG.md", - "url": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/packages/foo/CHANGELOG.md#4330-05-15-2020", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() ReleaseNotes Correctness parses adapter-utils 4.33.0 1`] = ` -{ - "body": "- add new auth, fix accept header and base path in mock - -Closes ADAPT-207 - -See merge request itentialopensource/adapter-utils!177 - -*** -", - "notesSourceUrl": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/CHANGELOG.md", - "url": "https://gitlab.com/itentialopensource/adapter-utils/blob/HEAD/CHANGELOG.md#4330-05-15-2020", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() ReleaseNotes Correctness parses yargs 15.2.0 1`] = ` -{ - "body": "##### âš  BREAKING CHANGES - -- **deps:** yargs-parser@17.0.0 no longer implicitly creates arrays out of boolean - arguments when duplicates are provided - -##### Features - -- **completion:** takes negated flags into account when boolean-negation is set ([#1509](https://www.github.com/yargs/yargs/issues/1509)) ([7293ad5](https://www.github.com/yargs/yargs/commit/7293ad50d20ea0fb7dd1ac9b925e90e1bd95dea8)) -- **deps:** pull in yargs-parser@17.0.0 ([#1553](https://www.github.com/yargs/yargs/issues/1553)) ([b9409da](https://www.github.com/yargs/yargs/commit/b9409da199ebca515a848489c206b807fab2e65d)) -- deprecateOption ([#1559](https://www.github.com/yargs/yargs/issues/1559)) ([8aae333](https://www.github.com/yargs/yargs/commit/8aae3332251d09fa136db17ef4a40d83fa052bc4)) -- display appropriate $0 for electron apps ([#1536](https://www.github.com/yargs/yargs/issues/1536)) ([d0e4379](https://www.github.com/yargs/yargs/commit/d0e437912917d6a66bb5128992fa2f566a5f830b)) -- introduces strictCommands() subset of strict mode ([#1540](https://www.github.com/yargs/yargs/issues/1540)) ([1d4cca3](https://www.github.com/yargs/yargs/commit/1d4cca395a98b395e6318f0505fc73bef8b01350)) -- **deps:** yargs-parser with 'greedy-array' configuration ([#1569](https://www.github.com/yargs/yargs/issues/1569)) ([a03a320](https://www.github.com/yargs/yargs/commit/a03a320dbf5c0ce33d829a857fc04a651c0bb53e)) - -##### Bug Fixes - -- help always displayed for the first command parsed having an async handler ([#1535](https://www.github.com/yargs/yargs/issues/1535)) ([d585b30](https://www.github.com/yargs/yargs/commit/d585b303a43746201b05c9c9fda94a444634df33)) -- **deps:** fix enumeration for normalized path arguments ([#1567](https://www.github.com/yargs/yargs/issues/1567)) ([0b5b1b0](https://www.github.com/yargs/yargs/commit/0b5b1b0e5f4f9baf393c48e9cc2bc85c1b67a47a)) -- **locales:** only translate default option group name ([acc16de](https://www.github.com/yargs/yargs/commit/acc16de6b846ea7332db753646a9cec76b589162)) -- **locales:** remove extra space in French for 'default' ([#1564](https://www.github.com/yargs/yargs/issues/1564)) ([ecfc2c4](https://www.github.com/yargs/yargs/commit/ecfc2c474575c6cdbc6d273c94c13181bd1dbaa6)) -- **translations:** add French translation for unknown command ([#1563](https://www.github.com/yargs/yargs/issues/1563)) ([18b0b75](https://www.github.com/yargs/yargs/commit/18b0b752424bf560271e670ff95a0f90c8386787)) -- **translations:** fix pluralization in error messages. ([#1557](https://www.github.com/yargs/yargs/issues/1557)) ([94fa38c](https://www.github.com/yargs/yargs/commit/94fa38cbab8d86943e87bf41d368ed56dffa6835)) -- **yargs:** correct support of bundled electron apps ([#1554](https://www.github.com/yargs/yargs/issues/1554)) ([a0b61ac](https://www.github.com/yargs/yargs/commit/a0b61ac21e2b554aa73dbf1a66d4a7af94047c2f)) -", - "notesSourceUrl": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md", - "url": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md#1520-httpswwwgithubcomyargsyargscomparev1510v1520-2020-03-01", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() ReleaseNotes Correctness parses yargs 15.3.0 1`] = ` -{ - "body": "##### Features - -- **yargs-parser:** introduce single-digit boolean aliases ([#1576](https://www.github.com/yargs/yargs/issues/1576)) ([3af7f04](https://www.github.com/yargs/yargs/commit/3af7f04cdbfcbd4b3f432aca5144d43f21958c39)) -- add usage for single-digit boolean aliases ([#1580](https://www.github.com/yargs/yargs/issues/1580)) ([6014e39](https://www.github.com/yargs/yargs/commit/6014e39bca3a1e8445aa0fb2a435f6181e344c45)) - -##### Bug Fixes - -- address ambiguity between nargs of 1 and requiresArg ([#1572](https://www.github.com/yargs/yargs/issues/1572)) ([a5edc32](https://www.github.com/yargs/yargs/commit/a5edc328ecb3f90d1ba09cfe70a0040f68adf50a)) -", - "notesSourceUrl": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md", - "url": "https://github.com/yargs/yargs/blob/HEAD/CHANGELOG.md#1530-httpswwwgithubcomyargsyargscomparev1520v1530-2020-03-08", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() handles github sourceDirectory 1`] = ` -{ - "body": "- Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370). -- Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368). -", - "notesSourceUrl": "https://github.com/nodeca/js-yaml/blob/HEAD/packages/foo/CHANGELOG.md", - "url": "https://github.com/nodeca/js-yaml/blob/HEAD/packages/foo/CHANGELOG.md#3100--2017-09-10", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses angular.js 1`] = ` -{ - "body": "#### Bug Fixes - -- **input:** add \`drop\` event support for IE - ([5dc076](https://github.com/angular/angular.js/commit/5dc07667de00c5e85fd69c5b7b7fe4fb5fd65a77)) -- **ngMessages:** prevent memory leak from messages that are never attached - ([9d058d](https://github.com/angular/angular.js/commit/9d058de04bb78694b83179e9b97bc40214eca01a), - [#16389](https://github.com/angular/angular.js/issues/16389), - [#16404](https://github.com/angular/angular.js/issues/16404), - [#16406](https://github.com/angular/angular.js/issues/16406)) -- **ngTransclude:** remove terminal: true - ([1d826e](https://github.com/angular/angular.js/commit/1d826e2f1e941d14c3c56d7a0249f5796ba11f85), - [#16411](https://github.com/angular/angular.js/issues/16411), - [#16412](https://github.com/angular/angular.js/issues/16412)) -- **$sanitize:** sanitize \`xml:base\` attributes - ([b9ef65](https://github.com/angular/angular.js/commit/b9ef6585e10477fbbf912a971fe0b390bca692a6)) - -#### New Features - -- **currencyFilter:** trim whitespace around an empty currency symbol - ([367390](https://github.com/angular/angular.js/commit/3673909896efb6ff47546caf7fc61549f193e043), - [#15018](https://github.com/angular/angular.js/issues/15018), - [#15085](https://github.com/angular/angular.js/issues/15085), - [#15105](https://github.com/angular/angular.js/issues/15105)) -", - "notesSourceUrl": "https://github.com/angular/angular.js/blob/HEAD/CHANGELOG.md", - "url": "https://github.com/angular/angular.js/blob/HEAD/CHANGELOG.md#169-fiery-basilisk-2018-02-02", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses gitlab.com/gitlab-org/gitter/webapp 1`] = ` -{ - "body": "- Removing markup from a part of the French translation, -- Fix typo documentation -> documentation, - - Thanks to [@auua](https://gitlab.com/auua) for the contribution -- Fix \`/channel\` slash command name regex to accept hyphenated names, - - Thanks to [@auua](https://gitlab.com/auua) for the contribution -- Add GitLab branding to the left-menu, -- Fix left-menu search state showing all rooms, -- Update Polish translation, - - Thanks to [@biesiad](https://gitlab.com/biesiad) for the contribution -", - "notesSourceUrl": "https://gitlab.com/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md", - "url": "https://gitlab.com/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md#20260---2020-05-18", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses jest 1`] = ` -{ - "body": "##### Fixes - -- \`[jest-resolve]\` Use \`module.builtinModules\` as \`BUILTIN_MODULES\` when it - exists -- \`[jest-worker]\` Remove \`debug\` and \`inspect\` flags from the arguments sent to - the child ([#5068](https://github.com/facebook/jest/pull/5068)) -- \`[jest-config]\` Use all \`--testPathPattern\` and \`\` args in - \`testPathPattern\` ([#5066](https://github.com/facebook/jest/pull/5066)) -- \`[jest-cli]\` Do not support \`--watch\` inside non-version-controlled - environments ([#5060](https://github.com/facebook/jest/pull/5060)) -- \`[jest-config]\` Escape Windows path separator in testPathPattern CLI arguments - ([#5054](https://github.com/facebook/jest/pull/5054) -- \`[jest-jasmine]\` Register sourcemaps as node environment to improve - performance with jsdom ([#5045](https://github.com/facebook/jest/pull/5045)) -- \`[pretty-format]\` Do not call toJSON recursively - ([#5044](https://github.com/facebook/jest/pull/5044)) -- \`[pretty-format]\` Fix errors when identity-obj-proxy mocks CSS Modules - ([#4935](https://github.com/facebook/jest/pull/4935)) -- \`[babel-jest]\` Fix support for namespaced babel version 7 - ([#4918](https://github.com/facebook/jest/pull/4918)) -- \`[expect]\` fix .toThrow for promises - ([#4884](https://github.com/facebook/jest/pull/4884)) -- \`[jest-docblock]\` pragmas should preserve urls - ([#4837](https://github.com/facebook/jest/pull/4629)) -- \`[jest-cli]\` Check if \`npm_lifecycle_script\` calls Jest directly - ([#4629](https://github.com/facebook/jest/pull/4629)) -- \`[jest-cli]\` Fix --showConfig to show all configs - ([#4494](https://github.com/facebook/jest/pull/4494)) -- \`[jest-cli]\` Throw if \`maxWorkers\` doesn't have a value - ([#4591](https://github.com/facebook/jest/pull/4591)) -- \`[jest-cli]\` Use \`fs.realpathSync.native\` if available - ([#5031](https://github.com/facebook/jest/pull/5031)) -- \`[jest-config]\` Fix \`--passWithNoTests\` - ([#4639](https://github.com/facebook/jest/pull/4639)) -- \`[jest-config]\` Support \`rootDir\` tag in testEnvironment - ([#4579](https://github.com/facebook/jest/pull/4579)) -- \`[jest-editor-support]\` Fix \`--showConfig\` to support jest 20 and jest 21 - ([#4575](https://github.com/facebook/jest/pull/4575)) -- \`[jest-editor-support]\` Fix editor support test for node 4 - ([#4640](https://github.com/facebook/jest/pull/4640)) -- \`[jest-mock]\` Support mocking constructor in \`mockImplementationOnce\` - ([#4599](https://github.com/facebook/jest/pull/4599)) -- \`[jest-runtime]\` Fix manual user mocks not working with custom resolver - ([#4489](https://github.com/facebook/jest/pull/4489)) -- \`[jest-util]\` Fix \`runOnlyPendingTimers\` for \`setTimeout\` inside - \`setImmediate\` ([#4608](https://github.com/facebook/jest/pull/4608)) -- \`[jest-message-util]\` Always remove node internals from stacktraces - ([#4695](https://github.com/facebook/jest/pull/4695)) -- \`[jest-resolve]\` changes method of determining builtin modules to include - missing builtins ([#4740](https://github.com/facebook/jest/pull/4740)) -- \`[pretty-format]\` Prevent error in pretty-format for window in jsdom test env - ([#4750](https://github.com/facebook/jest/pull/4750)) -- \`[jest-resolve]\` Preserve module identity for symlinks - ([#4761](https://github.com/facebook/jest/pull/4761)) -- \`[jest-config]\` Include error message for \`preset\` json - ([#4766](https://github.com/facebook/jest/pull/4766)) -- \`[pretty-format]\` Throw \`PrettyFormatPluginError\` if a plugin halts with an - exception ([#4787](https://github.com/facebook/jest/pull/4787)) -- \`[expect]\` Keep the stack trace unchanged when \`PrettyFormatPluginError\` is - thrown by pretty-format ([#4787](https://github.com/facebook/jest/pull/4787)) -- \`[jest-environment-jsdom]\` Fix asynchronous test will fail due to timeout - issue. ([#4669](https://github.com/facebook/jest/pull/4669)) -- \`[jest-cli]\` Fix \`--onlyChanged\` path case sensitivity on Windows platform - ([#4730](https://github.com/facebook/jest/pull/4730)) -- \`[jest-runtime]\` Use realpath to match transformers - ([#5000](https://github.com/facebook/jest/pull/5000)) -- \`[expect]\` \\[**BREAKING**] Replace identity equality with Object.is in toBe - matcher ([#4917](https://github.com/facebook/jest/pull/4917)) - -##### Features - -- \`[jest-message-util]\` Add codeframe to test assertion failures - ([#5087](https://github.com/facebook/jest/pull/5087)) -- \`[jest-config]\` Add Global Setup/Teardown options - ([#4716](https://github.com/facebook/jest/pull/4716)) -- \`[jest-config]\` Add \`testEnvironmentOptions\` to apply to jsdom options or node - context. ([#5003](https://github.com/facebook/jest/pull/5003)) -- \`[jest-jasmine2]\` Update Timeout error message to \`jest.timeout\` and display - current timeout value ([#4990](https://github.com/facebook/jest/pull/4990)) -- \`[jest-runner]\` Enable experimental detection of leaked contexts - ([#4895](https://github.com/facebook/jest/pull/4895)) -- \`[jest-cli]\` Add combined coverage threshold for directories. - ([#4885](https://github.com/facebook/jest/pull/4885)) -- \`[jest-mock]\` Add \`timestamps\` to mock state. - ([#4866](https://github.com/facebook/jest/pull/4866)) -- \`[eslint-plugin-jest]\` Add \`prefer-to-have-length\` lint rule. - ([#4771](https://github.com/facebook/jest/pull/4771)) -- \`[jest-environment-jsdom]\` \\[**BREAKING**] Upgrade to JSDOM@11 - ([#4770](https://github.com/facebook/jest/pull/4770)) -- \`[jest-environment-*]\` \\[**BREAKING**] Add Async Test Environment APIs, dispose - is now teardown ([#4506](https://github.com/facebook/jest/pull/4506)) -- \`[jest-cli]\` Add an option to clear the cache - ([#4430](https://github.com/facebook/jest/pull/4430)) -- \`[babel-plugin-jest-hoist]\` Improve error message, that the second argument of - \`jest.mock\` must be an inline function - ([#4593](https://github.com/facebook/jest/pull/4593)) -- \`[jest-snapshot]\` \\[**BREAKING**] Concatenate name of test and snapshot - ([#4460](https://github.com/facebook/jest/pull/4460)) -- \`[jest-cli]\` \\[**BREAKING**] Fail if no tests are found - ([#3672](https://github.com/facebook/jest/pull/3672)) -- \`[jest-diff]\` Highlight only last of odd length leading spaces - ([#4558](https://github.com/facebook/jest/pull/4558)) -- \`[jest-docblock]\` Add \`docblock.print()\` - ([#4517](https://github.com/facebook/jest/pull/4517)) -- \`[jest-docblock]\` Add \`strip\` - ([#4571](https://github.com/facebook/jest/pull/4571)) -- \`[jest-docblock]\` Preserve leading whitespace in docblock comments - ([#4576](https://github.com/facebook/jest/pull/4576)) -- \`[jest-docblock]\` remove leading newlines from \`parswWithComments().comments\` - ([#4610](https://github.com/facebook/jest/pull/4610)) -- \`[jest-editor-support]\` Add Snapshots metadata - ([#4570](https://github.com/facebook/jest/pull/4570)) -- \`[jest-editor-support]\` Adds an 'any' to the typedef for - \`updateFileWithJestStatus\` - ([#4636](https://github.com/facebook/jest/pull/4636)) -- \`[jest-editor-support]\` Better monorepo support - ([#4572](https://github.com/facebook/jest/pull/4572)) -- \`[jest-environment-jsdom]\` Add simple rAF polyfill in jsdom environment to - work with React 16 ([#4568](https://github.com/facebook/jest/pull/4568)) -- \`[jest-environment-node]\` Implement node Timer api - ([#4622](https://github.com/facebook/jest/pull/4622)) -- \`[jest-jasmine2]\` Add testPath to reporter callbacks - ([#4594](https://github.com/facebook/jest/pull/4594)) -- \`[jest-mock]\` Added support for naming mocked functions with - \`.mockName(value)\` and \`.mockGetName()\` - ([#4586](https://github.com/facebook/jest/pull/4586)) -- \`[jest-runtime]\` Add \`module.loaded\`, and make \`module.require\` not enumerable - ([#4623](https://github.com/facebook/jest/pull/4623)) -- \`[jest-runtime]\` Add \`module.parent\` - ([#4614](https://github.com/facebook/jest/pull/4614)) -- \`[jest-runtime]\` Support sourcemaps in transformers - ([#3458](https://github.com/facebook/jest/pull/3458)) -- \`[jest-snapshot]\` \\[**BREAKING**] Add a serializer for \`jest.fn\` to allow a - snapshot of a jest mock ([#4668](https://github.com/facebook/jest/pull/4668)) -- \`[jest-worker]\` Initial version of parallel worker abstraction, say hello! - ([#4497](https://github.com/facebook/jest/pull/4497)) -- \`[jest-jasmine2]\` Add \`testLocationInResults\` flag to add location information - per spec to test results ([#4782](https://github.com/facebook/jest/pull/4782)) -- \`[jest-environment-jsdom]\` Update JSOM to 11.4, which includes built-in - support for \`requestAnimationFrame\` - ([#4919](https://github.com/facebook/jest/pull/4919)) -- \`[jest-cli]\` Hide watch usage output when running on non-interactive - environments ([#4958](https://github.com/facebook/jest/pull/4958)) -- \`[jest-snapshot]\` Promises support for \`toThrowErrorMatchingSnapshot\` - ([#4946](https://github.com/facebook/jest/pull/4946)) -- \`[jest-cli]\` Explain which snapshots are obsolete - ([#5005](https://github.com/facebook/jest/pull/5005)) - -##### Chore & Maintenance - -- \`[docs]\` Add guide of using with puppeteer - ([#5093](https://github.com/facebook/jest/pull/5093)) -- \`[jest-util]\` \`jest-util\` should not depend on \`jest-mock\` - ([#4992](https://github.com/facebook/jest/pull/4992)) -- \`[*]\` \\[**BREAKING**] Drop support for Node.js version 4 - ([#4769](https://github.com/facebook/jest/pull/4769)) -- \`[docs]\` Wrap code comments at 80 characters - ([#4781](https://github.com/facebook/jest/pull/4781)) -- \`[eslint-plugin-jest]\` Removed from the Jest core repo, and moved to - - ([#4867](https://github.com/facebook/jest/pull/4867)) -- \`[babel-jest]\` Explicitly bump istanbul to newer versions - ([#4616](https://github.com/facebook/jest/pull/4616)) -- \`[expect]\` Upgrade mocha and rollup for browser testing - ([#4642](https://github.com/facebook/jest/pull/4642)) -- \`[docs]\` Add info about \`coveragePathIgnorePatterns\` - ([#4602](https://github.com/facebook/jest/pull/4602)) -- \`[docs]\` Add Vuejs series of testing with Jest - ([#4648](https://github.com/facebook/jest/pull/4648)) -- \`[docs]\` Mention about optional \`done\` argument in test function - ([#4556](https://github.com/facebook/jest/pull/4556)) -- \`[jest-cli]\` Bump node-notifier version - ([#4609](https://github.com/facebook/jest/pull/4609)) -- \`[jest-diff]\` Simplify highlight for leading and trailing spaces - ([#4553](https://github.com/facebook/jest/pull/4553)) -- \`[jest-get-type]\` Add support for date - ([#4621](https://github.com/facebook/jest/pull/4621)) -- \`[jest-matcher-utils]\` Call \`chalk.inverse\` for trailing spaces - ([#4578](https://github.com/facebook/jest/pull/4578)) -- \`[jest-runtime]\` Add \`.advanceTimersByTime\`; keep \`.runTimersToTime()\` as an - alias. -- \`[docs]\` Include missing dependency in TestEnvironment sample code -- \`[docs]\` Add clarification for hook execution order -- \`[docs]\` Update \`expect.anything()\` sample code - ([#5007](https://github.com/facebook/jest/pull/5007)) -", - "notesSourceUrl": "https://github.com/facebook/jest/blob/HEAD/CHANGELOG.md", - "url": "https://github.com/facebook/jest/blob/HEAD/CHANGELOG.md#jest-2200", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses js-yaml 1`] = ` -{ - "body": "- Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370). -- Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368). -", - "notesSourceUrl": "https://github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md", - "url": "https://github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md#3100--2017-09-10", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes addReleaseNotes() getReleaseNotesMd() parses self hosted gitlab 1`] = ` -{ - "body": "- Removing markup from a part of the French translation, -- Fix typo documentation -> documentation, - - Thanks to [@auua](https://gitlab.com/auua) for the contribution -- Fix \`/channel\` slash command name regex to accept hyphenated names, - - Thanks to [@auua](https://gitlab.com/auua) for the contribution -- Add GitLab branding to the left-menu, -- Fix left-menu search state showing all rooms, -- Update Polish translation, - - Thanks to [@biesiad](https://gitlab.com/biesiad) for the contribution -", - "notesSourceUrl": "https://my.custom.domain/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md", - "url": "https://my.custom.domain/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md#20260---2020-05-18", -} -`; - exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd() ReleaseNotes Correctness handles gitlab sourceDirectory 1`] = ` { "body": "- add new auth, fix accept header and base path in mock @@ -786,216 +354,3 @@ exports[`workers/repository/update/pr/changelog/release-notes getReleaseNotesMd( "url": "https://my.custom.domain/gitlab-org/gitter/webapp/blob/HEAD/CHANGELOG.md#20260---2020-05-18", } `; - -exports[`workers/repository/update/pr/changelog/release-notes handles github sourceDirectory 1`] = ` -{ - "body": "- Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370). -- Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368). -", - "notesSourceUrl": "https://github.com/nodeca/js-yaml/blob/HEAD/packages/foo/CHANGELOG.md", - "url": "https://github.com/nodeca/js-yaml/blob/HEAD/packages/foo/CHANGELOG.md#3100--2017-09-10", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes parses jest 1`] = ` -{ - "body": "##### Fixes - -- \`[jest-resolve]\` Use \`module.builtinModules\` as \`BUILTIN_MODULES\` when it - exists -- \`[jest-worker]\` Remove \`debug\` and \`inspect\` flags from the arguments sent to - the child ([#5068](https://github.com/facebook/jest/pull/5068)) -- \`[jest-config]\` Use all \`--testPathPattern\` and \`\` args in - \`testPathPattern\` ([#5066](https://github.com/facebook/jest/pull/5066)) -- \`[jest-cli]\` Do not support \`--watch\` inside non-version-controlled - environments ([#5060](https://github.com/facebook/jest/pull/5060)) -- \`[jest-config]\` Escape Windows path separator in testPathPattern CLI arguments - ([#5054](https://github.com/facebook/jest/pull/5054) -- \`[jest-jasmine]\` Register sourcemaps as node environment to improve - performance with jsdom ([#5045](https://github.com/facebook/jest/pull/5045)) -- \`[pretty-format]\` Do not call toJSON recursively - ([#5044](https://github.com/facebook/jest/pull/5044)) -- \`[pretty-format]\` Fix errors when identity-obj-proxy mocks CSS Modules - ([#4935](https://github.com/facebook/jest/pull/4935)) -- \`[babel-jest]\` Fix support for namespaced babel version 7 - ([#4918](https://github.com/facebook/jest/pull/4918)) -- \`[expect]\` fix .toThrow for promises - ([#4884](https://github.com/facebook/jest/pull/4884)) -- \`[jest-docblock]\` pragmas should preserve urls - ([#4837](https://github.com/facebook/jest/pull/4629)) -- \`[jest-cli]\` Check if \`npm_lifecycle_script\` calls Jest directly - ([#4629](https://github.com/facebook/jest/pull/4629)) -- \`[jest-cli]\` Fix --showConfig to show all configs - ([#4494](https://github.com/facebook/jest/pull/4494)) -- \`[jest-cli]\` Throw if \`maxWorkers\` doesn't have a value - ([#4591](https://github.com/facebook/jest/pull/4591)) -- \`[jest-cli]\` Use \`fs.realpathSync.native\` if available - ([#5031](https://github.com/facebook/jest/pull/5031)) -- \`[jest-config]\` Fix \`--passWithNoTests\` - ([#4639](https://github.com/facebook/jest/pull/4639)) -- \`[jest-config]\` Support \`rootDir\` tag in testEnvironment - ([#4579](https://github.com/facebook/jest/pull/4579)) -- \`[jest-editor-support]\` Fix \`--showConfig\` to support jest 20 and jest 21 - ([#4575](https://github.com/facebook/jest/pull/4575)) -- \`[jest-editor-support]\` Fix editor support test for node 4 - ([#4640](https://github.com/facebook/jest/pull/4640)) -- \`[jest-mock]\` Support mocking constructor in \`mockImplementationOnce\` - ([#4599](https://github.com/facebook/jest/pull/4599)) -- \`[jest-runtime]\` Fix manual user mocks not working with custom resolver - ([#4489](https://github.com/facebook/jest/pull/4489)) -- \`[jest-util]\` Fix \`runOnlyPendingTimers\` for \`setTimeout\` inside - \`setImmediate\` ([#4608](https://github.com/facebook/jest/pull/4608)) -- \`[jest-message-util]\` Always remove node internals from stacktraces - ([#4695](https://github.com/facebook/jest/pull/4695)) -- \`[jest-resolve]\` changes method of determining builtin modules to include - missing builtins ([#4740](https://github.com/facebook/jest/pull/4740)) -- \`[pretty-format]\` Prevent error in pretty-format for window in jsdom test env - ([#4750](https://github.com/facebook/jest/pull/4750)) -- \`[jest-resolve]\` Preserve module identity for symlinks - ([#4761](https://github.com/facebook/jest/pull/4761)) -- \`[jest-config]\` Include error message for \`preset\` json - ([#4766](https://github.com/facebook/jest/pull/4766)) -- \`[pretty-format]\` Throw \`PrettyFormatPluginError\` if a plugin halts with an - exception ([#4787](https://github.com/facebook/jest/pull/4787)) -- \`[expect]\` Keep the stack trace unchanged when \`PrettyFormatPluginError\` is - thrown by pretty-format ([#4787](https://github.com/facebook/jest/pull/4787)) -- \`[jest-environment-jsdom]\` Fix asynchronous test will fail due to timeout - issue. ([#4669](https://github.com/facebook/jest/pull/4669)) -- \`[jest-cli]\` Fix \`--onlyChanged\` path case sensitivity on Windows platform - ([#4730](https://github.com/facebook/jest/pull/4730)) -- \`[jest-runtime]\` Use realpath to match transformers - ([#5000](https://github.com/facebook/jest/pull/5000)) -- \`[expect]\` \\[**BREAKING**] Replace identity equality with Object.is in toBe - matcher ([#4917](https://github.com/facebook/jest/pull/4917)) - -##### Features - -- \`[jest-message-util]\` Add codeframe to test assertion failures - ([#5087](https://github.com/facebook/jest/pull/5087)) -- \`[jest-config]\` Add Global Setup/Teardown options - ([#4716](https://github.com/facebook/jest/pull/4716)) -- \`[jest-config]\` Add \`testEnvironmentOptions\` to apply to jsdom options or node - context. ([#5003](https://github.com/facebook/jest/pull/5003)) -- \`[jest-jasmine2]\` Update Timeout error message to \`jest.timeout\` and display - current timeout value ([#4990](https://github.com/facebook/jest/pull/4990)) -- \`[jest-runner]\` Enable experimental detection of leaked contexts - ([#4895](https://github.com/facebook/jest/pull/4895)) -- \`[jest-cli]\` Add combined coverage threshold for directories. - ([#4885](https://github.com/facebook/jest/pull/4885)) -- \`[jest-mock]\` Add \`timestamps\` to mock state. - ([#4866](https://github.com/facebook/jest/pull/4866)) -- \`[eslint-plugin-jest]\` Add \`prefer-to-have-length\` lint rule. - ([#4771](https://github.com/facebook/jest/pull/4771)) -- \`[jest-environment-jsdom]\` \\[**BREAKING**] Upgrade to JSDOM@11 - ([#4770](https://github.com/facebook/jest/pull/4770)) -- \`[jest-environment-*]\` \\[**BREAKING**] Add Async Test Environment APIs, dispose - is now teardown ([#4506](https://github.com/facebook/jest/pull/4506)) -- \`[jest-cli]\` Add an option to clear the cache - ([#4430](https://github.com/facebook/jest/pull/4430)) -- \`[babel-plugin-jest-hoist]\` Improve error message, that the second argument of - \`jest.mock\` must be an inline function - ([#4593](https://github.com/facebook/jest/pull/4593)) -- \`[jest-snapshot]\` \\[**BREAKING**] Concatenate name of test and snapshot - ([#4460](https://github.com/facebook/jest/pull/4460)) -- \`[jest-cli]\` \\[**BREAKING**] Fail if no tests are found - ([#3672](https://github.com/facebook/jest/pull/3672)) -- \`[jest-diff]\` Highlight only last of odd length leading spaces - ([#4558](https://github.com/facebook/jest/pull/4558)) -- \`[jest-docblock]\` Add \`docblock.print()\` - ([#4517](https://github.com/facebook/jest/pull/4517)) -- \`[jest-docblock]\` Add \`strip\` - ([#4571](https://github.com/facebook/jest/pull/4571)) -- \`[jest-docblock]\` Preserve leading whitespace in docblock comments - ([#4576](https://github.com/facebook/jest/pull/4576)) -- \`[jest-docblock]\` remove leading newlines from \`parswWithComments().comments\` - ([#4610](https://github.com/facebook/jest/pull/4610)) -- \`[jest-editor-support]\` Add Snapshots metadata - ([#4570](https://github.com/facebook/jest/pull/4570)) -- \`[jest-editor-support]\` Adds an 'any' to the typedef for - \`updateFileWithJestStatus\` - ([#4636](https://github.com/facebook/jest/pull/4636)) -- \`[jest-editor-support]\` Better monorepo support - ([#4572](https://github.com/facebook/jest/pull/4572)) -- \`[jest-environment-jsdom]\` Add simple rAF polyfill in jsdom environment to - work with React 16 ([#4568](https://github.com/facebook/jest/pull/4568)) -- \`[jest-environment-node]\` Implement node Timer api - ([#4622](https://github.com/facebook/jest/pull/4622)) -- \`[jest-jasmine2]\` Add testPath to reporter callbacks - ([#4594](https://github.com/facebook/jest/pull/4594)) -- \`[jest-mock]\` Added support for naming mocked functions with - \`.mockName(value)\` and \`.mockGetName()\` - ([#4586](https://github.com/facebook/jest/pull/4586)) -- \`[jest-runtime]\` Add \`module.loaded\`, and make \`module.require\` not enumerable - ([#4623](https://github.com/facebook/jest/pull/4623)) -- \`[jest-runtime]\` Add \`module.parent\` - ([#4614](https://github.com/facebook/jest/pull/4614)) -- \`[jest-runtime]\` Support sourcemaps in transformers - ([#3458](https://github.com/facebook/jest/pull/3458)) -- \`[jest-snapshot]\` \\[**BREAKING**] Add a serializer for \`jest.fn\` to allow a - snapshot of a jest mock ([#4668](https://github.com/facebook/jest/pull/4668)) -- \`[jest-worker]\` Initial version of parallel worker abstraction, say hello! - ([#4497](https://github.com/facebook/jest/pull/4497)) -- \`[jest-jasmine2]\` Add \`testLocationInResults\` flag to add location information - per spec to test results ([#4782](https://github.com/facebook/jest/pull/4782)) -- \`[jest-environment-jsdom]\` Update JSOM to 11.4, which includes built-in - support for \`requestAnimationFrame\` - ([#4919](https://github.com/facebook/jest/pull/4919)) -- \`[jest-cli]\` Hide watch usage output when running on non-interactive - environments ([#4958](https://github.com/facebook/jest/pull/4958)) -- \`[jest-snapshot]\` Promises support for \`toThrowErrorMatchingSnapshot\` - ([#4946](https://github.com/facebook/jest/pull/4946)) -- \`[jest-cli]\` Explain which snapshots are obsolete - ([#5005](https://github.com/facebook/jest/pull/5005)) - -##### Chore & Maintenance - -- \`[docs]\` Add guide of using with puppeteer - ([#5093](https://github.com/facebook/jest/pull/5093)) -- \`[jest-util]\` \`jest-util\` should not depend on \`jest-mock\` - ([#4992](https://github.com/facebook/jest/pull/4992)) -- \`[*]\` \\[**BREAKING**] Drop support for Node.js version 4 - ([#4769](https://github.com/facebook/jest/pull/4769)) -- \`[docs]\` Wrap code comments at 80 characters - ([#4781](https://github.com/facebook/jest/pull/4781)) -- \`[eslint-plugin-jest]\` Removed from the Jest core repo, and moved to - - ([#4867](https://github.com/facebook/jest/pull/4867)) -- \`[babel-jest]\` Explicitly bump istanbul to newer versions - ([#4616](https://github.com/facebook/jest/pull/4616)) -- \`[expect]\` Upgrade mocha and rollup for browser testing - ([#4642](https://github.com/facebook/jest/pull/4642)) -- \`[docs]\` Add info about \`coveragePathIgnorePatterns\` - ([#4602](https://github.com/facebook/jest/pull/4602)) -- \`[docs]\` Add Vuejs series of testing with Jest - ([#4648](https://github.com/facebook/jest/pull/4648)) -- \`[docs]\` Mention about optional \`done\` argument in test function - ([#4556](https://github.com/facebook/jest/pull/4556)) -- \`[jest-cli]\` Bump node-notifier version - ([#4609](https://github.com/facebook/jest/pull/4609)) -- \`[jest-diff]\` Simplify highlight for leading and trailing spaces - ([#4553](https://github.com/facebook/jest/pull/4553)) -- \`[jest-get-type]\` Add support for date - ([#4621](https://github.com/facebook/jest/pull/4621)) -- \`[jest-matcher-utils]\` Call \`chalk.inverse\` for trailing spaces - ([#4578](https://github.com/facebook/jest/pull/4578)) -- \`[jest-runtime]\` Add \`.advanceTimersByTime\`; keep \`.runTimersToTime()\` as an - alias. -- \`[docs]\` Include missing dependency in TestEnvironment sample code -- \`[docs]\` Add clarification for hook execution order -- \`[docs]\` Update \`expect.anything()\` sample code - ([#5007](https://github.com/facebook/jest/pull/5007)) -", - "notesSourceUrl": "https://github.com/facebook/jest/blob/HEAD/CHANGELOG.md", - "url": "https://github.com/facebook/jest/blob/HEAD/CHANGELOG.md#jest-2200", -} -`; - -exports[`workers/repository/update/pr/changelog/release-notes parses js-yaml 1`] = ` -{ - "body": "- Fix \`condenseFlow\` output (quote keys for sure, instead of spaces), [#371](https://github.com/nodeca/js-yaml/issues/371), [#370](https://github.com/nodeca/js-yaml/issues/370). -- Dump astrals as codepoints instead of surrogate pair, [#368](https://github.com/nodeca/js-yaml/issues/368). -", - "notesSourceUrl": "https://github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md", - "url": "https://github.com/nodeca/js-yaml/blob/HEAD/CHANGELOG.md#3100--2017-09-10", -} -`; From 2811c1c8679a8d3d895661a19ff494d1b890b6ed Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Mon, 26 Jun 2023 05:16:29 -0400 Subject: [PATCH 52/71] tests: add bitbucket tests --- lib/util/common.spec.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/util/common.spec.ts b/lib/util/common.spec.ts index b7c354a2bff2a6..b74ba872265648 100644 --- a/lib/util/common.spec.ts +++ b/lib/util/common.spec.ts @@ -15,6 +15,8 @@ describe('util/common', () => { ${'https://gitlab-enterprise.example.com/chalk/chalk'} | ${'gitlab'} ${'https://dev.azure.com/my-organization/my-project/_git/my-repo.git'} | ${'azure'} ${'https://myorg.visualstudio.com/my-project/_git/my-repo.git'} | ${'azure'} + ${'https://bitbucket.org/some-org/some-repo'} | ${'bitbucket'} + ${'https://bitbucket.com/some-org/some-repo'} | ${'bitbucket'} `('("$url") === $hostType', ({ url, hostType }) => { expect(detectPlatform(url)).toBe(hostType); }); @@ -32,12 +34,19 @@ describe('util/common', () => { hostType: 'gitea', matchHost: 'gt.example.com', }); + hostRules.add({ + hostType: 'bitbucket', + matchHost: 'bb.example.com', + }); expect(detectPlatform('https://gl.example.com/chalk/chalk')).toBe( 'gitlab' ); expect(detectPlatform('https://gh.example.com/chalk/chalk')).toBe( 'github' ); + expect(detectPlatform('https://bb.example.com/chalk/chalk')).toBe( + 'bitbucket' + ); expect(detectPlatform('https://gt.example.com/chalk/chalk')).toBeNull(); }); }); From 24805dfff37678eb332bce0eb7094a196eb95a10 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Tue, 27 Jun 2023 06:38:53 -0400 Subject: [PATCH 53/71] Update lib/workers/repository/update/pr/changelog/source.ts Co-authored-by: Sebastian Poxhofer --- lib/workers/repository/update/pr/changelog/source.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index bb53970a38dc12..cfeaffd7de2bd2 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -199,17 +199,10 @@ export abstract class ChangeLogSource { const exactTagsList = tags.filter((tag) => { return exactReleaseRegex.test(tag); }); - let tagName: string | undefined; - if (exactTagsList.length) { - tagName = exactTagsList + let tagList = exactTagsList.length ? exactTagsList : tags + return tagList .filter((tag) => version.isVersion(tag.replace(regex, ''))) .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); - } else { - tagName = tags - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); - } - return tagName; } private async getRef( From ac726339f56a61f065d77b8a9407525ca3323ae8 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Tue, 27 Jun 2023 06:39:18 -0400 Subject: [PATCH 54/71] change to const --- lib/workers/repository/update/pr/changelog/source.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index cfeaffd7de2bd2..ef8c679e9284ef 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -199,10 +199,10 @@ export abstract class ChangeLogSource { const exactTagsList = tags.filter((tag) => { return exactReleaseRegex.test(tag); }); - let tagList = exactTagsList.length ? exactTagsList : tags + const tagList = exactTagsList.length ? exactTagsList : tags; return tagList - .filter((tag) => version.isVersion(tag.replace(regex, ''))) - .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); + .filter((tag) => version.isVersion(tag.replace(regex, ''))) + .find((tag) => version.equals(tag.replace(regex, ''), depNewVersion)); } private async getRef( From 3ec58806b274ea589e77db0dc4d0bde2da4b0194 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Tue, 27 Jun 2023 06:41:30 -0400 Subject: [PATCH 55/71] refactor: move to api --- lib/workers/repository/update/pr/changelog/api.ts | 11 +++++++++++ lib/workers/repository/update/pr/changelog/index.ts | 11 ++--------- 2 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 lib/workers/repository/update/pr/changelog/api.ts diff --git a/lib/workers/repository/update/pr/changelog/api.ts b/lib/workers/repository/update/pr/changelog/api.ts new file mode 100644 index 00000000000000..f7be6b40936472 --- /dev/null +++ b/lib/workers/repository/update/pr/changelog/api.ts @@ -0,0 +1,11 @@ +import type { ChangeLogSource } from './source'; +import { BitbucketChangeLogSource } from './source-bitbucket'; +import { GitHubChangeLogSource } from './source-github'; +import { GitLabChangeLogSource } from './source-gitlab'; + +const api = new Map(); +export default api; + +api.set('gitlab', new GitLabChangeLogSource()); +api.set('github', new GitHubChangeLogSource()); +api.set('bitbucket', new BitbucketChangeLogSource()); diff --git a/lib/workers/repository/update/pr/changelog/index.ts b/lib/workers/repository/update/pr/changelog/index.ts index 2916643b20e557..229c40c0e95136 100644 --- a/lib/workers/repository/update/pr/changelog/index.ts +++ b/lib/workers/repository/update/pr/changelog/index.ts @@ -3,10 +3,8 @@ import { logger } from '../../../../../logger'; import * as allVersioning from '../../../../../modules/versioning'; import { detectPlatform } from '../../../../../util/common'; import type { BranchUpgradeConfig } from '../../../../types'; +import api from './api'; import type { ChangeLogSource } from './source'; -import { BitbucketChangeLogSource } from './source-bitbucket'; -import { GitHubChangeLogSource } from './source-github'; -import { GitLabChangeLogSource } from './source-gitlab'; import type { ChangeLogResult } from './types'; export * from './types'; @@ -56,13 +54,8 @@ export async function getChangeLogJSON( } } -const changeLogSources = new Map(); -changeLogSources.set('gitlab', new GitLabChangeLogSource()); -changeLogSources.set('github', new GitHubChangeLogSource()); -changeLogSources.set('bitbucket', new BitbucketChangeLogSource()); - export function getChangeLogSourceFor( platform: string ): ChangeLogSource | null { - return changeLogSources.get(platform) ?? null; + return api.get(platform) ?? null; } From 0c8d9d33142947b87d71dbbcef975aade47c9af9 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Tue, 27 Jun 2023 06:56:35 -0400 Subject: [PATCH 56/71] remove bang --- lib/workers/repository/update/pr/changelog/source.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/source.ts b/lib/workers/repository/update/pr/changelog/source.ts index ef8c679e9284ef..7a1498b1837209 100644 --- a/lib/workers/repository/update/pr/changelog/source.ts +++ b/lib/workers/repository/update/pr/changelog/source.ts @@ -71,7 +71,7 @@ export abstract class ChangeLogSource { const newVersion = config.newVersion!; const sourceUrl = config.sourceUrl!; const packageName = config.packageName!; - const sourceDirectory = config.sourceDirectory!; + const sourceDirectory = config.sourceDirectory; const version = allVersioning.get(versioning); if (this.shouldSkipPackage(config)) { From 4f9158d62257c1ad0f9cdc08b580de56899e09cf Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Tue, 27 Jun 2023 19:40:25 -0400 Subject: [PATCH 57/71] feedback: add zod schema --- lib/modules/platform/bitbucket/schema.ts | 27 +++++++++++++++++++ .../update/pr/changelog/bitbucket/index.ts | 10 +++---- 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 lib/modules/platform/bitbucket/schema.ts diff --git a/lib/modules/platform/bitbucket/schema.ts b/lib/modules/platform/bitbucket/schema.ts new file mode 100644 index 00000000000000..8654d9879f797d --- /dev/null +++ b/lib/modules/platform/bitbucket/schema.ts @@ -0,0 +1,27 @@ +import { ZodSchema, z } from 'zod'; +import type { PagedResult, SourceResults } from './types'; + +const BitbucketSourceTypeSchema = z.enum(['commit_directory', 'commit_file']); + +const SourceResultsSchema: ZodSchema = z.object({ + path: z.string(), + type: BitbucketSourceTypeSchema, + commit: z.object({ + hash: z.string(), + }), +}); + +export const PagedSourceResultsSchema = + createPagedResultSchema(SourceResultsSchema); + +function createPagedResultSchema( + valuesSchema: ZodSchema +): ZodSchema> { + return z.object({ + page: z.number().optional(), + pagelen: z.number(), + size: z.number().optional(), + next: z.string().optional(), + values: z.array(valuesSchema), + }); +} diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index 610161f1c48c65..a47a73d1280208 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -1,10 +1,7 @@ import is from '@sindresorhus/is'; import changelogFilenameRegex from 'changelog-filename-regex'; import { logger } from '../../../../../../logger'; -import type { - PagedResult, - SourceResults, -} from '../../../../../../modules/platform/bitbucket/types'; +import { PagedSourceResultsSchema } from '../../../../../../modules/platform/bitbucket/schema'; import { BitbucketHttp } from '../../../../../../util/http/bitbucket'; import { joinUrlParts } from '../../../../../../util/url'; import type { @@ -32,11 +29,12 @@ export async function getReleaseNotesMd( ); const rootFiles = ( - await bitbucketHttp.getJson>( + await bitbucketHttp.getJson( repositorySourceURl, { paginate: true, - } + }, + PagedSourceResultsSchema ) ).body.values; From 8dc8cabc7ab7eb84f9aa838d04373cf90ab6c66f Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Wed, 28 Jun 2023 06:09:48 -0400 Subject: [PATCH 58/71] zod, take two --- lib/modules/platform/bitbucket/schema.ts | 27 ++++++++++-------------- lib/modules/platform/bitbucket/types.ts | 10 --------- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/lib/modules/platform/bitbucket/schema.ts b/lib/modules/platform/bitbucket/schema.ts index 8654d9879f797d..48104f2dc55e90 100644 --- a/lib/modules/platform/bitbucket/schema.ts +++ b/lib/modules/platform/bitbucket/schema.ts @@ -1,9 +1,8 @@ -import { ZodSchema, z } from 'zod'; -import type { PagedResult, SourceResults } from './types'; +import { z } from 'zod'; const BitbucketSourceTypeSchema = z.enum(['commit_directory', 'commit_file']); -const SourceResultsSchema: ZodSchema = z.object({ +const SourceResultsSchema = z.object({ path: z.string(), type: BitbucketSourceTypeSchema, commit: z.object({ @@ -11,17 +10,13 @@ const SourceResultsSchema: ZodSchema = z.object({ }), }); -export const PagedSourceResultsSchema = - createPagedResultSchema(SourceResultsSchema); +const PagedSchema = z.object({ + page: z.number().optional(), + pagelen: z.number(), + size: z.number().optional(), + next: z.string().optional(), +}); -function createPagedResultSchema( - valuesSchema: ZodSchema -): ZodSchema> { - return z.object({ - page: z.number().optional(), - pagelen: z.number(), - size: z.number().optional(), - next: z.string().optional(), - values: z.array(valuesSchema), - }); -} +export const PagedSourceResultsSchema = PagedSchema.extend({ + values: z.array(SourceResultsSchema), +}); diff --git a/lib/modules/platform/bitbucket/types.ts b/lib/modules/platform/bitbucket/types.ts index eb1582ba9c9246..b3b95bb0f16cf7 100644 --- a/lib/modules/platform/bitbucket/types.ts +++ b/lib/modules/platform/bitbucket/types.ts @@ -102,13 +102,3 @@ export interface EffectiveReviewer { reviewer_type: string; user: Account; } - -export interface SourceResults { - path: string; - type: BitbucketSourceType; - commit: { - hash: string; - }; -} - -export type BitbucketSourceType = 'commit_directory' | 'commit_file'; From af260d57a62f702332ced3b7117e94e7a64d4398 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 05:14:08 -0400 Subject: [PATCH 59/71] reorder alpha --- lib/constants/platforms.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/constants/platforms.ts b/lib/constants/platforms.ts index 79814fb137e421..47f16640debaa1 100644 --- a/lib/constants/platforms.ts +++ b/lib/constants/platforms.ts @@ -28,6 +28,6 @@ export const GITLAB_API_USING_HOST_TYPES = [ export const BITBUCKET_API_USING_HOST_TYPES = [ 'bitbucket', - 'bitbucket-tags', 'bitbucket-changelog', + 'bitbucket-tags', ]; From e92219d2a73136386fbb7c8642434fb1965898e0 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 05:17:19 -0400 Subject: [PATCH 60/71] refactor --- lib/util/common.spec.ts | 3 +-- lib/workers/repository/update/pr/changelog/release-notes.ts | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/util/common.spec.ts b/lib/util/common.spec.ts index b3d92dff58f936..4ed8919ea95cc1 100644 --- a/lib/util/common.spec.ts +++ b/lib/util/common.spec.ts @@ -17,8 +17,6 @@ describe('util/common', () => { ${'https://github-enterprise.example.com/chalk/chalk'} | ${'github'} ${'https://gitlab.com/chalk/chalk'} | ${'gitlab'} ${'https://gitlab-enterprise.example.com/chalk/chalk'} | ${'gitlab'} - ${'https://dev.azure.com/my-organization/my-project/_git/my-repo.git'} | ${'azure'} - ${'https://myorg.visualstudio.com/my-project/_git/my-repo.git'} | ${'azure'} `('("$url") === $hostType', ({ url, hostType }) => { expect(detectPlatform(url)).toBe(hostType); }); @@ -40,6 +38,7 @@ describe('util/common', () => { hostType: 'gitlab-changelog', matchHost: 'gl.example.com', }); + expect(detectPlatform('https://bb.example.com/chalk/chalk')).toBe( 'bitbucket' ); diff --git a/lib/workers/repository/update/pr/changelog/release-notes.ts b/lib/workers/repository/update/pr/changelog/release-notes.ts index e409547e323288..b4db11ab34d740 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.ts @@ -250,7 +250,6 @@ export async function getReleaseNotesMdFileInner( const { repository, type } = project; const apiBaseUrl = project.apiBaseUrl!; const sourceDirectory = project.sourceDirectory!; - try { switch (type) { case 'gitlab': @@ -321,7 +320,6 @@ export async function getReleaseNotesMd( return null; } const changelog = await getReleaseNotesMdFile(project); - if (!changelog) { return null; } From 7b65d873d7dbe923750f8b71438ce1bedd36c341 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 05:32:20 -0400 Subject: [PATCH 61/71] refactor --- .../repository/update/pr/changelog/api.ts | 2 +- .../update/pr/changelog/bitbucket.spec.ts | 64 ------- .../pr/changelog/bitbucket/bitbucket.spec.ts | 164 ++++++++++++++++++ .../source.ts} | 4 +- .../update/pr/changelog/release-notes.spec.ts | 91 ---------- 5 files changed, 167 insertions(+), 158 deletions(-) delete mode 100644 lib/workers/repository/update/pr/changelog/bitbucket.spec.ts create mode 100644 lib/workers/repository/update/pr/changelog/bitbucket/bitbucket.spec.ts rename lib/workers/repository/update/pr/changelog/{source-bitbucket.ts => bitbucket/source.ts} (84%) diff --git a/lib/workers/repository/update/pr/changelog/api.ts b/lib/workers/repository/update/pr/changelog/api.ts index ec0a4ca96f9d01..d4fa3edb6da822 100644 --- a/lib/workers/repository/update/pr/changelog/api.ts +++ b/lib/workers/repository/update/pr/changelog/api.ts @@ -1,5 +1,5 @@ +import { BitbucketChangeLogSource } from './bitbucket/source'; import type { ChangeLogSource } from './source'; -import { BitbucketChangeLogSource } from './source-bitbucket'; import { GitHubChangeLogSource } from './source-github'; import { GitLabChangeLogSource } from './source-gitlab'; diff --git a/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts deleted file mode 100644 index 54f1d8838ab8a6..00000000000000 --- a/lib/workers/repository/update/pr/changelog/bitbucket.spec.ts +++ /dev/null @@ -1,64 +0,0 @@ -import * as httpMock from '../../../../../../test/http-mock'; -import { partial } from '../../../../../../test/util'; -import * as semverVersioning from '../../../../../modules/versioning/semver'; -import type { BranchUpgradeConfig } from '../../../../types'; -import { getChangeLogJSON } from '.'; - -jest.mock('../../../../../modules/datasource/npm'); - -const upgrade = partial({ - manager: 'some-manager', - branchName: '', - endpoint: 'https://api.bitbucket.org/', - packageName: 'some-repo', - versioning: semverVersioning.id, - currentVersion: '5.2.0', - newVersion: '5.7.0', - sourceUrl: 'https://bitbucket.org/some-org/some-repo', - releases: [ - { version: '5.2.0' }, - { - version: '5.4.0', - releaseTimestamp: '2018-08-24T14:23:00.000Z', - }, - { version: '5.5.0', gitRef: 'abcd' }, - { - version: '5.6.0', - gitRef: '1234', - releaseTimestamp: '2020-02-13T15:37:00.000Z', - }, - { version: '5.6.1', gitRef: 'asdf' }, - ], -}); - -describe('workers/repository/update/pr/changelog/bitbucket', () => { - afterEach(() => { - // FIXME: add missing http mocks - httpMock.clear(false); - }); - - it('works with Bitbucket', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - }) - ).toEqual({ - hasReleaseNotes: true, - project: { - apiBaseUrl: 'https://api.bitbucket.org/', - baseUrl: 'https://bitbucket.org/', - packageName: 'some-repo', - repository: 'some-org/some-repo', - sourceDirectory: undefined, - sourceUrl: 'https://bitbucket.org/some-org/some-repo', - type: 'bitbucket', - }, - versions: [ - expect.objectContaining({ version: '5.6.1' }), - expect.objectContaining({ version: '5.6.0' }), - expect.objectContaining({ version: '5.5.0' }), - expect.objectContaining({ version: '5.4.0' }), - ], - }); - }); -}); diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/bitbucket.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket/bitbucket.spec.ts new file mode 100644 index 00000000000000..7601ff7ce2c557 --- /dev/null +++ b/lib/workers/repository/update/pr/changelog/bitbucket/bitbucket.spec.ts @@ -0,0 +1,164 @@ +import { ChangeLogProject, ChangeLogRelease, getChangeLogJSON } from '..'; +import { Fixtures } from '../../../../../../../test/fixtures'; +import * as httpMock from '../../../../../../../test/http-mock'; +import { mocked, partial } from '../../../../../../../test/util'; +import * as semverVersioning from '../../../../../../modules/versioning/semver'; +import * as _hostRules from '../../../../../../util/host-rules'; +import type { BranchUpgradeConfig } from '../../../../../types'; +import { getReleaseNotesMd } from '../release-notes'; + +jest.mock('../../../../../../modules/datasource/npm'); +jest.mock('../../../../../../util/host-rules'); + +const hostRules = mocked(_hostRules); + +const changelogMd = Fixtures.get('gitter-webapp.md', '../..'); + +const upgrade = partial({ + manager: 'some-manager', + branchName: '', + endpoint: 'https://api.bitbucket.org/', + packageName: 'some-repo', + versioning: semverVersioning.id, + currentVersion: '5.2.0', + newVersion: '5.7.0', + sourceUrl: 'https://bitbucket.org/some-org/some-repo', + releases: [ + { version: '5.2.0' }, + { + version: '5.4.0', + releaseTimestamp: '2018-08-24T14:23:00.000Z', + }, + { version: '5.5.0', gitRef: 'abcd' }, + { + version: '5.6.0', + gitRef: '1234', + releaseTimestamp: '2020-02-13T15:37:00.000Z', + }, + { version: '5.6.1', gitRef: 'asdf' }, + ], +}); + +const bitbucketTreeResponse = { + values: [ + { + type: 'commit_directory', + path: 'lib', + commit: { + hash: '1234', + }, + }, + { + type: 'commit_file', + path: 'CHANGELOG.md', + commit: { + hash: 'abcd', + }, + }, + { + type: 'commit_file', + path: 'RELEASE_NOTES.md', + commit: { + hash: 'asdf', + }, + }, + ], +}; + +const bitbucketTreeResponseNoChangelogFiles = { + values: [ + { + type: 'commit_directory', + path: 'lib', + commit: { + hash: '1234', + }, + }, + ], +}; + +const bitbucketProject = partial({ + type: 'bitbucket', + apiBaseUrl: 'https://api.bitbucket.org', + baseUrl: 'https://bitbucket.org/', +}); + +describe('workers/repository/update/pr/changelog/bitbucket/bitbucket', () => { + afterEach(() => { + // FIXME: add missing http mocks + httpMock.clear(false); + }); + + it('works with Bitbucket', async () => { + expect( + await getChangeLogJSON({ + ...upgrade, + }) + ).toEqual({ + hasReleaseNotes: true, + project: { + apiBaseUrl: 'https://api.bitbucket.org/', + baseUrl: 'https://bitbucket.org/', + packageName: 'some-repo', + repository: 'some-org/some-repo', + sourceDirectory: undefined, + sourceUrl: 'https://bitbucket.org/some-org/some-repo', + type: 'bitbucket', + }, + versions: [ + expect.objectContaining({ version: '5.6.1' }), + expect.objectContaining({ version: '5.6.0' }), + expect.objectContaining({ version: '5.5.0' }), + expect.objectContaining({ version: '5.4.0' }), + ], + }); + }); + + it('bitbucket: parses changelog', async () => { + hostRules.find.mockReturnValue({ token: 'some-token' }); + jest.setTimeout(0); + httpMock + .scope('https://api.bitbucket.org/') + .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') + .reply(200, bitbucketTreeResponse) + .get('/2.0/repositories/some-org/some-repo/src/abcd/CHANGELOG.md') + .reply(200, changelogMd); + const res = await getReleaseNotesMd( + { + ...bitbucketProject, + repository: 'some-org/some-repo', + apiBaseUrl: 'https://api.bitbucket.org/', + baseUrl: 'https://bitbucket.org/', + }, + partial({ + version: '20.26.0', + gitRef: '20.26.0', + }) + ); + + expect(res?.notesSourceUrl).toBe( + 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md' + ); + expect(res?.url).toBe( + 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md#20260---2020-05-18' + ); + }); + + it('bitbucket: handles not found', async () => { + httpMock + .scope('https://api.bitbucket.org/') + .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') + .reply(200, bitbucketTreeResponseNoChangelogFiles); + const res = await getReleaseNotesMd( + { + ...bitbucketProject, + repository: 'some-org/some-repo', + }, + partial({ + version: '2.0.0', + gitRef: '2.0.0', + }) + ); + expect(res).toBeNull(); + }); +}); diff --git a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts similarity index 84% rename from lib/workers/repository/update/pr/changelog/source-bitbucket.ts rename to lib/workers/repository/update/pr/changelog/bitbucket/source.ts index 17ef5457c8d16a..6ba2da5ec7aade 100644 --- a/lib/workers/repository/update/pr/changelog/source-bitbucket.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts @@ -1,6 +1,6 @@ import URL from 'node:url'; -import type { BranchUpgradeConfig } from '../../../../types'; -import { ChangeLogSource } from './source'; +import type { BranchUpgradeConfig } from '../../../../../types'; +import { ChangeLogSource } from '../source'; export class BitbucketChangeLogSource extends ChangeLogSource { constructor() { diff --git a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts index 75134833e6eb8f..7f3071e55919f2 100644 --- a/lib/workers/repository/update/pr/changelog/release-notes.spec.ts +++ b/lib/workers/repository/update/pr/changelog/release-notes.spec.ts @@ -47,43 +47,6 @@ const gitlabTreeResponse = [ { path: 'README.md', name: 'README.md', type: 'blob' }, ]; -const bitbucketTreeResponse = { - values: [ - { - type: 'commit_directory', - path: 'lib', - commit: { - hash: '1234', - }, - }, - { - type: 'commit_file', - path: 'CHANGELOG.md', - commit: { - hash: 'abcd', - }, - }, - { - type: 'commit_file', - path: 'RELEASE_NOTES.md', - commit: { - hash: 'asdf', - }, - }, - ], -}; - -const bitbucketTreeResponseNoChangelogFiles = { - values: [ - { - type: 'commit_directory', - path: 'lib', - commit: { - hash: '1234', - }, - }, - ], -}; const githubProject = partial({ type: 'github', apiBaseUrl: 'https://api.github.com/', @@ -96,12 +59,6 @@ const gitlabProject = partial({ baseUrl: 'https://gitlab.com/', }); -const bitbucketProject = partial({ - type: 'bitbucket', - apiBaseUrl: 'https://api.bitbucket.org', - baseUrl: 'https://bitbucket.org/', -}); - describe('workers/repository/update/pr/changelog/release-notes', () => { const githubReleasesMock = jest.spyOn(githubGraphql, 'queryReleases'); @@ -1147,54 +1104,6 @@ describe('workers/repository/update/pr/changelog/release-notes', () => { }); }); - it('bitbucket: parses changelog', async () => { - hostRules.find.mockReturnValue({ token: 'some-token' }); - jest.setTimeout(0); - httpMock - .scope('https://api.bitbucket.org/') - .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') - .reply(200, bitbucketTreeResponse) - .get('/2.0/repositories/some-org/some-repo/src/abcd/CHANGELOG.md') - .reply(200, gitterWebappChangelogMd); - const res = await getReleaseNotesMd( - { - ...bitbucketProject, - repository: 'some-org/some-repo', - apiBaseUrl: 'https://api.bitbucket.org/', - baseUrl: 'https://bitbucket.org/', - }, - partial({ - version: '20.26.0', - gitRef: '20.26.0', - }) - ); - - expect(res?.notesSourceUrl).toBe( - 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md' - ); - expect(res?.url).toBe( - 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md#20260---2020-05-18' - ); - }); - - it('bitbucket: handles not found', async () => { - httpMock - .scope('https://api.bitbucket.org/') - .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') - .reply(200, bitbucketTreeResponseNoChangelogFiles); - const res = await getReleaseNotesMd( - { - ...bitbucketProject, - repository: 'some-org/some-repo', - }, - partial({ - version: '2.0.0', - gitRef: '2.0.0', - }) - ); - expect(res).toBeNull(); - }); - it('parses jest', async () => { httpMock .scope('https://api.github.com') From 72d79e76c05207022e371b11dfbb1c5af64478b9 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 05:37:02 -0400 Subject: [PATCH 62/71] refactor --- lib/modules/platform/bitbucket/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/modules/platform/bitbucket/types.ts b/lib/modules/platform/bitbucket/types.ts index b3b95bb0f16cf7..d11477412b963b 100644 --- a/lib/modules/platform/bitbucket/types.ts +++ b/lib/modules/platform/bitbucket/types.ts @@ -19,7 +19,6 @@ export interface Config { } export interface PagedResult { - page?: number; pagelen: number; size?: number; next?: string; From ec26c10ecd241b4dd2c79c2a9a0bf662c98cb3f3 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 08:46:14 -0400 Subject: [PATCH 63/71] rename test --- .../pr/changelog/bitbucket/{bitbucket.spec.ts => index.spec.ts} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename lib/workers/repository/update/pr/changelog/bitbucket/{bitbucket.spec.ts => index.spec.ts} (98%) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/bitbucket.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts similarity index 98% rename from lib/workers/repository/update/pr/changelog/bitbucket/bitbucket.spec.ts rename to lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts index 7601ff7ce2c557..e3ec41ffd2038f 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/bitbucket.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts @@ -83,7 +83,7 @@ const bitbucketProject = partial({ baseUrl: 'https://bitbucket.org/', }); -describe('workers/repository/update/pr/changelog/bitbucket/bitbucket', () => { +describe('workers/repository/update/pr/changelog/bitbucket/index', () => { afterEach(() => { // FIXME: add missing http mocks httpMock.clear(false); From ea14d7693e1ec1fc154679d05d4c58f23323c452 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 08:46:24 -0400 Subject: [PATCH 64/71] refactor: use url util --- .../update/pr/changelog/bitbucket/source.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/source.ts b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts index 6ba2da5ec7aade..f9e59d405efcea 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/source.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts @@ -1,4 +1,4 @@ -import URL from 'node:url'; +import { parseUrl } from '../../../../../../util/url'; import type { BranchUpgradeConfig } from '../../../../../types'; import { ChangeLogSource } from '../source'; @@ -8,9 +8,12 @@ export class BitbucketChangeLogSource extends ChangeLogSource { } getAPIBaseUrl(config: BranchUpgradeConfig): string { - const parsedUrl = URL.parse(config.sourceUrl!); - const protocol = parsedUrl.protocol!; - const host = parsedUrl.host!; + const parsedUrl = parseUrl(config.sourceUrl); + if (!parsedUrl) { + return ''; + } + const protocol = parsedUrl.protocol; + const host = parsedUrl.host; return `${protocol}//api.${host}/`; } From a77dc3a577335cab6ad92160c27e5c3578d328ff Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 08:56:24 -0400 Subject: [PATCH 65/71] test: add coverage for missing source url --- .../update/pr/changelog/bitbucket/index.spec.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts index e3ec41ffd2038f..b197f858c4eb34 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts @@ -6,6 +6,7 @@ import * as semverVersioning from '../../../../../../modules/versioning/semver'; import * as _hostRules from '../../../../../../util/host-rules'; import type { BranchUpgradeConfig } from '../../../../../types'; import { getReleaseNotesMd } from '../release-notes'; +import { BitbucketChangeLogSource } from './source'; jest.mock('../../../../../../modules/datasource/npm'); jest.mock('../../../../../../util/host-rules'); @@ -89,7 +90,7 @@ describe('workers/repository/update/pr/changelog/bitbucket/index', () => { httpMock.clear(false); }); - it('works with Bitbucket', async () => { + it('retrieves changelog json', async () => { expect( await getChangeLogJSON({ ...upgrade, @@ -114,7 +115,7 @@ describe('workers/repository/update/pr/changelog/bitbucket/index', () => { }); }); - it('bitbucket: parses changelog', async () => { + it('generates release notes', async () => { hostRules.find.mockReturnValue({ token: 'some-token' }); jest.setTimeout(0); httpMock @@ -144,7 +145,7 @@ describe('workers/repository/update/pr/changelog/bitbucket/index', () => { ); }); - it('bitbucket: handles not found', async () => { + it('handles not found', async () => { httpMock .scope('https://api.bitbucket.org/') .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') @@ -161,4 +162,14 @@ describe('workers/repository/update/pr/changelog/bitbucket/index', () => { ); expect(res).toBeNull(); }); + + it('handles missing sourceUrl', () => { + const source = new BitbucketChangeLogSource(); + expect( + source.getAPIBaseUrl({ + ...upgrade, + sourceUrl: undefined, + }) + ).toBeEmptyString(); + }); }); From 53f8016736de4e5fd84b46633b90d6ddf7e6a265 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 08:57:11 -0400 Subject: [PATCH 66/71] refactor: use url util --- lib/workers/repository/update/pr/changelog/bitbucket/source.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/source.ts b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts index f9e59d405efcea..ddc3ff70a58d3c 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/source.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts @@ -1,3 +1,4 @@ +import is from '@sindresorhus/is'; import { parseUrl } from '../../../../../../util/url'; import type { BranchUpgradeConfig } from '../../../../../types'; import { ChangeLogSource } from '../source'; @@ -9,7 +10,7 @@ export class BitbucketChangeLogSource extends ChangeLogSource { getAPIBaseUrl(config: BranchUpgradeConfig): string { const parsedUrl = parseUrl(config.sourceUrl); - if (!parsedUrl) { + if (is.nullOrUndefined(parsedUrl)) { return ''; } const protocol = parsedUrl.protocol; From d4a8f6164089379cc94c8502ea89df6206d51940 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 09:14:48 -0400 Subject: [PATCH 67/71] refactor --- .../repository/update/pr/changelog/bitbucket/index.spec.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts index b197f858c4eb34..04f123b17c6999 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts @@ -85,9 +85,8 @@ const bitbucketProject = partial({ }); describe('workers/repository/update/pr/changelog/bitbucket/index', () => { - afterEach(() => { - // FIXME: add missing http mocks - httpMock.clear(false); + beforeEach(() => { + hostRules.clear(); }); it('retrieves changelog json', async () => { From 5c67eefe6f086600ba33c55832afb902bf3b903e Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 10:17:58 -0400 Subject: [PATCH 68/71] pr feedback --- .../pr/changelog/bitbucket/index.spec.ts | 23 ++++--------------- .../update/pr/changelog/bitbucket/index.ts | 2 +- .../update/pr/changelog/bitbucket/source.ts | 10 +------- 3 files changed, 7 insertions(+), 28 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts index 04f123b17c6999..e362834dc0571c 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts @@ -6,7 +6,6 @@ import * as semverVersioning from '../../../../../../modules/versioning/semver'; import * as _hostRules from '../../../../../../util/host-rules'; import type { BranchUpgradeConfig } from '../../../../../types'; import { getReleaseNotesMd } from '../release-notes'; -import { BitbucketChangeLogSource } from './source'; jest.mock('../../../../../../modules/datasource/npm'); jest.mock('../../../../../../util/host-rules'); @@ -116,7 +115,6 @@ describe('workers/repository/update/pr/changelog/bitbucket/index', () => { it('generates release notes', async () => { hostRules.find.mockReturnValue({ token: 'some-token' }); - jest.setTimeout(0); httpMock .scope('https://api.bitbucket.org/') .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') @@ -136,12 +134,11 @@ describe('workers/repository/update/pr/changelog/bitbucket/index', () => { }) ); - expect(res?.notesSourceUrl).toBe( - 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md' - ); - expect(res?.url).toBe( - 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md#20260---2020-05-18' - ); + expect(res).toMatchObject({ + notesSourceUrl: + 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md', + url: 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md#20260---2020-05-18', + }); }); it('handles not found', async () => { @@ -161,14 +158,4 @@ describe('workers/repository/update/pr/changelog/bitbucket/index', () => { ); expect(res).toBeNull(); }); - - it('handles missing sourceUrl', () => { - const source = new BitbucketChangeLogSource(); - expect( - source.getAPIBaseUrl({ - ...upgrade, - sourceUrl: undefined, - }) - ).toBeEmptyString(); - }); }); diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index a47a73d1280208..026d7f186b2fbd 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -70,7 +70,7 @@ export function getReleaseList( project: ChangeLogProject, _release: ChangeLogRelease ): ChangeLogNotes[] { - logger.trace('github.getReleaseList()'); + logger.trace('bitbucket.getReleaseList()'); logger.warn('TODO: implement getReleaseList() for Bitbucket'); return []; } diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/source.ts b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts index ddc3ff70a58d3c..ebb1ca06c7f27f 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/source.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts @@ -1,5 +1,3 @@ -import is from '@sindresorhus/is'; -import { parseUrl } from '../../../../../../util/url'; import type { BranchUpgradeConfig } from '../../../../../types'; import { ChangeLogSource } from '../source'; @@ -9,13 +7,7 @@ export class BitbucketChangeLogSource extends ChangeLogSource { } getAPIBaseUrl(config: BranchUpgradeConfig): string { - const parsedUrl = parseUrl(config.sourceUrl); - if (is.nullOrUndefined(parsedUrl)) { - return ''; - } - const protocol = parsedUrl.protocol; - const host = parsedUrl.host; - return `${protocol}//api.${host}/`; + return 'https://api.bitbucket.org/'; } getCompareURL( From 250eb6ce250b26f34ab5b6daf37ae741c5ad5da8 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 10:20:22 -0400 Subject: [PATCH 69/71] remove hostrules --- .../update/pr/changelog/bitbucket/index.spec.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts index e362834dc0571c..0869569aad1080 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts @@ -1,16 +1,12 @@ import { ChangeLogProject, ChangeLogRelease, getChangeLogJSON } from '..'; import { Fixtures } from '../../../../../../../test/fixtures'; import * as httpMock from '../../../../../../../test/http-mock'; -import { mocked, partial } from '../../../../../../../test/util'; +import { partial } from '../../../../../../../test/util'; import * as semverVersioning from '../../../../../../modules/versioning/semver'; -import * as _hostRules from '../../../../../../util/host-rules'; import type { BranchUpgradeConfig } from '../../../../../types'; import { getReleaseNotesMd } from '../release-notes'; jest.mock('../../../../../../modules/datasource/npm'); -jest.mock('../../../../../../util/host-rules'); - -const hostRules = mocked(_hostRules); const changelogMd = Fixtures.get('gitter-webapp.md', '../..'); @@ -84,8 +80,10 @@ const bitbucketProject = partial({ }); describe('workers/repository/update/pr/changelog/bitbucket/index', () => { - beforeEach(() => { - hostRules.clear(); + afterEach(() => { + // FIXME: add missing http mocks + httpMock.clear(false); + jest.resetAllMocks(); }); it('retrieves changelog json', async () => { @@ -114,7 +112,6 @@ describe('workers/repository/update/pr/changelog/bitbucket/index', () => { }); it('generates release notes', async () => { - hostRules.find.mockReturnValue({ token: 'some-token' }); httpMock .scope('https://api.bitbucket.org/') .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') From 3eb94ebb4ca932a9de9944dab1aa760c03e014de Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 14:02:25 -0400 Subject: [PATCH 70/71] test: rewrite tests --- .../pr/changelog/bitbucket/index.spec.ts | 128 ++++++------------ .../update/pr/changelog/bitbucket/index.ts | 8 +- .../update/pr/changelog/bitbucket/source.ts | 2 +- 3 files changed, 47 insertions(+), 91 deletions(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts index 0869569aad1080..b7a4f7cb6df3f9 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts @@ -1,38 +1,19 @@ -import { ChangeLogProject, ChangeLogRelease, getChangeLogJSON } from '..'; +import type { ChangeLogProject, ChangeLogRelease } from '..'; import { Fixtures } from '../../../../../../../test/fixtures'; import * as httpMock from '../../../../../../../test/http-mock'; import { partial } from '../../../../../../../test/util'; -import * as semverVersioning from '../../../../../../modules/versioning/semver'; import type { BranchUpgradeConfig } from '../../../../../types'; -import { getReleaseNotesMd } from '../release-notes'; +import { getReleaseList, getReleaseNotesMdFile } from '../release-notes'; +import { BitbucketChangeLogSource } from './source'; -jest.mock('../../../../../../modules/datasource/npm'); +const baseUrl = 'https://bitbucket.org/'; +const apiBaseUrl = 'https://api.bitbucket.org/'; -const changelogMd = Fixtures.get('gitter-webapp.md', '../..'); +const changelogMd = Fixtures.get('jest.md', '../..'); const upgrade = partial({ manager: 'some-manager', - branchName: '', - endpoint: 'https://api.bitbucket.org/', packageName: 'some-repo', - versioning: semverVersioning.id, - currentVersion: '5.2.0', - newVersion: '5.7.0', - sourceUrl: 'https://bitbucket.org/some-org/some-repo', - releases: [ - { version: '5.2.0' }, - { - version: '5.4.0', - releaseTimestamp: '2018-08-24T14:23:00.000Z', - }, - { version: '5.5.0', gitRef: 'abcd' }, - { - version: '5.6.0', - gitRef: '1234', - releaseTimestamp: '2020-02-13T15:37:00.000Z', - }, - { version: '5.6.1', gitRef: 'asdf' }, - ], }); const bitbucketTreeResponse = { @@ -75,84 +56,57 @@ const bitbucketTreeResponseNoChangelogFiles = { const bitbucketProject = partial({ type: 'bitbucket', - apiBaseUrl: 'https://api.bitbucket.org', - baseUrl: 'https://bitbucket.org/', + repository: 'some-org/some-repo', + baseUrl, + apiBaseUrl, }); describe('workers/repository/update/pr/changelog/bitbucket/index', () => { - afterEach(() => { - // FIXME: add missing http mocks - httpMock.clear(false); - jest.resetAllMocks(); - }); - - it('retrieves changelog json', async () => { - expect( - await getChangeLogJSON({ - ...upgrade, - }) - ).toEqual({ - hasReleaseNotes: true, - project: { - apiBaseUrl: 'https://api.bitbucket.org/', - baseUrl: 'https://bitbucket.org/', - packageName: 'some-repo', - repository: 'some-org/some-repo', - sourceDirectory: undefined, - sourceUrl: 'https://bitbucket.org/some-org/some-repo', - type: 'bitbucket', - }, - versions: [ - expect.objectContaining({ version: '5.6.1' }), - expect.objectContaining({ version: '5.6.0' }), - expect.objectContaining({ version: '5.5.0' }), - expect.objectContaining({ version: '5.4.0' }), - ], - }); - }); - - it('generates release notes', async () => { + it('handles release notes', async () => { httpMock - .scope('https://api.bitbucket.org/') + .scope(apiBaseUrl) .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') .reply(200, bitbucketTreeResponse) .get('/2.0/repositories/some-org/some-repo/src/abcd/CHANGELOG.md') .reply(200, changelogMd); - const res = await getReleaseNotesMd( - { - ...bitbucketProject, - repository: 'some-org/some-repo', - apiBaseUrl: 'https://api.bitbucket.org/', - baseUrl: 'https://bitbucket.org/', - }, - partial({ - version: '20.26.0', - gitRef: '20.26.0', - }) - ); + const res = await getReleaseNotesMdFile(bitbucketProject); expect(res).toMatchObject({ - notesSourceUrl: - 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md', - url: 'https://bitbucket.org/some-org/some-repo/blob/HEAD/CHANGELOG.md#20260---2020-05-18', + changelogFile: 'CHANGELOG.md', + changelogMd: changelogMd + '\n#\n##', }); }); - it('handles not found', async () => { + it('handles missing release notes', async () => { httpMock - .scope('https://api.bitbucket.org/') + .scope(apiBaseUrl) .get('/2.0/repositories/some-org/some-repo/src?pagelen=100') .reply(200, bitbucketTreeResponseNoChangelogFiles); - const res = await getReleaseNotesMd( - { - ...bitbucketProject, - repository: 'some-org/some-repo', - }, - partial({ - version: '2.0.0', - gitRef: '2.0.0', - }) - ); + const res = await getReleaseNotesMdFile(bitbucketProject); expect(res).toBeNull(); }); + + it('handles release list', async () => { + const res = await getReleaseList( + bitbucketProject, + partial({}) + ); + expect(res).toBeEmptyArray(); + }); + + describe('bitbucket source', () => { + it('returns api base url', () => { + const source = new BitbucketChangeLogSource(); + expect(source.getAPIBaseUrl(upgrade)).toBe(apiBaseUrl); + }); + + it('returns get ref comparison url', () => { + const source = new BitbucketChangeLogSource(); + expect( + source.getCompareURL(baseUrl, 'some-org/some-repo', 'abc', 'xzy') + ).toBe( + 'https://bitbucket.org/some-org/some-repo/branches/compare/xzy%0Dabc' + ); + }); + }); }); diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts index 026d7f186b2fbd..594f32befa65f0 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.ts @@ -17,7 +17,7 @@ const bitbucketHttp = new BitbucketHttp(id); export async function getReleaseNotesMd( repository: string, apiBaseUrl: string, - sourceDirectory?: string + _sourceDirectory?: string ): Promise { logger.trace('bitbucket.getReleaseNotesMd()'); @@ -67,10 +67,12 @@ export async function getReleaseNotesMd( } export function getReleaseList( - project: ChangeLogProject, + _project: ChangeLogProject, _release: ChangeLogRelease ): ChangeLogNotes[] { logger.trace('bitbucket.getReleaseList()'); - logger.warn('TODO: implement getReleaseList() for Bitbucket'); + logger.info( + 'Unsupported Bitbucket Cloud feature. Skipping release fetching.' + ); return []; } diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/source.ts b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts index ebb1ca06c7f27f..bfbc12ea6dd85d 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/source.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/source.ts @@ -6,7 +6,7 @@ export class BitbucketChangeLogSource extends ChangeLogSource { super('bitbucket', 'bitbucket-tags'); } - getAPIBaseUrl(config: BranchUpgradeConfig): string { + getAPIBaseUrl(_config: BranchUpgradeConfig): string { return 'https://api.bitbucket.org/'; } From 8032e6940cea56be44e024582fe4f5a388299806 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Sun, 2 Jul 2023 14:04:49 -0400 Subject: [PATCH 71/71] test: rewrite tests --- .../repository/update/pr/changelog/bitbucket/index.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts index b7a4f7cb6df3f9..a0ba419de79d14 100644 --- a/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts +++ b/lib/workers/repository/update/pr/changelog/bitbucket/index.spec.ts @@ -94,7 +94,7 @@ describe('workers/repository/update/pr/changelog/bitbucket/index', () => { expect(res).toBeEmptyArray(); }); - describe('bitbucket source', () => { + describe('source', () => { it('returns api base url', () => { const source = new BitbucketChangeLogSource(); expect(source.getAPIBaseUrl(upgrade)).toBe(apiBaseUrl);