blob: e42b432bed386e8bf79ec31f7682001753b989e2 [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ínezde942802022-07-15 14:06:55 +0200137# TODO: change to FlaskInternalTask when convert to flask
Copybara854996b2021-09-07 19:36:02 +0000138class FLTConvertTask(jsonfeed.InternalTask):
139 """FLTConvert converts current Type=Launch issues into Type=FLT-Launch."""
140
141 def AssertBasePermission(self, mr):
142 super(FLTConvertTask, self).AssertBasePermission(mr)
143 if not mr.auth.user_pb.is_site_admin:
144 raise permissions.PermissionException(
145 'Only site admins may trigger conversion job')
146
147 def UndoConversion(self, mr):
148 with work_env.WorkEnv(mr, self.services) as we:
149 pipeline = we.ListIssues(
150 'Type=FLT-Launch FLT=Conversion', ['chromium'], mr.auth.user_id,
151 CONVERT_NUM, CONVERT_START, 2, GROUP_BY_SPEC, SORT_SPEC, False)
152
153 project = self.services.project.GetProjectByName(mr.cnxn, 'chromium')
154 config = self.services.config.GetProjectConfig(mr.cnxn, project.project_id)
155 pm_id = tracker_bizobj.FindFieldDef('PM', config).field_id
156 tl_id = tracker_bizobj.FindFieldDef('TL', config).field_id
157 te_id = tracker_bizobj.FindFieldDef('TE', config).field_id
158 ux_id = tracker_bizobj.FindFieldDef('UX', config).field_id
159 for possible_stale_issue in pipeline.visible_results:
160 issue = self.services.issue.GetIssue(
161 mr.cnxn, possible_stale_issue.issue_id, use_cache=False)
162
163 issue.approval_values = []
164 issue.phases = []
165 issue.field_values = [fv for fv in issue.field_values
166 if fv.phase_id is None]
167 issue.field_values = [fv for fv in issue.field_values
168 if fv.field_id not in
169 [pm_id, tl_id, te_id, ux_id]]
170 issue.labels.remove('Type-FLT-Launch')
171 issue.labels.remove('FLT-Conversion')
172 issue.labels.append('Type-Launch')
173
174 self.services.issue._UpdateIssuesApprovals(mr.cnxn, issue)
175 self.services.issue.UpdateIssue(mr.cnxn, issue)
176 return {'deleting': [issue.local_id for issue in pipeline.visible_results],
177 'num': len(pipeline.visible_results),
178 }
179
180 def VerifyConversion(self, mr):
181 """Verify that all FLT-Conversion issues were converted correctly."""
182 with work_env.WorkEnv(mr, self.services) as we:
183 pipeline = we.ListIssues(
184 'FLT=Conversion', ['chromium'], mr.auth.user_id, VERIFY_NUM,
185 CONVERT_START, 2, GROUP_BY_SPEC, SORT_SPEC, False)
186
187 project = self.services.project.GetProjectByName(mr.cnxn, 'chromium')
188 config = self.services.config.GetProjectConfig(mr.cnxn, project.project_id)
189 browser_approval_names = {fd.field_id: fd.field_name for fd
190 in config.field_defs if fd.field_name in
191 BROWSER_APPROVALS_TO_LABELS.keys()}
192 os_approval_names = {fd.field_id: fd.field_name for fd in config.field_defs
193 if (fd.field_name in OS_APPROVALS_TO_LABELS.keys())
194 or fd.field_name == 'ChromeOS-Enterprise'}
195 pm_id = tracker_bizobj.FindFieldDef('PM', config).field_id
196 tl_id = tracker_bizobj.FindFieldDef('TL', config).field_id
197 te_id = tracker_bizobj.FindFieldDef('TE', config).field_id
198 ux_id = tracker_bizobj.FindFieldDef('UX', config).field_id
199 mapproved_id = tracker_bizobj.FindFieldDef('M-Approved', config).field_id
200 mtarget_id = tracker_bizobj.FindFieldDef('M-Target', config).field_id
201
202 problems = []
203 for possible_stale_issue in pipeline.allowed_results:
204 issue = self.services.issue.GetIssue(
205 mr.cnxn, possible_stale_issue.issue_id, use_cache=False)
206 # Check correct template used
207 approval_names = browser_approval_names
208 approvals_to_labels = BROWSER_APPROVALS_TO_LABELS
209 m_labels_re = BROWSER_M_LABELS_RE
210 label_channel_to_phase_id = {
211 phase.name.lower(): phase.phase_id for phase in issue.phases}
212 if [l for l in issue.labels if l.startswith('OS-')] == ['OS-Chrome']:
213 approval_names = os_approval_names
214 m_labels_re = OS_M_LABELS_RE
215 approvals_to_labels = OS_APPROVALS_TO_LABELS
216 # OS default launch
217 if 'Rollout-Type-Default' in issue.labels:
218 if not all(phase.name in ['Feature Freeze', 'Branch', 'Stable']
219 for phase in issue.phases):
220 problems.append((
221 issue.local_id, 'incorrect phases for OS default launch.'))
222 # OS finch launch
223 elif 'Rollout-Type-Finch' in issue.labels:
224 if not all(phase.name in (
225 'Feature Freeze', 'Branch', 'Stable-Exp', 'Stable-Full')
226 for phase in issue.phases):
227 problems.append((
228 issue.local_id, 'incorrect phases for OS finch launch.'))
229 else:
230 problems.append((
231 issue.local_id,
232 'no rollout-type; should not have been converted'))
233 # Browser default launch
234 elif 'Rollout-Type-Default' in issue.labels:
235 if not all(phase.name.lower() in ['beta', 'stable']
236 for phase in issue.phases):
237 problems.append((
238 issue.local_id, 'incorrect phases for Default rollout'))
239 # Browser finch launch
240 elif 'Rollout-Type-Finch' in issue.labels:
241 if not all(phase.name.lower() in ['beta', 'stable-exp', 'stable-full']
242 for phase in issue.phases):
243 problems.append((
244 issue.local_id, 'incorrect phases for Finch rollout'))
245 else:
246 problems.append((
247 issue.local_id,
248 'no rollout-type; should not have been converted'))
249
250 # Check approval_values
251 for av in issue.approval_values:
252 name = approval_names.get(av.approval_id)
253 if name == 'ChromeOS-Enterprise':
254 if av.status != tracker_pb2.ApprovalStatus.NEEDS_REVIEW:
255 problems.append((issue.local_id, 'bad ChromeOS-Enterprise status'))
256 continue
257 label_pre = approvals_to_labels.get(name)
258 if not label_pre:
259 # either name was None or not found in APPROVALS_TO_LABELS
260 problems.append((issue.local_id, 'approval %s not recognized' % name))
261 continue
262 label_value = next((l[len(label_pre):] for l in issue.labels
263 if l.startswith(label_pre)), None)
264 if (not label_value or label_value == 'NotReviewed') and av.status in [
265 tracker_pb2.ApprovalStatus.NOT_SET,
266 tracker_pb2.ApprovalStatus.NEEDS_REVIEW]:
267 continue
268 if av.status is VALUE_TO_STATUS.get(label_value):
269 continue
270 # neither of the above ifs passed
271 problems.append((issue.local_id,
272 'approval %s has status %r for label value %s' % (
273 name, av.status.name, label_value)))
274
275 # Check people field_values
276 expected_people_fvs = self.ConvertPeopleLabels(
277 mr, issue.labels, pm_id, tl_id, te_id, ux_id)
278 for people_fv in expected_people_fvs:
279 if people_fv not in issue.field_values:
280 if people_fv.field_id == tl_id:
281 role = 'TL'
282 elif people_fv.field_id == pm_id:
283 role = 'PM'
284 elif people_fv.field_id == ux_id:
285 role = 'UX'
286 else:
287 role = 'TE'
288 problems.append((issue.local_id, 'missing a field for %s' % role))
289
290 # Check M phase field_values
291 for label in issue.labels:
292 match = re.match(m_labels_re, label)
293 if match:
294 channel = match.group('channel')
295 if (channel.lower() == 'stable-exp'
296 and 'Rollout-Type-Default' in issue.labels):
297 # ignore stable-exp for default rollouts.
298 continue
299 milestone = match.group('m')
300 m_type = match.group('type')
301 m_id = mapproved_id if m_type == 'Approved' else mtarget_id
302 phase_id = label_channel_to_phase_id.get(
303 channel.lower(), label_channel_to_phase_id.get('stable-full'))
304 if not next((
305 fv for fv in issue.field_values
306 if fv.phase_id == phase_id and fv.field_id == m_id and
307 fv.int_value == int(milestone)), None):
308 problems.append((
309 issue.local_id, 'no phase field for label %s' % label))
310
311 return {
312 'problems found': ['issue %d: %s' % problem for problem in problems],
313 'issues verified': ['issue %d' % issue.local_id for
314 issue in pipeline.allowed_results],
315 'num': len(pipeline.allowed_results),
316 }
317
318 def HandleRequest(self, mr):
319 """Convert Type=Launch issues to new Type=FLT-Launch issues."""
320 launch = mr.GetParam('launch')
321 if launch == 'delete':
322 return self.UndoConversion(mr)
323 if launch == 'verify':
324 return self.VerifyConversion(mr)
325 project_info = self.FetchAndAssertProjectInfo(mr)
326
327 # Search for issues:
328 with work_env.WorkEnv(mr, self.services) as we:
329 pipeline = we.ListIssues(
330 project_info.q, ['chromium'], mr.auth.user_id, CONVERT_NUM,
331 CONVERT_START, 2, GROUP_BY_SPEC, SORT_SPEC, False)
332
333 # Convert issues:
334 for possible_stale_issue in pipeline.visible_results:
335 # Note: These approval values and phases from templates will be used
336 # and modified to create approval values and phases for each issue.
337 # We need to create copies for each issue so changes are not carried
338 # over to the conversion of the next issue in the loop.
339 template_avs = self.CreateApprovalCopies(project_info.approval_values)
340 template_phases = self.CreatePhasesCopies(project_info.phases)
341 issue = self.services.issue.GetIssue(
342 mr.cnxn, possible_stale_issue.issue_id, use_cache=False)
343 new_approvals = ConvertLaunchLabels(
344 issue.labels, template_avs,
345 project_info.config.field_defs, project_info.approvals_to_labels)
346 m_fvs = ConvertMLabels(
347 issue.labels, template_phases,
348 project_info.m_target_id, project_info.m_approved_id,
349 project_info.labels_re, project_info.phase_map)
350 people_fvs = self.ConvertPeopleLabels(
351 mr, issue.labels,
352 project_info.pm_fid, project_info.tl_fid, project_info.te_fid,
353 project_info.ux_fid)
354 amendments = self.ExecuteIssueChanges(
355 project_info.config, issue, new_approvals,
356 template_phases, m_fvs + people_fvs)
357 logging.info(amendments)
358
359 return {
360 'converted_issues': [
361 issue.local_id for issue in pipeline.visible_results],
362 'num': len(pipeline.visible_results),
363 }
364
365 def CreateApprovalCopies(self, avs):
366 return [
367 tracker_pb2.ApprovalValue(
368 approval_id=av.approval_id,
369 status=av.status,
370 setter_id=av.setter_id,
371 set_on=av.set_on,
372 phase_id=av.phase_id) for av in avs
373 ]
374
375 def CreatePhasesCopies(self, phases):
376 return [
377 tracker_pb2.Phase(
378 phase_id=phase.phase_id,
379 name=phase.name,
380 rank=phase.rank) for phase in phases
381 ]
382
383 def FetchAndAssertProjectInfo(self, mr):
384 # Get request details
385 launch = mr.GetParam('launch')
386 logging.info(launch)
387 q = QUERY_MAP.get(launch)
388 template_name = TEMPLATE_MAP.get(launch)
389 assert q and template_name, 'bad launch type: %s' % launch
390
391 phase_map = (
392 OS_PHASE_MAP if launch in ['os', 'os-finch'] else BROWSER_PHASE_MAP)
393 approvals_to_labels = (
394 OS_APPROVALS_TO_LABELS if launch in ['os', 'os-finch']
395 else BROWSER_APPROVALS_TO_LABELS)
396 m_labels_re = (
397 OS_M_LABELS_RE if launch in ['os', 'os-finch'] else BROWSER_M_LABELS_RE)
398
399 # Get project, config, template, assert template in project
400 project = self.services.project.GetProjectByName(mr.cnxn, 'chromium')
401 config = self.services.config.GetProjectConfig(mr.cnxn, project.project_id)
402 template = self.services.template.GetTemplateByName(
403 mr.cnxn, template_name, project.project_id)
404 assert template, 'template %s not found in chromium project' % template_name
405
406 # Get template approval_values/phases and assert they are expected
407 approval_values, phases = template_helpers.FilterApprovalsAndPhases(
408 template.approval_values, template.phases, config)
409 assert approval_values and phases, (
410 'no approvals or phases in %s' % template_name)
411 assert all(phase.name.lower() in list(
412 phase_map.keys()) for phase in phases), (
413 'one or more phases not recognized')
414 if launch in ['finch', 'os', 'os-finch']:
415 assert all(
416 av.status is tracker_pb2.ApprovalStatus.NEEDS_REVIEW
417 for av in approval_values
418 ), '%s template not set up correctly' % launch
419
420 approval_fds = {fd.field_id: fd.field_name for fd in config.field_defs
421 if fd.field_type is tracker_pb2.FieldTypes.APPROVAL_TYPE}
422 assert all(
423 approval_fds.get(av.approval_id) in list(approvals_to_labels.keys())
424 for av in approval_values
425 if approval_fds.get(av.approval_id) != 'ChromeOS-Enterprise'), (
426 'one or more approvals not recognized')
427 approval_def_ids = [ad.approval_id for ad in config.approval_defs]
428 assert all(av.approval_id in approval_def_ids for av in approval_values), (
429 'one or more approvals not in config.approval_defs')
430
431 # Get relevant USER_TYPE FieldDef ids and assert they exist
432 user_fds = {fd.field_name.lower(): fd.field_id for fd in config.field_defs
433 if fd.field_type is tracker_pb2.FieldTypes.USER_TYPE}
434 logging.info('project USER_TYPE FieldDefs: %s' % user_fds)
435 pm_fid = user_fds.get(PM_FIELD)
436 assert pm_fid, 'project has no FieldDef %s' % PM_FIELD
437 tl_fid = user_fds.get(TL_FIELD)
438 assert tl_fid, 'project has no FieldDef %s' % TL_FIELD
439 te_fid = user_fds.get(TE_FIELD)
440 assert te_fid, 'project has no FieldDef %s' % TE_FIELD
441 ux_fid = user_fds.get(UX_FIELD)
442 assert ux_fid, 'project has no FieldDef %s' % UX_FIELD
443
444 # Get relevant M Phase INT_TYPE FieldDef ids and assert they exist
445 phase_int_fds = {fd.field_name.lower(): fd.field_id
446 for fd in config.field_defs
447 if fd.field_type is tracker_pb2.FieldTypes.INT_TYPE
448 and fd.is_phase_field and fd.is_multivalued}
449 logging.info(
450 'project Phase INT_TYPE multivalued FieldDefs: %s' % phase_int_fds)
451 m_target_id = phase_int_fds.get(MTARGET_FIELD)
452 assert m_target_id, 'project has no FieldDef %s' % MTARGET_FIELD
453 m_approved_id = phase_int_fds.get(MAPPROVED_FIELD)
454 assert m_approved_id, 'project has no FieldDef %s' % MAPPROVED_FIELD
455
456 return ProjectInfo(config, q, approval_values, phases, pm_fid, tl_fid,
457 te_fid, ux_fid, m_target_id, m_approved_id, phase_map,
458 approvals_to_labels, m_labels_re)
459
460 # TODO(jojwang): mr needs to be passed in as arg and
461 # all self.mr should be changed to mr
462 def ExecuteIssueChanges(self, config, issue, new_approvals, phases, new_fvs):
463 # Apply Approval and phase changes
464 approval_defs_by_id = {ad.approval_id: ad for ad in config.approval_defs}
465 for av in new_approvals:
466 ad = approval_defs_by_id.get(av.approval_id)
467 if ad:
468 av.approver_ids = ad.approver_ids
469 survey = ''
470 if ad.survey:
471 questions = ad.survey.split('\n')
472 survey = '\n'.join(['<b>' + q + '</b>' for q in questions])
473 self.services.issue.InsertComment(
474 self.mr.cnxn, tracker_pb2.IssueComment(
475 issue_id=issue.issue_id, project_id=issue.project_id,
476 user_id=self.mr.auth.user_id, content=survey,
477 is_description=True, approval_id=av.approval_id,
478 timestamp=int(time.time())))
479 else:
480 logging.info(
481 'ERROR: ApprovalDef %r for ApprovalValue %r not valid', ad, av)
482 issue.approval_values = new_approvals
483 self.services.issue._UpdateIssuesApprovals(self.mr.cnxn, issue)
484
485 # Apply field value changes
486 issue.phases = phases
487 delta = tracker_bizobj.MakeIssueDelta(
488 None, None, [], [], [], [], ['Type-FLT-Launch', 'FLT-Conversion'],
489 ['Type-Launch'], new_fvs, [], [], [], [], [], [], None, None)
490 amendments, _ = self.services.issue.DeltaUpdateIssue(
491 self.mr.cnxn, self.services, self.mr.auth.user_id, issue.project_id,
492 config, issue, delta, comment=CONVERSION_COMMENT)
493
494 return amendments
495
496 def ConvertPeopleLabels(
497 self, mr, labels, pm_field_id, tl_field_id, te_field_id, ux_field_id):
498 field_values = []
499 pm_ldap, tl_ldap, test_ldaps, ux_ldaps = ExtractLabelLDAPs(labels)
500
501 pm_fv = self.CreateUserFieldValue(mr, pm_ldap, pm_field_id)
502 if pm_fv:
503 field_values.append(pm_fv)
504
505 tl_fv = self.CreateUserFieldValue(mr, tl_ldap, tl_field_id)
506 if tl_fv:
507 field_values.append(tl_fv)
508
509 for test_ldap in test_ldaps:
510 te_fv = self.CreateUserFieldValue(mr, test_ldap, te_field_id)
511 if te_fv:
512 field_values.append(te_fv)
513
514 for ux_ldap in ux_ldaps:
515 ux_fv = self.CreateUserFieldValue(mr, ux_ldap, ux_field_id)
516 if ux_fv:
517 field_values.append(ux_fv)
518 return field_values
519
520 def CreateUserFieldValue(self, mr, ldap, field_id):
521 if ldap is None:
522 return None
523 try:
524 user_id = self.services.user.LookupUserID(mr.cnxn, ldap+'@chromium.org')
525 except exceptions.NoSuchUserException:
526 try:
527 user_id = self.services.user.LookupUserID(mr.cnxn, ldap+'@google.com')
528 except exceptions.NoSuchUserException:
529 logging.info('No chromium.org or google.com accound found for %s', ldap)
530 return None
531 return tracker_bizobj.MakeFieldValue(
532 field_id, None, None, user_id, None, None, False)
533
Adrià Vilanova Martínezde942802022-07-15 14:06:55 +0200534 # def GetFLTConvertTask(self, **kwargs):
535 # return self.handler(**kwargs)
536
537 # def PostFLTConvertTask(self, **kwargs):
538 # return self.handler(**kwargs)
539
Copybara854996b2021-09-07 19:36:02 +0000540
541def ConvertMLabels(
542 labels, phases, m_target_id, m_approved_id, labels_re, phase_map):
543 field_values = []
544 for label in labels:
545 match = re.match(labels_re, label)
546 if match:
547 milestone = match.group('m')
548 m_type = match.group('type')
549 channel = match.group('channel')
550 for phase in phases:
551 # We know get(phase) will return something because
552 # we're checking before ConvertMLabels, that all phases
553 # exist in BROWSER_PHASE_MAP or OS_PHASE_MAP
554 if phase_map.get(phase.name.lower()) == channel.lower():
555 field_id = m_target_id if (
556 m_type.lower() == 'target') else m_approved_id
557 field_values.append(tracker_bizobj.MakeFieldValue(
558 field_id, int(milestone), None, None, None, None, False,
559 phase_id=phase.phase_id))
560 break # exit phase loop if match is found.
561 return field_values
562
563
564def ConvertLaunchLabels(labels, approvals, project_fds, approvals_to_labels):
565 """Converts 'Launch-[Review]' values into statuses for given approvals."""
566 label_values = {}
567 for label in labels:
568 launch_match = REVIEW_LABELS_RE.match(label)
569 if launch_match:
570 prefix = launch_match.group()
571 value = label[len(prefix):] # returns 'Yes' from 'Launch-UI-Yes'
572 label_values[prefix] = value
573
574 field_names_dict = {fd.field_id: fd.field_name for fd in project_fds}
575 for approval in approvals:
576 approval_name = field_names_dict.get(approval.approval_id, '')
577 old_prefix = approvals_to_labels.get(approval_name)
578 label_value = label_values.get(old_prefix, '')
579 # if label_value not found in VALUE_TO_STATUS, use current status.
580 approval.status = VALUE_TO_STATUS.get(label_value, approval.status)
581
582 return approvals
583
584
585def ExtractLabelLDAPs(labels):
586 """Extracts LDAPs from labels 'PM-', 'TL-', 'UX-', and 'test-'"""
587
588 pm_ldap = None
589 tl_ldap = None
590 test_ldaps = []
591 ux_ldaps = []
592 for label in labels:
593 label = label.lower()
594 if label.startswith(PM_PREFIX):
595 pm_ldap = label[len(PM_PREFIX):]
596 elif label.startswith(TL_PREFIX):
597 tl_ldap = label[len(TL_PREFIX):]
598 elif label.startswith(TEST_PREFIX):
599 ldap = label[len(TEST_PREFIX):]
600 if ldap:
601 test_ldaps.append(ldap)
602 elif label.startswith(UX_PREFIX):
603 ldap = label[len(UX_PREFIX):]
604 if ldap:
605 ux_ldaps.append(ldap)
606 return pm_ldap, tl_ldap, test_ldaps, ux_ldaps