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 5from __future__ import absolute_import, print_function, unicode_literals 6 7import re 8 9import six 10 11 12INTEGRATION_PROJECTS = { 13 "autoland", 14} 15 16TRUNK_PROJECTS = INTEGRATION_PROJECTS | {"mozilla-central", "comm-central"} 17 18RELEASE_PROJECTS = { 19 "mozilla-central", 20 "mozilla-beta", 21 "mozilla-release", 22 "mozilla-esr78", 23 "mozilla-esr91", 24 "comm-central", 25 "comm-beta", 26 "comm-esr78", 27 "comm-esr91", 28 "oak", 29} 30 31RELEASE_PROMOTION_PROJECTS = { 32 "jamun", 33 "maple", 34 "try", 35 "try-comm-central", 36} | RELEASE_PROJECTS 37 38TEMPORARY_PROJECTS = set( 39 { 40 # When using a "Disposeabel Project Branch" you can specify your branch here. e.g.: 41 # 'oak', 42 } 43) 44 45TRY_PROJECTS = { 46 "try", 47 "try-comm-central", 48} 49 50ALL_PROJECTS = RELEASE_PROMOTION_PROJECTS | TRUNK_PROJECTS | TEMPORARY_PROJECTS 51 52RUN_ON_PROJECT_ALIASES = { 53 # key is alias, value is lambda to test it against 54 "all": lambda project: True, 55 "integration": lambda project: project in INTEGRATION_PROJECTS, 56 "release": lambda project: project in RELEASE_PROJECTS, 57 "trunk": lambda project: project in TRUNK_PROJECTS, 58} 59 60_COPYABLE_ATTRIBUTES = ( 61 "accepted-mar-channel-ids", 62 "artifact_map", 63 "artifact_prefix", 64 "build_platform", 65 "build_type", 66 "l10n_chunk", 67 "locale", 68 "mar-channel-id", 69 "nightly", 70 "required_signoffs", 71 "shippable", 72 "shipping_phase", 73 "shipping_product", 74 "signed", 75 "stub-installer", 76 "update-channel", 77) 78 79 80def attrmatch(attributes, **kwargs): 81 """Determine whether the given set of task attributes matches. The 82 conditions are given as keyword arguments, where each keyword names an 83 attribute. The keyword value can be a literal, a set, or a callable. A 84 literal must match the attribute exactly. Given a set, the attribute value 85 must be in the set. A callable is called with the attribute value. If an 86 attribute is specified as a keyword argument but not present in the 87 attributes, the result is False.""" 88 for kwkey, kwval in six.iteritems(kwargs): 89 if kwkey not in attributes: 90 return False 91 attval = attributes[kwkey] 92 if isinstance(kwval, set): 93 if attval not in kwval: 94 return False 95 elif callable(kwval): 96 if not kwval(attval): 97 return False 98 elif kwval != attributes[kwkey]: 99 return False 100 return True 101 102 103def keymatch(attributes, target): 104 """Determine if any keys in attributes are a match to target, then return 105 a list of matching values. First exact matches will be checked. Failing 106 that, regex matches and finally a default key. 107 """ 108 # exact match 109 if target in attributes: 110 return [attributes[target]] 111 112 # regular expression match 113 matches = [v for k, v in six.iteritems(attributes) if re.match(k + "$", target)] 114 if matches: 115 return matches 116 117 # default 118 if "default" in attributes: 119 return [attributes["default"]] 120 121 return [] 122 123 124def match_run_on_projects(project, run_on_projects): 125 """Determine whether the given project is included in the `run-on-projects` 126 parameter, applying expansions for things like "integration" mentioned in 127 the attribute documentation.""" 128 aliases = RUN_ON_PROJECT_ALIASES.keys() 129 run_aliases = set(aliases) & set(run_on_projects) 130 if run_aliases: 131 if any(RUN_ON_PROJECT_ALIASES[alias](project) for alias in run_aliases): 132 return True 133 134 return project in run_on_projects 135 136 137def match_run_on_hg_branches(hg_branch, run_on_hg_branches): 138 """Determine whether the given project is included in the `run-on-hg-branches` 139 parameter. Allows 'all'.""" 140 if "all" in run_on_hg_branches: 141 return True 142 143 for expected_hg_branch_pattern in run_on_hg_branches: 144 if re.match(expected_hg_branch_pattern, hg_branch): 145 return True 146 147 return False 148 149 150def copy_attributes_from_dependent_job(dep_job, denylist=()): 151 return { 152 attr: dep_job.attributes[attr] 153 for attr in _COPYABLE_ATTRIBUTES 154 if attr in dep_job.attributes and attr not in denylist 155 } 156 157 158def sorted_unique_list(*args): 159 """Join one or more lists, and return a sorted list of unique members""" 160 combined = set().union(*args) 161 return sorted(combined) 162 163 164def release_level(project): 165 """ 166 Whether this is a staging release or not. 167 168 :return six.text_type: One of "production" or "staging". 169 """ 170 return "production" if project in RELEASE_PROJECTS else "staging" 171