Merge ~cjwatson/launchpad:mark-charm-recipes-stale into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 4173b1254ea41f5c7665be6dd6c945a9a0a4fa7c
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:mark-charm-recipes-stale
Merge into: launchpad:master
Diff against target: 115 lines (+65/-1)
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 (+46/-1)
lib/lp/code/subscribers/git.py (+1/-0)
Reviewer Review Type Date Requested Status
Jürgen Gmach Approve
Review via email: mp+411464@code.launchpad.net

Commit message

Mark charm recipes stale when their source branches changed

To post a comment you must log in.
Revision history for this message
Jürgen Gmach (jugmac00) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/code/interfaces/gitrepository.py b/lib/lp/code/interfaces/gitrepository.py
2index 363356d..cb12a5d 100644
3--- a/lib/lp/code/interfaces/gitrepository.py
4+++ b/lib/lp/code/interfaces/gitrepository.py
5@@ -644,6 +644,14 @@ class IGitRepositoryView(IHasRecipes):
6 based on one of these paths will be marked as stale.
7 """
8
9+ def markCharmRecipesStale(paths):
10+ """Mark charm recipes associated with this repository as stale.
11+
12+ :param paths: A list of reference paths. Any charm recipes that
13+ include an entry that points to this repository and that are
14+ based on one of these paths will be marked as stale.
15+ """
16+
17 def detectMerges(paths, logger=None):
18 """Detect merges of landing candidates.
19
20diff --git a/lib/lp/code/model/gitrepository.py b/lib/lp/code/model/gitrepository.py
21index 99d451b..796ab80 100644
22--- a/lib/lp/code/model/gitrepository.py
23+++ b/lib/lp/code/model/gitrepository.py
24@@ -1290,6 +1290,16 @@ class GitRepository(StormBase, WebhookTargetMixin, AccessTokenTargetMixin,
25 # this.
26 removeSecurityProxy(snap).is_stale = True
27
28+ def markCharmRecipesStale(self, paths):
29+ """See `IGitRepository`."""
30+ recipes = getUtility(ICharmRecipeSet).findByGitRepository(
31+ self, paths=paths, check_permissions=False)
32+ for recipe in recipes:
33+ # ICharmRecipeSet.findByGitRepository returns security-proxied
34+ # CharmRecipe objects on which the is_stale attribute is
35+ # read-only. Bypass this.
36+ removeSecurityProxy(recipe).is_stale = True
37+
38 def _markProposalMerged(self, proposal, merged_revision_id, logger=None):
39 if logger is not None:
40 logger.info(
41diff --git a/lib/lp/code/model/tests/test_gitrepository.py b/lib/lp/code/model/tests/test_gitrepository.py
42index e1579ee..dbdf8d9 100644
43--- a/lib/lp/code/model/tests/test_gitrepository.py
44+++ b/lib/lp/code/model/tests/test_gitrepository.py
45@@ -55,7 +55,10 @@ from lp.app.enums import (
46 )
47 from lp.app.errors import NotFoundError
48 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
49-from lp.charms.interfaces.charmrecipe import CHARM_RECIPE_ALLOW_CREATE
50+from lp.charms.interfaces.charmrecipe import (
51+ CHARM_RECIPE_ALLOW_CREATE,
52+ CHARM_RECIPE_PRIVATE_FEATURE_FLAG,
53+ )
54 from lp.code.enums import (
55 BranchMergeProposalStatus,
56 BranchSubscriptionDiffSize,
57@@ -2796,6 +2799,48 @@ class TestGitRepositoryMarkSnapsStale(TestCaseWithFactory):
58 self.assertTrue(snap.is_stale)
59
60
61+class TestGitRepositoryMarkCharmRecipesStale(TestCaseWithFactory):
62+
63+ layer = ZopelessDatabaseLayer
64+
65+ def setUp(self):
66+ super().setUp()
67+ self.useFixture(FeatureFixture({
68+ CHARM_RECIPE_ALLOW_CREATE: "on",
69+ CHARM_RECIPE_PRIVATE_FEATURE_FLAG: "on",
70+ }))
71+
72+ def test_same_repository(self):
73+ # On ref changes, charm recipes using this ref become stale.
74+ [ref] = self.factory.makeGitRefs()
75+ recipe = self.factory.makeCharmRecipe(git_ref=ref)
76+ removeSecurityProxy(recipe).is_stale = False
77+ ref.repository.createOrUpdateRefs(
78+ {ref.path: {"sha1": "0" * 40, "type": GitObjectType.COMMIT}})
79+ self.assertTrue(recipe.is_stale)
80+
81+ def test_same_repository_different_ref(self):
82+ # On ref changes, charm recipes using a different ref in the same
83+ # repository are left alone.
84+ ref1, ref2 = self.factory.makeGitRefs(
85+ paths=["refs/heads/a", "refs/heads/b"])
86+ recipe = self.factory.makeCharmRecipe(git_ref=ref1)
87+ removeSecurityProxy(recipe).is_stale = False
88+ ref1.repository.createOrUpdateRefs(
89+ {ref2.path: {"sha1": "0" * 40, "type": GitObjectType.COMMIT}})
90+ self.assertFalse(recipe.is_stale)
91+
92+ def test_different_repository(self):
93+ # On ref changes, unrelated charm recipes are left alone.
94+ [ref] = self.factory.makeGitRefs()
95+ recipe = self.factory.makeCharmRecipe(
96+ git_ref=self.factory.makeGitRefs()[0])
97+ removeSecurityProxy(recipe).is_stale = False
98+ ref.repository.createOrUpdateRefs(
99+ {ref.path: {"sha1": "0" * 40, "type": GitObjectType.COMMIT}})
100+ self.assertFalse(recipe.is_stale)
101+
102+
103 class TestGitRepositoryFork(TestCaseWithFactory):
104
105 layer = DatabaseFunctionalLayer
106diff --git a/lib/lp/code/subscribers/git.py b/lib/lp/code/subscribers/git.py
107index 5a4ad04..30b432e 100644
108--- a/lib/lp/code/subscribers/git.py
109+++ b/lib/lp/code/subscribers/git.py
110@@ -9,4 +9,5 @@ def refs_updated(repository, event):
111 repository.updateLandingTargets(event.paths)
112 repository.markRecipesStale(event.paths)
113 repository.markSnapsStale(event.paths)
114+ repository.markCharmRecipesStale(event.paths)
115 repository.detectMerges(event.paths, logger=event.logger)

Subscribers

People subscribed via source and target branches

to status/vote changes: