blob: 63a7e632ebe2285250016ef85a00d61e56753ad0 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# Copyright 2018 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file or at
4# https://developers.google.com/open-source/licenses/bsd
5
6"""FLT task to be manually triggered to convert launch issues."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import collections
12import logging
13import re
14import settings
15import time
16
17from businesslogic import work_env
18from framework import permissions
19from framework import exceptions
20from framework import jsonfeed
21from proto import tracker_pb2
22from tracker import template_helpers
23from tracker import tracker_bizobj
24
25PM_PREFIX = 'pm-'
26TL_PREFIX = 'tl-'
27TEST_PREFIX = 'test-'
28UX_PREFIX = 'ux-'
29
30PM_FIELD = 'pm'
31TL_FIELD = 'tl'
32TE_FIELD = 'te'
33UX_FIELD = 'ux'
34MTARGET_FIELD = 'm-target'
35MAPPROVED_FIELD = 'm-approved'
36
37CONVERSION_COMMENT = 'Automatic generating of FLT Launch data.'
38
39BROWSER_APPROVALS_TO_LABELS = {
40 'Chrome-Accessibility': 'Launch-Accessibility-',
41 'Chrome-Leadership-Exp': 'Launch-Exp-Leadership-',
42 'Chrome-Leadership-Full': 'Launch-Leadership-',
43 'Chrome-Legal': 'Launch-Legal-',
44 'Chrome-Privacy': 'Launch-Privacy-',
45 'Chrome-Security': 'Launch-Security-',
46 'Chrome-Test': 'Launch-Test-',
47 'Chrome-UX': 'Launch-UI-',
48 }
49
50OS_APPROVALS_TO_LABELS = {
51 'ChromeOS-Accessibility': 'Launch-Accessibility-',
52 'ChromeOS-Leadership-Exp': 'Launch-Exp-Leadership-',
53 'ChromeOS-Leadership-Full': 'Launch-Leadership-',
54 'ChromeOS-Legal': 'Launch-Legal-',
55 'ChromeOS-Privacy': 'Launch-Privacy-',
56 'ChromeOS-Security': 'Launch-Security-',
57 'ChromeOS-Test': 'Launch-Test-',
58 'ChromeOS-UX': 'Launch-UI-',
59 }
60
61# 'NotReviewed' not included because this should be converted to
62# the template approval's default value, eg NOT_SET OR NEEDS_REVIEW
63VALUE_TO_STATUS = {
64 'ReviewRequested': tracker_pb2.ApprovalStatus.REVIEW_REQUESTED,
65 'NeedInfo': tracker_pb2.ApprovalStatus.NEED_INFO,
66 'Yes': tracker_pb2.ApprovalStatus.APPROVED,
67 'No': tracker_pb2.ApprovalStatus.NOT_APPROVED,
68 'NA': tracker_pb2.ApprovalStatus.NA,
69 # 'Started' is not a valid label value in the chromium project,
70 # but for some reason, some labels have this value.
71 'Started': tracker_pb2.ApprovalStatus.REVIEW_STARTED,
72}
73
74# This works in the Browser and OS process because
75# BROWSER_APPROVALS_TO_LABELS and OS_APPROVALS_TO_LABELS have the same values.
76# Adding '^' before each label prefix to ensure Blah-Launch-UI-Yes is ignored
77REVIEW_LABELS_RE = re.compile('^' + '|^'.join(
78 list(OS_APPROVALS_TO_LABELS.values())))
79
80# Maps template phases to channel names in 'Launch-M-Target-80-[Channel]' labels
81BROWSER_PHASE_MAP = {
82 'beta': 'beta',
83 'stable': 'stable',
84 'stable-full': 'stable',
85 'stable-exp': 'stable-exp',
86 }
87
88PHASE_PAT = '$|'.join(list(BROWSER_PHASE_MAP.values()))
89# Matches launch milestone labels, eg. Launch-M-Target-70-Stable-Exp
90BROWSER_M_LABELS_RE = re.compile(
91 r'^Launch-M-(?P<type>Approved|Target)-(?P<m>\d\d)-'
92 r'(?P<channel>%s$)' % PHASE_PAT,
93 re.IGNORECASE)
94
95OS_PHASE_MAP = {'feature freeze': '',
96 'branch': '',
97 'stable': 'stable',
98 'stable-full': 'stable',
99 'stable-exp': 'stable-exp',}
100# We only care about Launch-M-<type>-<m>-Stable|Stable-Exp labels for OS.
101OS_M_LABELS_RE = re.compile(
102 r'^Launch-M-(?P<type>Approved|Target)-(?P<m>\d\d)-'
103 r'(?P<channel>Stable$|Stable-Exp$)', re.IGNORECASE)
104
105CAN = 2 # Query for open issues only
106# Ensure empty group_by_spec and sort_spec so issues are sorted by 'ID'.
107GROUP_BY_SPEC = ''
108SORT_SPEC = ''
109
110CONVERT_NUM = 20
111CONVERT_START = 0
112VERIFY_NUM = 400
113
114# Queries
115QUERY_MAP = {
116 'default':
117 'Type=Launch Rollout-Type=Default OS=Windows,Mac,Linux,Android,iOS',
118 'finch': 'Type=Launch Rollout-Type=Finch OS=Windows,Mac,Linux,Android,iOS',
119 'os': 'Type=Launch OS=Chrome -OS=Windows,Mac,Linux,Android,iOS'
120 ' Rollout-Type=Default',
121 'os-finch': 'Type=Launch OS=Chrome -OS=Windows,Mac,Linux,Android,iOS'
122 ' Rollout-Type=Finch'}
123
124TEMPLATE_MAP = {
125 'default': 'Chrome Launch - Default',
126 'finch': 'Chrome Launch - Experimental',
127 'os': 'Chrome OS Launch - Default',
128 'os-finch': 'Chrome OS Launch - Experimental',
129}
130
131ProjectInfo = collections.namedtuple(
132 'ProjectInfo', 'config, q, approval_values, phases, '
133 'pm_fid, tl_fid, te_fid, ux_fid, m_target_id, m_approved_id, '
134 'phase_map, approvals_to_labels, labels_re')
135
136
Adrià Vilanova Martínez9f9ade52022-10-10 23:20:11 +0200137class FLTConvertTask(jsonfeed.FlaskInternalTask):
Copybara854996b2021-09-07 19:36:02 +0000138 """FLTConvert converts current Type=Launch issues into Type=FLT-Launch."""
139
140 def AssertBasePermission(self, mr):
141 super(FLTConvertTask, self).AssertBasePermission(mr)
142 if not mr.auth.user_pb.is_site_admin:
143 raise permissions.PermissionException(
144 'Only site admins may trigger conversion job')
145
146 def UndoConversion(self, mr):
147 with work_env.WorkEnv(mr, self.services) as we:
148 pipeline = we.ListIssues(
149 'Type=FLT-Launch FLT=Conversion', ['chromium'], mr.auth.user_id,
150 CONVERT_NUM, CONVERT_START, 2, GROUP_BY_SPEC, SORT_SPEC, False)
151
152 project = self.services.project.GetProjectByName(mr.cnxn, 'chromium')
153 config = self.services.config.GetProjectConfig(mr.cnxn, project.project_id)
154 pm_id = tracker_bizobj.FindFieldDef('PM', config).field_id
155 tl_id = tracker_bizobj.FindFieldDef('TL', config).field_id
156 te_id = tracker_bizobj.FindFieldDef('TE', config).field_id
157 ux_id = tracker_bizobj.FindFieldDef('UX', config).field_id
158 for possible_stale_issue in pipeline.visible_results:
159 issue = self.services.issue.GetIssue(
160 mr.cnxn, possible_stale_issue.issue_id, use_cache=False)
161
162 issue.approval_values = []
163 issue.phases = []
164 issue.field_values = [fv for fv in issue.field_values
165 if fv.phase_id is None]
166 issue.field_values = [fv for fv in issue.field_values
167 if fv.field_id not in
168 [pm_id, tl_id, te_id, ux_id]]
169 issue.labels.remove('Type-FLT-Launch')
170 issue.labels.remove('FLT-Conversion')
171 issue.labels.append('Type-Launch')
172
173 self.services.issue._UpdateIssuesApprovals(mr.cnxn, issue)
174 self.services.issue.UpdateIssue(mr.cnxn, issue)
175 return {'deleting': [issue.local_id for issue in pipeline.visible_results],
176 'num': len(pipeline.visible_results),
177 }
178
179 def VerifyConversion(self, mr):
180 """Verify that all FLT-Conversion issues were converted correctly."""
181 with work_env.WorkEnv(mr, self.services) as we:
182 pipeline = we.ListIssues(
183 'FLT=Conversion', ['chromium'], mr.auth.user_id, VERIFY_NUM,
184 CONVERT_START, 2, GROUP_BY_SPEC, SORT_SPEC, False)
185
186 project = self.services.project.GetProjectByName(mr.cnxn, 'chromium')
187 config = self.services.config.GetProjectConfig(mr.cnxn, project.project_id)
188 browser_approval_names = {fd.field_id: fd.field_name for fd
189 in config.field_defs if fd.field_name in
190 BROWSER_APPROVALS_TO_LABELS.keys()}
191 os_approval_names = {fd.field_id: fd.field_name for fd in config.field_defs
192 if (fd.field_name in OS_APPROVALS_TO_LABELS.keys())
193 or fd.field_name == 'ChromeOS-Enterprise'}
194 pm_id = tracker_bizobj.FindFieldDef('PM', config).field_id
195 tl_id = tracker_bizobj.FindFieldDef('TL', config).field_id
196 te_id = tracker_bizobj.FindFieldDef('TE', config).field_id
197 ux_id = tracker_bizobj.FindFieldDef('UX', config).field_id
198 mapproved_id = tracker_bizobj.FindFieldDef('M-Approved', config).field_id
199 mtarget_id = tracker_bizobj.FindFieldDef('M-Target', config).field_id
200
201 problems = []
202 for possible_stale_issue in pipeline.allowed_results:
203 issue = self.services.issue.GetIssue(
204 mr.cnxn, possible_stale_issue.issue_id, use_cache=False)
205 # Check correct template used
206 approval_names = browser_approval_names
207 approvals_to_labels = BROWSER_APPROVALS_TO_LABELS
208 m_labels_re = BROWSER_M_LABELS_RE
209 label_channel_to_phase_id = {
210 phase.name.lower(): phase.phase_id for phase in issue.phases}
211 if [l for l in issue.labels if l.startswith('OS-')] == ['OS-Chrome']:
212 approval_names = os_approval_names
213 m_labels_re = OS_M_LABELS_RE
214 approvals_to_labels = OS_APPROVALS_TO_LABELS
215 # OS default launch
216 if 'Rollout-Type-Default' in issue.labels:
217 if not all(phase.name in ['Feature Freeze', 'Branch', 'Stable']
218 for phase in issue.phases):
219 problems.append((
220 issue.local_id, 'incorrect phases for OS default launch.'))
221 # OS finch launch
222 elif 'Rollout-Type-Finch' in issue.labels:
223 if not all(phase.name in (
224 'Feature Freeze', 'Branch', 'Stable-Exp', 'Stable-Full')
225 for phase in issue.phases):
226 problems.append((
227 issue.local_id, 'incorrect phases for OS finch launch.'))
228 else:
229 problems.append((
230 issue.local_id,
231 'no rollout-type; should not have been converted'))
232 # Browser default launch
233 elif 'Rollout-Type-Default' in issue.labels:
234 if not all(phase.name.lower() in ['beta', 'stable']
235 for phase in issue.phases):
236 problems.append((
237 issue.local_id, 'incorrect phases for Default rollout'))
238 # Browser finch launch
239 elif 'Rollout-Type-Finch' in issue.labels:
240 if not all(phase.name.lower() in ['beta', 'stable-exp', 'stable-full']
241 for phase in issue.phases):
242 problems.append((
243 issue.local_id, 'incorrect phases for Finch rollout'))
244 else:
245 problems.append((
246 issue.local_id,
247 'no rollout-type; should not have been converted'))
248
249 # Check approval_values
250 for av in issue.approval_values:
251 name = approval_names.get(av.approval_id)
252 if name == 'ChromeOS-Enterprise':
253 if av.status != tracker_pb2.ApprovalStatus.NEEDS_REVIEW:
254 problems.append((issue.local_id, 'bad ChromeOS-Enterprise status'))
255 continue
256 label_pre = approvals_to_labels.get(name)
257 if not label_pre:
258 # either name was None or not found in APPROVALS_TO_LABELS
259 problems.append((issue.local_id, 'approval %s not recognized' % name))
260 continue
261 label_value = next((l[len(label_pre):] for l in issue.labels
262 if l.startswith(label_pre)), None)
263 if (not label_value or label_value == 'NotReviewed') and av.status in [
264 tracker_pb2.ApprovalStatus.NOT_SET,
265 tracker_pb2.ApprovalStatus.NEEDS_REVIEW]:
266 continue
267 if av.status is VALUE_TO_STATUS.get(label_value):
268 continue
269 # neither of the above ifs passed
270 problems.append((issue.local_id,
271 'approval %s has status %r for label value %s' % (
272 name, av.status.name, label_value)))
273
274 # Check people field_values
275 expected_people_fvs = self.ConvertPeopleLabels(
276 mr, issue.labels, pm_id, tl_id, te_id, ux_id)
277 for people_fv in expected_people_fvs:
278 if people_fv not in issue.field_values:
279 if people_fv.field_id == tl_id:
280 role = 'TL'
281 elif people_fv.field_id == pm_id:
282 role = 'PM'
283 elif people_fv.field_id == ux_id:
284 role = 'UX'
285 else:
286 role = 'TE'
287 problems.append((issue.local_id, 'missing a field for %s' % role))
288
289 # Check M phase field_values
290 for label in issue.labels:
291 match = re.match(m_labels_re, label)
292 if match:
293 channel = match.group('channel')
294 if (channel.lower() == 'stable-exp'
295 and 'Rollout-Type-Default' in issue.labels):
296 # ignore stable-exp for default rollouts.
297 continue
298 milestone = match.group('m')
299 m_type = match.group('type')
300 m_id = mapproved_id if m_type == 'Approved' else mtarget_id
301 phase_id = label_channel_to_phase_id.get(
302 channel.lower(), label_channel_to_phase_id.get('stable-full'))
303 if not next((
304 fv for fv in issue.field_values
305 if fv.phase_id == phase_id and fv.field_id == m_id and
306 fv.int_value == int(milestone)), None):
307 problems.append((
308 issue.local_id, 'no phase field for label %s' % label))
309
310 return {
311 'problems found': ['issue %d: %s' % problem for problem in problems],
312 'issues verified': ['issue %d' % issue.local_id for
313 issue in pipeline.allowed_results],
314 'num': len(pipeline.allowed_results),
315 }
316
317 def HandleRequest(self, mr):
318 """Convert Type=Launch issues to new Type=FLT-Launch issues."""
319 launch = mr.GetParam('launch')
320 if launch == 'delete':
321 return self.UndoConversion(mr)
322 if launch == 'verify':
323 return self.VerifyConversion(mr)
324 project_info = self.FetchAndAssertProjectInfo(mr)
325
326 # Search for issues:
327 with work_env.WorkEnv(mr, self.services) as we:
328 pipeline = we.ListIssues(
329 project_info.q, ['chromium'], mr.auth.user_id, CONVERT_NUM,
330 CONVERT_START, 2, GROUP_BY_SPEC, SORT_SPEC, False)
331
332 # Convert issues:
333 for possible_stale_issue in pipeline.visible_results:
334 # Note: These approval values and phases from templates will be used
335 # and modified to create approval values and phases for each issue.
336 # We need to create copies for each issue so changes are not carried
337 # over to the conversion of the next issue in the loop.
338 template_avs = self.CreateApprovalCopies(project_info.approval_values)
339 template_phases = self.CreatePhasesCopies(project_info.phases)
340 issue = self.services.issue.GetIssue(
341 mr.cnxn, possible_stale_issue.issue_id, use_cache=False)
342 new_approvals = ConvertLaunchLabels(
343 issue.labels, template_avs,
344 project_info.config.field_defs, project_info.approvals_to_labels)
345 m_fvs = ConvertMLabels(
346 issue.labels, template_phases,
347 project_info.m_target_id, project_info.m_approved_id,
348 project_info.labels_re, project_info.phase_map)
349 people_fvs = self.ConvertPeopleLabels(
350 mr, issue.labels,
351 project_info.pm_fid, project_info.tl_fid, project_info.te_fid,
352 project_info.ux_fid)
353 amendments = self.ExecuteIssueChanges(
354 project_info.config, issue, new_approvals,
355 template_phases, m_fvs + people_fvs)
356 logging.info(amendments)
357
358 return {
359 'converted_issues': [
360 issue.local_id for issue in pipeline.visible_results],
361 'num': len(pipeline.visible_results),
362 }
363
364 def CreateApprovalCopies(self, avs):
365 return [
366 tracker_pb2.ApprovalValue(
367 approval_id=av.approval_id,
368 status=av.status,
369 setter_id=av.setter_id,
370 set_on=av.set_on,
371 phase_id=av.phase_id) for av in avs
372 ]
373
374 def CreatePhasesCopies(self, phases):
375 return [
376 tracker_pb2.Phase(
377 phase_id=phase.phase_id,
378 name=phase.name,
379 rank=phase.rank) for phase in phases
380 ]
381
382 def FetchAndAssertProjectInfo(self, mr):
383 # Get request details
384 launch = mr.GetParam('launch')
385 logging.info(launch)
386 q = QUERY_MAP.get(launch)
387 template_name = TEMPLATE_MAP.get(launch)
388 assert q and template_name, 'bad launch type: %s' % launch
389
390 phase_map = (
391 OS_PHASE_MAP if launch in ['os', 'os-finch'] else BROWSER_PHASE_MAP)
392 approvals_to_labels = (
393 OS_APPROVALS_TO_LABELS if launch in ['os', 'os-finch']
394 else BROWSER_APPROVALS_TO_LABELS)
395 m_labels_re = (
396 OS_M_LABELS_RE if launch in ['os', 'os-finch'] else BROWSER_M_LABELS_RE)
397
398 # Get project, config, template, assert template in project
399 project = self.services.project.GetProjectByName(mr.cnxn, 'chromium')
400 config = self.services.config.GetProjectConfig(mr.cnxn, project.project_id)
401 template = self.services.template.GetTemplateByName(
402 mr.cnxn, template_name, project.project_id)
403 assert template, 'template %s not found in chromium project' % template_name
404
405 # Get template approval_values/phases and assert they are expected
406 approval_values, phases = template_helpers.FilterApprovalsAndPhases(
407 template.approval_values, template.phases, config)
408 assert approval_values and phases, (
409 'no approvals or phases in %s' % template_name)
410 assert all(phase.name.lower() in list(
411 phase_map.keys()) for phase in phases), (
412 'one or more phases not recognized')
413 if launch in ['finch', 'os', 'os-finch']:
414 assert all(
415 av.status is tracker_pb2.ApprovalStatus.NEEDS_REVIEW
416 for av in approval_values
417 ), '%s template not set up correctly' % launch
418
419 approval_fds = {fd.field_id: fd.field_name for fd in config.field_defs
420 if fd.field_type is tracker_pb2.FieldTypes.APPROVAL_TYPE}
421 assert all(
422 approval_fds.get(av.approval_id) in list(approvals_to_labels.keys())
423 for av in approval_values
424 if approval_fds.get(av.approval_id) != 'ChromeOS-Enterprise'), (
425 'one or more approvals not recognized')
426 approval_def_ids = [ad.approval_id for ad in config.approval_defs]
427 assert all(av.approval_id in approval_def_ids for av in approval_values), (
428 'one or more approvals not in config.approval_defs')
429
430 # Get relevant USER_TYPE FieldDef ids and assert they exist
431 user_fds = {fd.field_name.lower(): fd.field_id for fd in config.field_defs
432 if fd.field_type is tracker_pb2.FieldTypes.USER_TYPE}
433 logging.info('project USER_TYPE FieldDefs: %s' % user_fds)
434 pm_fid = user_fds.get(PM_FIELD)
435 assert pm_fid, 'project has no FieldDef %s' % PM_FIELD
436 tl_fid = user_fds.get(TL_FIELD)
437 assert tl_fid, 'project has no FieldDef %s' % TL_FIELD
438 te_fid = user_fds.get(TE_FIELD)
439 assert te_fid, 'project has no FieldDef %s' % TE_FIELD
440 ux_fid = user_fds.get(UX_FIELD)
441 assert ux_fid, 'project has no FieldDef %s' % UX_FIELD
442
443 # Get relevant M Phase INT_TYPE FieldDef ids and assert they exist
444 phase_int_fds = {fd.field_name.lower(): fd.field_id
445 for fd in config.field_defs
446 if fd.field_type is tracker_pb2.FieldTypes.INT_TYPE
447 and fd.is_phase_field and fd.is_multivalued}
448 logging.info(
449 'project Phase INT_TYPE multivalued FieldDefs: %s' % phase_int_fds)
450 m_target_id = phase_int_fds.get(MTARGET_FIELD)
451 assert m_target_id, 'project has no FieldDef %s' % MTARGET_FIELD
452 m_approved_id = phase_int_fds.get(MAPPROVED_FIELD)
453 assert m_approved_id, 'project has no FieldDef %s' % MAPPROVED_FIELD
454
455 return ProjectInfo(config, q, approval_values, phases, pm_fid, tl_fid,
456 te_fid, ux_fid, m_target_id, m_approved_id, phase_map,
457 approvals_to_labels, m_labels_re)
458
459 # TODO(jojwang): mr needs to be passed in as arg and
460 # all self.mr should be changed to mr
461 def ExecuteIssueChanges(self, config, issue, new_approvals, phases, new_fvs):
462 # Apply Approval and phase changes
463 approval_defs_by_id = {ad.approval_id: ad for ad in config.approval_defs}
464 for av in new_approvals:
465 ad = approval_defs_by_id.get(av.approval_id)
466 if ad:
467 av.approver_ids = ad.approver_ids
468 survey = ''
469 if ad.survey:
470 questions = ad.survey.split('\n')
471 survey = '\n'.join(['<b>' + q + '</b>' for q in questions])
472 self.services.issue.InsertComment(
473 self.mr.cnxn, tracker_pb2.IssueComment(
474 issue_id=issue.issue_id, project_id=issue.project_id,
475 user_id=self.mr.auth.user_id, content=survey,
476 is_description=True, approval_id=av.approval_id,
477 timestamp=int(time.time())))
478 else:
479 logging.info(
480 'ERROR: ApprovalDef %r for ApprovalValue %r not valid', ad, av)
481 issue.approval_values = new_approvals
482 self.services.issue._UpdateIssuesApprovals(self.mr.cnxn, issue)
483
484 # Apply field value changes
485 issue.phases = phases
486 delta = tracker_bizobj.MakeIssueDelta(
487 None, None, [], [], [], [], ['Type-FLT-Launch', 'FLT-Conversion'],
488 ['Type-Launch'], new_fvs, [], [], [], [], [], [], None, None)
489 amendments, _ = self.services.issue.DeltaUpdateIssue(
490 self.mr.cnxn, self.services, self.mr.auth.user_id, issue.project_id,
491 config, issue, delta, comment=CONVERSION_COMMENT)
492
493 return amendments
494
495 def ConvertPeopleLabels(
496 self, mr, labels, pm_field_id, tl_field_id, te_field_id, ux_field_id):
497 field_values = []
498 pm_ldap, tl_ldap, test_ldaps, ux_ldaps = ExtractLabelLDAPs(labels)
499
500 pm_fv = self.CreateUserFieldValue(mr, pm_ldap, pm_field_id)
501 if pm_fv:
502 field_values.append(pm_fv)
503
504 tl_fv = self.CreateUserFieldValue(mr, tl_ldap, tl_field_id)
505 if tl_fv:
506 field_values.append(tl_fv)
507
508 for test_ldap in test_ldaps:
509 te_fv = self.CreateUserFieldValue(mr, test_ldap, te_field_id)
510 if te_fv:
511 field_values.append(te_fv)
512
513 for ux_ldap in ux_ldaps:
514 ux_fv = self.CreateUserFieldValue(mr, ux_ldap, ux_field_id)
515 if ux_fv:
516 field_values.append(ux_fv)
517 return field_values
518
519 def CreateUserFieldValue(self, mr, ldap, field_id):
520 if ldap is None:
521 return None
522 try:
523 user_id = self.services.user.LookupUserID(mr.cnxn, ldap+'@chromium.org')
524 except exceptions.NoSuchUserException:
525 try:
526 user_id = self.services.user.LookupUserID(mr.cnxn, ldap+'@google.com')
527 except exceptions.NoSuchUserException:
528 logging.info('No chromium.org or google.com accound found for %s', ldap)
529 return None
530 return tracker_bizobj.MakeFieldValue(
531 field_id, None, None, user_id, None, None, False)
532
Adrià Vilanova Martínez9f9ade52022-10-10 23:20:11 +0200533 def PostFLTConvertTask(self, **kwargs):
534 return self.handler(**kwargs)
Adrià Vilanova Martínezde942802022-07-15 14:06:55 +0200535
Copybara854996b2021-09-07 19:36:02 +0000536
537def ConvertMLabels(
538 labels, phases, m_target_id, m_approved_id, labels_re, phase_map):
539 field_values = []
540 for label in labels:
541 match = re.match(labels_re, label)
542 if match:
543 milestone = match.group('m')
544 m_type = match.group('type')
545 channel = match.group('channel')
546 for phase in phases:
547 # We know get(phase) will return something because
548 # we're checking before ConvertMLabels, that all phases
549 # exist in BROWSER_PHASE_MAP or OS_PHASE_MAP
550 if phase_map.get(phase.name.lower()) == channel.lower():
551 field_id = m_target_id if (
552 m_type.lower() == 'target') else m_approved_id
553 field_values.append(tracker_bizobj.MakeFieldValue(
554 field_id, int(milestone), None, None, None, None, False,
555 phase_id=phase.phase_id))
556 break # exit phase loop if match is found.
557 return field_values
558
559
560def ConvertLaunchLabels(labels, approvals, project_fds, approvals_to_labels):
561 """Converts 'Launch-[Review]' values into statuses for given approvals."""
562 label_values = {}
563 for label in labels:
564 launch_match = REVIEW_LABELS_RE.match(label)
565 if launch_match:
566 prefix = launch_match.group()
567 value = label[len(prefix):] # returns 'Yes' from 'Launch-UI-Yes'
568 label_values[prefix] = value
569
570 field_names_dict = {fd.field_id: fd.field_name for fd in project_fds}
571 for approval in approvals:
572 approval_name = field_names_dict.get(approval.approval_id, '')
573 old_prefix = approvals_to_labels.get(approval_name)
574 label_value = label_values.get(old_prefix, '')
575 # if label_value not found in VALUE_TO_STATUS, use current status.
576 approval.status = VALUE_TO_STATUS.get(label_value, approval.status)
577
578 return approvals
579
580
581def ExtractLabelLDAPs(labels):
582 """Extracts LDAPs from labels 'PM-', 'TL-', 'UX-', and 'test-'"""
583
584 pm_ldap = None
585 tl_ldap = None
586 test_ldaps = []
587 ux_ldaps = []
588 for label in labels:
589 label = label.lower()
590 if label.startswith(PM_PREFIX):
591 pm_ldap = label[len(PM_PREFIX):]
592 elif label.startswith(TL_PREFIX):
593 tl_ldap = label[len(TL_PREFIX):]
594 elif label.startswith(TEST_PREFIX):
595 ldap = label[len(TEST_PREFIX):]
596 if ldap:
597 test_ldaps.append(ldap)
598 elif label.startswith(UX_PREFIX):
599 ldap = label[len(UX_PREFIX):]
600 if ldap:
601 ux_ldaps.append(ldap)
602 return pm_ldap, tl_ldap, test_ldaps, ux_ldaps