Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ def _sync_repos_for_org(
organization_id=rpc_org.id,
integration_id=integration.id,
providers=[provider],
external_ids=safe_to_disable,
)
repo_by_eid = {
r.external_id: r
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ def disable_repos_batch(
organization_id=rpc_org.id,
integration_id=integration.id,
providers=[provider],
external_ids=external_ids,
)
repo_by_external_id = {r.external_id: r for r in all_repos}

Expand Down Expand Up @@ -517,6 +518,7 @@ def restore_repos_batch(
organization_id=rpc_org.id,
integration_id=integration.id,
providers=[provider],
external_ids=external_ids,
)
integration_repo_provider = get_integration_repository_provider(integration)
restore_set = set(external_ids)
Expand Down
9 changes: 8 additions & 1 deletion src/sentry/plugins/providers/integration_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def _adoptable_repositories(self, organization_id: int, **filters: Any) -> list[
organization_id=organization_id,
providers=[self.id],
external_id=filters.get("external_id"),
external_ids=filters.get("external_ids"),
)
}
return [
Expand Down Expand Up @@ -378,11 +379,17 @@ def _find_repositories(
Includes unlinked rows this provider may adopt: plugin-era ones and ones with no
provider (see ``_adoptable_repositories``).
"""
external_id_list = sorted(external_ids)
provider_repos = repository_service.get_repositories(
organization_id=organization.id,
providers=[self.id],
external_ids=external_id_list,
)
legacy_repos = self._adoptable_repositories(
organization.id,
external_ids=external_id_list,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will the additional external_ids filter allow the service calls that create candidates to behave correctly? It looks like they would filter the return of those service calls so that the taken check on line 188 wouldn't work the same anymore.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently given the set of external_ids, and the fact that the way a row can be considered "taken" involves the external_id it doesn't matter if you filter before or after.

From clanker:
The filtering and adoptability check commute for the requested IDs. For a candidate with external ID A, only a canonical row with external ID A can mark it as taken. Filtering both candidates and taken by the same requested set therefore cannot remove a relevant blocker.

Also test_create_repositories__does_not_adopt_over_an_existing_row was not added by this PR but seems to show the behavior remains correct

has_integration=False,
)
legacy_repos = self._adoptable_repositories(organization.id, has_integration=False)

found: dict[str, RpcRepository] = {}
for repo in provider_repos + legacy_repos:
Expand Down
15 changes: 15 additions & 0 deletions tests/sentry/plugins/test_integration_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from sentry.constants import ObjectStatus
from sentry.integrations.github.repository import GitHubRepositoryProvider
from sentry.integrations.services.repository import repository_service
from sentry.models.repository import REPOSITORY_NAME_LENGTH, REPOSITORY_URL_LENGTH, Repository
from sentry.plugins.providers.integration_repository import RepoExistsError
from sentry.shared_integrations.exceptions import IntegrationError
Expand Down Expand Up @@ -325,6 +326,20 @@ def test_create_repositories__adopts_own_and_provider_less_rows(
assert repo.provider == "integrations:github"
assert repo.integration_id == self.integration.id

def test_create_repositories__scopes_lookups_to_external_ids(self, get_jwt: MagicMock) -> None:
other_config = {**self.config, "external_id": "999", "identifier": "getsentry/other"}

with patch.object(
repository_service,
"get_repositories",
wraps=repository_service.get_repositories,
) as get_repositories:
self.provider.create_repositories([self.config, other_config], self.organization)

assert get_repositories.call_count == 4
for call in get_repositories.call_args_list:
assert set(call.kwargs["external_ids"]) == {"654321", "999"}

def test_create_repository__does_not_adopt_over_an_existing_row(
self, get_jwt: MagicMock
) -> None:
Expand Down
Loading