Source code
Revision control
Copy as Markdown
Other Tools
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
import datetime
from mozilla_version.mobile import GeckoVersion
from taskgraph.transforms.base import TransformSequence
from taskgraph.util.schema import resolve_keyed_by
from ..build_config import get_extensions, get_path
transforms = TransformSequence()
@transforms.add
def resolve_keys(config, tasks):
for task in tasks:
for field in (
"include-coverage",
"run-on-projects",
"shipping-phase",
"run.gradlew",
"treeherder.symbol",
"dependencies.build-fat-aar",
):
resolve_keyed_by(
task,
field,
item_name=task["name"],
**{
"build-type": task["attributes"]["build-type"],
"component": task["attributes"]["component"],
},
)
yield task
@transforms.add
def handle_update_channel(config, tasks):
for task in tasks:
build_fat_aar = config.kind_dependencies_tasks[
task["dependencies"]["build-fat-aar"]
]
if build_fat_aar.attributes.get("shippable"):
task["worker"].setdefault("env", {}).setdefault(
"MOZ_UPDATE_CHANNEL",
build_fat_aar.attributes.get("update-channel", "default"),
)
yield task
@transforms.add
def handle_coverage(config, tasks):
for task in tasks:
if task.pop("include-coverage", False):
task["run"]["gradlew"].insert(0, "-Pcoverage")
yield task
@transforms.add
def interpolate_missing_values(config, tasks):
timestamp = _get_timestamp(config)
version = config.params["version"]
nightly_version = get_nightly_version(config, version)
for task in tasks:
for field in ("description", "run.gradlew", "treeherder.symbol"):
component = task["attributes"]["component"]
_deep_format(
task,
field,
component=component,
nightlyVersion=nightly_version,
timestamp=timestamp,
treeherder_group=component[:25],
)
yield task
def _get_timestamp(config):
push_date_string = config.params["moz_build_date"]
push_date_time = datetime.datetime.strptime(push_date_string, "%Y%m%d%H%M%S")
return push_date_time.strftime("%Y%m%d.%H%M%S-1")
def _get_buildid(config):
return config.params.moz_build_date.strftime("%Y%m%d%H%M%S")
def get_nightly_version(config, version):
buildid = _get_buildid(config)
parsed_version = GeckoVersion.parse(version)
return f"{parsed_version.major_number}.{parsed_version.minor_number}.{buildid}"
def craft_path_version(version, build_type, nightly_version):
"""Helper function to craft the correct version to bake in the artifacts full
path section"""
path_version = version
# XXX: for nightly releases we need to s/X.0.0/X.0.<buildid>/g in versions
if build_type == "nightly":
path_version = path_version.replace(version, nightly_version)
return path_version
def _deep_format(object, field, **format_kwargs):
keys = field.split(".")
last_key = keys[-1]
for key in keys[:-1]:
object = object[key]
one_before_last_object = object
object = object[last_key]
if isinstance(object, str):
one_before_last_object[last_key] = object.format(**format_kwargs)
elif isinstance(object, list):
one_before_last_object[last_key] = [
item.format(**format_kwargs) for item in object
]
else:
raise ValueError(f"Unsupported type for object: {object}")
@transforms.add
def add_artifacts(config, tasks):
_get_timestamp(config)
version = config.params["version"]
nightly_version = get_nightly_version(config, version)
for task in tasks:
artifact_template = task.pop("artifact-template", {})
task["attributes"]["artifacts"] = artifacts = {}
component = task["attributes"]["component"]
build_artifact_definitions = task.setdefault("worker", {}).setdefault(
"artifacts", []
)
for key in [
"tests-artifact-template",
"lint-artifact-template",
"jacoco-coverage-template",
]:
if key in task:
optional_artifact_template = task.pop(key, {})
build_artifact_definitions.append(
{
"type": optional_artifact_template["type"],
"name": optional_artifact_template["name"],
"path": optional_artifact_template["path"].format(
component_path=get_path(component)
),
}
)
if artifact_template:
all_extensions = get_extensions(component)
artifact_file_names_per_extension = {
extension: "{component}-{version}{timestamp}{extension}".format(
component=component,
version=version,
timestamp="",
extension=extension,
)
for extension in all_extensions
}
# XXX: rather than adding more complex logic above, we simply post-adjust the
# dictionary for `nightly` types of graphs
if task["attributes"]["build-type"] == "nightly":
for ext, path in artifact_file_names_per_extension.items():
if version in path:
artifact_file_names_per_extension[ext] = path.replace(
version, nightly_version
)
for (
extension,
artifact_file_name,
) in artifact_file_names_per_extension.items():
artifact_full_name = artifact_template["name"].format(
artifact_file_name=artifact_file_name,
)
build_artifact_definitions.append(
{
"type": artifact_template["type"],
"name": artifact_full_name,
"path": artifact_template["path"].format(
component_path=get_path(component),
component=component,
version=craft_path_version(
version,
task["attributes"]["build-type"],
nightly_version,
),
artifact_file_name=artifact_file_name,
),
}
)
artifacts[extension] = artifact_full_name
yield task