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"""
6Utilities for generating a decision task from :file:`.taskcluster.yml`.
7"""
8
9
10import jsone
11import yaml
12import os
13import slugid
14
15from .vcs import find_hg_revision_push_info
16from .templates import merge
17from .time import current_json_time
18
19
20def make_decision_task(params, root, context, head_rev=None):
21    """Generate a basic decision task, based on the root .taskcluster.yml"""
22    with open(os.path.join(root, ".taskcluster.yml"), "rb") as f:
23        taskcluster_yml = yaml.safe_load(f)
24
25    if not head_rev:
26        head_rev = params["head_rev"]
27
28    if params["repository_type"] == "hg":
29        pushlog = find_hg_revision_push_info(params["repository_url"], head_rev)
30
31        hg_push_context = {
32            "pushlog_id": pushlog["pushid"],
33            "pushdate": pushlog["pushdate"],
34            "owner": pushlog["user"],
35        }
36    else:
37        hg_push_context = {}
38
39    slugids = {}
40
41    def as_slugid(name):
42        # https://github.com/taskcluster/json-e/issues/164
43        name = name[0]
44        if name not in slugids:
45            slugids[name] = slugid.nice()
46        return slugids[name]
47
48    # provide a similar JSON-e context to what mozilla-taskcluster provides:
49    # https://docs.taskcluster.net/reference/integrations/mozilla-taskcluster/docs/taskcluster-yml
50    # but with a different tasks_for and an extra `cron` section
51    context = merge(
52        {
53            "repository": {
54                "url": params["repository_url"],
55                "project": params["project"],
56                "level": params["level"],
57            },
58            "push": merge(
59                {
60                    "revision": params["head_rev"],
61                    # remainder are fake values, but the decision task expects them anyway
62                    "comment": " ",
63                },
64                hg_push_context,
65            ),
66            "now": current_json_time(),
67            "as_slugid": as_slugid,
68        },
69        context,
70    )
71
72    rendered = jsone.render(taskcluster_yml, context)
73    if len(rendered["tasks"]) != 1:
74        raise Exception("Expected .taskcluster.yml to only produce one cron task")
75    task = rendered["tasks"][0]
76
77    task_id = task.pop("taskId")
78    return (task_id, task)
79