Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(platform/bitbucket): add support for fetching release notes #22094

Merged
Merged
Show file tree
Hide file tree
Changes from 76 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
d7a6493
feat: bitbucket changelogs
setchy May 11, 2023
9c301da
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy May 11, 2023
291a8d8
feat: bitbucket changelogs
setchy May 11, 2023
a906921
fix: update api base url
setchy May 11, 2023
453c613
bitbucket doesnt have the concept of releases
setchy May 11, 2023
fdc2a03
refactor: make unpaginated function reusable
setchy May 11, 2023
7925c27
Merge branch 'feature/14964-bitbucket-release-notes' of https://githu…
setchy May 11, 2023
d2e3e47
revert: remove id usage
setchy May 11, 2023
aa12bf3
revert: refactor not required
setchy May 11, 2023
3e7c20c
types: add page to paginated bitbucket response
setchy May 12, 2023
36b9eb8
add paginate query
setchy May 12, 2023
1375e34
revert http/bitbucket
setchy May 13, 2023
5e9a52b
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy May 13, 2023
1273cb4
refactor to match other changelog impls
setchy May 14, 2023
d13dc6d
refactor to match other changelog impls
setchy May 14, 2023
3af6724
update bitbucket host types
setchy May 14, 2023
89d4e43
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy May 14, 2023
700d819
remove unused type
setchy May 14, 2023
df5d87d
tests
setchy May 14, 2023
73b5cf0
update apiBaseUrl
setchy May 14, 2023
de67134
Update lib/workers/repository/update/pr/changelog/bitbucket/index.ts
setchy May 14, 2023
f4800a7
simplify
setchy May 14, 2023
83155cd
Merge branch 'feature/14964-bitbucket-release-notes' of https://githu…
setchy May 14, 2023
18a7151
Update lib/workers/repository/update/pr/changelog/bitbucket/index.ts
setchy May 14, 2023
788229d
Update lib/workers/repository/update/pr/changelog/bitbucket/index.ts
setchy May 14, 2023
15c46dd
Update lib/workers/repository/update/pr/changelog/bitbucket/index.ts
setchy May 14, 2023
9bf934a
update to return versions
setchy May 14, 2023
48aba12
Merge branch 'feature/14964-bitbucket-release-notes' of https://githu…
setchy May 14, 2023
fb8e3d6
Update lib/workers/repository/update/pr/changelog/source-bitbucket.ts
setchy May 14, 2023
3832401
Update lib/workers/repository/update/pr/changelog/source-bitbucket.ts
setchy May 14, 2023
4fc6bb5
Update lib/workers/repository/update/pr/changelog/source-bitbucket.ts
setchy May 14, 2023
99fc1fc
Update lib/workers/repository/update/pr/changelog/source-bitbucket.ts
setchy May 14, 2023
3dcf963
add imports
setchy May 15, 2023
610a286
per feedback, use early return
setchy May 15, 2023
2ec9d49
fix linting
setchy May 15, 2023
8a3e3a7
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy May 22, 2023
230f260
export function
setchy May 24, 2023
2e17661
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy Jun 19, 2023
46ef4ea
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy Jun 19, 2023
488a86e
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy Jun 19, 2023
250c7e4
rename type
setchy Jun 19, 2023
f8acb57
refactor: make source-* more aligned
setchy Jun 19, 2023
5555cf8
refactor: make source-* more aligned
setchy Jun 19, 2023
1cad979
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy Jun 24, 2023
25b210d
refactor: remove inner functions
setchy Jun 24, 2023
cd83835
refactor: add base class
setchy Jun 24, 2023
7ed34f4
refactor: add base class
setchy Jun 24, 2023
8fecd6d
refactor: add base class
setchy Jun 24, 2023
f1ad9c2
refactor: add base class
setchy Jun 24, 2023
5d237af
refactor: change how host validation is handled
setchy Jun 24, 2023
444ee52
tests: update mocks
setchy Jun 24, 2023
2579384
refactor: use cache decorator
setchy Jun 24, 2023
805fb18
refactor: use getPkgReleases
setchy Jun 24, 2023
a239f4e
revert: github queryTags returns richer data than getPkgReleases
setchy Jun 24, 2023
25e0a9b
refactor
setchy Jun 24, 2023
3de7e5d
fix: change order of tags
setchy Jun 24, 2023
b056d8f
fix: use regex versioning to fetch tags which may have package prefix
setchy Jun 25, 2023
99ef3f9
reorder functions for consistency
setchy Jun 25, 2023
9b41474
tests: coverage
setchy Jun 25, 2023
b10f88c
fix linting
setchy Jun 25, 2023
8b16265
tests: update snapshot
setchy Jun 25, 2023
2811c1c
tests: add bitbucket tests
setchy Jun 26, 2023
6121f05
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy Jun 26, 2023
24805df
Update lib/workers/repository/update/pr/changelog/source.ts
setchy Jun 27, 2023
ac72633
change to const
setchy Jun 27, 2023
3ec5880
refactor: move to api
setchy Jun 27, 2023
0c8d9d3
remove bang
setchy Jun 27, 2023
4f9158d
feedback: add zod schema
setchy Jun 27, 2023
8dc8cab
zod, take two
setchy Jun 28, 2023
d321800
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy Jul 2, 2023
fa4393a
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy Jul 2, 2023
af260d5
reorder alpha
setchy Jul 2, 2023
7a9e160
Merge branch 'feature/14964-bitbucket-release-notes' of https://githu…
setchy Jul 2, 2023
e92219d
refactor
setchy Jul 2, 2023
7b65d87
refactor
setchy Jul 2, 2023
72d79e7
refactor
setchy Jul 2, 2023
ec26c10
rename test
setchy Jul 2, 2023
ea14d76
refactor: use url util
setchy Jul 2, 2023
a77dc3a
test: add coverage for missing source url
setchy Jul 2, 2023
53f8016
refactor: use url util
setchy Jul 2, 2023
d4a8f61
refactor
setchy Jul 2, 2023
5c67eef
pr feedback
setchy Jul 2, 2023
250eb6c
remove hostrules
setchy Jul 2, 2023
3eb94eb
test: rewrite tests
setchy Jul 2, 2023
61ac5b6
Merge branch 'main' into feature/14964-bitbucket-release-notes
setchy Jul 2, 2023
8032e69
test: rewrite tests
setchy Jul 2, 2023
f937ce7
Merge branch 'feature/14964-bitbucket-release-notes' of https://githu…
setchy Jul 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/constants/platforms.ts
Expand Up @@ -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-changelog',
'bitbucket-tags',
];
22 changes: 22 additions & 0 deletions lib/modules/platform/bitbucket/schema.ts
@@ -0,0 +1,22 @@
import { z } from 'zod';

const BitbucketSourceTypeSchema = z.enum(['commit_directory', 'commit_file']);

const SourceResultsSchema = z.object({
path: z.string(),
type: BitbucketSourceTypeSchema,
commit: z.object({
hash: z.string(),
}),
});

const PagedSchema = z.object({
page: z.number().optional(),
pagelen: z.number(),
size: z.number().optional(),
next: z.string().optional(),
});

setchy marked this conversation as resolved.
Show resolved Hide resolved
export const PagedSourceResultsSchema = PagedSchema.extend({
values: z.array(SourceResultsSchema),
});
2 changes: 2 additions & 0 deletions lib/workers/repository/update/pr/changelog/api.ts
@@ -1,9 +1,11 @@
import { BitbucketChangeLogSource } from './bitbucket/source';
secustor marked this conversation as resolved.
Show resolved Hide resolved
import type { ChangeLogSource } from './source';
import { GitHubChangeLogSource } from './source-github';
import { GitLabChangeLogSource } from './source-gitlab';

const api = new Map<string, ChangeLogSource>();
export default api;

api.set('bitbucket', new BitbucketChangeLogSource());
api.set('github', new GitHubChangeLogSource());
api.set('gitlab', new GitLabChangeLogSource());
164 changes: 164 additions & 0 deletions lib/workers/repository/update/pr/changelog/bitbucket/bitbucket.spec.ts
@@ -0,0 +1,164 @@
import { ChangeLogProject, ChangeLogRelease, getChangeLogJSON } from '..';
setchy marked this conversation as resolved.
Show resolved Hide resolved
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);
setchy marked this conversation as resolved.
Show resolved Hide resolved

const changelogMd = Fixtures.get('gitter-webapp.md', '../..');

const upgrade = partial<BranchUpgradeConfig>({
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<ChangeLogProject>({
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<ChangeLogRelease>({
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<ChangeLogRelease>({
version: '2.0.0',
gitRef: '2.0.0',
})
);
expect(res).toBeNull();
});
});
76 changes: 76 additions & 0 deletions lib/workers/repository/update/pr/changelog/bitbucket/index.ts
@@ -0,0 +1,76 @@
import is from '@sindresorhus/is';
import changelogFilenameRegex from 'changelog-filename-regex';
import { logger } from '../../../../../../logger';
import { PagedSourceResultsSchema } from '../../../../../../modules/platform/bitbucket/schema';
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);

export async function getReleaseNotesMd(
repository: string,
apiBaseUrl: string,
sourceDirectory?: string
): Promise<ChangeLogFile | null> {
logger.trace('bitbucket.getReleaseNotesMd()');

const repositorySourceURl = joinUrlParts(
apiBaseUrl,
`2.0/repositories`,
repository,
'src'
);

const rootFiles = (
await bitbucketHttp.getJson(
repositorySourceURl,
{
paginate: true,
},
PagedSourceResultsSchema
)
).body.values;

const allFiles = rootFiles.filter((f) => f.type === 'commit_file');

const files = allFiles.filter((f) => changelogFilenameRegex.test(f.path));

const changelogFile = files.shift();
if (is.nullOrUndefined(changelogFile)) {
logger.trace('no changelog file found');
return null;
}

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##`;
setchy marked this conversation as resolved.
Show resolved Hide resolved
setchy marked this conversation as resolved.
Show resolved Hide resolved
return { changelogFile: changelogFile.path, changelogMd };
}

export function getReleaseList(
project: ChangeLogProject,
_release: ChangeLogRelease
): ChangeLogNotes[] {
logger.trace('github.getReleaseList()');
setchy marked this conversation as resolved.
Show resolved Hide resolved
logger.warn('TODO: implement getReleaseList() for Bitbucket');
setchy marked this conversation as resolved.
Show resolved Hide resolved
return [];
}
25 changes: 25 additions & 0 deletions lib/workers/repository/update/pr/changelog/bitbucket/source.ts
@@ -0,0 +1,25 @@
import URL from 'node:url';
setchy marked this conversation as resolved.
Show resolved Hide resolved
import type { BranchUpgradeConfig } from '../../../../../types';
import { ChangeLogSource } from '../source';

export class BitbucketChangeLogSource extends ChangeLogSource {
constructor() {
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,
prevHead: string,
nextHead: string
): string {
return `${baseUrl}${repository}/branches/compare/${nextHead}%0D${prevHead}`;
}
}
11 changes: 9 additions & 2 deletions lib/workers/repository/update/pr/changelog/release-notes.ts
Expand Up @@ -10,6 +10,7 @@ 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 {
Expand All @@ -35,7 +36,8 @@ export async function getReleaseList(
return await gitlab.getReleaseList(project, release);
case 'github':
return await github.getReleaseList(project, release);

case 'bitbucket':
return bitbucket.getReleaseList(project, release);
default:
logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type');
return [];
Expand Down Expand Up @@ -262,7 +264,12 @@ export async function getReleaseNotesMdFileInner(
apiBaseUrl,
sourceDirectory
);

case 'bitbucket':
return await bitbucket.getReleaseNotesMd(
repository,
apiBaseUrl,
sourceDirectory
);
default:
logger.warn({ apiBaseUrl, repository, type }, 'Invalid project type');
return null;
Expand Down
4 changes: 2 additions & 2 deletions lib/workers/repository/update/pr/changelog/source.ts
Expand Up @@ -23,8 +23,8 @@ export abstract class ChangeLogSource {
private cacheNamespace: string;

constructor(
platform: 'github' | 'gitlab',
datasource: 'github-tags' | 'gitlab-tags'
platform: 'bitbucket' | 'github' | 'gitlab',
datasource: 'bitbucket-tags' | 'github-tags' | 'gitlab-tags'
) {
this.platform = platform;
this.datasource = datasource;
Expand Down
7 changes: 5 additions & 2 deletions lib/workers/repository/update/pr/changelog/types.ts
Expand Up @@ -25,15 +25,18 @@ export interface ChangeLogRelease {

export interface ChangeLogProject {
packageName?: string;
type: 'github' | 'gitlab';
type: 'bitbucket' | 'github' | 'gitlab';
apiBaseUrl?: string;
baseUrl: string;
repository: string;
sourceUrl: string;
sourceDirectory?: string;
}

export type ChangeLogError = 'MissingGithubToken' | 'MissingGitlabToken';
export type ChangeLogError =
| 'MissingBitbucketToken'
| 'MissingGithubToken'
| 'MissingGitlabToken';

export interface ChangeLogResult {
hasReleaseNotes?: boolean;
Expand Down