backstop.py (3528B)
1 # This Source Code Form is subject to the terms of the Mozilla Public 2 # License, v. 2.0. If a copy of the MPL was not distributed with this 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 4 5 6 from taskcluster.exceptions import TaskclusterRestFailure 7 from taskgraph.util.taskcluster import find_task_id, get_artifact 8 9 from gecko_taskgraph.util.attributes import INTEGRATION_PROJECTS, TRY_PROJECTS 10 from gecko_taskgraph.util.taskcluster import state_task 11 12 BACKSTOP_PUSH_INTERVAL = 20 13 BACKSTOP_TIME_INTERVAL = 60 * 4 # minutes 14 ANDROID_PERFTEST_BACKSTOP_INDEX = ( 15 "{trust-domain}.v2.{project}.latest.taskgraph.android_backstop" 16 ) 17 BACKSTOP_INDEX = "{trust-domain}.v2.{project}.latest.taskgraph.backstop" 18 19 STRATEGY_TO_INDEX_MAP = { 20 "android_perftest_backstop": ANDROID_PERFTEST_BACKSTOP_INDEX, 21 "backstop": BACKSTOP_INDEX, 22 } 23 24 25 def is_backstop( 26 params, 27 push_interval=BACKSTOP_PUSH_INTERVAL, 28 time_interval=BACKSTOP_TIME_INTERVAL, 29 trust_domain="gecko", 30 integration_projects=INTEGRATION_PROJECTS, 31 backstop_strategy="backstop", 32 ): 33 """Determines whether the given parameters represent a backstop push. 34 35 Args: 36 push_interval (int): Number of pushes 37 time_interval (int): Minutes between forced schedules. 38 Use 0 to disable. 39 trust_domain (str): "gecko" for Firefox, "comm" for Thunderbird 40 integration_projects (set): project that uses backstop optimization 41 Returns: 42 bool: True if this is a backstop, otherwise False. 43 """ 44 # In case this is being faked on try. 45 if params.get(backstop_strategy, False): 46 return True 47 48 # Backstops not used / supported on Github yet. 49 if params["repository_type"] == "git": 50 return True 51 52 project = params["project"] 53 if project in TRY_PROJECTS: 54 return False 55 if project not in integration_projects: 56 return True 57 58 # This push was explicitly set to run nothing (e.g via DONTBUILD), so 59 # shouldn't be a backstop candidate. 60 if params["target_tasks_method"] == "nothing": 61 return False 62 63 # Find the last backstop to compute push and time intervals. 64 subs = {"trust-domain": trust_domain, "project": project} 65 index = STRATEGY_TO_INDEX_MAP[backstop_strategy].format(**subs) 66 67 try: 68 last_backstop_id = find_task_id(index) 69 except TaskclusterRestFailure: 70 # Index wasn't found, implying there hasn't been a backstop push yet. 71 return True 72 73 if state_task(last_backstop_id) in ("failed", "exception"): 74 # If the last backstop failed its decision task, make this a backstop. 75 return True 76 77 try: 78 last_params = get_artifact(last_backstop_id, "public/parameters.yml") 79 except TaskclusterRestFailure as e: 80 # If the last backstop decision task exists in the index, but 81 # parameters.yml isn't available yet, it means the decision task is 82 # still running. If that's the case, we can be pretty sure the time 83 # component will not cause a backstop, so just return False. 84 if e.status_code == 404: 85 return False 86 raise 87 88 # On every Nth push, want to run all tasks. 89 if int(params["pushlog_id"]) - int(last_params["pushlog_id"]) >= push_interval: 90 return True 91 92 if time_interval <= 0: 93 return False 94 95 # We also want to ensure we run all tasks at least once per N minutes. 96 if (params["pushdate"] - last_params["pushdate"]) / 60 >= time_interval: 97 return True 98 99 return False