Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
22 changes: 17 additions & 5 deletions jf_agent/git/bitbucket_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,11 @@ def get_repos(client, api_projects, include_repos, exclude_repos, redact_names_a
for repo in project.repos.list():
if all(filt(repo) for filt in filters):
api_repo = project.repos[repo['name']]
yield api_repo, _standardize_repo(api_project, api_repo, redact_names_and_urls)
try:
yield api_repo, _standardize_repo(api_project, api_repo, redact_names_and_urls)
except stashy.errors.NotFoundException as e:
logger.warning(f'WARN: Got NotFoundException fetching repo, skipping: {e}')
continue

logger.info('✓')

Expand Down Expand Up @@ -257,7 +261,11 @@ def get_commits_for_included_branches(
):
for i, api_repo in enumerate(api_repos, start=1):
with logging_helper.log_loop_iters('repo for branch commits', i, 1):
repo = api_repo.get()
try:
repo = api_repo.get()
except stashy.errors.NotFoundException as e:
logger.warning(f'WARN: Got NotFoundException fetching repo, skipping: {e}')
continue
if verbose:
logger.info(f"Beginning download of commits for repo {repo}")
api_project = client.projects[repo['project']['key']]
Expand All @@ -270,7 +278,7 @@ def get_commits_for_included_branches(
# We are working with the BBS api object rather than a StandardizedRepository here,
# so we can not use get_branches_for_standardized_repo as we do in bitbucket_cloud_adapter and gitlab_adapter.
branches_to_process = [_get_default_branch_name(api_repo)]
additional_branch_patterns = included_branches.get(api_repo.get()['name'])
additional_branch_patterns = included_branches.get(repo['name'])

if additional_branch_patterns:
repo_branches = [b['displayId'] for b in api_repo.branches()]
Expand Down Expand Up @@ -333,7 +341,11 @@ def get_pull_requests(
):
for i, api_repo in enumerate(api_repos, start=1):
with logging_helper.log_loop_iters('repo for pull requests', i, 1):
repo = api_repo.get()
try:
repo = api_repo.get()
except stashy.errors.NotFoundException as e:
logger.warning(f'WARN: Got NotFoundException fetching repo, skipping: {e}')
continue
if verbose:
logger.info(f"Beginning download of PRs for repo {repo}")
api_project = client.projects[repo['project']['key']]
Expand Down Expand Up @@ -369,7 +381,7 @@ def get_pull_requests(
additions, deletions, changed_files = None, None, None
except RetryError:
logger.warning(
f"Could not retrieve diff data for PR {pr['id']} in repo {api_repo.get()['name']}"
f"Could not retrieve diff data for PR {pr['id']} in repo {repo['name']}"
)
additions, deletions, changed_files = None, None, None
except ChunkedEncodingError as e:
Expand Down
106 changes: 105 additions & 1 deletion tests/test_bitbucket_server.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import json
import unittest

from unittest import TestCase
from unittest.mock import MagicMock

import stashy.errors

from jf_agent.git import bitbucket_server

TEST_INPUT_FILE_PATH = f'tests/test_data/bitbucket_server/'
Expand Down Expand Up @@ -324,6 +325,109 @@
"resulting PR body does not match input",
)

def test_get_repos_skips_deleted_repo(self):

Check warning on line 328 in tests/test_bitbucket_server.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add a return type hint to this function declaration.

See more on https://sonarcloud.io/project/issues?id=Jellyfish-AI_jf_agent&issues=AZ5mXe_OCCYY0sBvlPbw&open=AZ5mXe_OCCYY0sBvlPbw&pullRequest=458
# Arrange
test_projects = _get_test_data('test_projects.json')
test_repos = _get_test_data('test_repos.json')
test_branches = _get_test_data('test_branches.json')

mock_client = MagicMock()
mock_project = MagicMock()

mock_deleted_repo = MagicMock()
mock_deleted_repo.get.side_effect = stashy.errors.NotFoundException(MagicMock())

mock_live_repo = MagicMock()
mock_live_repo.get.return_value = test_repos[0]
mock_live_repo.branches.return_value = test_branches
mock_live_repo.default_branch = MagicMock()

mock_client.projects = {'test_project_key': mock_project}
mock_project.repos.list.return_value = [test_repos[0], test_repos[0]]
mock_project.repos.__getitem__.side_effect = [mock_deleted_repo, mock_live_repo]

# Act — should not raise despite first repo being deleted
result_repos = list(bitbucket_server.get_repos(mock_client, test_projects, {}, {}, False))

# Assert — deleted repo skipped, live repo still returned
self.assertEqual(len(result_repos), 1)
self.assertEqual(result_repos[0][0], mock_live_repo)

def test_get_branch_commits_skips_deleted_repo(self):

Check warning on line 356 in tests/test_bitbucket_server.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add a return type hint to this function declaration.

See more on https://sonarcloud.io/project/issues?id=Jellyfish-AI_jf_agent&issues=AZ5mXe_OCCYY0sBvlPbx&open=AZ5mXe_OCCYY0sBvlPbx&pullRequest=458
# Arrange
test_repos = _get_test_data('test_repos.json')
test_branches = _get_test_data('test_branches.json')
test_commits = _get_test_data('test_commits.json')

mock_client = MagicMock()
mock_project = MagicMock()

mock_deleted_repo = MagicMock()
mock_deleted_repo.get.side_effect = stashy.errors.NotFoundException(MagicMock())

mock_live_repo = MagicMock()
mock_live_repo.get.return_value = test_repos[0]
mock_live_repo.default_branch = test_branches[0]

mock_client.projects = {'test_project_key': mock_project}
mock_project.repos = {'test_repo_name': mock_live_repo}
mock_live_repo.commits.return_value = test_commits

test_git_instance_info = {'pull_from': '1900-07-23', 'repos_dict_v2': {}}

# Act — should not raise despite the first repo being deleted
result_commits = list(
bitbucket_server.get_commits_for_included_branches(
mock_client,
[mock_deleted_repo, mock_live_repo],
{},
False,
test_git_instance_info,
False,
False,
)
)

# Assert — deleted repo produced nothing, live repo's commits still returned
self.assertEqual(len(result_commits), len(test_commits))

def test_get_pull_requests_skips_deleted_repo(self):

Check warning on line 394 in tests/test_bitbucket_server.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add a return type hint to this function declaration.

See more on https://sonarcloud.io/project/issues?id=Jellyfish-AI_jf_agent&issues=AZ5mXe_OCCYY0sBvlPby&open=AZ5mXe_OCCYY0sBvlPby&pullRequest=458
# Arrange
test_prs = _get_test_data('test_prs.json')
test_repos = _get_test_data('test_repos.json')
test_commits = _get_test_data('test_commits.json')

mock_client = MagicMock()
mock_project = MagicMock()

mock_deleted_repo = MagicMock()
mock_deleted_repo.get.side_effect = stashy.errors.NotFoundException(MagicMock())

mock_live_repo = MagicMock()
mock_live_repo.get.return_value = test_repos[0]
mock_live_repo.pull_requests.all.return_value = test_prs

mock_client.projects = {'test_project_key': mock_project}
mock_project.repos = {'test_repo_name': mock_live_repo}
mock_live_repo.commits.return_value = test_commits

test_git_instance_info = {'pull_from': '1900-07-23', 'repos_dict_v2': {}}

# Act — should not raise despite the first repo being deleted
result_prs = list(
bitbucket_server.get_pull_requests(
mock_client,
[mock_deleted_repo, mock_live_repo],
False,
test_git_instance_info,
False,
False,
)
)

# Assert — deleted repo produced nothing, live repo's PRs still returned
self.assertEqual(len(result_prs), len(test_prs))


def _get_test_data(file_name):
with open(f'{TEST_INPUT_FILE_PATH}{file_name}', 'r') as f:
Expand Down
Loading