-
Notifications
You must be signed in to change notification settings - Fork 72
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
[Integration][bitbucket] Added bitbucket ocean integration #1448
base: main
Are you sure you want to change the base?
Conversation
…ders and pull request
CI Feedback 🧐(Feedback updated until commit ec7261a)A test triggered by this PR failed. Here is an AI-generated analysis of the failure:
|
This pull request is automatically being deployed by Amplify Hosting (learn more). |
Qodo Merge was enabled for this repository. To continue using it, please link your Git account with your Qodo account here. PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
Qodo Merge was enabled for this repository. To continue using it, please link your Git account with your Qodo account here. PR Code Suggestions ✨Explore these optional code suggestions:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments
except HTTPStatusError as e: | ||
error_data = e.response.json() | ||
error_message = error_data.get("error", {}).get("message", str(e)) | ||
logger.error(f"Bitbucket API error: {error_message}") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You've suppressed error propagation entirely here, it won't be possible to catch errors anywhere else
values = response.get("values", []) | ||
if values: | ||
yield values | ||
next_page = response.get("next") | ||
if not next_page: | ||
break | ||
endpoint = next_page.replace(self.base_url + "/", "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is values
not consistent in all the api responses, if it is, lets be explicit..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there are situation where values is empty yet the next page has resources ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left more comments
break | ||
endpoint = next_page.replace(self.base_url + "/", "") | ||
|
||
# Project endpoints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove
): | ||
yield projects | ||
|
||
# Repository endpoints |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove comment
class ObjectKind(StrEnum): | ||
PROJECT = "project" | ||
FOLDER = "folder" | ||
REPOSITORY = "repository" | ||
PULL_REQUEST = "pull-request" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to client or some utility
class AsyncIteratorMock: | ||
"""Helper class to mock async iterators.""" | ||
|
||
def __init__(self, items: Iterator[Any]) -> None: | ||
self.items = items | ||
|
||
def __aiter__(self) -> "AsyncIteratorMock": | ||
return self | ||
|
||
async def __anext__(self) -> Any: | ||
try: | ||
return next(self.items) | ||
except StopIteration: | ||
raise StopAsyncIteration | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whats the need for this ?
@pytest.mark.asyncio | ||
async def test_send_api_request_error(mock_client: BitbucketClient) -> None: | ||
"""Test API request with error response.""" | ||
error_response = Response(400, json={"error": {"message": "Test error"}}) | ||
mock_error = HTTPStatusError( | ||
"Test error", request=MagicMock(), response=error_response | ||
) | ||
with patch.object( | ||
mock_client.client, "request", new_callable=AsyncMock | ||
) as mock_request: | ||
mock_request.side_effect = mock_error | ||
with pytest.raises(HTTPStatusError) as exc_info: | ||
await mock_client._send_api_request("test/endpoint") | ||
assert "Test error" in str(exc_info.value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand the goal of this test
The test patches the request method on mock_client.client to immediately raise an HTTPStatusError (via side_effect). This means that the error is raised at the line:
response = await self.client.request(...)
So, the function never even gets a chance to enter the try block where it would normally call response.raise_for_status().
As a result, the error handling code inside the except block (e.g., extracting and logging the error message) isn’t exercised.
Please Reiterate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its concerning because your _send_api_request
doesn't raise an error at all from its design.
async def test_send_paginated_api_request(mock_client: BitbucketClient) -> None: | ||
"""Test paginated API request.""" | ||
page1 = { | ||
"values": [{"id": 1}, {"id": 2}], | ||
"next": "https://api.bitbucket.org/2.0/test/endpoint?page=2", | ||
} | ||
page2 = {"values": [{"id": 3}], "next": None} | ||
with patch.object( | ||
mock_client, "_send_api_request", new_callable=AsyncMock | ||
) as mock_request: | ||
mock_request.side_effect = [page1, page2] | ||
results = [] | ||
async for batch in mock_client._send_paginated_api_request("test/endpoint"): | ||
results.extend(batch) | ||
assert len(results) == 3 | ||
assert [item["id"] for item in results] == [1, 2, 3] | ||
assert mock_request.call_count == 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also assert that its capable of yielding one page at a time
User description
Description
What - Created a new Ocean integration for Bitbucket that enables ingestion of Bitbucket resources into Port's catalog. The integration supports:
Why - To enable users using Bitbucket cloud version to automatically sync their resources to Port
How -
Type of change
Please leave one option from the following and delete the rest:
All tests should be run against the port production environment(using a testing org).
Core testing checklist
Integration testing checklist
examples
folder in the integration directory.Preflight checklist
Screenshots
Include screenshots from your environment showing how the resources of the integration will look.
API Documentation
Provide links to the API documentation used for this integration.
PR Type
Enhancement, Tests, Documentation
Description
Added a new Bitbucket integration for syncing resources.
Implemented support for Projects, Repositories, Folders, and Pull Requests.
Included tests for client functionality and API interactions.
Added configuration files, documentation, and examples for integration setup.
Changes walkthrough 📝
4 files
Implement Bitbucket API client for resource fetching
Define integration configuration and resource selectors
Implement resync logic for Bitbucket resources
Add blueprints for Bitbucket resource types
1 files
Add debug entry point for integration
2 files
Add test fixtures for mocking Bitbucket context
Add tests for Bitbucket client functionality
5 files
Provide example environment variables for integration
Define mappings for Bitbucket resources in Port
Add integration specification for Bitbucket
Add Makefile for integration build and testing
Add SonarQube project configuration
3 files
Add changelog for Bitbucket integration
Add contributing guidelines for Bitbucket integration
Add README for Bitbucket integration usage and development
2 files
Configure virtual environments for integration development
Define project dependencies and settings
1 files