Skip to content

Commit b83c8cb

Browse files
committed
feat(fetch): expose fetch-mode on git fetch tasks
Lets a kind opt into fetch-content's init_and_fetch mode for repos whose git server cannot serve a full clone. The flag and its digest entry are only added when the mode is not the default, so existing fetch tasks keep their command and their cached artifacts.
1 parent 1e696c9 commit b83c8cb

2 files changed

Lines changed: 97 additions & 0 deletions

File tree

‎src/taskgraph/transforms/fetch.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,11 @@ class GitFetchSchema(Schema, forbid_unknown_fields=False, kw_only=True):
281281
include_dot_git: Optional[bool] = None
282282
artifact_name: Optional[str] = None
283283
path_prefix: Optional[str] = None
284+
# How to populate the checkout. "clone" (the default) clones the repo,
285+
# "fetch" fetches only `revision` and leaves no branches or tags,
286+
# for git servers that cannot serve a full clone. See
287+
# https://bugzilla.mozilla.org/show_bug.cgi?id=2047876
288+
fetch_mode: Optional[Literal["clone", "fetch"]] = None
284289
# ssh-key is a taskcluster secret path (e.g. project/civet/github-deploy-key)
285290
# In the secret dictionary, the key should be specified as
286291
# "ssh_privkey": "-----BEGIN OPENSSH PRIVATE KEY-----\nkfksnb3jc..."
@@ -320,6 +325,11 @@ def create_git_fetch_task(config, name, fetch):
320325
args.append("--include-dot-git")
321326
digest_data.append(".git")
322327

328+
fetch_mode = fetch.get("fetch-mode")
329+
if fetch_mode and fetch_mode != "clone":
330+
args.extend(["--fetch-mode", fetch_mode])
331+
digest_data.append(f"fetch-mode={fetch_mode}")
332+
323333
return {
324334
"command": args,
325335
"artifact_name": artifact_name,

‎test/test_transforms_fetch.py‎

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@ def assert_static_url(task):
3131
assert task["attributes"]["fetch-artifact"] == "public/resource"
3232

3333

34+
GIT_REVISION = "0123456789abcdef0123456789abcdef01234567"
35+
36+
37+
def expected_git_command(*extra_args):
38+
return [
39+
"fetch-content",
40+
"git-checkout-archive",
41+
"--path-prefix",
42+
"repo",
43+
"https://example.com/repo",
44+
GIT_REVISION,
45+
"/builds/worker/artifacts/repo.tar.zst",
46+
*extra_args,
47+
]
48+
49+
50+
def assert_git(task):
51+
assert task["run"]["command"] == expected_git_command()
52+
53+
54+
def assert_git_fetch_mode_clone(task):
55+
assert task["run"]["command"] == expected_git_command()
56+
57+
58+
def assert_git_fetch_mode_fetch(task):
59+
assert task["run"]["command"] == expected_git_command("--fetch-mode", "fetch")
60+
61+
3462
@pytest.mark.parametrize(
3563
"task_input",
3664
(
@@ -48,6 +76,38 @@ def assert_static_url(task):
4876
},
4977
id="static-url",
5078
),
79+
pytest.param(
80+
{
81+
"fetch": {
82+
"type": "git",
83+
"repo": "https://example.com/repo",
84+
"revision": GIT_REVISION,
85+
},
86+
},
87+
id="git",
88+
),
89+
pytest.param(
90+
{
91+
"fetch": {
92+
"type": "git",
93+
"repo": "https://example.com/repo",
94+
"revision": GIT_REVISION,
95+
"fetch-mode": "clone",
96+
},
97+
},
98+
id="git-fetch-mode-clone",
99+
),
100+
pytest.param(
101+
{
102+
"fetch": {
103+
"type": "git",
104+
"repo": "https://example.com/repo",
105+
"revision": GIT_REVISION,
106+
"fetch-mode": "fetch",
107+
},
108+
},
109+
id="git-fetch-mode-fetch",
110+
),
51111
),
52112
)
53113
def test_transforms(request, run_transform, task_input):
@@ -62,3 +122,30 @@ def test_transforms(request, run_transform, task_input):
62122
param_id = request.node.callspec.id
63123
assertion_func = globals()[f"assert_{param_id.replace('-', '_')}"]
64124
assertion_func(task)
125+
126+
127+
@pytest.mark.parametrize(
128+
"fetch_mode,expected_extra_digest",
129+
(
130+
pytest.param(None, [], id="unset"),
131+
pytest.param("clone", [], id="clone"),
132+
pytest.param("fetch", ["fetch-mode=fetch"], id="fetch"),
133+
),
134+
)
135+
def test_git_fetch_mode_digest_data(fetch_mode, expected_extra_digest):
136+
fetch_config = {
137+
"type": "git",
138+
"repo": "https://example.com/repo",
139+
"revision": GIT_REVISION,
140+
}
141+
if fetch_mode:
142+
fetch_config["fetch-mode"] = fetch_mode
143+
144+
result = fetch.create_git_fetch_task(None, "fake-task-name", fetch_config)
145+
146+
assert result["digest_data"] == [
147+
GIT_REVISION,
148+
"repo",
149+
"repo.tar.zst",
150+
*expected_extra_digest,
151+
]

0 commit comments

Comments
 (0)