Merge lp:~albaguirre/jenkins-launchpad-plugin/support-lp-trigger-for-git-mps into lp:jenkins-launchpad-plugin
- support-lp-trigger-for-git-mps
- Merge into trunk
Proposed by
Alberto Aguirre
Status: | Merged |
---|---|
Merged at revision: | 132 |
Proposed branch: | lp:~albaguirre/jenkins-launchpad-plugin/support-lp-trigger-for-git-mps |
Merge into: | lp:jenkins-launchpad-plugin |
Prerequisite: | lp:~albaguirre/jenkins-launchpad-plugin/support-voting-on-git-mps |
Diff against target: |
338 lines (+174/-20) 5 files modified
jlp/commands/launchpadTrigger.py (+11/-7) jlp/jenkinsutils.py (+12/-4) jlp/launchpadutils.py (+42/-5) tests/test_launchpadTrigger.py (+36/-2) tests/test_launchpadutils.py (+73/-2) |
To merge this branch: | bzr merge lp:~albaguirre/jenkins-launchpad-plugin/support-lp-trigger-for-git-mps |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandros Frantzis (community) | Approve | ||
Review via email: mp+302868@code.launchpad.net |
Commit message
launchPadTrigger: Add support for git projects
Description of the change
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 'jlp/commands/launchpadTrigger.py' |
2 | --- jlp/commands/launchpadTrigger.py 2013-05-10 14:10:52 +0000 |
3 | +++ jlp/commands/launchpadTrigger.py 2016-08-13 18:04:14 +0000 |
4 | @@ -8,20 +8,20 @@ |
5 | LAUNCHPADLIB_DIR_PREFIX = os.path.expanduser('~/.launchpadlib') |
6 | |
7 | |
8 | -def trigger_ci_build(branch, job, jenkins_url, launchpadlib_dir): |
9 | +def trigger_ci_build(branch, job, jenkins_url, launchpadlib_dir, repo_type): |
10 | """Trigger a CI build.""" |
11 | |
12 | launchpad = get_launchpad(launchpadlib_dir) |
13 | - mps = get_merge_proposals(launchpad, branch, ['Needs review']) |
14 | + mps = get_merge_proposals(launchpad, branch, ['Needs review'], repo_type) |
15 | jenkinsutils.trigger_ci_build(launchpad, mps, job, jenkins_url) |
16 | |
17 | |
18 | def trigger_al_build(branch, job, jenkins_url, fasttrack_merge, |
19 | - launchpadlib_dir): |
20 | + launchpadlib_dir, repo_type): |
21 | """Trigger an autolanding build.""" |
22 | |
23 | launchpad = get_launchpad(launchpadlib_dir) |
24 | - mps = get_merge_proposals(launchpad, branch, ['Approved']) |
25 | + mps = get_merge_proposals(launchpad, branch, ['Approved'], repo_type) |
26 | jenkinsutils.trigger_al_build(launchpad, mps, job, jenkins_url, |
27 | fasttrack_merge) |
28 | |
29 | @@ -32,7 +32,8 @@ |
30 | job=None, |
31 | jenkins_url=None, |
32 | fasttrack_merge=False, |
33 | - lock_name=''): |
34 | + lock_name='', |
35 | + repo_type='bazaar'): |
36 | """Trigger a Jenkins build.""" |
37 | |
38 | if jenkins_url is None: |
39 | @@ -43,10 +44,10 @@ |
40 | launchpadlib_dir)) |
41 | |
42 | if trigger_ci: |
43 | - trigger_ci_build(branch, job, jenkins_url, launchpadlib_dir) |
44 | + trigger_ci_build(branch, job, jenkins_url, launchpadlib_dir, repo_type) |
45 | elif autoland: |
46 | trigger_al_build(branch, job, jenkins_url, fasttrack_merge, |
47 | - launchpadlib_dir) |
48 | + launchpadlib_dir, repo_type) |
49 | return 1 |
50 | |
51 | |
52 | @@ -75,6 +76,9 @@ |
53 | default='launchpadTrigger', |
54 | help='''Name of the lock and launchpadlib cache |
55 | to be used''') |
56 | + parser.add_argument('-r', '--repo-type', |
57 | + default='bazaar', |
58 | + help='''What type of branches to trigger jobs for [git or bazaar]''') |
59 | |
60 | args = vars(parser.parse_args()) |
61 | |
62 | |
63 | === modified file 'jlp/jenkinsutils.py' |
64 | --- jlp/jenkinsutils.py 2016-02-05 13:20:38 +0000 |
65 | +++ jlp/jenkinsutils.py 2016-08-13 18:04:14 +0000 |
66 | @@ -670,6 +670,16 @@ |
67 | params['hooks'] = get_parameter(jenkins, job_url, 'dput_hooks', '') |
68 | params['test_result'] = "PASSED" |
69 | |
70 | +def get_jenkins_params(mp): |
71 | + params = { |
72 | + 'landing_candidate': launchpadutils.get_source_repo(mp), |
73 | + 'merge_proposal': mp.web_link, |
74 | + 'candidate_revision': launchpadutils.get_latest_revision(mp)} |
75 | + |
76 | + if '+git' in mp.web_link: |
77 | + params['landing_candidate_branch'] = launchpadutils.get_source_branch(mp) |
78 | + |
79 | + return params |
80 | |
81 | def start_jenkins_job(lp_handle, launchpaduser, jenkins_url, jenkins_job, mp, |
82 | fasttrack_merge=False): |
83 | @@ -686,10 +696,8 @@ |
84 | """ |
85 | j = jenkins.Jenkins(jenkins_url, get_config_option('jenkins_user'), |
86 | get_config_option('jenkins_password')) |
87 | - jenkins_params = { |
88 | - 'landing_candidate': mp.source_branch.bzr_identity, |
89 | - 'merge_proposal': mp.web_link, |
90 | - 'candidate_revision': mp.source_branch.revision_count} |
91 | + |
92 | + jenkins_params = get_jenkins_params(mp) |
93 | |
94 | job_info = j.get_job_info(jenkins_job) |
95 | if not job_info['buildable']: |
96 | |
97 | === modified file 'jlp/launchpadutils.py' |
98 | --- jlp/launchpadutils.py 2016-08-13 18:04:14 +0000 |
99 | +++ jlp/launchpadutils.py 2016-08-13 18:04:14 +0000 |
100 | @@ -9,6 +9,23 @@ |
101 | DISAPPROVE = 'Disapprove' |
102 | NEEDS_FIXING = 'Needs Fixing' |
103 | |
104 | +def get_source_repo(mp): |
105 | + if '+git' in mp.web_link: |
106 | + return mp.source_git_repository.git_identity |
107 | + else: |
108 | + return mp.target_branch.bzr_identity |
109 | + |
110 | +def get_source_branch(mp): |
111 | + if '+git' in mp.web_link: |
112 | + return mp.source_git_path.replace('refs/heads/', '') |
113 | + else: |
114 | + return mp.source_branch.bzr_identity |
115 | + |
116 | +def get_target_branch(mp): |
117 | + if '+git' in mp.web_link: |
118 | + return mp.target_git_path.replace('refs/heads/', '') |
119 | + else: |
120 | + return mp.target_branch.bzr_identity |
121 | |
122 | def get_vote_subject(mp): |
123 | """Given a mp handle return a subject for the vote message |
124 | @@ -271,6 +288,11 @@ |
125 | return True |
126 | return False |
127 | |
128 | +def get_review_revision_regex(mp): |
129 | + if '+git' in mp.web_link: |
130 | + return '^(PASSED|FAILED): Continuous integration, rev:([0-9a-f]+)' |
131 | + else: |
132 | + return '^(PASSED|FAILED): Continuous integration, rev:(\d+)' |
133 | |
134 | def get_latest_review(launchpad_user, mp): |
135 | """Return the latest revision reviewed by the given launchpad_user. |
136 | @@ -287,12 +309,25 @@ |
137 | if comment.author.name == launchpad_user.name: |
138 | if comment.vote_tag == launchpad_review_type: |
139 | m = re.search( |
140 | - '^(PASSED|FAILED): Continuous integration, rev:(\d+)', |
141 | + get_review_revision_regex(mp), |
142 | comment.message_body) |
143 | - if m and (int(m.group(2)) > revision): |
144 | - revision = int(m.group(2)) |
145 | + if m: |
146 | + revision = m.group(2) |
147 | return revision |
148 | |
149 | +def get_latest_revision(mp): |
150 | + """Return the latest revision of the given merge proposal. |
151 | + |
152 | + :param mp: handle to merge proposal |
153 | + """ |
154 | + if '+git' in mp.web_link: |
155 | + for ref in mp.source_git_repository.refs_collection: |
156 | + if ref.path == mp.source_git_path: |
157 | + return ref.commit_sha1 |
158 | + return str(0) |
159 | + else: |
160 | + return mp.source_branch.revision_count |
161 | + |
162 | |
163 | def latest_candidate_validated(launchpad_user, mp): |
164 | """Return if the latest candidate revision of the merge proposal is |
165 | @@ -305,9 +340,11 @@ |
166 | |
167 | latest_review = get_latest_review(launchpad_user, mp) |
168 | logger.debug('Latest_review is revision: ' + str(latest_review)) |
169 | - if latest_review >= mp.source_branch.revision_count: |
170 | + latest_revision = get_latest_revision(mp) |
171 | + logger.debug('Latest revision is: ' + str(latest_revision)) |
172 | + if latest_review == latest_revision: |
173 | logger.debug('Skipping this MP. Current revision: ' + |
174 | - str(mp.source_branch.revision_count)) |
175 | + str(latest_revision)) |
176 | return True |
177 | return False |
178 | |
179 | |
180 | === modified file 'tests/test_launchpadTrigger.py' |
181 | --- tests/test_launchpadTrigger.py 2013-05-10 14:10:52 +0000 |
182 | +++ tests/test_launchpadTrigger.py 2016-08-13 18:04:14 +0000 |
183 | @@ -142,6 +142,27 @@ |
184 | 'http://localhost:8080/') |
185 | |
186 | |
187 | + def test_trigger_git_ci(self): |
188 | + """Trigger CI got a git repo.""" |
189 | + |
190 | + sys_argv = ["launchpadTrigger.py", |
191 | + "--branch=lp:faux-dbus-test-runner", |
192 | + "--trigger-ci", |
193 | + "--job=faux-dbus-test-runner", |
194 | + "--repo-type=git"] |
195 | + with patch('sys.argv', sys_argv), \ |
196 | + patch('jlp.commands.launchpadTrigger.get_merge_proposals') as \ |
197 | + get_merge_proposals, \ |
198 | + patch('jlp.commands.launchpadTrigger.jenkinsutils.' + |
199 | + 'trigger_ci_build') as trigger_ci_build: |
200 | + get_merge_proposals.return_value = [self.merge_proposal] |
201 | + launchpadTrigger() |
202 | + get_merge_proposals.assert_called_with(self.launchpad, |
203 | + 'lp:faux-dbus-test-runner', |
204 | + ['Needs review'], |
205 | + 'git') |
206 | + |
207 | + |
208 | class TestLockNames(PatchedLaunchpadTriggerTest): |
209 | |
210 | sys_argv = ["launchpadTrigger.py", |
211 | @@ -192,7 +213,7 @@ |
212 | lock_name=self.lock_name) |
213 | trigger_ci_build.assert_called_with( |
214 | None, None, get_config_option('jenkins_url'), |
215 | - self.expected_cache_dir) |
216 | + self.expected_cache_dir, 'bazaar') |
217 | |
218 | def test_lock_name_autolanding(self): |
219 | """test trigger_jenkins method for correct use of lock_name param""" |
220 | @@ -204,4 +225,17 @@ |
221 | lock_name=self.lock_name) |
222 | trigger_al_build.assert_called_with( |
223 | None, None, get_config_option('jenkins_url'), |
224 | - False, self.expected_cache_dir) |
225 | + False, self.expected_cache_dir, 'bazaar') |
226 | + |
227 | + def test_repo_type_is_propagated(self): |
228 | + """test trigger_jenkins method for correct use of lock_name param""" |
229 | + |
230 | + with patch('jlp.commands.launchpadTrigger.trigger_al_build') \ |
231 | + as trigger_al_build: |
232 | + trigger_jenkins(branch=None, |
233 | + autoland=True, |
234 | + lock_name=self.lock_name, |
235 | + repo_type='git') |
236 | + trigger_al_build.assert_called_with( |
237 | + None, None, get_config_option('jenkins_url'), |
238 | + False, self.expected_cache_dir, 'git') |
239 | |
240 | === modified file 'tests/test_launchpadutils.py' |
241 | --- tests/test_launchpadutils.py 2016-08-13 18:04:14 +0000 |
242 | +++ tests/test_launchpadutils.py 2016-08-13 18:04:14 +0000 |
243 | @@ -411,7 +411,7 @@ |
244 | "URL:..." |
245 | mp.all_comments = [comment] |
246 | self.assertEqual( |
247 | - launchpadutils.get_latest_review(self.launchpad_user, mp), 47) |
248 | + launchpadutils.get_latest_review(self.launchpad_user, mp), '47') |
249 | |
250 | def test_get_latest_review_which_failed(self): |
251 | mp = MagicMock() |
252 | @@ -422,7 +422,7 @@ |
253 | "URL:..." |
254 | mp.all_comments = [comment] |
255 | self.assertEqual( |
256 | - launchpadutils.get_latest_review(self.launchpad_user, mp), 47) |
257 | + launchpadutils.get_latest_review(self.launchpad_user, mp), '47') |
258 | |
259 | @patch('jlp.launchpadutils.get_latest_review', new=lambda x, y: 60) |
260 | def test_new_mp_candidate_revision_in_queue(self): |
261 | @@ -448,6 +448,77 @@ |
262 | self.launchpad_user, mp) |
263 | self.assertTrue(ret) |
264 | |
265 | +class TestLatestReviewForGitMPs(unittest.TestCase): |
266 | + def setUp(self): |
267 | + self.launchpad_user = MagicMock() |
268 | + self.jenkinsUserName = 'name' |
269 | + self.launchpad_user.name = self.jenkinsUserName |
270 | + |
271 | + def create_mp(self): |
272 | + mp = MagicMock() |
273 | + mp.web_link = 'https://code.launchpad.net/~user/project/+git/project/+merge/777' |
274 | + return mp |
275 | + |
276 | + def create_mp_with_revision(self, revision): |
277 | + mp = self.create_mp() |
278 | + path = "refs/heads/nice" |
279 | + ref = MagicMock() |
280 | + ref.path = path |
281 | + ref.commit_sha1 = revision |
282 | + mp.source_git_path = path |
283 | + mp.source_git_repository.refs_collection = [ref] |
284 | + return mp |
285 | + |
286 | + def test_get_latest_review_no_comments(self): |
287 | + mp = self.create_mp() |
288 | + mp.all_comments = [] |
289 | + self.assertEqual( |
290 | + launchpadutils.get_latest_review(self.launchpad_user, mp), 0) |
291 | + |
292 | + def test_get_latest_review_unrelated_comment(self): |
293 | + mp = self.create_mp() |
294 | + comment = MagicMock() |
295 | + comment.vote_tag = get_config_option('launchpad_review_type') |
296 | + comment.message_body = 'unrelated comment' |
297 | + mp.all_comments = [comment] |
298 | + self.assertEqual( |
299 | + launchpadutils.get_latest_review(self.launchpad_user, mp), 0) |
300 | + |
301 | + def test_get_latest_review_which_passed(self): |
302 | + mp = self.create_mp() |
303 | + comment = MagicMock() |
304 | + comment.author.name = self.jenkinsUserName |
305 | + comment.vote_tag = get_config_option('launchpad_review_type') |
306 | + comment.message_body = "PASSED: Continuous integration, rev:2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\n" + \ |
307 | + "URL:..." |
308 | + mp.all_comments = [comment] |
309 | + self.assertEqual( |
310 | + launchpadutils.get_latest_review(self.launchpad_user, mp), '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12') |
311 | + |
312 | + def test_get_latest_review_which_failed(self): |
313 | + mp = self.create_mp() |
314 | + comment = MagicMock() |
315 | + comment.author.name = self.jenkinsUserName |
316 | + comment.vote_tag = get_config_option('launchpad_review_type') |
317 | + comment.message_body = "FAILED: Continuous integration, rev:2fd4e1c67a2d28fced849ee1bb76e7391b93eb12\n" + \ |
318 | + "URL:..." |
319 | + mp.all_comments = [comment] |
320 | + self.assertEqual( |
321 | + launchpadutils.get_latest_review(self.launchpad_user, mp), '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12') |
322 | + |
323 | + @patch('jlp.launchpadutils.get_latest_review', new=lambda x, y: '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12') |
324 | + def test_new_mp_candidate_revision_in_queue(self): |
325 | + mp = self.create_mp_with_revision('de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3') |
326 | + ret = launchpadutils.latest_candidate_validated( |
327 | + self.launchpad_user, mp) |
328 | + self.assertFalse(ret) |
329 | + |
330 | + @patch('jlp.launchpadutils.get_latest_review', new=lambda x, y: '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12') |
331 | + def test_mp_already_validated(self): |
332 | + mp = self.create_mp_with_revision('2fd4e1c67a2d28fced849ee1bb76e7391b93eb12') |
333 | + ret = launchpadutils.latest_candidate_validated( |
334 | + self.launchpad_user, mp) |
335 | + self.assertTrue(ret) |
336 | |
337 | class TestApproveAndDisapprove(unittest.TestCase): |
338 | jenkinsUserName = 'jenkins-user' |
Looks good.