# 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 # file, You can obtain one at http://mozilla.org/MPL/2.0/. import os from taskcluster.exceptions import TaskclusterRestFailure from taskgraph.parameters import Parameters from taskgraph.taskgraph import TaskGraph from taskgraph.util.taskcluster import get_artifact, list_task_group_incomplete_tasks from gecko_taskgraph.actions.registry import register_callback_action from gecko_taskgraph.decision import taskgraph_decision from gecko_taskgraph.util.partials import populate_release_history from gecko_taskgraph.util.taskgraph import ( find_decision_task, find_existing_tasks_from_previous_kinds, ) @register_callback_action( name="nightly-build-tasks", title="Run Nightly Builds Tasks", symbol="nbt", description="Runs tasks associated with Nightly builds. Exists solely to make it possible to test Nightly-specific tasks and behaviours on Try, where it is not viable to run these things through cron hooks.", order=500, context=[], available=lambda params: params["project"] == "try", schema=lambda graph_config: { "type": "object", "properties": { "do_not_optimize": { "type": "array", "description": ( "Optional: a list of labels to avoid optimizing out " "of the graph (to force a rerun of, say, " "funsize docker-image tasks)." ), "items": { "type": "string", }, }, "rebuild_kinds": { "type": "array", "description": ( "Optional: an array of kinds to ignore from the previous graph(s)." ), "default": graph_config["release-promotion"].get("rebuild-kinds", []), "items": { "type": "string", }, }, "previous_graph_ids": { "type": "array", "description": ( "Optional: an array of taskIds of decision or action " "tasks from the previous graph(s) to use to populate " "our `previous_graph_kinds`." ), "items": { "type": "string", }, }, }, }, ) def run_nightly_builds_action(parameters, graph_config, input, task_group_id, task_id): rebuild_kinds = input.get("rebuild_kinds", []) do_not_optimize = input.get("do_not_optimize", []) # Make sure no pending tasks remain from a previous run own_task_id = os.environ.get("TASK_ID", "") try: for t in list_task_group_incomplete_tasks(own_task_id): if t == own_task_id: continue raise Exception( f"task group has unexpected pre-existing incomplete tasks (e.g. {t})" ) except TaskclusterRestFailure as e: # 404 means the task group doesn't exist yet, and we're fine if e.status_code != 404: raise previous_graph_ids = input.get("previous_graph_ids") if not previous_graph_ids: previous_graph_ids = [find_decision_task(parameters, graph_config)] # Download parameters from the first decision task parameters = get_artifact(previous_graph_ids[0], "public/parameters.yml") # Download and combine full task graphs from each of the previous_graph_ids. # Sometimes previous relpro action tasks will add tasks, like partials, # that didn't exist in the first full_task_graph, so combining them is # important. The rightmost graph should take precedence in the case of # conflicts. combined_full_task_graph = {} for graph_id in previous_graph_ids: full_task_graph = get_artifact(graph_id, "public/full-task-graph.json") combined_full_task_graph.update(full_task_graph) _, combined_full_task_graph = TaskGraph.from_json(combined_full_task_graph) parameters["existing_tasks"] = find_existing_tasks_from_previous_kinds( combined_full_task_graph, previous_graph_ids, rebuild_kinds ) parameters["do_not_optimize"] = do_not_optimize parameters["target_tasks_method"] = "nightly_all" parameters["release_history"] = populate_release_history( "Firefox", "mozilla-central" ) # When doing staging releases on try, we still want to re-use tasks from # previous graphs. parameters["optimize_target_tasks"] = True # make parameters read-only parameters = Parameters(**parameters) taskgraph_decision({"root": graph_config.root_dir}, parameters=parameters)