From 26c469af111e7e298ad9a6e124afbd9b5a1a3d95 Mon Sep 17 00:00:00 2001 From: fenrirx22 Date: Sat, 2 Dec 2023 12:28:20 +0100 Subject: [PATCH 1/4] added support for bitbucket repository --- docs/configuration/overview.mdx | 1 + .../melos/lib/src/common/git_repository.dart | 47 ++++++++ packages/melos/test/git_repository_test.dart | 100 ++++++++++++++++++ 3 files changed, 148 insertions(+) diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index 8b6c6a14..c59122e0 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -30,6 +30,7 @@ Supported hosts: - GitHub - GitLab (https://gitlab.com) +- Bitbucket (https://bitbucket.org) ```yaml repository: https://github.com/invertase/melos diff --git a/packages/melos/lib/src/common/git_repository.dart b/packages/melos/lib/src/common/git_repository.dart index 51da7f77..5e0d966f 100644 --- a/packages/melos/lib/src/common/git_repository.dart +++ b/packages/melos/lib/src/common/git_repository.dart @@ -217,14 +217,61 @@ GitLabRepository( int get hashCode => origin.hashCode ^ owner.hashCode ^ name.hashCode; } +class BitbucketRepository extends HostedGitRepository { + BitbucketRepository({ + String origin = defaultOrigin, + required this.owner, + required this.name, + }) : origin = removeTrailingSlash(origin); + + factory BitbucketRepository.fromUrl(Uri uri) { + if (uri.scheme == 'https' && uri.host == 'bitbucket.org') { + final match = RegExp(r'^/(.+)?/(.+)/?$').firstMatch(uri.path); + if (match != null) { + return BitbucketRepository( + owner: match.group(1)!, + name: match.group(2)!, + ); + } + } + + throw FormatException( + 'The URL $uri is not a valid Bitbucket repository URL.'); + } + + static const defaultOrigin = 'https://bitbucket.org'; + + /// The origin of the Bitbucket server, defaults to `https://bitbucket.org`. + final String origin; + + /// The owning workspace name. + final String owner; + + @override + final String name; + + @override + Uri commitUrl(String id) => url.resolve('commits/$id'); + + @override + Uri issueUrl(String id) => throw UnsupportedError( + 'Not supported yet as it require Jira url', + ); + + @override + Uri get url => Uri.parse('$origin/$owner/$name/'); +} + final _hostsToUrlParser = { 'GitHub': GitHubRepository.fromUrl, 'GitLab': GitLabRepository.fromUrl, + 'Bitbucket': BitbucketRepository.fromUrl, }; final _hostsToSpecParser = { 'GitHub': GitHubRepository.new, 'GitLab': GitLabRepository.new, + 'Bitbucket': BitbucketRepository.new, }; /// Tries to parse [url] into a [HostedGitRepository]. diff --git a/packages/melos/test/git_repository_test.dart b/packages/melos/test/git_repository_test.dart index 2d6fcb1f..2c301d6b 100644 --- a/packages/melos/test/git_repository_test.dart +++ b/packages/melos/test/git_repository_test.dart @@ -225,6 +225,106 @@ void main() { }); }); + group('BitBucketRepository', () { + group('fromUrl', () { + test('parse Bitbucket repository URL correctly', () { + final url = Uri.parse('https://bitbucket.org/a/b'); + final repo = BitbucketRepository.fromUrl(url); + + expect(repo.origin, 'https://bitbucket.org'); + expect(repo.owner, 'a'); + expect(repo.name, 'b'); + expect(repo.url, Uri.parse('https://bitbucket.org/a/b/')); + }); + + test('throws if URL is not a valid GitLab repository URL', () { + void expectBadUrl(String url) { + final uri = Uri.parse(url); + expect( + () => BitbucketRepository.fromUrl(uri), + throwsFormatException, + reason: url, + ); + } + + const [ + '', + 'http://bitbucket.org/a/b', + 'https://gitlab.com/a/b', + 'https://github.com/a/b', + 'https://bitbucket.org/a', + 'https://bitbucket.org/', + 'https://bitbucket.org', + ].forEach(expectBadUrl); + }); + }); + + group('fromSpec', () { + test('parse Bitbucket repository spec correctly', () { + final repo = BitbucketRepository( + origin: 'https://bitbucket.invertase.dev', + owner: 'a', + name: 'b', + ); + + expect(repo.origin, 'https://bitbucket.invertase.dev'); + expect(repo.owner, 'a'); + expect(repo.name, 'b'); + expect(repo.url, Uri.parse('https://bitbucket.invertase.dev/a/b/')); + }); + + test('parse Bitbucket repository spec with nested groups correctly', () { + final repo = BitbucketRepository( + origin: 'https://bitbucket.invertase.dev', + owner: 'a/b', + name: 'c', + ); + + expect(repo.origin, 'https://bitbucket.invertase.dev'); + expect(repo.owner, 'a/b'); + expect(repo.name, 'c'); + expect(repo.url, Uri.parse('https://bitbucket.invertase.dev/a/b/c/')); + }); + + test( + 'parse Bitbucket repository spec with sub-path and nested groups ' + 'correctly', () { + final repo = BitbucketRepository( + origin: 'https://invertase.dev/bitbucket', + owner: 'a/b', + name: 'c', + ); + + expect(repo.origin, 'https://invertase.dev/bitbucket'); + expect(repo.owner, 'a/b'); + expect(repo.name, 'c'); + expect(repo.url, Uri.parse('https://invertase.dev/bitbucket/a/b/c/')); + }); + }); + + test('commitUrl returns correct URL', () { + final repo = BitbucketRepository(owner: 'a', name: 'b'); + const commitId = 'b2841394a48cd7d84a4966a788842690e543b2ef'; + + expect( + repo.commitUrl(commitId), + Uri.parse( + 'https://bitbucket.org/a/b/commits/b2841394a48cd7d84a4966a788842690e543b2ef', + ), + ); + }); + + test('issueUrl returns correct URL', () { + final repo = BitbucketRepository(owner: 'a', name: 'b'); + const issueId = '123'; + + expect( + repo.issueUrl(issueId), + Uri.parse('https://bitbucket.org/a/b/pull-requests/123'), + ); + }); + }); + group('parseHostedGitRepositoryUrl', () { test('parses GitHub repository URL', () { final repo = From 07bfc98d6f09f6b25f4243fbd7762f60b974d891 Mon Sep 17 00:00:00 2001 From: fenrirx22 Date: Sat, 2 Dec 2023 12:28:20 +0100 Subject: [PATCH 2/4] set bitbucket repository issueUrl to return empty uri for now --- packages/melos/lib/src/common/git_repository.dart | 5 ++--- packages/melos/test/git_repository_test.dart | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/melos/lib/src/common/git_repository.dart b/packages/melos/lib/src/common/git_repository.dart index 5e0d966f..38ae0f98 100644 --- a/packages/melos/lib/src/common/git_repository.dart +++ b/packages/melos/lib/src/common/git_repository.dart @@ -253,10 +253,9 @@ class BitbucketRepository extends HostedGitRepository { @override Uri commitUrl(String id) => url.resolve('commits/$id'); + // TODO(fenrirx22): Implementing an issueUrl for Bitbucket requires a Jira URL @override - Uri issueUrl(String id) => throw UnsupportedError( - 'Not supported yet as it require Jira url', - ); + Uri issueUrl(String id) => Uri(); @override Uri get url => Uri.parse('$origin/$owner/$name/'); diff --git a/packages/melos/test/git_repository_test.dart b/packages/melos/test/git_repository_test.dart index 2c301d6b..b24a6cf7 100644 --- a/packages/melos/test/git_repository_test.dart +++ b/packages/melos/test/git_repository_test.dart @@ -314,13 +314,13 @@ void main() { ); }); - test('issueUrl returns correct URL', () { + test('issueUrl returns empty URL', () { final repo = BitbucketRepository(owner: 'a', name: 'b'); const issueId = '123'; expect( repo.issueUrl(issueId), - Uri.parse('https://bitbucket.org/a/b/pull-requests/123'), + Uri(), ); }); }); From b97931d9e1ee53b250010ffb7edaf3380e5b6e33 Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Mon, 4 Dec 2023 13:53:51 +0100 Subject: [PATCH 3/4] Update packages/melos/lib/src/common/git_repository.dart --- packages/melos/lib/src/common/git_repository.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/melos/lib/src/common/git_repository.dart b/packages/melos/lib/src/common/git_repository.dart index 38ae0f98..15363ed9 100644 --- a/packages/melos/lib/src/common/git_repository.dart +++ b/packages/melos/lib/src/common/git_repository.dart @@ -236,7 +236,8 @@ class BitbucketRepository extends HostedGitRepository { } throw FormatException( - 'The URL $uri is not a valid Bitbucket repository URL.'); + 'The URL $uri is not a valid Bitbucket repository URL.', + ); } static const defaultOrigin = 'https://bitbucket.org'; From de37bf5251c191c63fbfafcaac1f808975517add Mon Sep 17 00:00:00 2001 From: fenrirx22 Date: Mon, 4 Dec 2023 14:12:15 +0100 Subject: [PATCH 4/4] docs: mentioned bitbucked in self hosted repository location --- docs/configuration/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/overview.mdx b/docs/configuration/overview.mdx index c59122e0..9a7a01d8 100644 --- a/docs/configuration/overview.mdx +++ b/docs/configuration/overview.mdx @@ -36,7 +36,7 @@ Supported hosts: repository: https://github.com/invertase/melos ``` -When using a self-hosted GitHub or GitLab instance, you can specify the +When using a self-hosted GitHub, GitLab or Bitbucket instance, you can specify the repository location like this: ```yaml