attributes.py (5497B)
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 import re 7 from typing import Literal, Union 8 9 from taskgraph.util.attributes import _match_run_on 10 11 INTEGRATION_PROJECTS = { 12 "autoland", 13 } 14 15 TRUNK_PROJECTS = INTEGRATION_PROJECTS | {"mozilla-central", "comm-central"} 16 17 # Mapping of project to list of branches that should be considered "release" 18 # level. A value of `True` means all branches are considered release 19 # (used by hg.mozilla.org based projects). 20 PROJECT_RELEASE_BRANCHES: dict[str, Union[list[str], Literal[True]]] = { 21 # https://github.com/mozilla-firefox/firefox 22 "firefox": [ 23 "main", 24 "beta", 25 "release", 26 "esr115", 27 "esr128", 28 "esr140", 29 ], 30 "mozilla-central": True, 31 "mozilla-beta": True, 32 "mozilla-release": True, 33 "mozilla-esr115": True, 34 "mozilla-esr128": True, 35 "mozilla-esr140": True, 36 "comm-central": True, 37 "comm-beta": True, 38 "comm-release": True, 39 "comm-esr115": True, 40 "comm-esr128": True, 41 "comm-esr140": True, 42 # bug 1845368: pine is a permanent project branch used for testing 43 # nightly updates 44 "pine": True, 45 # bug 1877483: larch has similar needs for nightlies 46 "larch": True, 47 # maple is also an L3 branch: https://phabricator.services.mozilla.com/D184833 48 "maple": True, 49 # bug 1988213: cypress project branch 50 "cypress": True, 51 } 52 RELEASE_PROJECTS = set(PROJECT_RELEASE_BRANCHES) 53 RELEASE_PROMOTION_PROJECTS = { 54 "jamun", 55 "maple", 56 "try", 57 "try-comm-central", 58 } | RELEASE_PROJECTS 59 60 TEMPORARY_PROJECTS = set({ 61 # When using a "Disposable Project Branch" you can specify your branch here. e.g.: 62 "oak", 63 }) 64 65 TRY_PROJECTS = { 66 "staging-firefox", # https://github.com/mozilla-releng/staging-firefox 67 "try", 68 "try-comm-central", 69 } 70 71 ALL_PROJECTS = RELEASE_PROMOTION_PROJECTS | TRUNK_PROJECTS | TEMPORARY_PROJECTS 72 73 RUN_ON_PROJECT_ALIASES = { 74 # key is alias, value is lambda to test it against 75 "all": lambda params: True, 76 "integration": lambda params: ( 77 params["project"] in INTEGRATION_PROJECTS or params["project"] == "toolchains" 78 ), 79 "release": lambda params: ( 80 release_level(params) == "production" or params["project"] == "toolchains" 81 ), 82 "trunk": lambda params: ( 83 params["project"] in TRUNK_PROJECTS or params["project"] == "toolchains" 84 ), 85 "trunk-only": lambda params: params["project"] in TRUNK_PROJECTS, 86 "autoland": lambda params: params["project"] in ("autoland", "toolchains"), 87 "autoland-only": lambda params: params["project"] == "autoland", 88 "mozilla-central": lambda params: params["project"] 89 in ("mozilla-central", "toolchains"), 90 "mozilla-central-only": lambda params: params["project"] == "mozilla-central", 91 } 92 93 _COPYABLE_ATTRIBUTES = ( 94 "accepted-mar-channel-ids", 95 "artifact_map", 96 "artifact_prefix", 97 "build_platform", 98 "build_type", 99 "l10n_chunk", 100 "locale", 101 "mar-channel-id", 102 "maven_packages", 103 "nightly", 104 "required_signoffs", 105 "shippable", 106 "shipping_phase", 107 "shipping_product", 108 "signed", 109 "stub-installer", 110 "update-channel", 111 ) 112 113 114 def match_run_on_projects(params, run_on_projects): 115 """Determine whether the given project is included in the `run-on-projects` 116 parameter, applying expansions for things like "integration" mentioned in 117 the attribute documentation.""" 118 aliases = RUN_ON_PROJECT_ALIASES.keys() 119 run_aliases = set(aliases) & set(run_on_projects) 120 if run_aliases: 121 if any(RUN_ON_PROJECT_ALIASES[alias](params) for alias in run_aliases): 122 return True 123 124 return params["project"] in run_on_projects 125 126 127 def match_run_on_hg_branches(hg_branch, run_on_hg_branches): 128 """Determine whether the given project is included in the `run-on-hg-branches` 129 parameter. Allows 'all'.""" 130 if "all" in run_on_hg_branches: 131 return True 132 133 for expected_hg_branch_pattern in run_on_hg_branches: 134 if re.match(expected_hg_branch_pattern, hg_branch): 135 return True 136 137 return False 138 139 140 match_run_on_repo_type = _match_run_on 141 142 143 def copy_attributes_from_dependent_job(dep_job, denylist=()): 144 return { 145 attr: dep_job.attributes[attr] 146 for attr in _COPYABLE_ATTRIBUTES 147 if attr in dep_job.attributes and attr not in denylist 148 } 149 150 151 def sorted_unique_list(*args): 152 """Join one or more lists, and return a sorted list of unique members""" 153 combined = set().union(*args) 154 return sorted(combined) 155 156 157 def release_level(params): 158 """ 159 Whether this is a staging release or not. 160 161 :return str: One of "production" or "staging". 162 """ 163 if branches := PROJECT_RELEASE_BRANCHES.get(params.get("project")): 164 if branches is True: 165 return "production" 166 167 m = re.match(r"refs/heads/(\S+)$", params["head_ref"]) 168 if m is not None and m.group(1) in branches: 169 return "production" 170 171 return "staging" 172 173 174 def is_try(params): 175 """ 176 Determine whether this graph is being built on a try project or for 177 `mach try fuzzy`. 178 """ 179 return "try" in params["project"] or params["try_mode"] == "try_select" 180 181 182 def task_name(task): 183 if task.label.startswith(task.kind + "-"): 184 return task.label[len(task.kind) + 1 :] 185 raise AttributeError(f"Task {task.label} does not have a name.")