launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #26901
[Merge] ~ilasc/turnip:add-git-gc-api into turnip:master
Ioana Lasc has proposed merging ~ilasc/turnip:add-git-gc-api into turnip:master.
Commit message:
Add a Git GC api
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~ilasc/turnip/+git/turnip/+merge/401220
Add an async endpoint to enable us to run a Git GC on a repository ourselves.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~ilasc/turnip:add-git-gc-api into turnip:master.
diff --git a/turnip/api/store.py b/turnip/api/store.py
index f2719a7..f1e4664 100644
--- a/turnip/api/store.py
+++ b/turnip/api/store.py
@@ -498,6 +498,32 @@ def repack(repo_path):
raise
+@app.task
+def gc(repo_path):
+ """Run as git gc for repository."""
+ logger = tasks_logger
+ logger.info(
+ "Asynchronous GC run triggered for repository: "
+ "%s", repo_path)
+
+ ensure_config(repo_path)
+
+ gc_args = ['git', 'gc']
+
+ try:
+ subprocess.check_call(
+ gc_args, cwd=repo_path,
+ stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+ logger.info(
+ "GC completed for repository: "
+ "%s", repo_path)
+ except subprocess.CalledProcessError:
+ logger.info(
+ "GC failed for repository: "
+ "%s", repo_path)
+ raise
+
+
def get_refs(repo_store, repo_name, exclude_prefixes=None):
"""Return all refs for a git repository."""
with open_repo(repo_store, repo_name) as repo:
diff --git a/turnip/api/tests/test_api.py b/turnip/api/tests/test_api.py
index b3d0fb6..85683b1 100644
--- a/turnip/api/tests/test_api.py
+++ b/turnip/api/tests/test_api.py
@@ -837,6 +837,10 @@ class ApiTestCase(TestCase, ApiRepoStoreMixin):
resp = self.app.post_json('/repo/{}/repack'.format(self.repo_path))
self.assertEqual(200, resp.status_code)
+ def test_repo_gc(self):
+ resp = self.app.post_json('/repo/{}/gc'.format(self.repo_path))
+ self.assertEqual(200, resp.status_code)
+
def test_repo_detect_merges_missing_target(self):
"""A non-existent target OID returns HTTP 404."""
factory = RepoFactory(self.repo_store)
diff --git a/turnip/api/tests/test_store.py b/turnip/api/tests/test_store.py
index 24cdced..e54c127 100644
--- a/turnip/api/tests/test_store.py
+++ b/turnip/api/tests/test_store.py
@@ -475,3 +475,20 @@ class InitTestCase(TestCase):
# Assert we have 0 loose objects after repack job ran
celery_fixture.waitUntil(
5, lambda: self.hasZeroLooseObjects(orig_path))
+
+ def test_gc(self):
+ celery_fixture = CeleryWorkerFixture()
+ self.useFixture(celery_fixture)
+
+ self.makeOrig()
+ orig_path = self.orig_path
+
+ # First assert we have loose objects for this repo
+ self.assertFalse(self.hasZeroLooseObjects(orig_path))
+
+ # Trigger the GC job
+ store.gc.apply_async((orig_path, ))
+
+ # Assert we have 0 loose objects after a gc job ran
+ celery_fixture.waitUntil(
+ 5, lambda: self.hasZeroLooseObjects(orig_path))
diff --git a/turnip/api/views.py b/turnip/api/views.py
index cda3a00..09a9a92 100644
--- a/turnip/api/views.py
+++ b/turnip/api/views.py
@@ -148,6 +148,22 @@ class RepackAPI(BaseAPI):
return Response(status=200)
+@resource(path='/repo/{name}/gc')
+class GitGCAPI(BaseAPI):
+ """Provides HTTP API for running gc for repository."""
+
+ def __init__(self, request, context=None):
+ super(GitGCAPI, self).__init__()
+ self.request = request
+
+ @validate_path
+ def post(self, repo_store, repo_name):
+ repo_path = os.path.join(repo_store, repo_name)
+ kwargs = dict(repo_path=repo_path)
+ store.gc.apply_async(kwargs=kwargs)
+ return Response(status=200)
+
+
@resource(path='/repo/{name}/refs-copy')
class RefCopyAPI(BaseAPI):
"""Provides HTTP API for git references copy operations."""