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

Proposed by Colin Watson on 2016-01-12
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 2016-01-12 Approve on 2016-01-14
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.
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/code/interfaces/gitrepository.py'
2--- lib/lp/code/interfaces/gitrepository.py 2016-01-12 04:34:46 +0000
3+++ lib/lp/code/interfaces/gitrepository.py 2016-01-12 04:34:46 +0000
4@@ -516,6 +516,14 @@
5 diffs updated.
6 """
7
8+ def markRecipesStale(paths):
9+ """Mark recipes associated with this repository as stale.
10+
11+ :param paths: A list of reference paths. Any recipes that include
12+ an entry that points to this repository and that has a `revspec`
13+ that is one of these paths will be marked as stale.
14+ """
15+
16 def detectMerges(paths, logger=None):
17 """Detect merges of landing candidates.
18
19
20=== modified file 'lib/lp/code/model/gitrepository.py'
21--- lib/lp/code/model/gitrepository.py 2016-01-12 04:34:46 +0000
22+++ lib/lp/code/model/gitrepository.py 2016-01-12 04:34:46 +0000
23@@ -977,6 +977,11 @@
24 hook = SourcePackageRecipe.preLoadDataForSourcePackageRecipes
25 return DecoratedResultSet(self._getRecipes(), pre_iter_hook=hook)
26
27+ def markRecipesStale(self, paths):
28+ """See `IGitRepository`."""
29+ for recipe in self._getRecipes(paths):
30+ recipe.is_stale = True
31+
32 def _markProposalMerged(self, proposal, merged_revision_id, logger=None):
33 if logger is not None:
34 logger.info(
35@@ -1047,6 +1052,11 @@
36 prerequisite_git_repository=self):
37 alteration_operations.append(
38 ClearPrerequisiteRepository(merge_proposal))
39+ deletion_operations.extend(
40+ DeletionCallable(
41+ recipe, msg("This recipe uses this repository."),
42+ recipe.destroySelf)
43+ for recipe in self.recipes)
44 if not getUtility(ISnapSet).findByGitRepository(self).is_empty():
45 alteration_operations.append(DeletionCallable(
46 None, msg("Some snap packages build from this repository."),
47
48=== modified file 'lib/lp/code/model/tests/test_gitrepository.py'
49--- lib/lp/code/model/tests/test_gitrepository.py 2015-12-10 00:05:41 +0000
50+++ lib/lp/code/model/tests/test_gitrepository.py 2016-01-12 04:34:46 +0000
51@@ -1,4 +1,4 @@
52-# Copyright 2015 Canonical Ltd. This software is licensed under the
53+# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
54 # GNU Affero General Public License version 3 (see the file LICENSE).
55
56 """Tests for Git repositories."""
57@@ -452,6 +452,19 @@
58 [ReclaimGitRepositorySpaceJob(job).repository_path
59 for job in jobs])
60
61+ def test_destroySelf_with_SourcePackageRecipe(self):
62+ # If repository is a base_git_repository in a recipe, it is deleted.
63+ recipe = self.factory.makeSourcePackageRecipe(
64+ branches=self.factory.makeGitRefs(owner=self.user))
65+ recipe.base_git_repository.destroySelf(break_references=True)
66+
67+ def test_destroySelf_with_SourcePackageRecipe_as_non_base(self):
68+ # If repository is referred to by a recipe, it is deleted.
69+ [ref1] = self.factory.makeGitRefs(owner=self.user)
70+ [ref2] = self.factory.makeGitRefs(owner=self.user)
71+ self.factory.makeSourcePackageRecipe(branches=[ref1, ref2])
72+ ref2.repository.destroySelf(break_references=True)
73+
74 def test_destroySelf_with_inline_comments_draft(self):
75 # Draft inline comments related to a deleted repository (source or
76 # target MP repository) also get removed.
77@@ -683,6 +696,14 @@
78 self.assertRaises(
79 SQLObjectNotFound, BranchMergeProposal.get, merge_proposal_id)
80
81+ def test_deletionRequirements_with_SourcePackageRecipe(self):
82+ # Recipes are listed as deletion requirements.
83+ recipe = self.factory.makeSourcePackageRecipe(
84+ branches=self.factory.makeGitRefs())
85+ self.assertEqual(
86+ {recipe: ("delete", "This recipe uses this repository.")},
87+ recipe.base_git_repository.getDeletionRequirements())
88+
89
90 class TestGitRepositoryModifications(TestCaseWithFactory):
91 """Tests for Git repository modifications."""
92@@ -1820,6 +1841,64 @@
93 self.assertEqual(0, len(jobs))
94
95
96+class TestGitRepositoryMarkRecipesStale(TestCaseWithFactory):
97+
98+ layer = ZopelessDatabaseLayer
99+
100+ def test_base_repository_recipe(self):
101+ # On ref changes, recipes where this ref is the base become stale.
102+ [ref] = self.factory.makeGitRefs()
103+ recipe = self.factory.makeSourcePackageRecipe(branches=[ref])
104+ removeSecurityProxy(recipe).is_stale = False
105+ ref.repository.createOrUpdateRefs(
106+ {ref.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
107+ self.assertTrue(recipe.is_stale)
108+
109+ def test_base_repository_different_ref_recipe(self):
110+ # On ref changes, recipes where a different ref in the same
111+ # repository is the base are left alone.
112+ ref1, ref2 = self.factory.makeGitRefs(
113+ paths=[u"refs/heads/a", u"refs/heads/b"])
114+ recipe = self.factory.makeSourcePackageRecipe(branches=[ref1])
115+ removeSecurityProxy(recipe).is_stale = False
116+ ref1.repository.createOrUpdateRefs(
117+ {ref2.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
118+ self.assertFalse(recipe.is_stale)
119+
120+ def test_instruction_repository_recipe(self):
121+ # On ref changes, recipes including this repository become stale.
122+ [base_ref] = self.factory.makeGitRefs()
123+ [ref] = self.factory.makeGitRefs()
124+ recipe = self.factory.makeSourcePackageRecipe(branches=[base_ref, ref])
125+ removeSecurityProxy(recipe).is_stale = False
126+ ref.repository.createOrUpdateRefs(
127+ {ref.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
128+ self.assertTrue(recipe.is_stale)
129+
130+ def test_instruction_repository_different_ref_recipe(self):
131+ # On ref changes, recipes including a different ref in the same
132+ # repository are left alone.
133+ [base_ref] = self.factory.makeGitRefs()
134+ ref1, ref2 = self.factory.makeGitRefs(
135+ paths=[u"refs/heads/a", u"refs/heads/b"])
136+ recipe = self.factory.makeSourcePackageRecipe(
137+ branches=[base_ref, ref1])
138+ removeSecurityProxy(recipe).is_stale = False
139+ ref1.repository.createOrUpdateRefs(
140+ {ref2.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
141+ self.assertFalse(recipe.is_stale)
142+
143+ def test_unrelated_repository_recipe(self):
144+ # On ref changes, unrelated recipes are left alone.
145+ [ref] = self.factory.makeGitRefs()
146+ recipe = self.factory.makeSourcePackageRecipe(
147+ branches=self.factory.makeGitRefs())
148+ removeSecurityProxy(recipe).is_stale = False
149+ ref.repository.createOrUpdateRefs(
150+ {ref.path: {u"sha1": u"0" * 40, u"type": GitObjectType.COMMIT}})
151+ self.assertFalse(recipe.is_stale)
152+
153+
154 class TestGitRepositoryDetectMerges(TestCaseWithFactory):
155
156 layer = LaunchpadZopelessLayer
157
158=== modified file 'lib/lp/code/subscribers/git.py'
159--- lib/lp/code/subscribers/git.py 2015-06-12 17:55:28 +0000
160+++ lib/lp/code/subscribers/git.py 2016-01-12 04:34:46 +0000
161@@ -1,4 +1,4 @@
162-# Copyright 2015 Canonical Ltd. This software is licensed under the
163+# Copyright 2015-2016 Canonical Ltd. This software is licensed under the
164 # GNU Affero General Public License version 3 (see the file LICENSE).
165
166 """Event subscribers for Git repositories."""
167@@ -10,4 +10,5 @@
168 """Some references in a Git repository have been updated."""
169 repository.updateMergeCommitIDs(event.paths)
170 repository.scheduleDiffUpdates(event.paths)
171+ repository.markRecipesStale(event.paths)
172 repository.detectMerges(event.paths, logger=event.logger)