Merge ~cjwatson/launchpad:expire-questions-limit into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 67a110cfbc858ed7ff7d3de656499f56e9f1daef
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:expire-questions-limit
Merge into: launchpad:master
Diff against target: 125 lines (+43/-5)
4 files modified
cronscripts/expire-questions.py (+13/-1)
lib/lp/answers/model/question.py (+5/-2)
lib/lp/answers/model/tests/test_question.py (+21/-0)
lib/lp/answers/scripts/questionexpiration.py (+4/-2)
Reviewer Review Type Date Requested Status
Ines Almeida Approve
Review via email: mp+441559@code.launchpad.net

Commit message

expire-questions: Add a --limit option

Description of the change

This is in line with the otherwise quite similar `expire-bugtasks` script. We currently have a cowboyed patch on dogfood limiting expiry there to five questions for testing; this allows us to do that using a command-line option instead, and to drop that patch.

To post a comment you must log in.
Revision history for this message
Ines Almeida (ines-almeida) wrote :

Looks good to me!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/cronscripts/expire-questions.py b/cronscripts/expire-questions.py
2index 213fe63..64b1936 100755
3--- a/cronscripts/expire-questions.py
4+++ b/cronscripts/expire-questions.py
5@@ -30,9 +30,21 @@ class ExpireQuestions(LaunchpadCronScript):
6 usage = "usage: %prog [options]"
7 description = __doc__
8
9+ def add_my_options(self):
10+ self.parser.add_option(
11+ "-l",
12+ "--limit",
13+ action="store",
14+ dest="limit",
15+ type="int",
16+ metavar="NUMBER",
17+ default=None,
18+ help="Limit expiry to NUMBER of questions.",
19+ )
20+
21 def main(self):
22 """Expire old questions."""
23- janitor = QuestionJanitor(log=self.logger)
24+ janitor = QuestionJanitor(log=self.logger, limit=self.options.limit)
25 janitor.expireQuestions(self.txn)
26
27
28diff --git a/lib/lp/answers/model/question.py b/lib/lp/answers/model/question.py
29index 3704ac3..ccf0e74 100644
30--- a/lib/lp/answers/model/question.py
31+++ b/lib/lp/answers/model/question.py
32@@ -833,7 +833,7 @@ class QuestionSet:
33 """See `IQuestionSet`."""
34 self.title = "Launchpad"
35
36- def findExpiredQuestions(self, days_before_expiration):
37+ def findExpiredQuestions(self, days_before_expiration, limit=None):
38 """See `IQuestionSet`."""
39 # This query joins to bugtasks that are not BugTaskStatus.INVALID
40 # because there are many bugtasks to one question. A question is
41@@ -859,7 +859,7 @@ class QuestionSet:
42 expiry = datetime.now(timezone.utc) - timedelta(
43 days=days_before_expiration
44 )
45- return (
46+ rows = (
47 IStore(Question)
48 .using(*origin)
49 .find(
50@@ -877,6 +877,9 @@ class QuestionSet:
51 )
52 .config(distinct=True)
53 )
54+ if limit is not None:
55+ rows = rows[:limit]
56+ return rows
57
58 def searchQuestions(
59 self,
60diff --git a/lib/lp/answers/model/tests/test_question.py b/lib/lp/answers/model/tests/test_question.py
61index 8b3abf4..15ec010 100644
62--- a/lib/lp/answers/model/tests/test_question.py
63+++ b/lib/lp/answers/model/tests/test_question.py
64@@ -126,3 +126,24 @@ class TestQuestionSet(TestCaseWithFactory):
65 question_set = getUtility(IQuestionSet)
66 expired = question_set.findExpiredQuestions(3)
67 self.assertNotIn(question, expired)
68+
69+ def test_expiredQuestions_limit(self):
70+ for _ in range(10):
71+ question = self.factory.makeQuestion()
72+ removeSecurityProxy(question).datelastquery = datetime.now(
73+ timezone.utc
74+ ) - timedelta(days=5)
75+
76+ question_set = getUtility(IQuestionSet)
77+ self.assertGreaterEqual(
78+ question_set.findExpiredQuestions(
79+ days_before_expiration=3
80+ ).count(),
81+ 10,
82+ )
83+ self.assertEqual(
84+ 5,
85+ question_set.findExpiredQuestions(
86+ days_before_expiration=3, limit=5
87+ ).count(),
88+ )
89diff --git a/lib/lp/answers/scripts/questionexpiration.py b/lib/lp/answers/scripts/questionexpiration.py
90index 32b3c1c..48da01e 100644
91--- a/lib/lp/answers/scripts/questionexpiration.py
92+++ b/lib/lp/answers/scripts/questionexpiration.py
93@@ -19,13 +19,14 @@ class QuestionJanitor:
94 without activity in a configurable period.
95 """
96
97- def __init__(self, days_before_expiration=None, log=None):
98+ def __init__(self, days_before_expiration=None, log=None, limit=None):
99 """Create a new QuestionJanitor.
100
101 :days_before_expiration: Days of inactivity before a question is
102 expired. Defaults to config.answertracker.days_before_expiration
103 :log: A logger instance to use for logging. Defaults to the default
104 logger.
105+ :limit: Expire no more than limit questions.
106 """
107
108 if days_before_expiration is None:
109@@ -37,6 +38,7 @@ class QuestionJanitor:
110 log = getLogger()
111 self.days_before_expiration = days_before_expiration
112 self.log = log
113+ self.limit = limit
114
115 self.janitor = getUtility(ILaunchpadCelebrities).janitor
116
117@@ -57,7 +59,7 @@ class QuestionJanitor:
118 try:
119 count = 0
120 expired_questions = getUtility(IQuestionSet).findExpiredQuestions(
121- self.days_before_expiration
122+ self.days_before_expiration, limit=self.limit
123 )
124 self.log.info(
125 "Found %d questions to expire." % expired_questions.count()

Subscribers

People subscribed via source and target branches

to status/vote changes: