launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #25840
[Merge] ~ilasc/launchpad:add-repack-endpoint into launchpad:master
Ioana Lasc has proposed merging ~ilasc/launchpad:add-repack-endpoint into launchpad:master.
Commit message:
Add endpoint for git repository repack
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~ilasc/launchpad/+git/launchpad/+merge/395148
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~ilasc/launchpad:add-repack-endpoint into launchpad:master.
diff --git a/lib/lp/code/errors.py b/lib/lp/code/errors.py
index bed7db5..69646ef 100644
--- a/lib/lp/code/errors.py
+++ b/lib/lp/code/errors.py
@@ -25,6 +25,7 @@ __all__ = [
'CannotDeleteGitRepository',
'CannotHaveLinkedBranch',
'CannotModifyNonHostedGitRepository',
+ 'CannotRepackRepository',
'CannotUpgradeBranch',
'CannotUpgradeNonHosted',
'CodeImportAlreadyRequested',
@@ -490,6 +491,11 @@ class GitRepositoryBlobUnsupportedRemote(Exception):
self.repository_url)
+@error_status(http_client.FORBIDDEN)
+class CannotRepackRepository(Exception):
+ """Tried to repack a repository."""
+
+
class GitRepositoryDeletionFault(Exception):
"""Raised when there is a fault deleting a repository."""
diff --git a/lib/lp/code/interfaces/githosting.py b/lib/lp/code/interfaces/githosting.py
index 441e850..9d98c3f 100644
--- a/lib/lp/code/interfaces/githosting.py
+++ b/lib/lp/code/interfaces/githosting.py
@@ -148,3 +148,10 @@ class IGitHostingClient(Interface):
:param refs: A list of tuples like (repo_path, ref_name) to be deleted.
:param logger: An optional logger.
"""
+
+ def repackRepository(path):
+ """Repack a Git repository.
+
+ :param path: Physical path of the new repository on the hosting
+ service.
+ """
diff --git a/lib/lp/code/interfaces/gitrepository.py b/lib/lp/code/interfaces/gitrepository.py
index ed17183..8ef5043 100644
--- a/lib/lp/code/interfaces/gitrepository.py
+++ b/lib/lp/code/interfaces/gitrepository.py
@@ -1161,6 +1161,32 @@ class IGitRepositorySet(Interface):
Projects that do not have default repositories are omitted.
"""
+ @call_with(user=REQUEST_USER)
+ @operation_parameters(
+ path=TextLine(title=_("Repository path"), required=True))
+ @export_read_operation()
+ @operation_for_version("devel")
+ def repackRepository(user, path):
+ """Trigger a repack repository operation.
+
+ :param path: The repository path.
+
+ Any of these forms may be used::
+
+ Unique names:
+ ~OWNER/PROJECT/+git/NAME
+ ~OWNER/DISTRO/+source/SOURCE/+git/NAME
+ ~OWNER/+git/NAME
+ Owner-target default aliases:
+ ~OWNER/PROJECT
+ ~OWNER/DISTRO/+source/SOURCE
+ Official aliases:
+ PROJECT
+ DISTRO/+source/SOURCE
+
+ Return None if no match was found.
+ """
+
class IGitRepositoryDelta(Interface):
"""The quantitative changes made to a Git repository that was edited or
diff --git a/lib/lp/code/model/githosting.py b/lib/lp/code/model/githosting.py
index 74f4ec0..4aa9d7c 100644
--- a/lib/lp/code/model/githosting.py
+++ b/lib/lp/code/model/githosting.py
@@ -33,7 +33,6 @@ from lp.code.errors import (
GitRepositoryDeletionFault,
GitRepositoryScanFault,
GitTargetError,
- NoSuchGitReference,
)
from lp.code.interfaces.githosting import IGitHostingClient
from lp.services.config import config
@@ -309,3 +308,8 @@ class GitHostingClient:
raise GitReferenceDeletionFault(
"Error deleting %s from repo %s: HTTP %s" %
(ref, path, e.response.status_code))
+
+ def repackRepository(self, path):
+ """See `IGitHostingClient`."""
+ url = "/repo/%s/repack" % path
+ self._post(url)
diff --git a/lib/lp/code/model/gitrepository.py b/lib/lp/code/model/gitrepository.py
index fb5e703..843d653 100644
--- a/lib/lp/code/model/gitrepository.py
+++ b/lib/lp/code/model/gitrepository.py
@@ -102,6 +102,7 @@ from lp.code.enums import (
from lp.code.errors import (
CannotDeleteGitRepository,
CannotModifyNonHostedGitRepository,
+ CannotRepackRepository,
GitDefaultConflict,
GitTargetError,
NoSuchGitReference,
@@ -172,6 +173,7 @@ from lp.registry.model.accesspolicy import (
reconcile_access_for_artifact,
)
from lp.registry.model.person import Person
+from lp.registry.model.personroles import PersonRoles
from lp.registry.model.teammembership import TeamParticipation
from lp.services.config import config
from lp.services.database import bulk
@@ -1925,6 +1927,18 @@ class GitRepositorySet:
"""See `IGitRepositorySet`."""
return []
+ def repackRepository(self, user, path):
+ roles = PersonRoles(user)
+ if roles.in_admin or roles.in_registry_experts:
+ repository, extra_path = getUtility(IGitLookup).getByPath(path)
+ if repository is None:
+ return None
+ repository_path = repository.getInternalPath()
+ getUtility(IGitHostingClient).repackRepository(repository_path)
+ else:
+ raise CannotRepackRepository(
+ "Only admins and registry experts can repack repositories")
+
@staticmethod
def preloadDefaultRepositoriesForProjects(projects):
repositories = bulk.load_referencing(
diff --git a/lib/lp/code/model/tests/test_gitrepository.py b/lib/lp/code/model/tests/test_gitrepository.py
index b83f9da..99a1b81 100644
--- a/lib/lp/code/model/tests/test_gitrepository.py
+++ b/lib/lp/code/model/tests/test_gitrepository.py
@@ -139,7 +139,10 @@ from lp.registry.interfaces.accesspolicy import (
IAccessPolicyArtifactSource,
IAccessPolicySource,
)
-from lp.registry.interfaces.person import IPerson
+from lp.registry.interfaces.person import (
+ IPerson,
+ IPersonSet,
+ )
from lp.registry.interfaces.persondistributionsourcepackage import (
IPersonDistributionSourcePackageFactory,
)
@@ -195,6 +198,7 @@ from lp.testing.pages import (
LaunchpadWebServiceCaller,
webservice_for_person,
)
+from lp.testing.sampledata import ADMIN_EMAIL
from lp.xmlrpc import faults
from lp.xmlrpc.interfaces import IPrivateApplication
@@ -3824,6 +3828,46 @@ class TestGitRepositoryWebservice(TestCaseWithFactory):
layer = DatabaseFunctionalLayer
+ def test_repackRepository(self):
+ hosting_fixture = self.useFixture(GitHostingFixture())
+ owner_db = self.factory.makePerson()
+ repository_db = self.factory.makeGitRepository(
+ owner=owner_db, name="repository")
+ repo_path = repository_db.shortened_path
+ webservice_user = getUtility(IPersonSet).find(ADMIN_EMAIL).any()
+ admin_url = api_url(webservice_user)
+ webservice = webservice_for_person(
+ webservice_user, permission=OAuthPermission.WRITE_PUBLIC)
+ webservice.default_api_version = "devel"
+ response = webservice.named_get(
+ "/+git", "repackRepository", user=admin_url, path=repo_path)
+ self.assertEqual(200, response.status)
+ self.assertEqual(1, hosting_fixture.repackRepository.call_count)
+
+ with person_logged_in(ANONYMOUS):
+ user_url = api_url(owner_db)
+ webservice = webservice_for_person(
+ owner_db, permission=OAuthPermission.WRITE_PUBLIC)
+ webservice.default_api_version = "devel"
+ response = webservice.named_get(
+ "/+git", "repackRepository", user=user_url, path=repo_path)
+ self.assertEqual(403, response.status)
+ self.assertEqual(1, hosting_fixture.repackRepository.call_count)
+
+ logout()
+ with admin_logged_in():
+ person = self.factory.makePerson()
+ reg_expert = getUtility(IPersonSet).getByName('registry')
+ reg_expert.addMember(person, reg_expert)
+ reg_expert_url = api_url(reg_expert)
+ webservice = webservice_for_person(
+ webservice_user, permission=OAuthPermission.WRITE_PUBLIC)
+ webservice.default_api_version = "devel"
+ response = webservice.named_get(
+ "/+git", "repackRepository", user=reg_expert_url, path=repo_path)
+ self.assertEqual(200, response.status)
+ self.assertEqual(2, hosting_fixture.repackRepository.call_count)
+
def test_urls(self):
owner_db = self.factory.makePerson(name="person")
project_db = self.factory.makeProduct(name="project")
diff --git a/lib/lp/code/tests/helpers.py b/lib/lp/code/tests/helpers.py
index fae251a..a336a5c 100644
--- a/lib/lp/code/tests/helpers.py
+++ b/lib/lp/code/tests/helpers.py
@@ -329,6 +329,7 @@ class GitHostingFixture(fixtures.Fixture):
self.getBlob = FakeMethod(result=blob)
self.delete = FakeMethod()
self.disable_memcache = disable_memcache
+ self.repackRepository = FakeMethod()
def _setUp(self):
self.useFixture(ZopeUtilityFixture(self, IGitHostingClient))