Merge lp:~robru/cupstream2distro/fix-missing-commit-check into lp:cupstream2distro
- fix-missing-commit-check
- Merge into trunk
Proposed by
Robert Bruce Park
Status: | Merged |
---|---|
Approved by: | Robert Bruce Park |
Approved revision: | 1308 |
Merged at revision: | 1296 |
Proposed branch: | lp:~robru/cupstream2distro/fix-missing-commit-check |
Merge into: | lp:cupstream2distro |
Diff against target: |
321 lines (+89/-62) 5 files modified
citrain/recipes/merge.py (+6/-7) cupstream2distro/branchhandling.py (+32/-15) tests/strings.py (+22/-21) tests/unit/test_branchhandling.py (+25/-10) tests/unit/test_recipe_merge.py (+4/-9) |
To merge this branch: | bzr merge lp:~robru/cupstream2distro/fix-missing-commit-check |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Robert Bruce Park (community) | Approve | ||
Review via email: mp+279534@code.launchpad.net |
Commit message
Do three-way diffing in order to ignore false positive trunk commits.
Description of the change
To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1306
http://
Executed test runs:
Click here to trigger a rebuild:
http://
review:
Needs Fixing
(continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1307
http://
Executed test runs:
Click here to trigger a rebuild:
http://
review:
Needs Fixing
(continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1308
http://
Executed test runs:
Click here to trigger a rebuild:
http://
review:
Approve
(continuous-integration)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'citrain/recipes/merge.py' |
2 | --- citrain/recipes/merge.py 2015-12-02 05:35:19 +0000 |
3 | +++ citrain/recipes/merge.py 2015-12-04 01:43:03 +0000 |
4 | @@ -226,15 +226,14 @@ |
5 | def check_new_commits(self, source=None): |
6 | """Report if this package needs a rebuild, or not.""" |
7 | count = 0 |
8 | - branches = [self.merges[0].target_branch] + [ |
9 | + target = self.merges[0].target_branch |
10 | + branches = [target] + [ |
11 | branch.source_branch for branch in self.merges] |
12 | for branch in branches: |
13 | - try: |
14 | - if self.missing_branch_commits(branch.bzr_identity): |
15 | - logging.error('New commits: %s', branch.web_link) |
16 | - count += 1 |
17 | - except FileNotFoundError: |
18 | - return 'Ready to build' |
19 | + if self.missing_branch_commits( |
20 | + branch.bzr_identity, target.bzr_identity): |
21 | + logging.error('New commits: %s', branch.web_link) |
22 | + count += 1 |
23 | if count: |
24 | return 'Needs rebuild due to new commits' |
25 | return False |
26 | |
27 | === modified file 'cupstream2distro/branchhandling.py' |
28 | --- cupstream2distro/branchhandling.py 2015-12-02 05:35:19 +0000 |
29 | +++ cupstream2distro/branchhandling.py 2015-12-04 01:43:03 +0000 |
30 | @@ -36,8 +36,7 @@ |
31 | ) |
32 | |
33 | |
34 | -TRANSLATIONS = {'Launchpad', 'Translations', 'behalf'} |
35 | -ME = {'CI', 'Train', 'Bot'} |
36 | +REVID = 'revision-id: ' |
37 | SEPARATOR = '-' * 60 |
38 | IGNORED = ('Automatic PS uploader', 'Launchpad ') |
39 | BUG_REGEX = re.compile(r""" |
40 | @@ -61,6 +60,11 @@ |
41 | 'No handlers could be found for logger "bzr"'.split() |
42 | ) |
43 | |
44 | +ME = '<bzr-whoami-failed-oh-god-why>' |
45 | +with suppress(FileNotFoundError): |
46 | + ME = call('bzr whoami')[1] |
47 | +ME = ME[ME.index('<') + 1:ME.index('>')] |
48 | + |
49 | |
50 | def parse_bzr_log(log): |
51 | """Generate a list of dicts representing bzr log data.""" |
52 | @@ -113,11 +117,11 @@ |
53 | |
54 | def bzr_missing(*args): |
55 | """Call bzr missing.""" |
56 | - cmd = ('bzr', 'missing', '--directory') + args |
57 | + cmd = ('bzr', 'missing', '--show-ids', '--directory') + args |
58 | stdout, stderr = call(cmd)[1:] |
59 | if stderr: |
60 | if 'Not a branch' in stderr: |
61 | - return 'committer: First build' # Pretend there are new commits |
62 | + return 'revision-id: very-first' # Pretend there are new commits |
63 | tokens = set(stderr.split()) |
64 | err = NoStatusError if len(TRANSIENT & tokens) > 6 else BranchError |
65 | raise err('"bzr missing" failed: {}'.format(stderr)) |
66 | @@ -128,12 +132,23 @@ |
67 | def bzr_cat(branch, filename): |
68 | """Call bzr cat.""" |
69 | assert branch.startswith('lp:') |
70 | - log, err = call(['bzr', 'cat', '-d', branch, filename])[1:] |
71 | + log, err = call(['bzr', 'cat', '--directory', branch, filename])[1:] |
72 | if err or not log: |
73 | raise BranchError('{} unreachable: {}'.format(filename, err)) |
74 | return log |
75 | |
76 | |
77 | +def find_ids_to_ignore(branch, target): |
78 | + """Ignore trunk commits missing from input branches.""" |
79 | + ignore = set() |
80 | + if branch != target: |
81 | + for line in bzr_missing(branch, target, '--theirs-only').splitlines(): |
82 | + if line.startswith(REVID): |
83 | + ignore.add(line.partition(REVID)[-1]) |
84 | + log_value_of.ignore() |
85 | + return ignore |
86 | + |
87 | + |
88 | @ramdisk |
89 | def get_package_name_from_branch(branch): |
90 | """Get source package name for a particular branch. |
91 | @@ -260,19 +275,21 @@ |
92 | authors[author].append(msg + format_bugs(bugs)) |
93 | return authors |
94 | |
95 | - def missing_branch_commits(self, branch): |
96 | + def missing_branch_commits(self, branch, target): |
97 | """Report any missing commits between our branch & another.""" |
98 | - # Ignore commits by me that only I have |
99 | - ignore = TRANSLATIONS | ME |
100 | - commits = 0 |
101 | + ignore = find_ids_to_ignore(branch, target) |
102 | + ignore_me = True # Ignore commits by me that only I have |
103 | for line in bzr_missing(self.lp_branch, branch).splitlines(): |
104 | if line.startswith('You are missing '): |
105 | - # Watch commits by me that I am missing (most likely on trunk) |
106 | - ignore = TRANSLATIONS |
107 | - if line.startswith('committer:'): |
108 | - if len(set(line.split()) & ignore) < 3: |
109 | - commits += 1 |
110 | - return commits |
111 | + ignore_me = False # Watch commits by me that I'm missing |
112 | + if line.startswith(REVID): |
113 | + if 'launchpad_translations_on_behalf_of_' in line: |
114 | + continue |
115 | + if ignore_me and ME in line: |
116 | + continue |
117 | + if not set(line.split()) & ignore: |
118 | + logging.info('Disputed %s', line) |
119 | + return True |
120 | |
121 | def get_remote_branch_authors(self, branch): |
122 | """Identify names of unique authors/committers in a lp branch. |
123 | |
124 | === modified file 'tests/strings.py' |
125 | --- tests/strings.py 2015-11-26 02:05:01 +0000 |
126 | +++ tests/strings.py 2015-12-04 01:43:03 +0000 |
127 | @@ -269,43 +269,44 @@ |
128 | |
129 | BZR_MISSING_OURS = """ |
130 | You have 1000000 extra revisions: |
131 | -committer: CI Train Bot <ci-train-bot@canonical.com> |
132 | -committer: CI Train Bot <ci-train-bot@canonical.com> |
133 | -committer: CI Train Bot <ci-train-bot@canonical.com> |
134 | +revision-id: ci-train-bot@canonical.com-yyyymmdd-deadbeef1 |
135 | +revision-id: ci-train-bot@canonical.com-yyyymmdd-deadbeef2 |
136 | +revision-id: ci-train-bot@canonical.com-yyyymmdd-deadbeef3 |
137 | +revision-id: ci-train-bot@canonical.com-yyyymmdd-deadbeef4 |
138 | """ |
139 | |
140 | BZR_MISSING_IGNORED = BZR_MISSING_OURS + """ |
141 | You are missing 5000 revisions: |
142 | -committer: Launchpad Translations on behalf of phablet-team |
143 | -committer: Launchpad Translations on behalf of phablet-team |
144 | -committer: Launchpad Translations on behalf of phablet-team |
145 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef1 |
146 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef2 |
147 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef3 |
148 | """ |
149 | |
150 | BZR_MISSING_ONE = BZR_MISSING_OURS + """ |
151 | You are missing 10000 revisions: |
152 | -committer: CI Train Bot <ci-train-bot@canonical.com> |
153 | -committer: Launchpad Translations on behalf of phablet-team |
154 | -committer: Launchpad Translations on behalf of phablet-team |
155 | -committer: Launchpad Translations on behalf of phablet-team |
156 | +revision-id: ci-train-bot@canonical.com-yyyymmdd-deadbeef5 |
157 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef4 |
158 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef5 |
159 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef6 |
160 | """ |
161 | |
162 | BZR_MISSING_TWO = BZR_MISSING_OURS + """ |
163 | You are missing 5000 revisions: |
164 | -committer: CI Train Bot <ci-train-bot@canonical.com> |
165 | -committer: Launchpad Translations on behalf of phablet-team |
166 | -committer: Launchpad Translations on behalf of phablet-team |
167 | -committer: Launchpad Translations on behalf of phablet-team |
168 | -committer: Joe Blow deleted this commit from remote branch |
169 | +revision-id: ci-train-bot@canonical.com-yyyymmdd-deadbeef6 |
170 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef7 |
171 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef8 |
172 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef9 |
173 | +revision-id: joe-blow@deleted-this-commit-yyyymmdd-deadbeef6 |
174 | """ |
175 | |
176 | BZR_MISSING_THREE = BZR_MISSING_OURS + """ |
177 | You are missing 10000 revisions: |
178 | -committer: CI Train Bot <ci-train-bot@canonical.com> |
179 | -committer: CI Brain Rot on behalf of zombies |
180 | -committer: Lunchpad Translations on behalf of eating |
181 | -committer: Launchpad Translations on behalf of phablet-team |
182 | -committer: Launchpad Translations on behalf of phablet-team |
183 | -committer: Launchpad Translations on behalf of phablet-team |
184 | +revision-id: ci-train-bot@canonical.com-yyyymmdd-deadbeef7 |
185 | +revision-id: ci-brain-rot@canonical.com-yyyymmdd-deadbeef6 |
186 | +revision-id: lunchpad_translations_on_behalf_of_foo-20151202054232-deadbeef |
187 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef10 |
188 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef11 |
189 | +revision-id: launchpad_translations_on_behalf_of_foo-20151202054232-deadbeef12 |
190 | """ |
191 | |
192 | PACKAGING_DIFF_WARNING = """\ |
193 | |
194 | === modified file 'tests/unit/test_branchhandling.py' |
195 | --- tests/unit/test_branchhandling.py 2015-12-02 04:35:10 +0000 |
196 | +++ tests/unit/test_branchhandling.py 2015-12-04 01:43:03 +0000 |
197 | @@ -27,7 +27,8 @@ |
198 | from cupstream2distro.utils import utf8_open |
199 | from cupstream2distro.branchhandling import ( |
200 | Branch, |
201 | - get_package_name_from_branch |
202 | + get_package_name_from_branch, |
203 | + find_ids_to_ignore, |
204 | ) |
205 | from cupstream2distro.errors import BranchError, MergeError |
206 | |
207 | @@ -43,13 +44,26 @@ |
208 | self.branch.series = Mock() |
209 | self.branch.silo_ppa = Mock() |
210 | |
211 | + @patch('cupstream2distro.branchhandling.bzr_missing') |
212 | + def test_find_ids_to_ignore(self, missing): |
213 | + """Return a set of revision ids.""" |
214 | + missing.return_value = '' |
215 | + self.assertEqual(find_ids_to_ignore('a', 'b'), set()) |
216 | + missing.return_value = s.BZR_MISSING_OURS |
217 | + self.assertEqual(find_ids_to_ignore('a', 'b'), { |
218 | + 'ci-train-bot@canonical.com-yyyymmdd-deadbeef1', |
219 | + 'ci-train-bot@canonical.com-yyyymmdd-deadbeef4', |
220 | + 'ci-train-bot@canonical.com-yyyymmdd-deadbeef3', |
221 | + 'ci-train-bot@canonical.com-yyyymmdd-deadbeef2', |
222 | + }) |
223 | + |
224 | @patch('cupstream2distro.branchhandling.call') |
225 | def test_get_package_name_from_branch(self, call_mock): |
226 | """Correctly get the package name from the branch.""" |
227 | call_mock.return_value = (Mock(returncode=0), 'ex (1.0)', '') |
228 | self.assertEqual(get_package_name_from_branch('lp:example'), 'ex') |
229 | call_mock.assert_called_once_with( |
230 | - ['bzr', 'cat', '-d', 'lp:example', 'debian/changelog']) |
231 | + ['bzr', 'cat', '--directory', 'lp:example', 'debian/changelog']) |
232 | |
233 | @patch('cupstream2distro.branchhandling.call') |
234 | def test_get_package_name_from_branch_cached(self, call_mock): |
235 | @@ -58,7 +72,7 @@ |
236 | for count in range(10): |
237 | self.assertEqual(get_package_name_from_branch('lp:example'), 'ex') |
238 | call_mock.assert_called_once_with( # ONCE |
239 | - ['bzr', 'cat', '-d', 'lp:example', 'debian/changelog']) |
240 | + ['bzr', 'cat', '--directory', 'lp:example', 'debian/changelog']) |
241 | |
242 | @patch('cupstream2distro.branchhandling.call') |
243 | def test_get_package_name_from_branch_failed(self, call_mock): |
244 | @@ -67,7 +81,7 @@ |
245 | with self.assertRaisesRegexp(BranchError, 'unreachable: bark bark'): |
246 | get_package_name_from_branch('lp:example2') |
247 | call_mock.assert_called_once_with( |
248 | - ['bzr', 'cat', '-d', 'lp:example2', 'debian/changelog']) |
249 | + ['bzr', 'cat', '--directory', 'lp:example2', 'debian/changelog']) |
250 | |
251 | def test_branch_method_names(self): |
252 | """Ensure all Branch method names contain "branch" for clarity.""" |
253 | @@ -404,22 +418,23 @@ |
254 | self.assertEquals(self.branch.get_branch_commits(set()), ({})) |
255 | |
256 | @patch('cupstream2distro.branchhandling.bzr_missing') |
257 | + @patch('cupstream2distro.branchhandling.ME', 'ci-train-bot@canonical.com') |
258 | def test_missing_branch_commits(self, missing): |
259 | """Ensure we can correctly count the number of missing commits.""" |
260 | missing.return_value = s.BZR_MISSING_IGNORED |
261 | - self.assertEqual(self.branch.missing_branch_commits('lp:foo'), 0) |
262 | + self.assertIsNone(self.branch.missing_branch_commits('lp:tr', 'lp:tr')) |
263 | missing.return_value = s.BZR_MISSING_ONE |
264 | - self.assertEqual(self.branch.missing_branch_commits('lp:foo'), 1) |
265 | + self.assertTrue(self.branch.missing_branch_commits('lp:tr', 'lp:tr')) |
266 | missing.return_value = s.BZR_MISSING_TWO |
267 | - self.assertEqual(self.branch.missing_branch_commits('lp:foo'), 2) |
268 | + self.assertTrue(self.branch.missing_branch_commits('lp:tr', 'lp:tr')) |
269 | missing.return_value = s.BZR_MISSING_THREE |
270 | - self.assertEqual(self.branch.missing_branch_commits('lp:foo'), 3) |
271 | + self.assertTrue(self.branch.missing_branch_commits('lp:tr', 'lp:tr')) |
272 | |
273 | @patch('cupstream2distro.branchhandling.call') |
274 | def test_missing_branch_commits_notabranch(self, call_mock): |
275 | """Ensure we can correctly count the number of missing commits.""" |
276 | call_mock.return_value = None, '', 'Not a branch: /path/to/foo' |
277 | - self.assertEqual(self.branch.missing_branch_commits('lp:foo'), 1) |
278 | + self.assertTrue(self.branch.missing_branch_commits('lp:tr', 'lp:tr')) |
279 | |
280 | @patch('cupstream2distro.branchhandling.call') |
281 | def test_get_remote_branch_authors(self, call_mock): |
282 | @@ -432,7 +447,7 @@ |
283 | 'CI Train Bot <ci-train-bot@canonical.com>', |
284 | ])) |
285 | call_mock.assert_called_once_with( |
286 | - ('bzr', 'missing', '--directory', self.tempdir, |
287 | + ('bzr', 'missing', '--show-ids', '--directory', self.tempdir, |
288 | 'lp:~my/foo/features', '--other')) |
289 | |
290 | @patch('cupstream2distro.branchhandling.call') |
291 | |
292 | === modified file 'tests/unit/test_recipe_merge.py' |
293 | --- tests/unit/test_recipe_merge.py 2015-12-02 05:35:19 +0000 |
294 | +++ tests/unit/test_recipe_merge.py 2015-12-04 01:43:03 +0000 |
295 | @@ -438,13 +438,6 @@ |
296 | merge.missing_branch_commits = Mock(return_value=10) |
297 | self.assertIn('Needs rebuild', merge.check_new_commits()) |
298 | |
299 | - def test_merge_check_new_commits_filenotfound(self): |
300 | - """Report if this package is missing local source.""" |
301 | - Merge.all_mps = dict(checkered=[Mock()]) |
302 | - merge = Merge('checkered', self.series, self.dest, self.ppa) |
303 | - merge.missing_branch_commits = Mock(side_effect=FileNotFoundError) |
304 | - self.assertEqual('Ready to build', merge.check_new_commits()) |
305 | - |
306 | def test_merge_unbuilt_phase(self): |
307 | """Block publication if merges have new commits.""" |
308 | mp_obj = Mock() |
309 | @@ -456,8 +449,10 @@ |
310 | 'foobaz has new, unbuilt commits.' |
311 | }) |
312 | self.assertEqual(merge.missing_branch_commits.mock_calls, [ |
313 | - call(mp_obj.target_branch.bzr_identity), |
314 | - call(mp_obj.source_branch.bzr_identity), |
315 | + call(mp_obj.target_branch.bzr_identity, |
316 | + mp_obj.target_branch.bzr_identity), |
317 | + call(mp_obj.source_branch.bzr_identity, |
318 | + mp_obj.target_branch.bzr_identity), |
319 | ]) |
320 | |
321 | def test_merge_unbuilt_phase_none(self): |
Looks good in staging.