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: add support for bitbucket repository url #608

Merged
merged 6 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/configuration/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Supported hosts:

- GitHub
- GitLab (https://gitlab.com)
- Bitbucket (https://bitbucket.org)
spydon marked this conversation as resolved.
Show resolved Hide resolved

```yaml
repository: https://github.com/invertase/melos
Expand Down
46 changes: 46 additions & 0 deletions packages/melos/lib/src/common/git_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,60 @@
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.');

Check notice on line 239 in packages/melos/lib/src/common/git_repository.dart

View workflow job for this annotation

GitHub Actions / analyze

Missing a required trailing comma.

See https://dart.dev/lints/require_trailing_commas to learn more about this problem.
}
spydon marked this conversation as resolved.
Show resolved Hide resolved

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');

// TODO(fenrirx22): Implementing an issueUrl for Bitbucket requires a Jira URL
@override
Uri issueUrl(String id) => Uri();

@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].
Expand Down
100 changes: 100 additions & 0 deletions packages/melos/test/git_repository_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 empty URL', () {
final repo = BitbucketRepository(owner: 'a', name: 'b');
const issueId = '123';

expect(
repo.issueUrl(issueId),
Uri(),
);
});
});

group('parseHostedGitRepositoryUrl', () {
test('parses GitHub repository URL', () {
final repo =
Expand Down
Loading