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
6import sys
7
8import requests
9
10from taskgraph.parameters import Parameters
11from taskgraph.util.taskcluster import find_task_id, get_artifact, get_session
12from taskgraph.util.taskgraph import find_existing_tasks
13
14from ..cli import BaseTryParser
15from ..push import push_to_try
16
17TASK_TYPES = {
18    "linux-signing": [
19        "build-signing-linux-shippable/opt",
20        "build-signing-linux64-shippable/opt",
21        "build-signing-win64-shippable/opt",
22        "build-signing-win32-shippable/opt",
23        "repackage-signing-win64-shippable/opt",
24        "repackage-signing-win32-shippable/opt",
25        "repackage-signing-msi-win32-shippable/opt",
26        "repackage-signing-msi-win64-shippable/opt",
27        "mar-signing-linux64-shippable/opt",
28    ],
29    "linux-signing-partial": ["partials-signing-linux64-shippable/opt"],
30    "mac-signing": ["build-signing-macosx64-shippable/opt"],
31    "beetmover-candidates": ["beetmover-repackage-linux64-shippable/opt"],
32    "bouncer-submit": ["release-bouncer-sub-firefox"],
33    "balrog-submit": [
34        "release-balrog-submit-toplevel-firefox",
35        "balrog-linux64-shippable/opt",
36    ],
37    "tree": ["release-early-tagging-firefox", "release-version-bump-firefox"],
38}
39
40RELEASE_TO_BRANCH = {
41    "beta": "releases/mozilla-beta",
42    "release": "releases/mozilla-release",
43}
44
45
46class ScriptworkerParser(BaseTryParser):
47    name = "scriptworker"
48    arguments = [
49        [
50            ["task_type"],
51            {
52                "choices": ["list"] + list(TASK_TYPES.keys()),
53                "metavar": "TASK-TYPE",
54                "help": "Scriptworker task types to run. (Use `list` to show possibilities)",
55            },
56        ],
57        [
58            ["--release-type"],
59            {
60                "choices": ["nightly"] + list(RELEASE_TO_BRANCH.keys()),
61                "default": "beta",
62                "help": "Release type to run",
63            },
64        ],
65    ]
66
67    common_groups = ["push"]
68    task_configs = ["worker-overrides", "routes"]
69
70
71def get_releases(branch):
72    response = requests.get(
73        "https://shipitapi-public.services.mozilla.com/releases",
74        params={"product": "firefox", "branch": branch, "status": "shipped"},
75        headers={"Accept": "application/json"},
76    )
77    response.raise_for_status()
78    return response.json()
79
80
81def get_release_graph(release):
82    for phase in release["phases"]:
83        if phase["name"] in ("ship_firefox",):
84            return phase["actionTaskId"]
85    raise Exception("No ship phase.")
86
87
88def get_nightly_graph():
89    return find_task_id(
90        "gecko.v2.mozilla-central.latest.taskgraph.decision-nightly-desktop"
91    )
92
93
94def print_available_task_types():
95    print("Available task types:")
96    for task_type, tasks in TASK_TYPES.items():
97        print(" " * 4 + "{}:".format(task_type))
98        for task in tasks:
99            print(" " * 8 + "- {}".format(task))
100
101
102def get_hg_file(parameters, path):
103    session = get_session()
104    response = session.get(parameters.file_url(path))
105    response.raise_for_status()
106    return response.content
107
108
109def run(
110    task_type,
111    release_type,
112    try_config=None,
113    push=True,
114    message="{msg}",
115    closed_tree=False,
116):
117    if task_type == "list":
118        print_available_task_types()
119        sys.exit(0)
120
121    if release_type == "nightly":
122        previous_graph = get_nightly_graph()
123    else:
124        release = get_releases(RELEASE_TO_BRANCH[release_type])[-1]
125        previous_graph = get_release_graph(release)
126    existing_tasks = find_existing_tasks([previous_graph])
127
128    previous_parameters = Parameters(
129        strict=False, **get_artifact(previous_graph, "public/parameters.yml")
130    )
131
132    # Copy L10n configuration from the commit the release we are using was
133    # based on. This *should* ensure that the chunking of L10n tasks is the
134    # same between graphs.
135    files_to_change = {
136        path: get_hg_file(previous_parameters, path)
137        for path in [
138            "browser/locales/l10n-changesets.json",
139            "browser/locales/shipped-locales",
140        ]
141    }
142
143    try_config = try_config or {}
144    task_config = {
145        "version": 2,
146        "parameters": {
147            "existing_tasks": existing_tasks,
148            "try_task_config": try_config,
149            "try_mode": "try_task_config",
150        },
151    }
152    for param in (
153        "app_version",
154        "build_number",
155        "next_version",
156        "release_history",
157        "release_product",
158        "release_type",
159        "version",
160    ):
161        task_config["parameters"][param] = previous_parameters[param]
162
163    try_config["tasks"] = TASK_TYPES[task_type]
164    for label in try_config["tasks"]:
165        if label in existing_tasks:
166            del existing_tasks[label]
167
168    msg = "scriptworker tests: {}".format(task_type)
169    return push_to_try(
170        "scriptworker",
171        message.format(msg=msg),
172        push=push,
173        closed_tree=closed_tree,
174        try_task_config=task_config,
175        files_to_change=files_to_change,
176    )
177