Merge lp:~jelmer/launchpad/no-code-import-approval into lp:launchpad
- no-code-import-approval
- Merge into devel
Proposed by
Jelmer Vernooij
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Jelmer Vernooij | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 13821 | ||||
Proposed branch: | lp:~jelmer/launchpad/no-code-import-approval | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
581 lines (+81/-125) 13 files modified
lib/lp/code/doc/codeimport-event.txt (+5/-5) lib/lp/code/doc/codeimport.txt (+1/-5) lib/lp/code/model/codeimport.py (+4/-8) lib/lp/code/model/tests/test_branch.py (+0/-2) lib/lp/code/model/tests/test_codeimport.py (+12/-40) lib/lp/code/model/tests/test_codeimportjob.py (+16/-11) lib/lp/code/stories/codeimport/xx-admin-codeimport.txt (+3/-20) lib/lp/code/stories/codeimport/xx-create-codeimport.txt (+9/-4) lib/lp/code/stories/codeimport/xx-edit-codeimport.txt (+3/-1) lib/lp/code/stories/webservice/xx-code-import.txt (+2/-2) lib/lp/testing/factory.py (+11/-13) lib/lp/testing/tests/test_factory.py (+4/-3) utilities/sourcedeps.cache (+11/-11) |
||||
To merge this branch: | bzr merge lp:~jelmer/launchpad/no-code-import-approval | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Benji York (community) | code | Approve | |
Review via email:
|
This proposal supersedes a proposal from 2011-08-28.
Commit message
[r=benji][bug=418932] Remove the requirement for svn and cvs imports to be pre-approved by a Launchpad admin.
Description of the change
Remove the requirement for svn and cvs imports to be pre-approved by a Launchpad admin, fixing bug #418932.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/code/doc/codeimport-event.txt' | |||
2 | --- lib/lp/code/doc/codeimport-event.txt 2010-10-18 22:24:59 +0000 | |||
3 | +++ lib/lp/code/doc/codeimport-event.txt 2011-08-30 00:09:34 +0000 | |||
4 | @@ -120,7 +120,7 @@ | |||
5 | 120 | >>> print_items(svn_create_event) | 120 | >>> print_items(svn_create_event) |
6 | 121 | CODE_IMPORT <muted> | 121 | CODE_IMPORT <muted> |
7 | 122 | OWNER ... | 122 | OWNER ... |
9 | 123 | REVIEW_STATUS u'NEW' | 123 | REVIEW_STATUS u'REVIEWED' |
10 | 124 | ASSIGNEE None | 124 | ASSIGNEE None |
11 | 125 | UPDATE_INTERVAL None | 125 | UPDATE_INTERVAL None |
12 | 126 | URL u'svn://svn.example.com/trunk' | 126 | URL u'svn://svn.example.com/trunk' |
13 | @@ -144,7 +144,7 @@ | |||
14 | 144 | >>> print_items(cvs_create_event) | 144 | >>> print_items(cvs_create_event) |
15 | 145 | CODE_IMPORT <muted> | 145 | CODE_IMPORT <muted> |
16 | 146 | OWNER ... | 146 | OWNER ... |
18 | 147 | REVIEW_STATUS u'NEW' | 147 | REVIEW_STATUS u'REVIEWED' |
19 | 148 | ASSIGNEE None | 148 | ASSIGNEE None |
20 | 149 | UPDATE_INTERVAL None | 149 | UPDATE_INTERVAL None |
21 | 150 | CVS_ROOT u':pserver:anonymous@cvs.example.com:/cvsroot' | 150 | CVS_ROOT u':pserver:anonymous@cvs.example.com:/cvsroot' |
22 | @@ -206,7 +206,7 @@ | |||
23 | 206 | 206 | ||
24 | 207 | >>> from lp.code.enums import CodeImportReviewStatus | 207 | >>> from lp.code.enums import CodeImportReviewStatus |
25 | 208 | >>> removeSecurityProxy(svn_import).review_status = ( | 208 | >>> removeSecurityProxy(svn_import).review_status = ( |
27 | 209 | ... CodeImportReviewStatus.REVIEWED) | 209 | ... CodeImportReviewStatus.SUSPENDED) |
28 | 210 | 210 | ||
29 | 211 | After applying changes, the newModify method can create an event that | 211 | After applying changes, the newModify method can create an event that |
30 | 212 | details the changes that have been applied. | 212 | details the changes that have been applied. |
31 | @@ -234,8 +234,8 @@ | |||
32 | 234 | >>> print_items(modify_event) | 234 | >>> print_items(modify_event) |
33 | 235 | CODE_IMPORT <muted> | 235 | CODE_IMPORT <muted> |
34 | 236 | OWNER ... | 236 | OWNER ... |
37 | 237 | REVIEW_STATUS u'REVIEWED' | 237 | REVIEW_STATUS u'SUSPENDED' |
38 | 238 | OLD_REVIEW_STATUS u'NEW' | 238 | OLD_REVIEW_STATUS u'REVIEWED' |
39 | 239 | ASSIGNEE None | 239 | ASSIGNEE None |
40 | 240 | UPDATE_INTERVAL None | 240 | UPDATE_INTERVAL None |
41 | 241 | URL u'svn://svn.example.com/trunk' | 241 | URL u'svn://svn.example.com/trunk' |
42 | 242 | 242 | ||
43 | === modified file 'lib/lp/code/doc/codeimport.txt' | |||
44 | --- lib/lp/code/doc/codeimport.txt 2011-06-28 17:13:42 +0000 | |||
45 | +++ lib/lp/code/doc/codeimport.txt 2011-08-30 00:09:34 +0000 | |||
46 | @@ -243,7 +243,7 @@ | |||
47 | 243 | >>> code_import = factory.makeProductCodeImport( | 243 | >>> code_import = factory.makeProductCodeImport( |
48 | 244 | ... svn_branch_url='http://svn.example.com/project') | 244 | ... svn_branch_url='http://svn.example.com/project') |
49 | 245 | >>> print code_import.review_status.title | 245 | >>> print code_import.review_status.title |
51 | 246 | Pending Review | 246 | Reviewed |
52 | 247 | 247 | ||
53 | 248 | When an import operator updates the code import emails are sent out to | 248 | When an import operator updates the code import emails are sent out to |
54 | 249 | the branch subscribers and members of VCS Imports that describe the | 249 | the branch subscribers and members of VCS Imports that describe the |
55 | @@ -275,8 +275,6 @@ | |||
56 | 275 | To: david.allouche@canonical.com, ... | 275 | To: david.allouche@canonical.com, ... |
57 | 276 | Subject: Code import product.../name... status: Reviewed | 276 | Subject: Code import product.../name... status: Reviewed |
58 | 277 | <BLANKLINE> | 277 | <BLANKLINE> |
59 | 278 | The import has been approved and an import will start shortly. | ||
60 | 279 | <BLANKLINE> | ||
61 | 280 | ... is now being imported from: | 278 | ... is now being imported from: |
62 | 281 | http://svn.example.com/project/trunk | 279 | http://svn.example.com/project/trunk |
63 | 282 | instead of: | 280 | instead of: |
64 | @@ -293,8 +291,6 @@ | |||
65 | 293 | To: import@example.com | 291 | To: import@example.com |
66 | 294 | Subject: Code import product.../name... status: Reviewed | 292 | Subject: Code import product.../name... status: Reviewed |
67 | 295 | <BLANKLINE> | 293 | <BLANKLINE> |
68 | 296 | The import has been approved and an import will start shortly. | ||
69 | 297 | <BLANKLINE> | ||
70 | 298 | ... is now being imported from: | 294 | ... is now being imported from: |
71 | 299 | http://svn.example.com/project/trunk | 295 | http://svn.example.com/project/trunk |
72 | 300 | instead of: | 296 | instead of: |
73 | 301 | 297 | ||
74 | === modified file 'lib/lp/code/model/codeimport.py' | |||
75 | --- lib/lp/code/model/codeimport.py 2011-08-28 07:29:11 +0000 | |||
76 | +++ lib/lp/code/model/codeimport.py 2011-08-30 00:09:34 +0000 | |||
77 | @@ -198,7 +198,8 @@ | |||
78 | 198 | setattr(self, name, value) | 198 | setattr(self, name, value) |
79 | 199 | if 'review_status' in data: | 199 | if 'review_status' in data: |
80 | 200 | if data['review_status'] == CodeImportReviewStatus.REVIEWED: | 200 | if data['review_status'] == CodeImportReviewStatus.REVIEWED: |
82 | 201 | CodeImportJobWorkflow().newJob(self) | 201 | if self.import_job is None: |
83 | 202 | CodeImportJobWorkflow().newJob(self) | ||
84 | 202 | else: | 203 | else: |
85 | 203 | self._removeJob() | 204 | self._removeJob() |
86 | 204 | event = event_set.newModify(self, user, token) | 205 | event = event_set.newModify(self, user, token) |
87 | @@ -265,13 +266,8 @@ | |||
88 | 265 | "Don't know how to sanity check source details for unknown " | 266 | "Don't know how to sanity check source details for unknown " |
89 | 266 | "rcs_type %s" % rcs_type) | 267 | "rcs_type %s" % rcs_type) |
90 | 267 | if review_status is None: | 268 | if review_status is None: |
98 | 268 | # Auto approve git and hg imports. | 269 | # Auto approve imports. |
99 | 269 | if rcs_type in ( | 270 | review_status = CodeImportReviewStatus.REVIEWED |
93 | 270 | RevisionControlSystems.GIT, RevisionControlSystems.HG, | ||
94 | 271 | RevisionControlSystems.BZR): | ||
95 | 272 | review_status = CodeImportReviewStatus.REVIEWED | ||
96 | 273 | else: | ||
97 | 274 | review_status = CodeImportReviewStatus.NEW | ||
100 | 275 | if not target.supports_code_imports: | 271 | if not target.supports_code_imports: |
101 | 276 | raise AssertionError("%r doesn't support code imports" % target) | 272 | raise AssertionError("%r doesn't support code imports" % target) |
102 | 277 | if owner is None: | 273 | if owner is None: |
103 | 278 | 274 | ||
104 | === modified file 'lib/lp/code/model/tests/test_branch.py' | |||
105 | --- lib/lp/code/model/tests/test_branch.py 2011-08-25 22:58:14 +0000 | |||
106 | +++ lib/lp/code/model/tests/test_branch.py 2011-08-30 00:09:34 +0000 | |||
107 | @@ -1510,7 +1510,6 @@ | |||
108 | 1510 | """break_links allows deleting a code import branch.""" | 1510 | """break_links allows deleting a code import branch.""" |
109 | 1511 | code_import = self.factory.makeCodeImport() | 1511 | code_import = self.factory.makeCodeImport() |
110 | 1512 | code_import_id = code_import.id | 1512 | code_import_id = code_import.id |
111 | 1513 | self.factory.makeCodeImportJob(code_import) | ||
112 | 1514 | code_import.branch.destroySelf(break_references=True) | 1513 | code_import.branch.destroySelf(break_references=True) |
113 | 1515 | self.assertRaises( | 1514 | self.assertRaises( |
114 | 1516 | SQLObjectNotFound, CodeImport.get, code_import_id) | 1515 | SQLObjectNotFound, CodeImport.get, code_import_id) |
115 | @@ -1575,7 +1574,6 @@ | |||
116 | 1575 | """DeleteCodeImport.__call__ must delete the CodeImport.""" | 1574 | """DeleteCodeImport.__call__ must delete the CodeImport.""" |
117 | 1576 | code_import = self.factory.makeCodeImport() | 1575 | code_import = self.factory.makeCodeImport() |
118 | 1577 | code_import_id = code_import.id | 1576 | code_import_id = code_import.id |
119 | 1578 | self.factory.makeCodeImportJob(code_import) | ||
120 | 1579 | DeleteCodeImport(code_import)() | 1577 | DeleteCodeImport(code_import)() |
121 | 1580 | self.assertRaises( | 1578 | self.assertRaises( |
122 | 1581 | SQLObjectNotFound, CodeImport.get, code_import_id) | 1579 | SQLObjectNotFound, CodeImport.get, code_import_id) |
123 | 1582 | 1580 | ||
124 | === modified file 'lib/lp/code/model/tests/test_codeimport.py' | |||
125 | --- lib/lp/code/model/tests/test_codeimport.py 2011-08-28 08:36:14 +0000 | |||
126 | +++ lib/lp/code/model/tests/test_codeimport.py 2011-08-30 00:09:34 +0000 | |||
127 | @@ -56,20 +56,6 @@ | |||
128 | 56 | 56 | ||
129 | 57 | layer = DatabaseFunctionalLayer | 57 | layer = DatabaseFunctionalLayer |
130 | 58 | 58 | ||
131 | 59 | def test_new_svn_import(self): | ||
132 | 60 | """A new subversion code import should have NEW status.""" | ||
133 | 61 | code_import = CodeImportSet().new( | ||
134 | 62 | registrant=self.factory.makePerson(), | ||
135 | 63 | target=IBranchTarget(self.factory.makeProduct()), | ||
136 | 64 | branch_name='imported', | ||
137 | 65 | rcs_type=RevisionControlSystems.SVN, | ||
138 | 66 | url=self.factory.getUniqueURL()) | ||
139 | 67 | self.assertEqual( | ||
140 | 68 | CodeImportReviewStatus.NEW, | ||
141 | 69 | code_import.review_status) | ||
142 | 70 | # No job is created for the import. | ||
143 | 71 | self.assertIs(None, code_import.import_job) | ||
144 | 72 | |||
145 | 73 | def test_new_svn_import_svn_scheme(self): | 59 | def test_new_svn_import_svn_scheme(self): |
146 | 74 | """A subversion import can use the svn:// scheme.""" | 60 | """A subversion import can use the svn:// scheme.""" |
147 | 75 | code_import = CodeImportSet().new( | 61 | code_import = CodeImportSet().new( |
148 | @@ -79,10 +65,10 @@ | |||
149 | 79 | rcs_type=RevisionControlSystems.SVN, | 65 | rcs_type=RevisionControlSystems.SVN, |
150 | 80 | url=self.factory.getUniqueURL(scheme="svn")) | 66 | url=self.factory.getUniqueURL(scheme="svn")) |
151 | 81 | self.assertEqual( | 67 | self.assertEqual( |
153 | 82 | CodeImportReviewStatus.NEW, | 68 | CodeImportReviewStatus.REVIEWED, |
154 | 83 | code_import.review_status) | 69 | code_import.review_status) |
155 | 84 | # No job is created for the import. | 70 | # No job is created for the import. |
157 | 85 | self.assertIs(None, code_import.import_job) | 71 | self.assertIsNot(None, code_import.import_job) |
158 | 86 | 72 | ||
159 | 87 | def test_reviewed_svn_import(self): | 73 | def test_reviewed_svn_import(self): |
160 | 88 | """A specific review status can be set for a new import.""" | 74 | """A specific review status can be set for a new import.""" |
161 | @@ -92,30 +78,15 @@ | |||
162 | 92 | branch_name='imported', | 78 | branch_name='imported', |
163 | 93 | rcs_type=RevisionControlSystems.SVN, | 79 | rcs_type=RevisionControlSystems.SVN, |
164 | 94 | url=self.factory.getUniqueURL(), | 80 | url=self.factory.getUniqueURL(), |
166 | 95 | review_status=CodeImportReviewStatus.REVIEWED) | 81 | review_status=None) |
167 | 96 | self.assertEqual( | 82 | self.assertEqual( |
168 | 97 | CodeImportReviewStatus.REVIEWED, | 83 | CodeImportReviewStatus.REVIEWED, |
169 | 98 | code_import.review_status) | 84 | code_import.review_status) |
170 | 99 | # A job is created for the import. | 85 | # A job is created for the import. |
171 | 100 | self.assertIsNot(None, code_import.import_job) | 86 | self.assertIsNot(None, code_import.import_job) |
172 | 101 | 87 | ||
190 | 102 | def test_new_cvs_import(self): | 88 | def test_cvs_import_reviewed(self): |
191 | 103 | """A new CVS code import should have NEW status.""" | 89 | """A new CVS code import should have REVIEWED status.""" |
175 | 104 | code_import = CodeImportSet().new( | ||
176 | 105 | registrant=self.factory.makePerson(), | ||
177 | 106 | target=IBranchTarget(self.factory.makeProduct()), | ||
178 | 107 | branch_name='imported', | ||
179 | 108 | rcs_type=RevisionControlSystems.CVS, | ||
180 | 109 | cvs_root=self.factory.getUniqueURL(), | ||
181 | 110 | cvs_module='module') | ||
182 | 111 | self.assertEqual( | ||
183 | 112 | CodeImportReviewStatus.NEW, | ||
184 | 113 | code_import.review_status) | ||
185 | 114 | # No job is created for the import. | ||
186 | 115 | self.assertIs(None, code_import.import_job) | ||
187 | 116 | |||
188 | 117 | def test_reviewed_cvs_import(self): | ||
189 | 118 | """A specific review status can be set for a new import.""" | ||
192 | 119 | code_import = CodeImportSet().new( | 90 | code_import = CodeImportSet().new( |
193 | 120 | registrant=self.factory.makePerson(), | 91 | registrant=self.factory.makePerson(), |
194 | 121 | target=IBranchTarget(self.factory.makeProduct()), | 92 | target=IBranchTarget(self.factory.makeProduct()), |
195 | @@ -123,7 +94,7 @@ | |||
196 | 123 | rcs_type=RevisionControlSystems.CVS, | 94 | rcs_type=RevisionControlSystems.CVS, |
197 | 124 | cvs_root=self.factory.getUniqueURL(), | 95 | cvs_root=self.factory.getUniqueURL(), |
198 | 125 | cvs_module='module', | 96 | cvs_module='module', |
200 | 126 | review_status=CodeImportReviewStatus.REVIEWED) | 97 | review_status=None) |
201 | 127 | self.assertEqual( | 98 | self.assertEqual( |
202 | 128 | CodeImportReviewStatus.REVIEWED, | 99 | CodeImportReviewStatus.REVIEWED, |
203 | 129 | code_import.review_status) | 100 | code_import.review_status) |
204 | @@ -275,8 +246,7 @@ | |||
205 | 275 | """Ensure deleting CodeImport objects deletes associated jobs.""" | 246 | """Ensure deleting CodeImport objects deletes associated jobs.""" |
206 | 276 | code_import = self.factory.makeCodeImport() | 247 | code_import = self.factory.makeCodeImport() |
207 | 277 | login_person(getUtility(ILaunchpadCelebrities).vcs_imports.teamowner) | 248 | login_person(getUtility(ILaunchpadCelebrities).vcs_imports.teamowner) |
210 | 278 | code_import_job = self.factory.makeCodeImportJob(code_import) | 249 | job_id = code_import.import_job.id |
209 | 279 | job_id = code_import_job.id | ||
211 | 280 | CodeImportJobSet().getById(job_id) | 250 | CodeImportJobSet().getById(job_id) |
212 | 281 | job = CodeImportJobSet().getById(job_id) | 251 | job = CodeImportJobSet().getById(job_id) |
213 | 282 | assert job is not None | 252 | assert job is not None |
214 | @@ -644,7 +614,8 @@ | |||
215 | 644 | # tryFailingImportAgain only succeeds for imports that are FAILING. | 614 | # tryFailingImportAgain only succeeds for imports that are FAILING. |
216 | 645 | outcomes = {} | 615 | outcomes = {} |
217 | 646 | for status in CodeImportReviewStatus.items: | 616 | for status in CodeImportReviewStatus.items: |
219 | 647 | code_import = self.factory.makeCodeImport() | 617 | code_import = self.factory.makeCodeImport( |
220 | 618 | review_status=CodeImportReviewStatus.NEW) | ||
221 | 648 | code_import.updateFromData( | 619 | code_import.updateFromData( |
222 | 649 | {'review_status': status}, self.factory.makePerson()) | 620 | {'review_status': status}, self.factory.makePerson()) |
223 | 650 | try: | 621 | try: |
224 | @@ -726,9 +697,10 @@ | |||
225 | 726 | self.assertEqual(requester, e.requesting_user) | 697 | self.assertEqual(requester, e.requesting_user) |
226 | 727 | 698 | ||
227 | 728 | def test_exception_on_disabled(self): | 699 | def test_exception_on_disabled(self): |
229 | 729 | # get an SVN request, which isn't reviewed by default | 700 | # get an SVN request which is suspended |
230 | 730 | code_import = self.factory.makeCodeImport( | 701 | code_import = self.factory.makeCodeImport( |
232 | 731 | svn_branch_url=self.factory.getUniqueURL()) | 702 | svn_branch_url=self.factory.getUniqueURL(), |
233 | 703 | review_status=CodeImportReviewStatus.SUSPENDED) | ||
234 | 732 | requester = self.factory.makePerson() | 704 | requester = self.factory.makePerson() |
235 | 733 | # which leads to an exception if we try and ask for an import | 705 | # which leads to an exception if we try and ask for an import |
236 | 734 | self.assertRaises( | 706 | self.assertRaises( |
237 | 735 | 707 | ||
238 | === modified file 'lib/lp/code/model/tests/test_codeimportjob.py' | |||
239 | --- lib/lp/code/model/tests/test_codeimportjob.py 2011-06-29 12:00:39 +0000 | |||
240 | +++ lib/lp/code/model/tests/test_codeimportjob.py 2011-08-30 00:09:34 +0000 | |||
241 | @@ -115,7 +115,8 @@ | |||
242 | 115 | 115 | ||
243 | 116 | def makeJob(self, state, date_due_delta, requesting_user=None): | 116 | def makeJob(self, state, date_due_delta, requesting_user=None): |
244 | 117 | """Create a CodeImportJob object from a spec.""" | 117 | """Create a CodeImportJob object from a spec.""" |
246 | 118 | code_import = self.factory.makeCodeImport() | 118 | code_import = self.factory.makeCodeImport( |
247 | 119 | review_status=CodeImportReviewStatus.NEW) | ||
248 | 119 | job = self.factory.makeCodeImportJob(code_import) | 120 | job = self.factory.makeCodeImportJob(code_import) |
249 | 120 | if state == CodeImportJobState.RUNNING: | 121 | if state == CodeImportJobState.RUNNING: |
250 | 121 | getUtility(ICodeImportJobWorkflow).startJob(job, self.machine) | 122 | getUtility(ICodeImportJobWorkflow).startJob(job, self.machine) |
251 | @@ -387,11 +388,12 @@ | |||
252 | 387 | def test_wrongReviewStatus(self): | 388 | def test_wrongReviewStatus(self): |
253 | 388 | # CodeImportJobWorkflow.newJob fails if the CodeImport review_status | 389 | # CodeImportJobWorkflow.newJob fails if the CodeImport review_status |
254 | 389 | # is different from REVIEWED. | 390 | # is different from REVIEWED. |
256 | 390 | new_import = self.factory.makeCodeImport() | 391 | new_import = self.factory.makeCodeImport( |
257 | 392 | review_status=CodeImportReviewStatus.SUSPENDED) | ||
258 | 391 | branch_name = new_import.branch.unique_name | 393 | branch_name = new_import.branch.unique_name |
259 | 392 | # Testing newJob failure. | 394 | # Testing newJob failure. |
260 | 393 | self.assertFailure( | 395 | self.assertFailure( |
262 | 394 | "Review status of %s is not REVIEWED: NEW" % (branch_name,), | 396 | "Review status of %s is not REVIEWED: SUSPENDED" % (branch_name,), |
263 | 395 | getUtility(ICodeImportJobWorkflow).newJob, new_import) | 397 | getUtility(ICodeImportJobWorkflow).newJob, new_import) |
264 | 396 | 398 | ||
265 | 397 | def test_existingJob(self): | 399 | def test_existingJob(self): |
266 | @@ -417,14 +419,17 @@ | |||
267 | 417 | # If there is no CodeImportResult for the CodeImport, then the new | 419 | # If there is no CodeImportResult for the CodeImport, then the new |
268 | 418 | # CodeImportJob has date_due set to UTC_NOW. | 420 | # CodeImportJob has date_due set to UTC_NOW. |
269 | 419 | code_import = self.getCodeImportForDateDueTest() | 421 | code_import = self.getCodeImportForDateDueTest() |
272 | 420 | job = getUtility(ICodeImportJobWorkflow).newJob(code_import) | 422 | self.assertSqlAttributeEqualsDate(code_import.import_job, 'date_due', |
273 | 421 | self.assertSqlAttributeEqualsDate(job, 'date_due', UTC_NOW) | 423 | UTC_NOW) |
274 | 422 | 424 | ||
275 | 423 | def test_dateDueRecentPreviousResult(self): | 425 | def test_dateDueRecentPreviousResult(self): |
276 | 424 | # If there is a CodeImportResult for the CodeImport that is more | 426 | # If there is a CodeImportResult for the CodeImport that is more |
277 | 425 | # recent than the effective_update_interval, then the new | 427 | # recent than the effective_update_interval, then the new |
278 | 426 | # CodeImportJob has date_due set in the future. | 428 | # CodeImportJob has date_due set in the future. |
279 | 427 | code_import = self.getCodeImportForDateDueTest() | 429 | code_import = self.getCodeImportForDateDueTest() |
280 | 430 | # A code import job is automatically started when a reviewed code import | ||
281 | 431 | # is created. Remove it, so a "clean" one can be created later. | ||
282 | 432 | removeSecurityProxy(code_import).import_job.destroySelf() | ||
283 | 428 | # Create a CodeImportResult that started a long time ago. This one | 433 | # Create a CodeImportResult that started a long time ago. This one |
284 | 429 | # must be superseded by the more recent one created below. | 434 | # must be superseded by the more recent one created below. |
285 | 430 | machine = self.factory.makeCodeImportMachine() | 435 | machine = self.factory.makeCodeImportMachine() |
286 | @@ -469,8 +474,8 @@ | |||
287 | 469 | date_job_started=datetime(2000, 1, 1, 12, 0, 0, tzinfo=UTC), | 474 | date_job_started=datetime(2000, 1, 1, 12, 0, 0, tzinfo=UTC), |
288 | 470 | date_created=datetime(2000, 1, 1, 12, 5, 0, tzinfo=UTC)) | 475 | date_created=datetime(2000, 1, 1, 12, 5, 0, tzinfo=UTC)) |
289 | 471 | # When we create the job, its date due must be set to UTC_NOW. | 476 | # When we create the job, its date due must be set to UTC_NOW. |
292 | 472 | job = getUtility(ICodeImportJobWorkflow).newJob(code_import) | 477 | self.assertSqlAttributeEqualsDate(code_import.import_job, 'date_due', |
293 | 473 | self.assertSqlAttributeEqualsDate(job, 'date_due', UTC_NOW) | 478 | UTC_NOW) |
294 | 474 | 479 | ||
295 | 475 | 480 | ||
296 | 476 | class TestCodeImportJobWorkflowDeletePendingJob(TestCaseWithFactory, | 481 | class TestCodeImportJobWorkflowDeletePendingJob(TestCaseWithFactory, |
297 | @@ -500,7 +505,8 @@ | |||
298 | 500 | def test_noJob(self): | 505 | def test_noJob(self): |
299 | 501 | # CodeImportJobWorkflow.deletePendingJob fails if the | 506 | # CodeImportJobWorkflow.deletePendingJob fails if the |
300 | 502 | # CodeImport is not associated to a CodeImportJob. | 507 | # CodeImport is not associated to a CodeImportJob. |
302 | 503 | new_import = self.factory.makeCodeImport() | 508 | new_import = self.factory.makeCodeImport( |
303 | 509 | review_status=CodeImportReviewStatus.NEW) | ||
304 | 504 | branch_name = new_import.branch.unique_name | 510 | branch_name = new_import.branch.unique_name |
305 | 505 | # Testing deletePendingJob failure. | 511 | # Testing deletePendingJob failure. |
306 | 506 | self.assertFailure( | 512 | self.assertFailure( |
307 | @@ -578,7 +584,7 @@ | |||
308 | 578 | # CodeImportJobWorkflow.requestJob sets requesting_user and | 584 | # CodeImportJobWorkflow.requestJob sets requesting_user and |
309 | 579 | # date_due if the current date_due is in the future. | 585 | # date_due if the current date_due is in the future. |
310 | 580 | code_import = self.factory.makeCodeImport() | 586 | code_import = self.factory.makeCodeImport() |
312 | 581 | pending_job = self.factory.makeCodeImportJob(code_import) | 587 | pending_job = code_import.import_job |
313 | 582 | person = self.factory.makePerson() | 588 | person = self.factory.makePerson() |
314 | 583 | # Set date_due in the future. ICodeImportJob does not allow setting | 589 | # Set date_due in the future. ICodeImportJob does not allow setting |
315 | 584 | # date_due, so we must use removeSecurityProxy. | 590 | # date_due, so we must use removeSecurityProxy. |
316 | @@ -877,8 +883,7 @@ | |||
317 | 877 | unchecked_result_fields.difference_update(['log_file', 'status']) | 883 | unchecked_result_fields.difference_update(['log_file', 'status']) |
318 | 878 | 884 | ||
319 | 879 | code_import = self.factory.makeCodeImport() | 885 | code_import = self.factory.makeCodeImport() |
322 | 880 | removeSecurityProxy(code_import).review_status = \ | 886 | removeSecurityProxy(code_import).import_job.destroySelf() |
321 | 881 | CodeImportReviewStatus.REVIEWED | ||
323 | 882 | self.assertFinishJobPassesThroughJobField( | 887 | self.assertFinishJobPassesThroughJobField( |
324 | 883 | 'code_import', 'code_import', code_import) | 888 | 'code_import', 'code_import', code_import) |
325 | 884 | unchecked_result_fields.remove('code_import') | 889 | unchecked_result_fields.remove('code_import') |
326 | 885 | 890 | ||
327 | === modified file 'lib/lp/code/stories/codeimport/xx-admin-codeimport.txt' | |||
328 | --- lib/lp/code/stories/codeimport/xx-admin-codeimport.txt 2010-04-28 02:49:58 +0000 | |||
329 | +++ lib/lp/code/stories/codeimport/xx-admin-codeimport.txt 2011-08-30 00:09:34 +0000 | |||
330 | @@ -61,9 +61,11 @@ | |||
331 | 61 | ... print extract_text(div) | 61 | ... print extract_text(div) |
332 | 62 | >>> import_browser.open(svn_import_location) | 62 | >>> import_browser.open(svn_import_location) |
333 | 63 | >>> print_import_details(import_browser) | 63 | >>> print_import_details(import_browser) |
335 | 64 | Import Status: Pending Review | 64 | Import Status: Reviewed |
336 | 65 | This branch is an import of the Subversion branch | 65 | This branch is an import of the Subversion branch |
337 | 66 | from svn://svn.example.com/fooix/trunk. | 66 | from svn://svn.example.com/fooix/trunk. |
338 | 67 | The next import is scheduled to run | ||
339 | 68 | as soon as possible. | ||
340 | 67 | Edit import source or review import | 69 | Edit import source or review import |
341 | 68 | 70 | ||
342 | 69 | 71 | ||
343 | @@ -76,7 +78,6 @@ | |||
344 | 76 | >>> import_browser.getLink('Edit import source or review import').click() | 78 | >>> import_browser.getLink('Edit import source or review import').click() |
345 | 77 | >>> print_submit_buttons(import_browser.contents) | 79 | >>> print_submit_buttons(import_browser.contents) |
346 | 78 | Update | 80 | Update |
347 | 79 | Approve | ||
348 | 80 | Mark Invalid | 81 | Mark Invalid |
349 | 81 | Suspend | 82 | Suspend |
350 | 82 | Mark Failing | 83 | Mark Failing |
351 | @@ -190,24 +191,6 @@ | |||
352 | 190 | The code import has been updated. | 191 | The code import has been updated. |
353 | 191 | 192 | ||
354 | 192 | 193 | ||
355 | 193 | Approving an import | ||
356 | 194 | +++++++++++++++++++ | ||
357 | 195 | |||
358 | 196 | When a code import is approved, a pending job is created for it. | ||
359 | 197 | |||
360 | 198 | >>> import_browser.open(svn_import_location + '/+edit-import') | ||
361 | 199 | >>> import_browser.getControl('Approve').click() | ||
362 | 200 | >>> print_import_details(import_browser) | ||
363 | 201 | Import Status: Reviewed | ||
364 | 202 | ... | ||
365 | 203 | The next import is scheduled to run as soon as possible. | ||
366 | 204 | Edit import source or review import | ||
367 | 205 | |||
368 | 206 | >>> for message in get_feedback_messages(import_browser.contents): | ||
369 | 207 | ... print extract_text(message) | ||
370 | 208 | The code import has been approved. | ||
371 | 209 | |||
372 | 210 | |||
373 | 211 | Invalidating an import | 194 | Invalidating an import |
374 | 212 | ++++++++++++++++++++++ | 195 | ++++++++++++++++++++++ |
375 | 213 | 196 | ||
376 | 214 | 197 | ||
377 | === modified file 'lib/lp/code/stories/codeimport/xx-create-codeimport.txt' | |||
378 | --- lib/lp/code/stories/codeimport/xx-create-codeimport.txt 2010-09-28 19:25:54 +0000 | |||
379 | +++ lib/lp/code/stories/codeimport/xx-create-codeimport.txt 2011-08-30 00:09:34 +0000 | |||
380 | @@ -72,9 +72,11 @@ | |||
381 | 72 | When the user clicks continue, the import branch is created | 72 | When the user clicks continue, the import branch is created |
382 | 73 | 73 | ||
383 | 74 | >>> print extract_text(find_tag_by_id(browser.contents, "import-details")) | 74 | >>> print extract_text(find_tag_by_id(browser.contents, "import-details")) |
385 | 75 | Import Status: Pending Review | 75 | Import Status: Reviewed |
386 | 76 | This branch is an import of the Subversion branch | 76 | This branch is an import of the Subversion branch |
387 | 77 | from http://svn.example.com/firefox/trunk. | 77 | from http://svn.example.com/firefox/trunk. |
388 | 78 | The next import is scheduled to run | ||
389 | 79 | as soon as possible. | ||
390 | 78 | >>> browser.getLink("http://svn.example.com/firefox/trunk") | 80 | >>> browser.getLink("http://svn.example.com/firefox/trunk") |
391 | 79 | <Link text='http://svn.example.com/firefox/trunk' | 81 | <Link text='http://svn.example.com/firefox/trunk' |
392 | 80 | url='http://svn.example.com/firefox/trunk'> | 82 | url='http://svn.example.com/firefox/trunk'> |
393 | @@ -98,9 +100,11 @@ | |||
394 | 98 | >>> browser.getControl('Project').value = "firefox" | 100 | >>> browser.getControl('Project').value = "firefox" |
395 | 99 | >>> browser.getControl('Request Import').click() | 101 | >>> browser.getControl('Request Import').click() |
396 | 100 | >>> print extract_text(find_tag_by_id(browser.contents, "import-details")) | 102 | >>> print extract_text(find_tag_by_id(browser.contents, "import-details")) |
398 | 101 | Import Status: Pending Review | 103 | Import Status: Reviewed |
399 | 102 | This branch is an import of the Subversion branch | 104 | This branch is an import of the Subversion branch |
400 | 103 | from http://user:password@svn.example.com/firefox/trunk. | 105 | from http://user:password@svn.example.com/firefox/trunk. |
401 | 106 | The next import is scheduled to run | ||
402 | 107 | as soon as possible. | ||
403 | 104 | 108 | ||
404 | 105 | 109 | ||
405 | 106 | Requesting a Git import | 110 | Requesting a Git import |
406 | @@ -165,10 +169,11 @@ | |||
407 | 165 | >>> browser.getControl('Request Import').click() | 169 | >>> browser.getControl('Request Import').click() |
408 | 166 | 170 | ||
409 | 167 | >>> print extract_text(find_tag_by_id(browser.contents, "import-details")) | 171 | >>> print extract_text(find_tag_by_id(browser.contents, "import-details")) |
411 | 168 | Import Status: Pending Review | 172 | Import Status: Reviewed |
412 | 169 | This branch is an import of the CVS module firefox from | 173 | This branch is an import of the CVS module firefox from |
413 | 170 | :pserver:anonymous@cvs.example.com:/mozilla/cvs. | 174 | :pserver:anonymous@cvs.example.com:/mozilla/cvs. |
415 | 171 | 175 | The next import is scheduled to run | |
416 | 176 | as soon as possible. | ||
417 | 172 | 177 | ||
418 | 173 | Requesting a CVS import with invalid information | 178 | Requesting a CVS import with invalid information |
419 | 174 | ================================================ | 179 | ================================================ |
420 | 175 | 180 | ||
421 | === modified file 'lib/lp/code/stories/codeimport/xx-edit-codeimport.txt' | |||
422 | --- lib/lp/code/stories/codeimport/xx-edit-codeimport.txt 2010-03-18 15:39:58 +0000 | |||
423 | +++ lib/lp/code/stories/codeimport/xx-edit-codeimport.txt 2011-08-30 00:09:34 +0000 | |||
424 | @@ -43,9 +43,11 @@ | |||
425 | 43 | ... print extract_text(div) | 43 | ... print extract_text(div) |
426 | 44 | >>> anon_browser.open(svn_import_location) | 44 | >>> anon_browser.open(svn_import_location) |
427 | 45 | >>> print_import_details(anon_browser) | 45 | >>> print_import_details(anon_browser) |
429 | 46 | Import Status: Pending Review | 46 | Import Status: Reviewed |
430 | 47 | This branch is an import of the Subversion branch | 47 | This branch is an import of the Subversion branch |
431 | 48 | from svn://svn.example.com/fooix/trunk. | 48 | from svn://svn.example.com/fooix/trunk. |
432 | 49 | The next import is scheduled to run | ||
433 | 50 | as soon as possible. | ||
434 | 49 | 51 | ||
435 | 50 | Because it's an svn:// URL, it doesn't get linkified: | 52 | Because it's an svn:// URL, it doesn't get linkified: |
436 | 51 | 53 | ||
437 | 52 | 54 | ||
438 | === modified file 'lib/lp/code/stories/webservice/xx-code-import.txt' | |||
439 | --- lib/lp/code/stories/webservice/xx-code-import.txt 2010-04-16 05:03:03 +0000 | |||
440 | +++ lib/lp/code/stories/webservice/xx-code-import.txt 2011-08-30 00:09:34 +0000 | |||
441 | @@ -55,7 +55,7 @@ | |||
442 | 55 | >>> print representation['branch_link'] | 55 | >>> print representation['branch_link'] |
443 | 56 | http://.../~import-owner/scruff/import | 56 | http://.../~import-owner/scruff/import |
444 | 57 | >>> print representation['review_status'] | 57 | >>> print representation['review_status'] |
446 | 58 | Pending Review | 58 | Reviewed |
447 | 59 | >>> print representation['rcs_type'] | 59 | >>> print representation['rcs_type'] |
448 | 60 | Subversion via CSCVS | 60 | Subversion via CSCVS |
449 | 61 | >>> print representation['url'] | 61 | >>> print representation['url'] |
450 | @@ -105,7 +105,7 @@ | |||
451 | 105 | >>> print representation['branch_link'] | 105 | >>> print representation['branch_link'] |
452 | 106 | http://.../~import-owner/scruffbuntu/manic/scruff/import | 106 | http://.../~import-owner/scruffbuntu/manic/scruff/import |
453 | 107 | >>> print representation['review_status'] | 107 | >>> print representation['review_status'] |
455 | 108 | Pending Review | 108 | Reviewed |
456 | 109 | >>> print representation['rcs_type'] | 109 | >>> print representation['rcs_type'] |
457 | 110 | Subversion via CSCVS | 110 | Subversion via CSCVS |
458 | 111 | >>> print representation['url'] | 111 | >>> print representation['url'] |
459 | 112 | 112 | ||
460 | === modified file 'lib/lp/testing/factory.py' | |||
461 | --- lib/lp/testing/factory.py 2011-08-29 17:47:36 +0000 | |||
462 | +++ lib/lp/testing/factory.py 2011-08-30 00:09:34 +0000 | |||
463 | @@ -2153,34 +2153,32 @@ | |||
464 | 2153 | else: | 2153 | else: |
465 | 2154 | assert rcs_type in (RevisionControlSystems.SVN, | 2154 | assert rcs_type in (RevisionControlSystems.SVN, |
466 | 2155 | RevisionControlSystems.BZR_SVN) | 2155 | RevisionControlSystems.BZR_SVN) |
468 | 2156 | code_import = code_import_set.new( | 2156 | return code_import_set.new( |
469 | 2157 | registrant, target, branch_name, rcs_type=rcs_type, | 2157 | registrant, target, branch_name, rcs_type=rcs_type, |
471 | 2158 | url=svn_branch_url) | 2158 | url=svn_branch_url, review_status=review_status) |
472 | 2159 | elif git_repo_url is not None: | 2159 | elif git_repo_url is not None: |
473 | 2160 | assert rcs_type in (None, RevisionControlSystems.GIT) | 2160 | assert rcs_type in (None, RevisionControlSystems.GIT) |
475 | 2161 | code_import = code_import_set.new( | 2161 | return code_import_set.new( |
476 | 2162 | registrant, target, branch_name, | 2162 | registrant, target, branch_name, |
477 | 2163 | rcs_type=RevisionControlSystems.GIT, | 2163 | rcs_type=RevisionControlSystems.GIT, |
479 | 2164 | url=git_repo_url) | 2164 | url=git_repo_url, review_status=review_status) |
480 | 2165 | elif hg_repo_url is not None: | 2165 | elif hg_repo_url is not None: |
482 | 2166 | code_import = code_import_set.new( | 2166 | return code_import_set.new( |
483 | 2167 | registrant, target, branch_name, | 2167 | registrant, target, branch_name, |
484 | 2168 | rcs_type=RevisionControlSystems.HG, | 2168 | rcs_type=RevisionControlSystems.HG, |
486 | 2169 | url=hg_repo_url) | 2169 | url=hg_repo_url, review_status=review_status) |
487 | 2170 | elif bzr_branch_url is not None: | 2170 | elif bzr_branch_url is not None: |
489 | 2171 | code_import = code_import_set.new( | 2171 | return code_import_set.new( |
490 | 2172 | registrant, target, branch_name, | 2172 | registrant, target, branch_name, |
491 | 2173 | rcs_type=RevisionControlSystems.BZR, | 2173 | rcs_type=RevisionControlSystems.BZR, |
493 | 2174 | url=bzr_branch_url) | 2174 | url=bzr_branch_url, review_status=review_status) |
494 | 2175 | else: | 2175 | else: |
495 | 2176 | assert rcs_type in (None, RevisionControlSystems.CVS) | 2176 | assert rcs_type in (None, RevisionControlSystems.CVS) |
497 | 2177 | code_import = code_import_set.new( | 2177 | return code_import_set.new( |
498 | 2178 | registrant, target, branch_name, | 2178 | registrant, target, branch_name, |
499 | 2179 | rcs_type=RevisionControlSystems.CVS, | 2179 | rcs_type=RevisionControlSystems.CVS, |
504 | 2180 | cvs_root=cvs_root, cvs_module=cvs_module) | 2180 | cvs_root=cvs_root, cvs_module=cvs_module, |
505 | 2181 | if review_status: | 2181 | review_status=review_status) |
502 | 2182 | removeSecurityProxy(code_import).review_status = review_status | ||
503 | 2183 | return code_import | ||
506 | 2184 | 2182 | ||
507 | 2185 | def makeChangelog(self, spn=None, versions=[]): | 2183 | def makeChangelog(self, spn=None, versions=[]): |
508 | 2186 | """Create and return a LFA of a valid Debian-style changelog.""" | 2184 | """Create and return a LFA of a valid Debian-style changelog.""" |
509 | 2187 | 2185 | ||
510 | === modified file 'lib/lp/testing/tests/test_factory.py' | |||
511 | --- lib/lp/testing/tests/test_factory.py 2011-08-26 04:15:38 +0000 | |||
512 | +++ lib/lp/testing/tests/test_factory.py 2011-08-30 00:09:34 +0000 | |||
513 | @@ -345,15 +345,16 @@ | |||
514 | 345 | 345 | ||
515 | 346 | # makeCodeImport | 346 | # makeCodeImport |
516 | 347 | def test_makeCodeImportNoStatus(self): | 347 | def test_makeCodeImportNoStatus(self): |
518 | 348 | # If makeCodeImport is not given a review status, it defaults to NEW. | 348 | # If makeCodeImport is not given a review status, |
519 | 349 | # it defaults to REVIEWED. | ||
520 | 349 | code_import = self.factory.makeCodeImport() | 350 | code_import = self.factory.makeCodeImport() |
521 | 350 | self.assertEqual( | 351 | self.assertEqual( |
523 | 351 | CodeImportReviewStatus.NEW, code_import.review_status) | 352 | CodeImportReviewStatus.REVIEWED, code_import.review_status) |
524 | 352 | 353 | ||
525 | 353 | def test_makeCodeImportReviewStatus(self): | 354 | def test_makeCodeImportReviewStatus(self): |
526 | 354 | # If makeCodeImport is given a review status, then that is the status | 355 | # If makeCodeImport is given a review status, then that is the status |
527 | 355 | # of the created import. | 356 | # of the created import. |
529 | 356 | status = CodeImportReviewStatus.REVIEWED | 357 | status = CodeImportReviewStatus.SUSPENDED |
530 | 357 | code_import = self.factory.makeCodeImport(review_status=status) | 358 | code_import = self.factory.makeCodeImport(review_status=status) |
531 | 358 | self.assertEqual(status, code_import.review_status) | 359 | self.assertEqual(status, code_import.review_status) |
532 | 359 | 360 | ||
533 | 360 | 361 | ||
534 | === modified file 'utilities/sourcedeps.cache' | |||
535 | --- utilities/sourcedeps.cache 2011-08-28 22:55:16 +0000 | |||
536 | +++ utilities/sourcedeps.cache 2011-08-30 00:09:34 +0000 | |||
537 | @@ -1,4 +1,8 @@ | |||
538 | 1 | { | 1 | { |
539 | 2 | "bzr-builder": [ | ||
540 | 3 | 68, | ||
541 | 4 | "launchpad@pqm.canonical.com-20101123183213-777lz46xgagn1deg" | ||
542 | 5 | ], | ||
543 | 2 | "testresources": [ | 6 | "testresources": [ |
544 | 3 | 16, | 7 | 16, |
545 | 4 | "robertc@robertcollins.net-20050911111209-ee5da49011cf936a" | 8 | "robertc@robertcollins.net-20050911111209-ee5da49011cf936a" |
546 | @@ -27,18 +31,14 @@ | |||
547 | 27 | 24, | 31 | 24, |
548 | 28 | "launchpad@pqm.canonical.com-20100601182722-wo7h2fh0fvyw3aaq" | 32 | "launchpad@pqm.canonical.com-20100601182722-wo7h2fh0fvyw3aaq" |
549 | 29 | ], | 33 | ], |
550 | 34 | "lpreview": [ | ||
551 | 35 | 23, | ||
552 | 36 | "launchpad@pqm.canonical.com-20090720061538-euyh68ifavhy0pi8" | ||
553 | 37 | ], | ||
554 | 30 | "bzr-git": [ | 38 | "bzr-git": [ |
555 | 31 | 259, | 39 | 259, |
556 | 32 | "launchpad@pqm.canonical.com-20110601140035-gl5merbechngjw5s" | 40 | "launchpad@pqm.canonical.com-20110601140035-gl5merbechngjw5s" |
557 | 33 | ], | 41 | ], |
558 | 34 | "loggerhead": [ | ||
559 | 35 | 455, | ||
560 | 36 | "danilo@canonical.com-20110817125309-2r1fgcrqt5kr5h43" | ||
561 | 37 | ], | ||
562 | 38 | "bzr-builder": [ | ||
563 | 39 | 68, | ||
564 | 40 | "launchpad@pqm.canonical.com-20101123183213-777lz46xgagn1deg" | ||
565 | 41 | ], | ||
566 | 42 | "bzr-loom": [ | 42 | "bzr-loom": [ |
567 | 43 | 49, | 43 | 49, |
568 | 44 | "launchpad@pqm.canonical.com-20110601122412-54vo3k8yae9i2zve" | 44 | "launchpad@pqm.canonical.com-20110601122412-54vo3k8yae9i2zve" |
569 | @@ -47,9 +47,9 @@ | |||
570 | 47 | 4, | 47 | 4, |
571 | 48 | "sinzui-20090526164636-1swugzupwvjgomo4" | 48 | "sinzui-20090526164636-1swugzupwvjgomo4" |
572 | 49 | ], | 49 | ], |
576 | 50 | "lpreview": [ | 50 | "loggerhead": [ |
577 | 51 | 23, | 51 | 455, |
578 | 52 | "launchpad@pqm.canonical.com-20090720061538-euyh68ifavhy0pi8" | 52 | "danilo@canonical.com-20110817125309-2r1fgcrqt5kr5h43" |
579 | 53 | ], | 53 | ], |
580 | 54 | "difftacular": [ | 54 | "difftacular": [ |
581 | 55 | 6, | 55 | 6, |
This branch looks fine.
It's unfortunate that the state is named "reviewed" when no one has
actually reviewed the import. Perhaps we could rename that status to
something like "pending" or "awaiting import" and remove the notion of
approval altogether.