Skip to content

Commit 7bc741e

Browse files
committed
feat: support setting repo wide default values for cache selection
1 parent ee99fbf commit 7bc741e

File tree

8 files changed

+106
-65
lines changed

8 files changed

+106
-65
lines changed

packages/pytest-taskgraph/src/pytest_taskgraph/fixtures/gen.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,11 @@ def inner(
204204
if extra_params:
205205
parameters.update(extra_params)
206206
if extra_graph_config:
207-
graph_config._config.update(extra_graph_config)
207+
# We need this intermediate variable because `GraphConfig` is
208+
# frozen and we can't set attributes on it.
209+
new_graph_config = merge(graph_config._config, extra_graph_config)
210+
graph_config._config.update(new_graph_config)
211+
208212
return TransformConfig(
209213
"test",
210214
str(here),
@@ -220,12 +224,12 @@ def inner(
220224

221225
@pytest.fixture
222226
def run_transform(make_transform_config):
223-
def inner(func, tasks, config=None):
227+
def inner(func, tasks, config=None, **kwargs):
224228
if not isinstance(tasks, list):
225229
tasks = [tasks]
226230

227231
if not config:
228-
config = make_transform_config()
232+
config = make_transform_config(**kwargs)
229233
return list(func(config, tasks))
230234

231235
return inner

src/taskgraph/config.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from voluptuous import All, Any, Extra, Length, Optional, Required
1313

1414
from .util import path
15+
from .util.caches import CACHES
1516
from .util.python_path import find_object
1617
from .util.schema import Schema, optionally_keyed_by, validate_schema
1718
from .util.yaml import load_yaml
@@ -74,6 +75,16 @@
7475
"index-path-regexes",
7576
description="Regular expressions matching index paths to be summarized.",
7677
): [str],
78+
Optional(
79+
"run",
80+
description="Configuration related to the 'run' transforms.",
81+
): {
82+
Optional(
83+
"use-caches",
84+
description="List of caches to enable, or a boolean to "
85+
"enable/disable all of them.",
86+
): Any(bool, list(CACHES.keys())),
87+
},
7788
Required("repositories"): All(
7889
{
7990
str: {
@@ -106,8 +117,8 @@ def __getitem__(self, name):
106117
def __contains__(self, name):
107118
return name in self._config
108119

109-
def get(self, name):
110-
return self._config.get(name)
120+
def get(self, name, default=None):
121+
return self._config.get(name, default)
111122

112123
def register(self):
113124
"""

src/taskgraph/transforms/run/common.py

Lines changed: 10 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
consistency.
88
"""
99

10-
import hashlib
1110
import json
1211
from typing import Any, Dict, List, Union
1312

1413
from taskgraph.transforms.base import TransformConfig
1514
from taskgraph.util import path
15+
from taskgraph.util.caches import CACHES, get_checkout_dir
1616
from taskgraph.util.taskcluster import get_artifact_prefix
1717

1818

@@ -23,54 +23,6 @@ def get_vcsdir_name(os):
2323
return "vcs"
2424

2525

26-
def get_checkout_dir(task: Dict[str, Any]) -> str:
27-
worker = task["worker"]
28-
if worker["os"] == "windows":
29-
return "build"
30-
elif worker["implementation"] == "docker-worker":
31-
return f"{task['run']['workdir']}/checkouts"
32-
else:
33-
return "checkouts"
34-
35-
36-
def get_checkout_cache_name(config: TransformConfig, task: Dict[str, Any]) -> str:
37-
repo_configs = config.repo_configs
38-
cache_name = "checkouts"
39-
40-
# Robust checkout does not clean up subrepositories, so ensure that tasks
41-
# that checkout different sets of paths have separate caches.
42-
# See https://bugzilla.mozilla.org/show_bug.cgi?id=1631610
43-
if len(repo_configs) > 1:
44-
checkout_paths = {
45-
"\t".join([repo_config.path, repo_config.prefix])
46-
for repo_config in sorted(
47-
repo_configs.values(), key=lambda repo_config: repo_config.path
48-
)
49-
}
50-
checkout_paths_str = "\n".join(checkout_paths).encode("utf-8")
51-
digest = hashlib.sha256(checkout_paths_str).hexdigest()
52-
cache_name += f"-repos-{digest}"
53-
54-
# Sparse checkouts need their own cache because they can interfere
55-
# with clients that aren't sparse aware.
56-
if task["run"]["sparse-profile"]:
57-
cache_name += "-sparse"
58-
59-
return cache_name
60-
61-
62-
CACHES = {
63-
"cargo": {"env": "CARGO_HOME"},
64-
"checkout": {
65-
"cache_dir": get_checkout_dir,
66-
"cache_name": get_checkout_cache_name,
67-
},
68-
"npm": {"env": "npm_config_cache"},
69-
"pip": {"env": "PIP_CACHE_DIR"},
70-
"uv": {"env": "UV_CACHE_DIR"},
71-
}
72-
73-
7426
def add_cache(task, taskdesc, name, mount_point, skip_untrusted=False):
7527
"""Adds a cache based on the worker's implementation.
7628
@@ -216,8 +168,15 @@ def support_caches(
216168
workdir = workdir or "/builds/worker"
217169
base_cache_dir = path.join(workdir, base_cache_dir)
218170

219-
# Default to checkout cache if no selection is specified.
220-
use_caches = run.get("use-caches", ["checkout"])
171+
use_caches = run.get("use-caches")
172+
if use_caches is None:
173+
# Use project default values for filtering caches, default to
174+
# checkout cache if no selection is specified.
175+
use_caches = (
176+
config.graph_config.get("taskgraph", {})
177+
.get("run", {})
178+
.get("use-caches", ["checkout"])
179+
)
221180

222181
for name, cache_cfg in CACHES.items():
223182
if not should_use_cache(name, use_caches, run["checkout"]):

src/taskgraph/transforms/run/run_task.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212

1313
from taskgraph.transforms.run import run_task_using
1414
from taskgraph.transforms.run.common import (
15-
CACHES,
1615
support_caches,
1716
support_vcs_checkout,
1817
)
1918
from taskgraph.transforms.task import taskref_or_string
2019
from taskgraph.util import path, taskcluster
20+
from taskgraph.util.caches import CACHES
2121
from taskgraph.util.schema import Schema
2222

2323
EXEC_COMMANDS = {

src/taskgraph/util/caches.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
import hashlib
6+
from typing import TYPE_CHECKING, Any, Dict
7+
8+
if TYPE_CHECKING:
9+
from taskgraph.transforms.base import TransformConfig
10+
11+
12+
def get_checkout_dir(task: Dict[str, Any]) -> str:
13+
worker = task["worker"]
14+
if worker["os"] == "windows":
15+
return "build"
16+
elif worker["implementation"] == "docker-worker":
17+
return f"{task['run']['workdir']}/checkouts"
18+
else:
19+
return "checkouts"
20+
21+
22+
def get_checkout_cache_name(config: "TransformConfig", task: Dict[str, Any]) -> str:
23+
repo_configs = config.repo_configs
24+
cache_name = "checkouts"
25+
26+
# Robust checkout does not clean up subrepositories, so ensure that tasks
27+
# that checkout different sets of paths have separate caches.
28+
# See https://bugzilla.mozilla.org/show_bug.cgi?id=1631610
29+
if len(repo_configs) > 1:
30+
checkout_paths = {
31+
"\t".join([repo_config.path, repo_config.prefix])
32+
for repo_config in sorted(
33+
repo_configs.values(), key=lambda repo_config: repo_config.path
34+
)
35+
}
36+
checkout_paths_str = "\n".join(checkout_paths).encode("utf-8")
37+
digest = hashlib.sha256(checkout_paths_str).hexdigest()
38+
cache_name += f"-repos-{digest}"
39+
40+
# Sparse checkouts need their own cache because they can interfere
41+
# with clients that aren't sparse aware.
42+
if task["run"]["sparse-profile"]:
43+
cache_name += "-sparse"
44+
45+
return cache_name
46+
47+
48+
CACHES = {
49+
"cargo": {"env": "CARGO_HOME"},
50+
"checkout": {
51+
"cache_dir": get_checkout_dir,
52+
"cache_name": get_checkout_cache_name,
53+
},
54+
"npm": {"env": "npm_config_cache"},
55+
"pip": {"env": "PIP_CACHE_DIR"},
56+
"uv": {"env": "UV_CACHE_DIR"},
57+
}

taskcluster/docker/python/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ FROM debian:bookworm-slim
66
LABEL maintainer="Release Engineering <release@mozilla.com>"
77

88
VOLUME /builds/worker/checkouts
9-
VOLUME /builds/worker/.cache
9+
VOLUME /builds/worker/.task-cache/uv
1010

1111
# Add worker user
1212
RUN mkdir -p /builds && \

test/test_transforms_run.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ def transform(monkeypatch, run_transform):
4343
# Needed by 'generic_worker_run_task'
4444
monkeypatch.setenv("TASK_ID", "fakeid")
4545

46-
def inner(task_input):
46+
def inner(task_input, **kwargs):
4747
defaults = deepcopy(TASK_DEFAULTS)
4848
task = merge(defaults, task_input)
4949

5050
with patch("taskgraph.transforms.run.configure_taskdesc_for_run") as m:
5151
# This forces the generator to be evaluated
52-
run_transform(run.transforms, task)
52+
run_transform(run.transforms, task, **kwargs)
5353
return m.call_args[0]
5454

5555
return inner

test/test_transforms_run_run_task.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
import pytest
99

1010
from taskgraph.transforms.run import make_task_description
11-
from taskgraph.transforms.run.common import CACHES
1211
from taskgraph.transforms.task import payload_builders
12+
from taskgraph.util.caches import CACHES
1313
from taskgraph.util.schema import Schema, validate_schema
1414
from taskgraph.util.templates import merge
1515

@@ -36,9 +36,9 @@ def run_task_using(mocker, run_transform):
3636
"taskcluster/scripts/toolchain/run.ps1",
3737
]
3838

39-
def inner(task):
39+
def inner(task, **kwargs):
4040
task = merge(TASK_DEFAULTS, task)
41-
return run_transform(make_task_description, task)[0]
41+
return run_transform(make_task_description, task, **kwargs)[0]
4242

4343
return inner
4444

@@ -225,12 +225,12 @@ def test_run_task(monkeypatch, request, run_task_using, task):
225225

226226
@pytest.fixture
227227
def run_caches(run_task_using):
228-
def inner(task):
228+
def inner(task, **kwargs):
229229
task.setdefault("run", {}).setdefault("using", "run-task")
230230
impl = task.setdefault("worker", {}).setdefault(
231231
"implementation", "generic-worker"
232232
)
233-
result = run_task_using(task)
233+
result = run_task_using(task, **kwargs)
234234

235235
key = "mounts" if impl == "generic-worker" else "caches"
236236

@@ -281,3 +281,13 @@ def test_caches_explicit(run_caches):
281281
assert run_caches(task) == [
282282
{"cache-name": "cargo", "directory": "/builds/worker/.task-cache/cargo"}
283283
]
284+
285+
286+
def test_caches_project_explicit(run_caches):
287+
caches = run_caches(
288+
{},
289+
extra_graph_config={"taskgraph": {"run": {"use-caches": ["cargo"]}}},
290+
)
291+
assert caches == [
292+
{"cache-name": "cargo", "directory": "/builds/worker/.task-cache/cargo"}
293+
]

0 commit comments

Comments
 (0)