Merge lp:~cjwatson/launchpad/git-recipe-stale into lp:launchpad

Proposed by Colin Watson
Status: Merged
Merged at revision: 17896
Proposed branch: lp:~cjwatson/launchpad/git-recipe-stale
Merge into: lp:launchpad
Prerequisite: lp:~cjwatson/launchpad/git-recipe-delete
Diff against target: 172 lines (+100/-2)
4 files modified
lib/lp/code/interfaces/gitrepository.py (+8/-0)
lib/lp/code/model/gitrepository.py (+10/-0)
lib/lp/code/model/tests/test_gitrepository.py (+80/-1)
lib/lp/code/subscribers/git.py (+2/-1)
To merge this branch: bzr merge lp:~cjwatson/launchpad/git-recipe-stale
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+282261@code.launchpad.net

Commit message

Mark Git recipes as stale when their branches change.

Description of the change

Mark Git recipes as stale when their branches change.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lib/lp/code/interfaces/gitrepository.py'
--- lib/lp/code/interfaces/gitrepository.py 2016-01-12 04:34:46 +0000
+++ lib/lp/code/interfaces/gitrepository.py 2016-01-12 04:34:46 +0000
@@ -516,6 +516,14 @@
516 diffs updated.516 diffs updated.
517 """517 """
518518
519 def markRecipesStale(paths):
520 """Mark recipes associated with this repository as stale.
521
522 :param paths: A list of reference paths. Any recipes that include
523 an entry that points to this repository and that has a `revspec`
524 that is one of these paths will be marked as stale.
525 """
526
519 def detectMerges(paths, logger=None):527 def detectMerges(paths, logger=None):
520 """Detect merges of landing candidates.528 """Detect merges of landing candidates.
521529
522530
=== modified file 'lib/lp/code/model/gitrepository.py'
--- lib/lp/code/model/gitrepository.py 2016-01-12 04:34:46 +0000
+++ lib/lp/code/model/gitrepository.py 2016-01-12 04:34:46 +0000
@@ -977,6 +977,11 @@
977 hook = SourcePackageRecipe.preLoadDataForSourcePackageRecipes977 hook = SourcePackageRecipe.preLoadDataForSourcePackageRecipes
978 return DecoratedResultSet(self._getRecipes(), pre_iter_hook=hook)978 return DecoratedResultSet(self._getRecipes(), pre_iter_hook=hook)
979979
980 def markRecipesStale(self, paths):
981 """See `IGitRepository`."""
982 for recipe in self._getRecipes(paths):
983 recipe.is_stale = True
984
980 def _markProposalMerged(self, proposal, merged_revision_id, logger=None):985 def _markProposalMerged(self, proposal, merged_revision_id, logger=None):
981 if logger is not None:986 if logger is not None:
982 logger.info(987 logger.info(
@@ -1047,6 +1052,11 @@
1047 prerequisite_git_repository=self):1052 prerequisite_git_repository=self):
1048 alteration_operations.append(1053 alteration_operations.append(
1049 ClearPrerequisiteRepository(merge_proposal))1054 ClearPrerequisiteRepository(merge_proposal))
1055 deletion_operations.extend(
1056 DeletionCallable(
1057 recipe, msg("This recipe uses this repository."),
1058 recipe.destroySelf)
1059 for recipe in self.recipes)
1050 if not getUtility(ISnapSet).findByGitRepository(self).is_empty():1060 if not getUtility(ISnapSet).findByGitRepository(self).is_empty():
1051 alteration_operations.append(DeletionCallable(1061 alteration_operations.append(DeletionCallable(
1052 None, msg("Some snap packages build from this repository."),1062 None, msg("Some snap packages build from this repository."),
10531063
=== modified file 'lib/lp/code/model/tests/test_gitrepository.py'
--- lib/lp/code/model/tests/test_gitrepository.py 2015-12-10 00:05:41 +0000
+++ lib/lp/code/model/tests/test_gitrepository.py 2016-01-12 04:34:46 +0000
@@ -1,4 +1,4 @@
1# Copyright 2015 Canonical Ltd. This software is licensed under the1# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Tests for Git repositories."""4"""Tests for Git repositories."""
@@ -452,6 +452,19 @@
452 [ReclaimGitRepositorySpaceJob(job).repository_path452 [ReclaimGitRepositorySpaceJob(job).repository_path
453 for job in jobs])453 for job in jobs])
454454
455 def test_destroySelf_with_SourcePackageRecipe(self):
456 # If repository is a base_git_repository in a recipe, it is deleted.
457 recipe = self.factory.makeSourcePackageRecipe(
458 branches=self.factory.makeGitRefs(owner=self.user))
459 recipe.base_git_repository.destroySelf(break_references=True)
460
461 def test_destroySelf_with_SourcePackageRecipe_as_non_base(self):
462 # If repository is referred to by a recipe, it is deleted.
463 [ref1] = self.factory.makeGitRefs(owner=self.user)
464 [ref2] = self.factory.makeGitRefs(owner=self.user)
465 self.factory.makeSourcePackageRecipe(branches=[ref1, ref2])
466 ref2.repository.destroySelf(break_references=True)
467
455 def test_destroySelf_with_inline_comments_draft(self):468 def test_destroySelf_with_inline_comments_draft(self):
456 # Draft inline comments related to a deleted repository (source or469 # Draft inline comments related to a deleted repository (source or
457 # target MP repository) also get removed.470 # target MP repository) also get removed.
@@ -683,6 +696,14 @@
683 self.assertRaises(696 self.assertRaises(
684 SQLObjectNotFound, BranchMergeProposal.get, merge_proposal_id)697 SQLObjectNotFound, BranchMergeProposal.get, merge_proposal_id)
685698
699 def test_deletionRequirements_with_SourcePackageRecipe(self):
700 # Recipes are listed as deletion requirements.
701 recipe = self.factory.makeSourcePackageRecipe(
702 branches=self.factory.makeGitRefs())
703 self.assertEqual(
704 {recipe: ("delete", "This recipe uses this repository.")},
705 recipe.base_git_repository.getDeletionRequirements())
706
686707
687class TestGitRepositoryModifications(TestCaseWithFactory):708class TestGitRepositoryModifications(TestCaseWithFactory):
688 """Tests for Git repository modifications."""709 """Tests for Git repository modifications."""
@@ -1820,6 +1841,64 @@
1820 self.assertEqual(0, len(jobs))1841 self.assertEqual(0, len(jobs))
18211842
18221843
1844class TestGitRepositoryMarkRecipesStale(TestCaseWithFactory):
1845
1846 layer = ZopelessDatabaseLayer
1847
1848 def test_base_repository_recipe(self):
1849 # On ref changes, recipes where this ref is the base become stale.
1850 [ref] = self.factory.makeGitRefs()
1851 recipe = self.factory.makeSourcePackageRecipe(branches=[ref])
1852 removeSecurityProxy(recipe).is_stale = False
1853 ref.repository.createOrUpdateRefs(
1854 {ref.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
1855 self.assertTrue(recipe.is_stale)
1856
1857 def test_base_repository_different_ref_recipe(self):
1858 # On ref changes, recipes where a different ref in the same
1859 # repository is the base are left alone.
1860 ref1, ref2 = self.factory.makeGitRefs(
1861 paths=[u"refs/heads/a", u"refs/heads/b"])
1862 recipe = self.factory.makeSourcePackageRecipe(branches=[ref1])
1863 removeSecurityProxy(recipe).is_stale = False
1864 ref1.repository.createOrUpdateRefs(
1865 {ref2.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
1866 self.assertFalse(recipe.is_stale)
1867
1868 def test_instruction_repository_recipe(self):
1869 # On ref changes, recipes including this repository become stale.
1870 [base_ref] = self.factory.makeGitRefs()
1871 [ref] = self.factory.makeGitRefs()
1872 recipe = self.factory.makeSourcePackageRecipe(branches=[base_ref, ref])
1873 removeSecurityProxy(recipe).is_stale = False
1874 ref.repository.createOrUpdateRefs(
1875 {ref.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
1876 self.assertTrue(recipe.is_stale)
1877
1878 def test_instruction_repository_different_ref_recipe(self):
1879 # On ref changes, recipes including a different ref in the same
1880 # repository are left alone.
1881 [base_ref] = self.factory.makeGitRefs()
1882 ref1, ref2 = self.factory.makeGitRefs(
1883 paths=[u"refs/heads/a", u"refs/heads/b"])
1884 recipe = self.factory.makeSourcePackageRecipe(
1885 branches=[base_ref, ref1])
1886 removeSecurityProxy(recipe).is_stale = False
1887 ref1.repository.createOrUpdateRefs(
1888 {ref2.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
1889 self.assertFalse(recipe.is_stale)
1890
1891 def test_unrelated_repository_recipe(self):
1892 # On ref changes, unrelated recipes are left alone.
1893 [ref] = self.factory.makeGitRefs()
1894 recipe = self.factory.makeSourcePackageRecipe(
1895 branches=self.factory.makeGitRefs())
1896 removeSecurityProxy(recipe).is_stale = False
1897 ref.repository.createOrUpdateRefs(
1898 {ref.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
1899 self.assertFalse(recipe.is_stale)
1900
1901
1823class TestGitRepositoryDetectMerges(TestCaseWithFactory):1902class TestGitRepositoryDetectMerges(TestCaseWithFactory):
18241903
1825 layer = LaunchpadZopelessLayer1904 layer = LaunchpadZopelessLayer
18261905
=== modified file 'lib/lp/code/subscribers/git.py'
--- lib/lp/code/subscribers/git.py 2015-06-12 17:55:28 +0000
+++ lib/lp/code/subscribers/git.py 2016-01-12 04:34:46 +0000
@@ -1,4 +1,4 @@
1# Copyright 2015 Canonical Ltd. This software is licensed under the1# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
2# GNU Affero General Public License version 3 (see the file LICENSE).2# GNU Affero General Public License version 3 (see the file LICENSE).
33
4"""Event subscribers for Git repositories."""4"""Event subscribers for Git repositories."""
@@ -10,4 +10,5 @@
10 """Some references in a Git repository have been updated."""10 """Some references in a Git repository have been updated."""
11 repository.updateMergeCommitIDs(event.paths)11 repository.updateMergeCommitIDs(event.paths)
12 repository.scheduleDiffUpdates(event.paths)12 repository.scheduleDiffUpdates(event.paths)
13 repository.markRecipesStale(event.paths)
13 repository.detectMerges(event.paths, logger=event.logger)14 repository.detectMerges(event.paths, logger=event.logger)